diff options
Diffstat (limited to 'drivers')
3125 files changed, 47962 insertions, 34556 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index e8231663f201..61cf4ea2c229 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -188,8 +188,6 @@ source "drivers/ipack/Kconfig" source "drivers/reset/Kconfig" -source "drivers/fmc/Kconfig" - source "drivers/phy/Kconfig" source "drivers/powercap/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 28b030d7988d..6d37564e783c 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -168,7 +168,6 @@ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_IPACK_BUS) += ipack/ obj-$(CONFIG_NTB) += ntb/ -obj-$(CONFIG_FMC) += fmc/ obj-$(CONFIG_POWERCAP) += powercap/ obj-$(CONFIG_MCB) += mcb/ obj-$(CONFIG_PERF_EVENTS) += perf/ diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 283ee94224c6..4e1e517a33bc 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -155,7 +155,6 @@ config ACPI_EC_DEBUGFS config ACPI_AC tristate "AC Adapter" - depends on X86 select POWER_SUPPLY default y help @@ -168,7 +167,6 @@ config ACPI_AC config ACPI_BATTERY tristate "Battery" - depends on X86 select POWER_SUPPLY default y help diff --git a/drivers/acpi/acpi_amba.c b/drivers/acpi/acpi_amba.c index 7f77c071709a..8159f0a669b8 100644 --- a/drivers/acpi/acpi_amba.c +++ b/drivers/acpi/acpi_amba.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ACPI support for platform bus type. * * Copyright (C) 2015, Linaro Ltd * Author: Graeme Gregory <graeme.gregory@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index c16f9460c4a2..7cd0c9ac71ea 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD ACPI support for ACPI2platform device. * * Copyright (c) 2014,2015 AMD Corporation. * Authors: Ken Xue <Ken.Xue@amd.com> * Wu, Jeff <Jeff.Wu@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk-provider.h> @@ -60,7 +57,7 @@ struct apd_private_data { static int acpi_apd_setup(struct apd_private_data *pdata) { const struct apd_device_desc *dev_desc = pdata->dev_desc; - struct clk *clk = ERR_PTR(-ENODEV); + struct clk *clk; if (dev_desc->fixed_clk_rate) { clk = clk_register_fixed_rate(&pdata->adev->dev, diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c index 0980a133916f..33ac6cb428fe 100644 --- a/drivers/acpi/acpi_cmos_rtc.c +++ b/drivers/acpi/acpi_cmos_rtc.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ACPI support for CMOS RTC Address Space access * * Copyright (C) 2013, Intel Corporation * Authors: Lan Tianyu <tianyu.lan@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/acpi/acpi_configfs.c b/drivers/acpi/acpi_configfs.c index f92033661239..57d9d574d4dd 100644 --- a/drivers/acpi/acpi_configfs.c +++ b/drivers/acpi/acpi_configfs.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ACPI configfs support * * Copyright (c) 2016 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #define pr_fmt(fmt) "ACPI configfs: " fmt @@ -56,11 +53,7 @@ static ssize_t acpi_table_aml_write(struct config_item *cfg, if (!table->header) return -ENOMEM; - ACPI_INFO(("Host-directed Dynamic ACPI Table Load:")); - ret = acpi_tb_install_and_load_table( - ACPI_PTR_TO_PHYSADDR(table->header), - ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, FALSE, - &table->index); + ret = acpi_load_table(table->header); if (ret) { kfree(table->header); table->header = NULL; diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c index d18246a2a65e..7a265c2171c0 100644 --- a/drivers/acpi/acpi_dbg.c +++ b/drivers/acpi/acpi_dbg.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ACPI AML interfacing support * * Copyright (C) 2015, Intel Corporation * Authors: Lv Zheng <lv.zheng@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /* #define DEBUG */ diff --git a/drivers/acpi/acpi_lpit.c b/drivers/acpi/acpi_lpit.c index 6116b0fb86d4..433376e819bb 100644 --- a/drivers/acpi/acpi_lpit.c +++ b/drivers/acpi/acpi_lpit.c @@ -129,7 +129,7 @@ static void lpit_update_residency(struct lpit_residency_info *info, static void lpit_process(u64 begin, u64 end) { - while (begin + sizeof(struct acpi_lpit_native) < end) { + while (begin + sizeof(struct acpi_lpit_native) <= end) { struct acpi_lpit_native *lpit_native = (struct acpi_lpit_native *)begin; if (!lpit_native->header.type && !lpit_native->header.flags) { @@ -148,7 +148,6 @@ static void lpit_process(u64 begin, u64 end) void acpi_init_lpit(void) { acpi_status status; - u64 lpit_begin; struct acpi_table_lpit *lpit; status = acpi_get_table(ACPI_SIG_LPIT, 0, (struct acpi_table_header **)&lpit); @@ -156,6 +155,6 @@ void acpi_init_lpit(void) if (ACPI_FAILURE(status)) return; - lpit_begin = (u64)lpit + sizeof(*lpit); - lpit_process(lpit_begin, lpit_begin + lpit->header.length); + lpit_process((u64)lpit + sizeof(*lpit), + (u64)lpit + lpit->header.length); } diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index cf768608437e..398451839178 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ACPI support for Intel Lynxpoint LPSS. * * Copyright (C) 2013, Intel Corporation * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> * Rafael J. Wysocki <rafael.j.wysocki@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> @@ -1064,6 +1061,13 @@ static int acpi_lpss_suspend_noirq(struct device *dev) int ret; if (pdata->dev_desc->resume_from_noirq) { + /* + * The driver's ->suspend_late callback will be invoked by + * acpi_lpss_do_suspend_late(), with the assumption that the + * driver really wanted to run that code in ->suspend_noirq, but + * it could not run after acpi_dev_suspend() and the driver + * expected the latter to be called in the "late" phase. + */ ret = acpi_lpss_do_suspend_late(dev); if (ret) return ret; @@ -1094,16 +1098,99 @@ static int acpi_lpss_resume_noirq(struct device *dev) struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); int ret; - ret = acpi_subsys_resume_noirq(dev); + /* Follow acpi_subsys_resume_noirq(). */ + if (dev_pm_may_skip_resume(dev)) + return 0; + + if (dev_pm_smart_suspend_and_suspended(dev)) + pm_runtime_set_active(dev); + + ret = pm_generic_resume_noirq(dev); if (ret) return ret; - if (!dev_pm_may_skip_resume(dev) && pdata->dev_desc->resume_from_noirq) - ret = acpi_lpss_do_resume_early(dev); + if (!pdata->dev_desc->resume_from_noirq) + return 0; - return ret; + /* + * The driver's ->resume_early callback will be invoked by + * acpi_lpss_do_resume_early(), with the assumption that the driver + * really wanted to run that code in ->resume_noirq, but it could not + * run before acpi_dev_resume() and the driver expected the latter to be + * called in the "early" phase. + */ + return acpi_lpss_do_resume_early(dev); +} + +static int acpi_lpss_do_restore_early(struct device *dev) +{ + int ret = acpi_lpss_resume(dev); + + return ret ? ret : pm_generic_restore_early(dev); +} + +static int acpi_lpss_restore_early(struct device *dev) +{ + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + + if (pdata->dev_desc->resume_from_noirq) + return 0; + + return acpi_lpss_do_restore_early(dev); +} + +static int acpi_lpss_restore_noirq(struct device *dev) +{ + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + int ret; + + ret = pm_generic_restore_noirq(dev); + if (ret) + return ret; + + if (!pdata->dev_desc->resume_from_noirq) + return 0; + + /* This is analogous to what happens in acpi_lpss_resume_noirq(). */ + return acpi_lpss_do_restore_early(dev); +} + +static int acpi_lpss_do_poweroff_late(struct device *dev) +{ + int ret = pm_generic_poweroff_late(dev); + + return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev)); } +static int acpi_lpss_poweroff_late(struct device *dev) +{ + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + + if (dev_pm_smart_suspend_and_suspended(dev)) + return 0; + + if (pdata->dev_desc->resume_from_noirq) + return 0; + + return acpi_lpss_do_poweroff_late(dev); +} + +static int acpi_lpss_poweroff_noirq(struct device *dev) +{ + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + + if (dev_pm_smart_suspend_and_suspended(dev)) + return 0; + + if (pdata->dev_desc->resume_from_noirq) { + /* This is analogous to the acpi_lpss_suspend_noirq() case. */ + int ret = acpi_lpss_do_poweroff_late(dev); + if (ret) + return ret; + } + + return pm_generic_poweroff_noirq(dev); +} #endif /* CONFIG_PM_SLEEP */ static int acpi_lpss_runtime_suspend(struct device *dev) @@ -1137,14 +1224,11 @@ static struct dev_pm_domain acpi_lpss_pm_domain = { .resume_noirq = acpi_lpss_resume_noirq, .resume_early = acpi_lpss_resume_early, .freeze = acpi_subsys_freeze, - .freeze_late = acpi_subsys_freeze_late, - .freeze_noirq = acpi_subsys_freeze_noirq, - .thaw_noirq = acpi_subsys_thaw_noirq, - .poweroff = acpi_subsys_suspend, - .poweroff_late = acpi_lpss_suspend_late, - .poweroff_noirq = acpi_lpss_suspend_noirq, - .restore_noirq = acpi_lpss_resume_noirq, - .restore_early = acpi_lpss_resume_early, + .poweroff = acpi_subsys_poweroff, + .poweroff_late = acpi_lpss_poweroff_late, + .poweroff_noirq = acpi_lpss_poweroff_noirq, + .restore_noirq = acpi_lpss_restore_noirq, + .restore_early = acpi_lpss_restore_early, #endif .runtime_suspend = acpi_lpss_runtime_suspend, .runtime_resume = acpi_lpss_runtime_resume, diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 6b3f1217a237..e7dc0133f817 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -64,6 +64,7 @@ static void power_saving_mwait_init(void) case X86_VENDOR_HYGON: case X86_VENDOR_AMD: case X86_VENDOR_INTEL: + case X86_VENDOR_ZHAOXIN: /* * AMD Fam10h TSC will tick in all * C/P/S0/S1 states when this bit is set. diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 1f32caa87686..00ec4f2bf015 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ACPI support for platform bus type. * @@ -5,10 +6,6 @@ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> * Mathias Nyman <mathias.nyman@linux.intel.com> * Rafael J. Wysocki <rafael.j.wysocki@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c index 67d97c0090a2..f3039b93ff61 100644 --- a/drivers/acpi/acpi_pnp.c +++ b/drivers/acpi/acpi_pnp.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ACPI support for PNP bus type * * Copyright (C) 2014, Intel Corporation * Authors: Zhang Rui <rui.zhang@intel.com> * Rafael J. Wysocki <rafael.j.wysocki@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index fc447410ae4d..24f065114d42 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * acpi_processor.c - ACPI processor enumeration support * @@ -7,10 +8,6 @@ * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> * Copyright (C) 2013, Intel Corporation * Rafael J. Wysocki <rafael.j.wysocki@intel.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/acpi/acpi_watchdog.c b/drivers/acpi/acpi_watchdog.c index 95600309ce42..b5516b04ffc0 100644 --- a/drivers/acpi/acpi_watchdog.c +++ b/drivers/acpi/acpi_watchdog.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ACPI watchdog table parsing support. * * Copyright (C) 2016, Intel Corporation * Author: Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "ACPI: watchdog: " fmt diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 831660179662..c8652f91054e 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -69,7 +69,8 @@ acpi_status acpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked); acpi_status -acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); +acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info, + u8 clear_on_enable); acpi_status acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index d056a1845613..fd3beea93421 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -178,7 +178,6 @@ ACPI_GLOBAL(u8, acpi_gbl_verbose_leak_dump); ACPI_GLOBAL(struct acpi_namespace_node, acpi_gbl_root_node_struct); ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_root_node); ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_fadt_gpe_device); -ACPI_GLOBAL(union acpi_operand_object *, acpi_gbl_module_code_list); extern const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES]; extern const struct acpi_predefined_names diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 39812fc4386a..7da1864798a0 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -207,8 +207,6 @@ acpi_ns_dump_object_paths(acpi_object_type type, */ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info); -void acpi_ns_exec_module_code_list(void); - /* * nsarguments - Argument count/type checking for predefined/reserved names */ diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index 4ebd23700bbc..a1ffed29903b 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -202,7 +202,7 @@ acpi_ds_initialize_objects(u32 table_index, if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_DSDT)) { ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, - "\nInitializing Namespace objects:\n")); + "\nACPI table initialization:\n")); } /* Summary of objects initialized */ diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 62d3aa74277b..344feba29063 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -146,6 +146,7 @@ acpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked) * FUNCTION: acpi_ev_add_gpe_reference * * PARAMETERS: gpe_event_info - Add a reference to this GPE + * clear_on_enable - Clear GPE status before enabling it * * RETURN: Status * @@ -155,7 +156,8 @@ acpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked) ******************************************************************************/ acpi_status -acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) +acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info, + u8 clear_on_enable) { acpi_status status = AE_OK; @@ -170,6 +172,10 @@ acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) /* Enable on first reference */ + if (clear_on_enable) { + (void)acpi_hw_clear_gpe(gpe_event_info); + } + status = acpi_ev_update_gpe_enable_mask(gpe_event_info); if (ACPI_SUCCESS(status)) { status = acpi_ev_enable_gpe(gpe_event_info); diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 328d1d6123ad..fb15e9e2373b 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -453,7 +453,7 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, continue; } - status = acpi_ev_add_gpe_reference(gpe_event_info); + status = acpi_ev_add_gpe_reference(gpe_event_info, FALSE); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not enable GPE 0x%02X", diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 3df00eb6621b..279ef0557aa3 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -971,7 +971,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, ACPI_GPE_DISPATCH_METHOD) || (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == ACPI_GPE_DISPATCH_NOTIFY)) && handler->originally_enabled) { - (void)acpi_ev_add_gpe_reference(gpe_event_info); + (void)acpi_ev_add_gpe_reference(gpe_event_info, FALSE); if (ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) { /* Poll edge triggered GPEs to handle existing events */ diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 30a083902f52..710488ec59e9 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -108,7 +108,7 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) if (gpe_event_info) { if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != ACPI_GPE_DISPATCH_NONE) { - status = acpi_ev_add_gpe_reference(gpe_event_info); + status = acpi_ev_add_gpe_reference(gpe_event_info, TRUE); if (ACPI_SUCCESS(status) && ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) { diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 587aeeeb5070..58c04d706723 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -174,12 +174,9 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, return_ACPI_STATUS(status); } - /* Complete the initialization/resolution of package objects */ + /* Complete the initialization/resolution of new objects */ - status = acpi_ns_walk_namespace(ACPI_TYPE_PACKAGE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, 0, - acpi_ns_init_one_package, NULL, NULL, - NULL); + acpi_ns_initialize_objects(); /* Parameter Data (optional) */ @@ -437,12 +434,11 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(status); } - /* Complete the initialization/resolution of package objects */ + /* Complete the initialization/resolution of new objects */ - status = acpi_ns_walk_namespace(ACPI_TYPE_PACKAGE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, 0, - acpi_ns_init_one_package, NULL, NULL, - NULL); + acpi_ex_exit_interpreter(); + acpi_ns_initialize_objects(); + acpi_ex_enter_interpreter(); /* Store the ddb_handle into the Target operand */ diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 7b855603f81a..2566e2d4c780 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -36,6 +36,7 @@ acpi_status acpi_ns_root_initialize(void) acpi_status status; const struct acpi_predefined_names *init_val = NULL; struct acpi_namespace_node *new_node; + struct acpi_namespace_node *prev_node = NULL; union acpi_operand_object *obj_desc; acpi_string val = NULL; @@ -61,12 +62,28 @@ acpi_status acpi_ns_root_initialize(void) */ acpi_gbl_root_node = &acpi_gbl_root_node_struct; - /* Enter the pre-defined names in the name table */ + /* Enter the predefined names in the name table */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Entering predefined entries into namespace\n")); + /* + * Create the initial (default) namespace. + * This namespace looks like something similar to this: + * + * ACPI Namespace (from Namespace Root): + * 0 _GPE Scope 00203160 00 + * 0 _PR_ Scope 002031D0 00 + * 0 _SB_ Device 00203240 00 Notify Object: 0020ADD8 + * 0 _SI_ Scope 002032B0 00 + * 0 _TZ_ Device 00203320 00 + * 0 _REV Integer 00203390 00 = 0000000000000002 + * 0 _OS_ String 00203488 00 Len 14 "Microsoft Windows NT" + * 0 _GL_ Mutex 00203580 00 Object 002035F0 + * 0 _OSI Method 00203678 00 Args 1 Len 0000 Aml 00000000 + */ for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) { + status = AE_OK; /* _OSI is optional for now, will be permanent later */ @@ -75,17 +92,32 @@ acpi_status acpi_ns_root_initialize(void) continue; } - status = - acpi_ns_lookup(NULL, ACPI_CAST_PTR(char, init_val->name), - init_val->type, ACPI_IMODE_LOAD_PASS2, - ACPI_NS_NO_UPSEARCH, NULL, &new_node); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not create predefined name %s", - init_val->name)); - continue; + /* + * Create, init, and link the new predefined name + * Note: No need to use acpi_ns_lookup here because all the + * predefined names are at the root level. It is much easier to + * just create and link the new node(s) here. + */ + new_node = + ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_namespace_node)); + if (!new_node) { + status = AE_NO_MEMORY; + goto unlock_and_exit; } + ACPI_COPY_NAMESEG(new_node->name.ascii, init_val->name); + new_node->descriptor_type = ACPI_DESC_TYPE_NAMED; + new_node->type = init_val->type; + + if (!prev_node) { + acpi_gbl_root_node_struct.child = new_node; + } else { + prev_node->peer = new_node; + } + + new_node->parent = &acpi_gbl_root_node_struct; + prev_node = new_node; + /* * Name entered successfully. If entry in pre_defined_names[] specifies * an initial value, create the initial value. @@ -131,7 +163,7 @@ acpi_status acpi_ns_root_initialize(void) new_node->value = obj_desc->method.param_count; #else - /* Mark this as a very SPECIAL method */ + /* Mark this as a very SPECIAL method (_OSI) */ obj_desc->method.info_flags = ACPI_METHOD_INTERNAL_ONLY; diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index 6390b7951ebf..63748ac699f7 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -14,11 +14,6 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nseval") -/* Local prototypes */ -static void -acpi_ns_exec_module_code(union acpi_operand_object *method_obj, - struct acpi_evaluate_info *info); - /******************************************************************************* * * FUNCTION: acpi_ns_evaluate @@ -44,7 +39,6 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj, * MUTEX: Locks interpreter * ******************************************************************************/ - acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) { acpi_status status; @@ -310,187 +304,3 @@ cleanup: info->full_pathname = NULL; return_ACPI_STATUS(status); } - -/******************************************************************************* - * - * FUNCTION: acpi_ns_exec_module_code_list - * - * PARAMETERS: None - * - * RETURN: None. Exceptions during method execution are ignored, since - * we cannot abort a table load. - * - * DESCRIPTION: Execute all elements of the global module-level code list. - * Each element is executed as a single control method. - * - * NOTE: With this option enabled, each block of detected executable AML - * code that is outside of any control method is wrapped with a temporary - * control method object and placed on a global list. The methods on this - * list are executed below. - * - * This function executes the module-level code for all tables only after - * all of the tables have been loaded. It is a legacy option and is - * not compatible with other ACPI implementations. See acpi_ns_load_table. - * - * This function will be removed when the legacy option is removed. - * - ******************************************************************************/ - -void acpi_ns_exec_module_code_list(void) -{ - union acpi_operand_object *prev; - union acpi_operand_object *next; - struct acpi_evaluate_info *info; - u32 method_count = 0; - - ACPI_FUNCTION_TRACE(ns_exec_module_code_list); - - /* Exit now if the list is empty */ - - next = acpi_gbl_module_code_list; - if (!next) { - ACPI_DEBUG_PRINT((ACPI_DB_INIT_NAMES, - "Legacy MLC block list is empty\n")); - - return_VOID; - } - - /* Allocate the evaluation information block */ - - info = ACPI_ALLOCATE(sizeof(struct acpi_evaluate_info)); - if (!info) { - return_VOID; - } - - /* Walk the list, executing each "method" */ - - while (next) { - prev = next; - next = next->method.mutex; - - /* Clear the link field and execute the method */ - - prev->method.mutex = NULL; - acpi_ns_exec_module_code(prev, info); - method_count++; - - /* Delete the (temporary) method object */ - - acpi_ut_remove_reference(prev); - } - - ACPI_INFO(("Executed %u blocks of module-level executable AML code", - method_count)); - - ACPI_FREE(info); - acpi_gbl_module_code_list = NULL; - return_VOID; -} - -/******************************************************************************* - * - * FUNCTION: acpi_ns_exec_module_code - * - * PARAMETERS: method_obj - Object container for the module-level code - * info - Info block for method evaluation - * - * RETURN: None. Exceptions during method execution are ignored, since - * we cannot abort a table load. - * - * DESCRIPTION: Execute a control method containing a block of module-level - * executable AML code. The control method is temporarily - * installed to the root node, then evaluated. - * - ******************************************************************************/ - -static void -acpi_ns_exec_module_code(union acpi_operand_object *method_obj, - struct acpi_evaluate_info *info) -{ - union acpi_operand_object *parent_obj; - struct acpi_namespace_node *parent_node; - acpi_object_type type; - acpi_status status; - - ACPI_FUNCTION_TRACE(ns_exec_module_code); - - /* - * Get the parent node. We cheat by using the next_object field - * of the method object descriptor. - */ - parent_node = - ACPI_CAST_PTR(struct acpi_namespace_node, - method_obj->method.next_object); - type = acpi_ns_get_type(parent_node); - - /* - * Get the region handler and save it in the method object. We may need - * this if an operation region declaration causes a _REG method to be run. - * - * We can't do this in acpi_ps_link_module_code because - * acpi_gbl_root_node->Object is NULL at PASS1. - */ - if ((type == ACPI_TYPE_DEVICE) && parent_node->object) { - method_obj->method.dispatch.handler = - parent_node->object->device.handler; - } - - /* Must clear next_object (acpi_ns_attach_object needs the field) */ - - method_obj->method.next_object = NULL; - - /* Initialize the evaluation information block */ - - memset(info, 0, sizeof(struct acpi_evaluate_info)); - info->prefix_node = parent_node; - - /* - * Get the currently attached parent object. Add a reference, - * because the ref count will be decreased when the method object - * is installed to the parent node. - */ - parent_obj = acpi_ns_get_attached_object(parent_node); - if (parent_obj) { - acpi_ut_add_reference(parent_obj); - } - - /* Install the method (module-level code) in the parent node */ - - status = - acpi_ns_attach_object(parent_node, method_obj, ACPI_TYPE_METHOD); - if (ACPI_FAILURE(status)) { - goto exit; - } - - /* Execute the parent node as a control method */ - - status = acpi_ns_evaluate(info); - - ACPI_DEBUG_PRINT((ACPI_DB_INIT_NAMES, - "Executed module-level code at %p\n", - method_obj->method.aml_start)); - - /* Delete a possible implicit return value (in slack mode) */ - - if (info->return_object) { - acpi_ut_remove_reference(info->return_object); - } - - /* Detach the temporary method object */ - - acpi_ns_detach_object(parent_node); - - /* Restore the original parent object */ - - if (parent_obj) { - status = acpi_ns_attach_object(parent_node, parent_obj, type); - } else { - parent_node->type = (u8)type; - } - -exit: - if (parent_obj) { - acpi_ut_remove_reference(parent_obj); - } - return_VOID; -} diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index 53e5d00d3a5e..61e9dfc9fe8c 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -55,14 +55,19 @@ acpi_status acpi_ns_initialize_objects(void) ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "**** Starting initialization of namespace objects ****\n")); ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, - "Completing Region/Field/Buffer/Package initialization:\n")); + "Final data object initialization: ")); - /* Set all init info to zero */ + /* Clear the info block */ memset(&info, 0, sizeof(struct acpi_init_walk_info)); /* Walk entire namespace from the supplied root */ + /* + * TBD: will become ACPI_TYPE_PACKAGE as this type object + * is now the only one that supports deferred initialization + * (forward references). + */ status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, acpi_ns_init_one_object, NULL, &info, NULL); @@ -71,13 +76,8 @@ acpi_status acpi_ns_initialize_objects(void) } ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, - " Initialized %u/%u Regions %u/%u Fields %u/%u " - "Buffers %u/%u Packages (%u nodes)\n", - info.op_region_init, info.op_region_count, - info.field_init, info.field_count, - info.buffer_init, info.buffer_count, - info.package_init, info.package_count, - info.object_count)); + "Namespace contains %u (0x%X) objects\n", + info.object_count, info.object_count)); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "%u Control Methods found\n%u Op Regions found\n", @@ -382,34 +382,18 @@ acpi_ns_init_one_object(acpi_handle obj_handle, acpi_ex_enter_interpreter(); /* - * Each of these types can contain executable AML code within the - * declaration. + * Only initialization of Package objects can be deferred, in order + * to support forward references. */ switch (type) { - case ACPI_TYPE_REGION: - - info->op_region_init++; - status = acpi_ds_get_region_arguments(obj_desc); - break; - - case ACPI_TYPE_BUFFER_FIELD: - - info->field_init++; - status = acpi_ds_get_buffer_field_arguments(obj_desc); - break; - case ACPI_TYPE_LOCAL_BANK_FIELD: + /* TBD: bank_fields do not require deferred init, remove this code */ + info->field_init++; status = acpi_ds_get_bank_field_arguments(obj_desc); break; - case ACPI_TYPE_BUFFER: - - info->buffer_init++; - status = acpi_ds_get_buffer_arguments(obj_desc); - break; - case ACPI_TYPE_PACKAGE: /* Complete the initialization/resolution of the package object */ @@ -421,8 +405,13 @@ acpi_ns_init_one_object(acpi_handle obj_handle, default: - /* No other types can get here */ + /* No other types should get here */ + status = AE_TYPE; + ACPI_EXCEPTION((AE_INFO, status, + "Opcode is not deferred [%4.4s] (%s)", + acpi_ut_get_node_name(node), + acpi_ut_get_type_name(type))); break; } diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index 35fff5c75da1..d7c4d6e8e21e 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -109,18 +109,6 @@ unlock: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Completed Table Object Initialization\n")); - /* - * This case handles the legacy option that groups all module-level - * code blocks together and defers execution until all of the tables - * are loaded. Execute all of these blocks at this time. - * Execute any module-level code that was detected during the table - * load phase. - * - * Note: this option is deprecated and will be eliminated in the - * future. Use of this option can cause problems with AML code that - * depends upon in-order immediate execution of module-level code. - */ - acpi_ns_exec_module_code_list(); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 6bc90d46db5c..b8d007c84d32 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -560,21 +560,9 @@ struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle) void acpi_ns_terminate(void) { acpi_status status; - union acpi_operand_object *prev; - union acpi_operand_object *next; ACPI_FUNCTION_TRACE(ns_terminate); - /* Delete any module-level code blocks */ - - next = acpi_gbl_module_code_list; - while (next) { - prev = next; - next = next->method.mutex; - prev->method.mutex = NULL; /* Clear the Mutex (cheated) field */ - acpi_ut_remove_reference(prev); - } - /* * Free the entire namespace -- all nodes and all objects * attached to the nodes diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index 933f81316ad2..91a4b984f224 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -934,19 +934,6 @@ acpi_tb_load_table(u32 table_index, struct acpi_namespace_node *parent_node) status = acpi_ns_load_table(table_index, parent_node); /* - * This case handles the legacy option that groups all module-level - * code blocks together and defers execution until all of the tables - * are loaded. Execute all of these blocks at this time. - * Execute any module-level code that was detected during the table - * load phase. - * - * Note: this option is deprecated and will be eliminated in the - * future. Use of this option can cause problems with AML code that - * depends upon in-order immediate execution of module-level code. - */ - acpi_ns_exec_module_code_list(); - - /* * Update GPEs for any new _Lxx/_Exx methods. Ignore errors. The host is * responsible for discovering any new wake GPEs by running _PRW methods * that may have been loaded by this table. diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 4f30f06a6f78..86f1693f6d29 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -297,6 +297,13 @@ acpi_status acpi_load_table(struct acpi_table_header *table) status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table), ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, FALSE, &table_index); + if (ACPI_SUCCESS(status)) { + + /* Complete the initialization/resolution of new objects */ + + acpi_ns_initialize_objects(); + } + return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index bc124591320e..6f33e7c72327 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -180,7 +180,6 @@ acpi_status acpi_ut_init_globals(void) /* Namespace */ - acpi_gbl_module_code_list = NULL; acpi_gbl_root_node = NULL; acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME; acpi_gbl_root_node_struct.descriptor_type = ACPI_DESC_TYPE_NAMED; diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index 9f3b1e3a09de..cf769e94fe0f 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -211,24 +211,17 @@ acpi_status ACPI_INIT_FUNCTION acpi_initialize_objects(u32 flags) ACPI_FUNCTION_TRACE(acpi_initialize_objects); +#ifdef ACPI_OBSOLETE_BEHAVIOR /* - * This case handles the legacy option that groups all module-level - * code blocks together and defers execution until all of the tables - * are loaded. Execute all of these blocks at this time. - * Execute any module-level code that was detected during the table - * load phase. - * - * Note: this option is deprecated and will be eliminated in the - * future. Use of this option can cause problems with AML code that - * depends upon in-order immediate execution of module-level code. + * 05/2019: Removed, initialization now happens at both object + * creation and table load time */ - acpi_ns_exec_module_code_list(); /* * Initialize the objects that remain uninitialized. This * runs the executable AML that may be part of the - * declaration of these objects: - * operation_regions, buffer_fields, Buffers, and Packages. + * declaration of these objects: operation_regions, buffer_fields, + * bank_fields, Buffers, and Packages. */ if (!(flags & ACPI_NO_OBJECT_INIT)) { status = acpi_ns_initialize_objects(); @@ -236,6 +229,7 @@ acpi_status ACPI_INIT_FUNCTION acpi_initialize_objects(u32 flags) return_ACPI_STATUS(status); } } +#endif /* * Initialize all device/region objects in the namespace. This runs diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 993940d582f5..a66e00fe31fe 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -345,7 +345,7 @@ static int __ghes_peek_estatus(struct ghes *ghes, return -ENOENT; } - return __ghes_check_estatus(ghes, estatus); + return 0; } static int __ghes_read_estatus(struct acpi_hest_generic_status *estatus, diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c index 92f9edf9d11e..01962c63a711 100644 --- a/drivers/acpi/arm64/gtdt.c +++ b/drivers/acpi/arm64/gtdt.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ARM Specific GTDT table Support * @@ -5,10 +6,6 @@ * Author: Daniel Lezcano <daniel.lezcano@linaro.org> * Fu Wei <fu.wei@linaro.org> * Hanjun Guo <hanjun.guo@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c index 75af78361ce5..251f961c28cc 100644 --- a/drivers/acpi/bgrt.c +++ b/drivers/acpi/bgrt.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * BGRT boot graphic support * Authors: Matthew Garrett, Josh Triplett <josh@joshtriplett.org> * Copyright 2012 Red Hat, Inc <mjg@redhat.com> * Copyright 2012 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index e54956ae93d3..28cffaaf9d82 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -45,6 +45,19 @@ const char *acpi_power_state_string(int state) } } +static int acpi_dev_pm_explicit_get(struct acpi_device *device, int *state) +{ + unsigned long long psc; + acpi_status status; + + status = acpi_evaluate_integer(device->handle, "_PSC", NULL, &psc); + if (ACPI_FAILURE(status)) + return -ENODEV; + + *state = psc; + return 0; +} + /** * acpi_device_get_power - Get power state of an ACPI device. * @device: Device to get the power state of. @@ -53,10 +66,16 @@ const char *acpi_power_state_string(int state) * This function does not update the device's power.state field, but it may * update its parent's power.state field (when the parent's power state is * unknown and the device's power state turns out to be D0). + * + * Also, it does not update power resource reference counters to ensure that + * the power state returned by it will be persistent and it may return a power + * state shallower than previously set by acpi_device_set_power() for @device + * (if that power state depends on any power resources). */ int acpi_device_get_power(struct acpi_device *device, int *state) { int result = ACPI_STATE_UNKNOWN; + int error; if (!device || !state) return -EINVAL; @@ -73,18 +92,16 @@ int acpi_device_get_power(struct acpi_device *device, int *state) * if available. */ if (device->power.flags.power_resources) { - int error = acpi_power_get_inferred_state(device, &result); + error = acpi_power_get_inferred_state(device, &result); if (error) return error; } if (device->power.flags.explicit_get) { - acpi_handle handle = device->handle; - unsigned long long psc; - acpi_status status; + int psc; - status = acpi_evaluate_integer(handle, "_PSC", NULL, &psc); - if (ACPI_FAILURE(status)) - return -ENODEV; + error = acpi_dev_pm_explicit_get(device, &psc); + if (error) + return error; /* * The power resources settings may indicate a power state @@ -118,7 +135,6 @@ int acpi_device_get_power(struct acpi_device *device, int *state) return 0; } -EXPORT_SYMBOL(acpi_device_get_power); static int acpi_dev_pm_explicit_set(struct acpi_device *adev, int state) { @@ -152,7 +168,8 @@ int acpi_device_set_power(struct acpi_device *device, int state) /* Make sure this is a valid target state */ - if (state == device->power.state) { + /* There is a special case for D0 addressed below. */ + if (state > ACPI_STATE_D0 && state == device->power.state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already in %s\n", device->pnp.bus_id, acpi_power_state_string(state))); @@ -202,9 +219,15 @@ int acpi_device_set_power(struct acpi_device *device, int state) return -ENODEV; } - result = acpi_dev_pm_explicit_set(device, state); - if (result) - goto end; + /* + * If the device goes from D3hot to D3cold, _PS3 has been + * evaluated for it already, so skip it in that case. + */ + if (device->power.state < ACPI_STATE_D3_HOT) { + result = acpi_dev_pm_explicit_set(device, state); + if (result) + goto end; + } if (device->power.flags.power_resources) result = acpi_power_transition(device, target_state); @@ -214,6 +237,30 @@ int acpi_device_set_power(struct acpi_device *device, int state) if (result) goto end; } + + if (device->power.state == ACPI_STATE_D0) { + int psc; + + /* Nothing to do here if _PSC is not present. */ + if (!device->power.flags.explicit_get) + return 0; + + /* + * The power state of the device was set to D0 last + * time, but that might have happened before a + * system-wide transition involving the platform + * firmware, so it may be necessary to evaluate _PS0 + * for the device here. However, use extra care here + * and evaluate _PSC to check the device's current power + * state, and only invoke _PS0 if the evaluation of _PSC + * is successful and it returns a power state different + * from D0. + */ + result = acpi_dev_pm_explicit_get(device, &psc); + if (result || psc == ACPI_STATE_D0) + return 0; + } + result = acpi_dev_pm_explicit_set(device, ACPI_STATE_D0); } @@ -1073,7 +1120,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend_noirq); * acpi_subsys_resume_noirq - Run the device driver's "noirq" resume callback. * @dev: Device to handle. */ -int acpi_subsys_resume_noirq(struct device *dev) +static int acpi_subsys_resume_noirq(struct device *dev) { if (dev_pm_may_skip_resume(dev)) return 0; @@ -1088,7 +1135,6 @@ int acpi_subsys_resume_noirq(struct device *dev) return pm_generic_resume_noirq(dev); } -EXPORT_SYMBOL_GPL(acpi_subsys_resume_noirq); /** * acpi_subsys_resume_early - Resume device using ACPI. @@ -1098,12 +1144,11 @@ EXPORT_SYMBOL_GPL(acpi_subsys_resume_noirq); * generic early resume procedure for it during system transition into the * working state. */ -int acpi_subsys_resume_early(struct device *dev) +static int acpi_subsys_resume_early(struct device *dev) { int ret = acpi_dev_resume(dev); return ret ? ret : pm_generic_resume_early(dev); } -EXPORT_SYMBOL_GPL(acpi_subsys_resume_early); /** * acpi_subsys_freeze - Run the device driver's freeze callback. @@ -1112,65 +1157,81 @@ EXPORT_SYMBOL_GPL(acpi_subsys_resume_early); int acpi_subsys_freeze(struct device *dev) { /* - * This used to be done in acpi_subsys_prepare() for all devices and - * some drivers may depend on it, so do it here. Ideally, however, - * runtime-suspended devices should not be touched during freeze/thaw - * transitions. + * Resume all runtime-suspended devices before creating a snapshot + * image of system memory, because the restore kernel generally cannot + * be expected to always handle them consistently and they need to be + * put into the runtime-active metastate during system resume anyway, + * so it is better to ensure that the state saved in the image will be + * always consistent with that. */ - if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND)) - pm_runtime_resume(dev); + pm_runtime_resume(dev); return pm_generic_freeze(dev); } EXPORT_SYMBOL_GPL(acpi_subsys_freeze); /** - * acpi_subsys_freeze_late - Run the device driver's "late" freeze callback. - * @dev: Device to handle. + * acpi_subsys_restore_early - Restore device using ACPI. + * @dev: Device to restore. */ -int acpi_subsys_freeze_late(struct device *dev) +int acpi_subsys_restore_early(struct device *dev) { + int ret = acpi_dev_resume(dev); + return ret ? ret : pm_generic_restore_early(dev); +} +EXPORT_SYMBOL_GPL(acpi_subsys_restore_early); - if (dev_pm_smart_suspend_and_suspended(dev)) - return 0; +/** + * acpi_subsys_poweroff - Run the device driver's poweroff callback. + * @dev: Device to handle. + * + * Follow PCI and resume devices from runtime suspend before running their + * system poweroff callbacks, unless the driver can cope with runtime-suspended + * devices during system suspend and there are no ACPI-specific reasons for + * resuming them. + */ +int acpi_subsys_poweroff(struct device *dev) +{ + if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) || + acpi_dev_needs_resume(dev, ACPI_COMPANION(dev))) + pm_runtime_resume(dev); - return pm_generic_freeze_late(dev); + return pm_generic_poweroff(dev); } -EXPORT_SYMBOL_GPL(acpi_subsys_freeze_late); +EXPORT_SYMBOL_GPL(acpi_subsys_poweroff); /** - * acpi_subsys_freeze_noirq - Run the device driver's "noirq" freeze callback. + * acpi_subsys_poweroff_late - Run the device driver's poweroff callback. * @dev: Device to handle. + * + * Carry out the generic late poweroff procedure for @dev and use ACPI to put + * it into a low-power state during system transition into a sleep state. */ -int acpi_subsys_freeze_noirq(struct device *dev) +static int acpi_subsys_poweroff_late(struct device *dev) { + int ret; if (dev_pm_smart_suspend_and_suspended(dev)) return 0; - return pm_generic_freeze_noirq(dev); + ret = pm_generic_poweroff_late(dev); + if (ret) + return ret; + + return acpi_dev_suspend(dev, device_may_wakeup(dev)); } -EXPORT_SYMBOL_GPL(acpi_subsys_freeze_noirq); /** - * acpi_subsys_thaw_noirq - Run the device driver's "noirq" thaw callback. - * @dev: Device to handle. + * acpi_subsys_poweroff_noirq - Run the driver's "noirq" poweroff callback. + * @dev: Device to suspend. */ -int acpi_subsys_thaw_noirq(struct device *dev) +static int acpi_subsys_poweroff_noirq(struct device *dev) { - /* - * If the device is in runtime suspend, the "thaw" code may not work - * correctly with it, so skip the driver callback and make the PM core - * skip all of the subsequent "thaw" callbacks for the device. - */ - if (dev_pm_smart_suspend_and_suspended(dev)) { - dev_pm_skip_next_resume_phases(dev); + if (dev_pm_smart_suspend_and_suspended(dev)) return 0; - } - return pm_generic_thaw_noirq(dev); + return pm_generic_poweroff_noirq(dev); } -EXPORT_SYMBOL_GPL(acpi_subsys_thaw_noirq); #endif /* CONFIG_PM_SLEEP */ static struct dev_pm_domain acpi_general_pm_domain = { @@ -1186,14 +1247,10 @@ static struct dev_pm_domain acpi_general_pm_domain = { .resume_noirq = acpi_subsys_resume_noirq, .resume_early = acpi_subsys_resume_early, .freeze = acpi_subsys_freeze, - .freeze_late = acpi_subsys_freeze_late, - .freeze_noirq = acpi_subsys_freeze_noirq, - .thaw_noirq = acpi_subsys_thaw_noirq, - .poweroff = acpi_subsys_suspend, - .poweroff_late = acpi_subsys_suspend_late, - .poweroff_noirq = acpi_subsys_suspend_noirq, - .restore_noirq = acpi_subsys_resume_noirq, - .restore_early = acpi_subsys_resume_early, + .poweroff = acpi_subsys_poweroff, + .poweroff_late = acpi_subsys_poweroff_late, + .poweroff_noirq = acpi_subsys_poweroff_noirq, + .restore_early = acpi_subsys_restore_early, #endif }, }; diff --git a/drivers/acpi/dptf/int340x_thermal.c b/drivers/acpi/dptf/int340x_thermal.c index 0aa7c2e62e95..5c7a90186e3c 100644 --- a/drivers/acpi/dptf/int340x_thermal.c +++ b/drivers/acpi/dptf/int340x_thermal.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ACPI support for int340x thermal drivers * * Copyright (C) 2014, Intel Corporation * Authors: Zhang Rui <rui.zhang@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index 23faa66ea772..fd39c14493ab 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ec_sys.c * * Copyright (C) 2010 SUSE Products GmbH/Novell * Author: * Thomas Renninger <trenn@suse.de> - * - * This work is licensed under the terms of the GNU GPL, version 2. */ #include <linux/kernel.h> diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index f6157d4d637a..f4c2fe6be4f2 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -139,8 +139,15 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state); int acpi_power_on_resources(struct acpi_device *device, int state); int acpi_power_transition(struct acpi_device *device, int state); +/* -------------------------------------------------------------------------- + Device Power Management + -------------------------------------------------------------------------- */ +int acpi_device_get_power(struct acpi_device *device, int *state); int acpi_wakeup_device_init(void); +/* -------------------------------------------------------------------------- + Processor + -------------------------------------------------------------------------- */ #ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC void acpi_early_processor_set_pdc(void); #else diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c index 3595aa9c7c18..a690c7b18623 100644 --- a/drivers/acpi/ioapic.c +++ b/drivers/acpi/ioapic.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * IOAPIC/IOxAPIC/IOSAPIC driver * @@ -6,10 +7,6 @@ * * Copyright (C) 2014 Intel Corporation * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Based on original drivers/pci/ioapic.c * Yinghai Lu <yinghai@kernel.org> * Jiang Liu <jiang.liu@intel.com> diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c index c3b2222e2129..e209081d644b 100644 --- a/drivers/acpi/irq.c +++ b/drivers/acpi/irq.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ACPI GSI IRQ layer * * Copyright (C) 2015 ARM Ltd. * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> #include <linux/irq.h> @@ -295,3 +292,29 @@ void __init acpi_set_irq_model(enum acpi_irq_model_id model, acpi_irq_model = model; acpi_gsi_domain_id = fwnode; } + +/** + * acpi_irq_create_hierarchy - Create a hierarchical IRQ domain with the default + * GSI domain as its parent. + * @flags: Irq domain flags associated with the domain + * @size: Size of the domain. + * @fwnode: Optional fwnode of the interrupt controller + * @ops: Pointer to the interrupt domain callbacks + * @host_data: Controller private data pointer + */ +struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags, + unsigned int size, + struct fwnode_handle *fwnode, + const struct irq_domain_ops *ops, + void *host_data) +{ + struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id, + DOMAIN_BUS_ANY); + + if (!d) + return NULL; + + return irq_domain_create_hierarchy(d, flags, size, fwnode, ops, + host_data); +} +EXPORT_SYMBOL_GPL(acpi_irq_create_hierarchy); diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index cc7507091dec..9c0edf2fc0dd 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -301,8 +301,8 @@ static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr) * During early init (when acpi_permanent_mmap has not been set yet) this * routine simply calls __acpi_map_table() to get the job done. */ -void __iomem *__ref -acpi_os_map_iomem(acpi_physical_address phys, acpi_size size) +void __iomem __ref +*acpi_os_map_iomem(acpi_physical_address phys, acpi_size size) { struct acpi_ioremap *map; void __iomem *virt; diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index b42be067fb83..6b347d9920cc 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Broadcom * Author: Jayachandran C <jchandra@broadcom.com> * Copyright (C) 2016 Semihalf * Author: Tomasz Nowicki <tn@semihalf.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ #define pr_fmt(fmt) "ACPI: " fmt diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index e90b61f7d2db..ca2461d1bf14 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * pci_slot.c - ACPI PCI Slot Driver * @@ -11,15 +12,6 @@ * * Copyright (C) 2013 Huawei Tech. Co., Ltd. * Jiang Liu <jiang.liu@huawei.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c index 1b722fd57d5e..452041398b34 100644 --- a/drivers/acpi/pmic/intel_pmic.c +++ b/drivers/acpi/pmic/intel_pmic.c @@ -284,8 +284,6 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, intel_pmic_thermal_handler, NULL, opregion); if (ACPI_FAILURE(status)) { - acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, - intel_pmic_power_handler); ret = -ENODEV; goto out_remove_power_handler; } diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index a916417b9e70..fe1e7bc91a5e 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -42,6 +42,11 @@ ACPI_MODULE_NAME("power"); #define ACPI_POWER_RESOURCE_STATE_ON 0x01 #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF +struct acpi_power_dependent_device { + struct device *dev; + struct list_head node; +}; + struct acpi_power_resource { struct acpi_device device; struct list_head list_node; @@ -51,6 +56,7 @@ struct acpi_power_resource { unsigned int ref_count; bool wakeup_enabled; struct mutex resource_lock; + struct list_head dependents; }; struct acpi_power_resource_entry { @@ -232,8 +238,121 @@ static int acpi_power_get_list_state(struct list_head *list, int *state) return 0; } +static int +acpi_power_resource_add_dependent(struct acpi_power_resource *resource, + struct device *dev) +{ + struct acpi_power_dependent_device *dep; + int ret = 0; + + mutex_lock(&resource->resource_lock); + list_for_each_entry(dep, &resource->dependents, node) { + /* Only add it once */ + if (dep->dev == dev) + goto unlock; + } + + dep = kzalloc(sizeof(*dep), GFP_KERNEL); + if (!dep) { + ret = -ENOMEM; + goto unlock; + } + + dep->dev = dev; + list_add_tail(&dep->node, &resource->dependents); + dev_dbg(dev, "added power dependency to [%s]\n", resource->name); + +unlock: + mutex_unlock(&resource->resource_lock); + return ret; +} + +static void +acpi_power_resource_remove_dependent(struct acpi_power_resource *resource, + struct device *dev) +{ + struct acpi_power_dependent_device *dep; + + mutex_lock(&resource->resource_lock); + list_for_each_entry(dep, &resource->dependents, node) { + if (dep->dev == dev) { + list_del(&dep->node); + kfree(dep); + dev_dbg(dev, "removed power dependency to [%s]\n", + resource->name); + break; + } + } + mutex_unlock(&resource->resource_lock); +} + +/** + * acpi_device_power_add_dependent - Add dependent device of this ACPI device + * @adev: ACPI device pointer + * @dev: Dependent device + * + * If @adev has non-empty _PR0 the @dev is added as dependent device to all + * power resources returned by it. This means that whenever these power + * resources are turned _ON the dependent devices get runtime resumed. This + * is needed for devices such as PCI to allow its driver to re-initialize + * it after it went to D0uninitialized. + * + * If @adev does not have _PR0 this does nothing. + * + * Returns %0 in case of success and negative errno otherwise. + */ +int acpi_device_power_add_dependent(struct acpi_device *adev, + struct device *dev) +{ + struct acpi_power_resource_entry *entry; + struct list_head *resources; + int ret; + + if (!adev->flags.power_manageable) + return 0; + + resources = &adev->power.states[ACPI_STATE_D0].resources; + list_for_each_entry(entry, resources, node) { + ret = acpi_power_resource_add_dependent(entry->resource, dev); + if (ret) + goto err; + } + + return 0; + +err: + list_for_each_entry(entry, resources, node) + acpi_power_resource_remove_dependent(entry->resource, dev); + + return ret; +} + +/** + * acpi_device_power_remove_dependent - Remove dependent device + * @adev: ACPI device pointer + * @dev: Dependent device + * + * Does the opposite of acpi_device_power_add_dependent() and removes the + * dependent device if it is found. Can be called to @adev that does not + * have _PR0 as well. + */ +void acpi_device_power_remove_dependent(struct acpi_device *adev, + struct device *dev) +{ + struct acpi_power_resource_entry *entry; + struct list_head *resources; + + if (!adev->flags.power_manageable) + return; + + resources = &adev->power.states[ACPI_STATE_D0].resources; + list_for_each_entry_reverse(entry, resources, node) + acpi_power_resource_remove_dependent(entry->resource, dev); +} + static int __acpi_power_on(struct acpi_power_resource *resource) { + struct acpi_power_dependent_device *dep; acpi_status status = AE_OK; status = acpi_evaluate_object(resource->device.handle, "_ON", NULL, NULL); @@ -243,6 +362,21 @@ static int __acpi_power_on(struct acpi_power_resource *resource) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n", resource->name)); + /* + * If there are other dependents on this power resource we need to + * resume them now so that their drivers can re-initialize the + * hardware properly after it went back to D0. + */ + if (list_empty(&resource->dependents) || + list_is_singular(&resource->dependents)) + return 0; + + list_for_each_entry(dep, &resource->dependents, node) { + dev_dbg(dep->dev, "runtime resuming because [%s] turned on\n", + resource->name); + pm_request_resume(dep->dev); + } + return 0; } @@ -810,6 +944,7 @@ int acpi_add_power_resource(acpi_handle handle) ACPI_STA_DEFAULT); mutex_init(&resource->resource_lock); INIT_LIST_HEAD(&resource->list_node); + INIT_LIST_HEAD(&resource->dependents); resource->name = device->pnp.bus_id; strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_POWER_CLASS); diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c index b72e6afaa8fb..1e7ac0bd0d3a 100644 --- a/drivers/acpi/pptt.c +++ b/drivers/acpi/pptt.c @@ -432,17 +432,40 @@ static void cache_setup_acpi_cpu(struct acpi_table_header *table, } } +static bool flag_identical(struct acpi_table_header *table_hdr, + struct acpi_pptt_processor *cpu) +{ + struct acpi_pptt_processor *next; + + /* heterogeneous machines must use PPTT revision > 1 */ + if (table_hdr->revision < 2) + return false; + + /* Locate the last node in the tree with IDENTICAL set */ + if (cpu->flags & ACPI_PPTT_ACPI_IDENTICAL) { + next = fetch_pptt_node(table_hdr, cpu->parent); + if (!(next && next->flags & ACPI_PPTT_ACPI_IDENTICAL)) + return true; + } + + return false; +} + /* Passing level values greater than this will result in search termination */ #define PPTT_ABORT_PACKAGE 0xFF -static struct acpi_pptt_processor *acpi_find_processor_package_id(struct acpi_table_header *table_hdr, - struct acpi_pptt_processor *cpu, - int level, int flag) +static struct acpi_pptt_processor *acpi_find_processor_tag(struct acpi_table_header *table_hdr, + struct acpi_pptt_processor *cpu, + int level, int flag) { struct acpi_pptt_processor *prev_node; while (cpu && level) { - if (cpu->flags & flag) + /* special case the identical flag to find last identical */ + if (flag == ACPI_PPTT_ACPI_IDENTICAL) { + if (flag_identical(table_hdr, cpu)) + break; + } else if (cpu->flags & flag) break; pr_debug("level %d\n", level); prev_node = fetch_pptt_node(table_hdr, cpu->parent); @@ -480,8 +503,8 @@ static int topology_get_acpi_cpu_tag(struct acpi_table_header *table, cpu_node = acpi_find_processor_node(table, acpi_cpu_id); if (cpu_node) { - cpu_node = acpi_find_processor_package_id(table, cpu_node, - level, flag); + cpu_node = acpi_find_processor_tag(table, cpu_node, + level, flag); /* * As per specification if the processor structure represents * an actual processor, then ACPI processor ID must be valid. @@ -660,3 +683,29 @@ int find_acpi_cpu_topology_package(unsigned int cpu) return find_acpi_cpu_topology_tag(cpu, PPTT_ABORT_PACKAGE, ACPI_PPTT_PHYSICAL_PACKAGE); } + +/** + * find_acpi_cpu_topology_hetero_id() - Get a core architecture tag + * @cpu: Kernel logical CPU number + * + * Determine a unique heterogeneous tag for the given CPU. CPUs with the same + * implementation should have matching tags. + * + * The returned tag can be used to group peers with identical implementation. + * + * The search terminates when a level is found with the identical implementation + * flag set or we reach a root node. + * + * Due to limitations in the PPTT data structure, there may be rare situations + * where two cores in a heterogeneous machine may be identical, but won't have + * the same tag. + * + * Return: -ENOENT if the PPTT doesn't exist, or the CPU cannot be found. + * Otherwise returns a value which represents a group of identical cores + * similar to this CPU. + */ +int find_acpi_cpu_topology_hetero_id(unsigned int cpu) +{ + return find_acpi_cpu_topology_tag(cpu, PPTT_ABORT_PACKAGE, + ACPI_PPTT_ACPI_IDENTICAL); +} diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index e387a258d649..ed56c6d20b08 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -196,6 +196,7 @@ static void tsc_check_state(int state) case X86_VENDOR_AMD: case X86_VENDOR_INTEL: case X86_VENDOR_CENTAUR: + case X86_VENDOR_ZHAOXIN: /* * AMD Fam10h TSC will tick in all * C/P/S0/S1 states when this bit is set. diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 9d460a859be0..ea3d700da3ca 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ACPI device specific properties support. * @@ -7,10 +8,6 @@ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> * Darren Hart <dvhart@linux.intel.com> * Rafael J. Wysocki <rafael.j.wysocki@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> @@ -603,15 +600,29 @@ static struct fwnode_handle * acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode, const char *childname) { + char name[ACPI_PATH_SEGMENT_LENGTH]; struct fwnode_handle *child; + struct acpi_buffer path; + acpi_status status; - /* - * Find first matching named child node of this fwnode. - * For ACPI this will be a data only sub-node. - */ - fwnode_for_each_child_node(fwnode, child) - if (acpi_data_node_match(child, childname)) + path.length = sizeof(name); + path.pointer = name; + + fwnode_for_each_child_node(fwnode, child) { + if (is_acpi_data_node(child)) { + if (acpi_data_node_match(child, childname)) + return child; + continue; + } + + status = acpi_get_name(ACPI_HANDLE_FWNODE(child), + ACPI_SINGLE_NAME, &path); + if (ACPI_FAILURE(status)) + break; + + if (!strncmp(name, childname, ACPI_NAMESEG_SIZE)) return child; + } return NULL; } diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 8ff08e531443..f0fe7c15d657 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -77,7 +77,7 @@ static int acpi_sleep_prepare(u32 acpi_state) return 0; } -static bool acpi_sleep_state_supported(u8 sleep_state) +bool acpi_sleep_state_supported(u8 sleep_state) { acpi_status status; u8 type_a, type_b; @@ -452,14 +452,6 @@ static int acpi_pm_prepare(void) return error; } -static int find_powerf_dev(struct device *dev, void *data) -{ - struct acpi_device *device = to_acpi_device(dev); - const char *hid = acpi_device_hid(device); - - return !strcmp(hid, ACPI_BUTTON_HID_POWERF); -} - /** * acpi_pm_finish - Instruct the platform to leave a sleep state. * @@ -468,7 +460,7 @@ static int find_powerf_dev(struct device *dev, void *data) */ static void acpi_pm_finish(void) { - struct device *pwr_btn_dev; + struct acpi_device *pwr_btn_adev; u32 acpi_state = acpi_target_sleep_state; acpi_ec_unblock_transactions(); @@ -499,11 +491,11 @@ static void acpi_pm_finish(void) return; pwr_btn_event_pending = false; - pwr_btn_dev = bus_find_device(&acpi_bus_type, NULL, NULL, - find_powerf_dev); - if (pwr_btn_dev) { - pm_wakeup_event(pwr_btn_dev, 0); - put_device(pwr_btn_dev); + pwr_btn_adev = acpi_dev_get_first_match_dev(ACPI_BUTTON_HID_POWERF, + NULL, -1); + if (pwr_btn_adev) { + pm_wakeup_event(&pwr_btn_adev->dev, 0); + acpi_dev_put(pwr_btn_adev); } } diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index b34d05e365b7..d73b4535e79d 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012, Intel Corporation * Copyright (c) 2015, Red Hat, Inc. * Copyright (c) 2015, 2016 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #define pr_fmt(fmt) "ACPI: SPCR: " fmt diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index de974322a197..b32327759380 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -490,16 +490,17 @@ static u8 __init acpi_table_checksum(u8 *buffer, u32 length) /* All but ACPI_SIG_RSDP and ACPI_SIG_FACS: */ static const char * const table_sigs[] = { - ACPI_SIG_BERT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, ACPI_SIG_EINJ, - ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT, ACPI_SIG_MSCT, - ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT, ACPI_SIG_ASF, - ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR, ACPI_SIG_HPET, - ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG, ACPI_SIG_MCHI, - ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI, ACPI_SIG_TCPA, - ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, ACPI_SIG_WDDT, - ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT, - ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, ACPI_SIG_IORT, - ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT, NULL }; + ACPI_SIG_BERT, ACPI_SIG_BGRT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, + ACPI_SIG_EINJ, ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT, + ACPI_SIG_MSCT, ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT, + ACPI_SIG_ASF, ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR, + ACPI_SIG_HPET, ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG, + ACPI_SIG_MCHI, ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI, + ACPI_SIG_TCPA, ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, + ACPI_SIG_WDDT, ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, + ACPI_SIG_PSDT, ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, + ACPI_SIG_IORT, ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT, + NULL }; #define ACPI_HEADER_SIZE sizeof(struct acpi_table_header) diff --git a/drivers/acpi/x86/apple.c b/drivers/acpi/x86/apple.c index b7c98ff82d78..c285c91a5e9c 100644 --- a/drivers/acpi/x86/apple.c +++ b/drivers/acpi/x86/apple.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * apple.c - Apple ACPI quirks * Copyright (C) 2017 Lukas Wunner <lukas@wunner.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (version 2) as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index c6df14802741..ba277cd5c7fa 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * X86 ACPI Utility Functions * @@ -5,10 +6,6 @@ * * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index b4dae624b9af..100e798a5c82 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/arch/arm/common/amba.c * * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 748ac489ef7e..bc26b5511f0a 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1941,8 +1941,18 @@ static void binder_free_txn_fixups(struct binder_transaction *t) static void binder_free_transaction(struct binder_transaction *t) { - if (t->buffer) - t->buffer->transaction = NULL; + struct binder_proc *target_proc = t->to_proc; + + if (target_proc) { + binder_inner_proc_lock(target_proc); + if (t->buffer) + t->buffer->transaction = NULL; + binder_inner_proc_unlock(target_proc); + } + /* + * If the transaction has no target_proc, then + * t->buffer->transaction has already been cleared. + */ binder_free_txn_fixups(t); kfree(t); binder_stats_deleted(BINDER_STAT_TRANSACTION); @@ -3551,10 +3561,12 @@ err_invalid_target_handle: static void binder_free_buf(struct binder_proc *proc, struct binder_buffer *buffer) { + binder_inner_proc_lock(proc); if (buffer->transaction) { buffer->transaction->buffer = NULL; buffer->transaction = NULL; } + binder_inner_proc_unlock(proc); if (buffer->async_transaction && buffer->target_node) { struct binder_node *buf_node; struct binder_work *w; diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c index b1b49dbd0b14..85357f27a66b 100644 --- a/drivers/ata/acard-ahci.c +++ b/drivers/ata/acard-ahci.c @@ -344,7 +344,6 @@ static int acard_ahci_port_start(struct ata_port *ap) mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL); if (!mem) return -ENOMEM; - memset(mem, 0, dma_sz); /* * First item in chunk of DMA memory: 32-slot command table, diff --git a/drivers/ata/ahci_seattle.c b/drivers/ata/ahci_seattle.c index e57b6f92c288..ced12705ed9d 100644 --- a/drivers/ata/ahci_seattle.c +++ b/drivers/ata/ahci_seattle.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Seattle AHCI SATA driver * @@ -5,15 +6,6 @@ * Author: Brijesh Singh <brijesh.singh@amd.com> * * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/kernel.h> diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c index 21c5c44832ef..c268264c2129 100644 --- a/drivers/ata/ahci_st.c +++ b/drivers/ata/ahci_st.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 STMicroelectronics Limited * * Authors: Francesco Virlinzi <francesco.virlinzi@st.com> * Alexandre Torgue <alexandre.torgue@st.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c index 4100e904376b..cb69b737cb49 100644 --- a/drivers/ata/ahci_sunxi.c +++ b/drivers/ata/ahci_sunxi.c @@ -149,8 +149,51 @@ static void ahci_sunxi_start_engine(struct ata_port *ap) void __iomem *port_mmio = ahci_port_base(ap); struct ahci_host_priv *hpriv = ap->host->private_data; - /* Setup DMA before DMA start */ - sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ff00, 0x00004400); + /* Setup DMA before DMA start + * + * NOTE: A similar SoC with SATA/AHCI by Texas Instruments documents + * this Vendor Specific Port (P0DMACR, aka PxDMACR) in its + * User's Guide document (TMS320C674x/OMAP-L1x Processor + * Serial ATA (SATA) Controller, Literature Number: SPRUGJ8C, + * March 2011, Chapter 4.33 Port DMA Control Register (P0DMACR), + * p.68, https://www.ti.com/lit/ug/sprugj8c/sprugj8c.pdf) + * as equivalent to the following struct: + * + * struct AHCI_P0DMACR_t + * { + * unsigned TXTS : 4; + * unsigned RXTS : 4; + * unsigned TXABL : 4; + * unsigned RXABL : 4; + * unsigned Reserved : 16; + * }; + * + * TXTS: Transmit Transaction Size (TX_TRANSACTION_SIZE). + * This field defines the DMA transaction size in DWORDs for + * transmit (system bus read, device write) operation. [...] + * + * RXTS: Receive Transaction Size (RX_TRANSACTION_SIZE). + * This field defines the Port DMA transaction size in DWORDs + * for receive (system bus write, device read) operation. [...] + * + * TXABL: Transmit Burst Limit. + * This field allows software to limit the VBUSP master read + * burst size. [...] + * + * RXABL: Receive Burst Limit. + * Allows software to limit the VBUSP master write burst + * size. [...] + * + * Reserved: Reserved. + * + * + * NOTE: According to the above document, the following alternative + * to the code below could perhaps be a better option + * (or preparation) for possible further improvements later: + * sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ffff, + * 0x00000033); + */ + sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ffff, 0x00004433); /* Start DMA */ sunxi_setbits(port_mmio + PORT_CMD, PORT_CMD_START); diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 0984c4b76d7e..e4c45d3cca79 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -2365,7 +2365,6 @@ static int ahci_port_start(struct ata_port *ap) mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL); if (!mem) return -ENOMEM; - memset(mem, 0, dma_sz); /* * First item in chunk of DMA memory: 32-slot command table, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 4a2dff303865..28c492be0a57 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4462,9 +4462,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* drives which fail FPDMA_AA activation (some may freeze afterwards) the ST disks also have LPM issues */ - { "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA | - ATA_HORKAGE_NOLPM, }, - { "ST1000LM024 HN-M101MBB", "2BA30001", ATA_HORKAGE_BROKEN_FPDMA_AA | + { "ST1000LM024 HN-M101MBB", NULL, ATA_HORKAGE_BROKEN_FPDMA_AA | ATA_HORKAGE_NOLPM, }, { "VB0250EAVER", "HPG7", ATA_HORKAGE_BROKEN_FPDMA_AA }, diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 9d687e1d4325..3bfd9da58473 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1469,7 +1469,7 @@ static int ata_eh_read_log_10h(struct ata_device *dev, tf->hob_lbah = buf[10]; tf->nsect = buf[12]; tf->hob_nsect = buf[13]; - if (ata_id_has_ncq_autosense(dev->id)) + if (dev->class == ATA_DEV_ZAC && ata_id_has_ncq_autosense(dev->id)) tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16]; return 0; @@ -1716,7 +1716,8 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) memcpy(&qc->result_tf, &tf, sizeof(tf)); qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48; qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ; - if ((qc->result_tf.command & ATA_SENSE) || qc->result_tf.auxiliary) { + if (dev->class == ATA_DEV_ZAC && + ((qc->result_tf.command & ATA_SENSE) || qc->result_tf.auxiliary)) { char sense_key, asc, ascq; sense_key = (qc->result_tf.auxiliary >> 16) & 0xff; @@ -1770,10 +1771,11 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, } switch (qc->dev->class) { - case ATA_DEV_ATA: case ATA_DEV_ZAC: if (stat & ATA_SENSE) ata_eh_request_sense(qc, qc->scsicmd); + /* fall through */ + case ATA_DEV_ATA: if (err & ATA_ICRC) qc->err_mask |= AC_ERR_ATA_BUS; if (err & (ATA_UNC | ATA_AMNF)) diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 0b0d93065f5a..d1644a8ef9fa 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ixp4xx PATA/Compact Flash driver * Copyright (C) 2006-07 Tower Technologies @@ -9,11 +10,6 @@ * on the ixp4xx. In the irq is not available, you might * want to modify both this driver and libata to run in * polling mode. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c index 7a0b1759e5f0..35aa158fc976 100644 --- a/drivers/ata/pata_of_platform.c +++ b/drivers/ata/pata_of_platform.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OF-platform PATA driver * * Copyright (c) 2007 MontaVista Software, Inc. * Anton Vorontsov <avorontsov@ru.mvista.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/ata/pata_palmld.c b/drivers/ata/pata_palmld.c index 26817fd91700..2448441571ed 100644 --- a/drivers/ata/pata_palmld.c +++ b/drivers/ata/pata_palmld.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/ata/pata_palmld.c * @@ -13,11 +14,6 @@ * ixp4xx PATA/Compact Flash driver * Copyright (C) 2006-07 Tower Technologies * Author: Alessandro Zummo <a.zummo@towertech.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c index 66bb5bff126b..7c37f2ff09e4 100644 --- a/drivers/ata/pata_rb532_cf.c +++ b/drivers/ata/pata_rb532_cf.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * A low-level PATA driver to handle a Compact Flash connected on the * Mikrotik's RouterBoard 532 board. @@ -12,11 +13,6 @@ * Also was based on the driver for Linux 2.4.xx published by Mikrotik for * their RouterBoard 1xx and 5xx series devices. The original Mikrotik code * seems not to have a license. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/gfp.h> diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c index 1dc3361cb5a5..3da0e8e30286 100644 --- a/drivers/ata/pata_samsung_cf.c +++ b/drivers/ata/pata_samsung_cf.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2010 Samsung Electronics Co., Ltd. * http://www.samsung.com @@ -9,10 +10,6 @@ * Based on: * PATA driver for AT91SAM9260 Static Memory Controller * PATA driver for Toshiba SCC controller - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 52fa8606a25f..c5bbb07aa7d9 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -550,7 +550,6 @@ static int adma_port_start(struct ata_port *ap) (u32)pp->pkt_dma); return -ENOMEM; } - memset(pp->pkt, 0, ADMA_PKT_BYTES); ap->private_data = pp; adma_reinit_engine(ap); return 0; diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 54bfab15c74a..b44b4b64354c 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -1136,7 +1136,6 @@ static int nv_adma_port_start(struct ata_port *ap) &mem_dma, GFP_KERNEL); if (!mem) return -ENOMEM; - memset(mem, 0, NV_ADMA_PORT_PRIV_DMA_SZ); /* * First item in chunk of DMA memory: @@ -1946,7 +1945,6 @@ static int nv_swncq_port_start(struct ata_port *ap) &pp->prd_dma, GFP_KERNEL); if (!pp->prd) return -ENOMEM; - memset(pp->prd, 0, ATA_PRD_TBL_SZ * ATA_MAX_QUEUE); ap->private_data = pp; pp->sactive_block = ap->ioaddr.scr_addr + 4 * SCR_ACTIVE; diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 7ec0c216a6a6..865e5c58bd94 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -477,7 +477,6 @@ static int qs_port_start(struct ata_port *ap) GFP_KERNEL); if (!pp->pkt) return -ENOMEM; - memset(pp->pkt, 0, QS_PKT_BYTES); ap->private_data = pp; qs_enter_reg_mode(ap); diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index bfdf41912588..98aad8206921 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -1202,7 +1202,6 @@ static int sil24_port_start(struct ata_port *ap) cb = dmam_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL); if (!cb) return -ENOMEM; - memset(cb, 0, cb_size); pp->cmd_block = cb; pp->cmd_block_dma = cb_dma; diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c index 40c8a552a478..4074886b7bc8 100644 --- a/drivers/auxdisplay/cfag12864bfb.c +++ b/drivers/auxdisplay/cfag12864bfb.c @@ -52,8 +52,9 @@ static const struct fb_var_screeninfo cfag12864bfb_var = { static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { - return vm_insert_page(vma, vma->vm_start, - virt_to_page(cfag12864b_buffer)); + struct page *pages = virt_to_page(cfag12864b_buffer); + + return vm_map_pages_zero(vma, &pages, 1); } static struct fb_ops cfag12864bfb_ops = { diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c index 21393ec3b9a4..9c0bb771751d 100644 --- a/drivers/auxdisplay/ht16k33.c +++ b/drivers/auxdisplay/ht16k33.c @@ -223,9 +223,9 @@ static const struct backlight_ops ht16k33_bl_ops = { static int ht16k33_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct ht16k33_priv *priv = info->par; + struct page *pages = virt_to_page(priv->fbdev.buffer); - return vm_insert_page(vma, vma->vm_start, - virt_to_page(priv->fbdev.buffer)); + return vm_map_pages_zero(vma, &pages, 1); } static struct fb_ops ht16k33_fb_ops = { diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 1739d7e1952a..9b09e31ae82f 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -43,7 +43,7 @@ static ssize_t cpu_capacity_show(struct device *dev, { struct cpu *cpu = container_of(dev, struct cpu, dev); - return sprintf(buf, "%lu\n", topology_get_cpu_scale(NULL, cpu->dev.id)); + return sprintf(buf, "%lu\n", topology_get_cpu_scale(cpu->dev.id)); } static void update_topology_flags_workfn(struct work_struct *work); @@ -116,7 +116,7 @@ void topology_normalize_cpu_scale(void) / capacity_scale; topology_set_cpu_scale(cpu, capacity); pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n", - cpu, topology_get_cpu_scale(NULL, cpu)); + cpu, topology_get_cpu_scale(cpu)); } } @@ -185,7 +185,7 @@ init_cpu_capacity_callback(struct notifier_block *nb, cpumask_andnot(cpus_to_visit, cpus_to_visit, policy->related_cpus); for_each_cpu(cpu, policy->related_cpus) { - raw_capacity[cpu] = topology_get_cpu_scale(NULL, cpu) * + raw_capacity[cpu] = topology_get_cpu_scale(cpu) * policy->cpuinfo.max_freq / 1000UL; capacity_scale = max(raw_capacity[cpu], capacity_scale); } diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index a7359535caf5..8827c60f51e2 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -213,6 +213,8 @@ int __weak cache_setup_acpi(unsigned int cpu) return -ENOTSUPP; } +unsigned int coherency_max_size; + static int cache_shared_cpu_map_setup(unsigned int cpu) { struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); @@ -251,6 +253,9 @@ static int cache_shared_cpu_map_setup(unsigned int cpu) cpumask_set_cpu(i, &this_leaf->shared_cpu_map); } } + /* record the maximum cache line size */ + if (this_leaf->coherency_line_size > coherency_max_size) + coherency_max_size = this_leaf->coherency_line_size; } return 0; diff --git a/drivers/base/core.c b/drivers/base/core.c index fd7511e04e62..b4c64528f13c 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -2474,6 +2474,34 @@ struct device *device_find_child(struct device *parent, void *data, } EXPORT_SYMBOL_GPL(device_find_child); +/** + * device_find_child_by_name - device iterator for locating a child device. + * @parent: parent struct device + * @name: name of the child device + * + * This is similar to the device_find_child() function above, but it + * returns a reference to a device that has the name @name. + * + * NOTE: you will need to drop the reference with put_device() after use. + */ +struct device *device_find_child_by_name(struct device *parent, + const char *name) +{ + struct klist_iter i; + struct device *child; + + if (!parent) + return NULL; + + klist_iter_init(&parent->p->klist_children, &i); + while ((child = next_device(&i))) + if (!strcmp(dev_name(child), name) && get_device(child)) + break; + klist_iter_exit(&i); + return child; +} +EXPORT_SYMBOL_GPL(device_find_child_by_name); + int __init devices_init(void) { devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); diff --git a/drivers/base/devcon.c b/drivers/base/devcon.c index 04db9ae235e4..f7035fc12b92 100644 --- a/drivers/base/devcon.c +++ b/drivers/base/devcon.c @@ -38,6 +38,28 @@ fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id, return NULL; } +static void * +fwnode_devcon_match(struct fwnode_handle *fwnode, const char *con_id, + void *data, devcon_match_fn_t match) +{ + struct device_connection con = { }; + void *ret; + int i; + + for (i = 0; ; i++) { + con.fwnode = fwnode_find_reference(fwnode, con_id, i); + if (IS_ERR(con.fwnode)) + break; + + ret = match(&con, -1, data); + fwnode_handle_put(con.fwnode); + if (ret) + return ret; + } + + return NULL; +} + /** * device_connection_find_match - Find physical connection to a device * @dev: Device with the connection @@ -65,6 +87,10 @@ void *device_connection_find_match(struct device *dev, const char *con_id, ret = fwnode_graph_devcon_match(fwnode, con_id, data, match); if (ret) return ret; + + ret = fwnode_devcon_match(fwnode, con_id, data, match); + if (ret) + return ret; } mutex_lock(&devcon_lock); diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 59d19dd64928..ced6863a16a5 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -12,6 +12,7 @@ #include <linux/pm_clock.h> #include <linux/clk.h> #include <linux/clkdev.h> +#include <linux/of_clk.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/pm_domain.h> @@ -92,8 +93,6 @@ static int __pm_clk_add(struct device *dev, const char *con_id, if (con_id) { ce->con_id = kstrdup(con_id, GFP_KERNEL); if (!ce->con_id) { - dev_err(dev, - "Not enough memory for clock connection ID.\n"); kfree(ce); return -ENOMEM; } @@ -195,8 +194,7 @@ int of_pm_clk_add_clks(struct device *dev) if (!dev || !dev->of_node) return -EINVAL; - count = of_count_phandle_with_args(dev->of_node, "clocks", - "#clock-cells"); + count = of_clk_get_parent_count(dev->of_node); if (count <= 0) return -ENODEV; diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index dcfc0a36c8f7..7fb2c39bc725 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -530,21 +530,6 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd) /*------------------------- Resume routines -------------------------*/ /** - * dev_pm_skip_next_resume_phases - Skip next system resume phases for device. - * @dev: Target device. - * - * Make the core skip the "early resume" and "resume" phases for @dev. - * - * This function can be called by middle-layer code during the "noirq" phase of - * system resume if necessary, but not by device drivers. - */ -void dev_pm_skip_next_resume_phases(struct device *dev) -{ - dev->power.is_late_suspended = false; - dev->power.is_suspended = false; -} - -/** * suspend_event - Return a "suspend" message for given "resume" one. * @resume_msg: PM message representing a system-wide resume transition. */ @@ -681,6 +666,9 @@ Skip: dev->power.is_noirq_suspended = false; if (skip_resume) { + /* Make the next phases of resume skip the device. */ + dev->power.is_late_suspended = false; + dev->power.is_suspended = false; /* * The device is going to be left in suspend, but it might not * have been in runtime suspend before the system suspended, so @@ -689,7 +677,6 @@ Skip: * device again. */ pm_runtime_set_suspended(dev); - dev_pm_skip_next_resume_phases(dev); } Out: @@ -1631,17 +1618,20 @@ int dpm_suspend_late(pm_message_t state) */ int dpm_suspend_end(pm_message_t state) { - int error = dpm_suspend_late(state); + ktime_t starttime = ktime_get(); + int error; + + error = dpm_suspend_late(state); if (error) - return error; + goto out; error = dpm_suspend_noirq(state); - if (error) { + if (error) dpm_resume_early(resume_event(state)); - return error; - } - return 0; +out: + dpm_show_time(starttime, state, error, "end"); + return error; } EXPORT_SYMBOL_GPL(dpm_suspend_end); @@ -2034,6 +2024,7 @@ int dpm_prepare(pm_message_t state) */ int dpm_suspend_start(pm_message_t state) { + ktime_t starttime = ktime_get(); int error; error = dpm_prepare(state); @@ -2042,6 +2033,7 @@ int dpm_suspend_start(pm_message_t state) dpm_save_failed_step(SUSPEND_PREPARE); } else error = dpm_suspend(state); + dpm_show_time(starttime, state, error, "start"); return error; } EXPORT_SYMBOL_GPL(dpm_suspend_start); diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 5b2b6a05a4f3..ee31d4f8d856 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -968,8 +968,6 @@ void pm_wakep_autosleep_enabled(bool set) } #endif /* CONFIG_PM_AUTOSLEEP */ -static struct dentry *wakeup_sources_stats_dentry; - /** * print_wakeup_source_stats - Print wakeup source statistics information. * @m: seq_file to print the statistics into. @@ -1099,8 +1097,8 @@ static const struct file_operations wakeup_sources_stats_fops = { static int __init wakeup_sources_debugfs_init(void) { - wakeup_sources_stats_dentry = debugfs_create_file("wakeup_sources", - S_IRUGO, NULL, NULL, &wakeup_sources_stats_fops); + debugfs_create_file("wakeup_sources", S_IRUGO, NULL, NULL, + &wakeup_sources_stats_fops); return 0; } diff --git a/drivers/base/property.c b/drivers/base/property.c index 348b37e64944..81bd01ed4042 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -485,6 +485,30 @@ int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode, EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args); /** + * fwnode_find_reference - Find named reference to a fwnode_handle + * @fwnode: Firmware node where to look for the reference + * @name: The name of the reference + * @index: Index of the reference + * + * @index can be used when the named reference holds a table of references. + * + * Returns pointer to the reference fwnode, or ERR_PTR. Caller is responsible to + * call fwnode_handle_put() on the returned fwnode pointer. + */ +struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode, + const char *name, + unsigned int index) +{ + struct fwnode_reference_args args; + int ret; + + ret = fwnode_property_get_reference_args(fwnode, name, NULL, 0, index, + &args); + return ret ? ERR_PTR(ret) : args.fwnode; +} +EXPORT_SYMBOL_GPL(fwnode_find_reference); + +/** * device_remove_properties - Remove properties from a device object. * @dev: Device whose properties to remove. * diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 6ad5ef48b61e..a4984136c19d 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -4,7 +4,7 @@ # subsystems should select the appropriate symbols. config REGMAP - default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) + default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SCCB || REGMAP_I3C) select IRQ_DOMAIN if REGMAP_IRQ bool @@ -49,3 +49,7 @@ config REGMAP_SOUNDWIRE config REGMAP_SCCB tristate depends on I2C + +config REGMAP_I3C + tristate + depends on I3C diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index f5b4e8851d00..ff6c7d8ec1cd 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o obj-$(CONFIG_REGMAP_W1) += regmap-w1.o obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o +obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c index fc14e8b9344f..7886303eb026 100644 --- a/drivers/base/regmap/regcache-lzo.c +++ b/drivers/base/regmap/regcache-lzo.c @@ -148,20 +148,18 @@ static int regcache_lzo_init(struct regmap *map) * that register. */ bmp_size = map->num_reg_defaults_raw; - sync_bmp = kmalloc_array(BITS_TO_LONGS(bmp_size), sizeof(long), - GFP_KERNEL); + sync_bmp = bitmap_zalloc(bmp_size, GFP_KERNEL); if (!sync_bmp) { ret = -ENOMEM; goto err; } - bitmap_zero(sync_bmp, bmp_size); /* allocate the lzo blocks and initialize them */ for (i = 0; i < blkcount; i++) { lzo_blocks[i] = kzalloc(sizeof **lzo_blocks, GFP_KERNEL); if (!lzo_blocks[i]) { - kfree(sync_bmp); + bitmap_free(sync_bmp); ret = -ENOMEM; goto err; } @@ -213,7 +211,7 @@ static int regcache_lzo_exit(struct regmap *map) * only once. */ if (lzo_blocks[0]) - kfree(lzo_blocks[0]->sync_bmp); + bitmap_free(lzo_blocks[0]->sync_bmp); for (i = 0; i < blkcount; i++) { if (lzo_blocks[i]) { kfree(lzo_blocks[i]->wmem); diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 263f82516ff4..e5e1b3a01b1a 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -579,6 +579,8 @@ void regmap_debugfs_init(struct regmap *map, const char *name) } if (!strcmp(name, "dummy")) { + kfree(map->debugfs_name); + map->debugfs_name = kasprintf(GFP_KERNEL, "dummy%d", dummy_index); name = map->debugfs_name; diff --git a/drivers/base/regmap/regmap-i3c.c b/drivers/base/regmap/regmap-i3c.c new file mode 100644 index 000000000000..1578fb506683 --- /dev/null +++ b/drivers/base/regmap/regmap-i3c.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. + +#include <linux/regmap.h> +#include <linux/i3c/device.h> +#include <linux/i3c/master.h> +#include <linux/module.h> + +static int regmap_i3c_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct i3c_device *i3c = dev_to_i3cdev(dev); + struct i3c_priv_xfer xfers[] = { + { + .rnw = false, + .len = count, + .data.out = data, + }, + }; + + return i3c_device_do_priv_xfers(i3c, xfers, 1); +} + +static int regmap_i3c_read(void *context, + const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct device *dev = context; + struct i3c_device *i3c = dev_to_i3cdev(dev); + struct i3c_priv_xfer xfers[2]; + + xfers[0].rnw = false; + xfers[0].len = reg_size; + xfers[0].data.out = reg; + + xfers[1].rnw = true; + xfers[1].len = val_size; + xfers[1].data.in = val; + + return i3c_device_do_priv_xfers(i3c, xfers, 2); +} + +static struct regmap_bus regmap_i3c = { + .write = regmap_i3c_write, + .read = regmap_i3c_read, +}; + +struct regmap *__devm_regmap_init_i3c(struct i3c_device *i3c, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) +{ + return __devm_regmap_init(&i3c->dev, ®map_i3c, &i3c->dev, config, + lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__devm_regmap_init_i3c); + +MODULE_AUTHOR("Vitor Soares <vitor.soares@synopsys.com>"); +MODULE_DESCRIPTION("Regmap I3C Module"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index f1025452bb39..19f57ccfbe1d 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1637,6 +1637,8 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg, map->format.reg_bytes + map->format.pad_bytes, val, val_len); + else + ret = -ENOTSUPP; /* If that didn't work fall back on linearising by hand. */ if (ret == -ENOTSUPP) { diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index 7fc5a18e02ad..e7b3aa3bd55a 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -11,25 +11,25 @@ #include <linux/property.h> #include <linux/slab.h> -struct software_node { +struct swnode { int id; struct kobject kobj; struct fwnode_handle fwnode; + const struct software_node *node; /* hierarchy */ struct ida child_ids; struct list_head entry; struct list_head children; - struct software_node *parent; + struct swnode *parent; - /* properties */ - const struct property_entry *properties; + unsigned int allocated:1; }; static DEFINE_IDA(swnode_root_ids); static struct kset *swnode_kset; -#define kobj_to_swnode(_kobj_) container_of(_kobj_, struct software_node, kobj) +#define kobj_to_swnode(_kobj_) container_of(_kobj_, struct swnode, kobj) static const struct fwnode_operations software_node_ops; @@ -37,17 +37,56 @@ bool is_software_node(const struct fwnode_handle *fwnode) { return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &software_node_ops; } +EXPORT_SYMBOL_GPL(is_software_node); -#define to_software_node(__fwnode) \ +#define to_swnode(__fwnode) \ ({ \ - typeof(__fwnode) __to_software_node_fwnode = __fwnode; \ + typeof(__fwnode) __to_swnode_fwnode = __fwnode; \ \ - is_software_node(__to_software_node_fwnode) ? \ - container_of(__to_software_node_fwnode, \ - struct software_node, fwnode) : \ - NULL; \ + is_software_node(__to_swnode_fwnode) ? \ + container_of(__to_swnode_fwnode, \ + struct swnode, fwnode) : NULL; \ }) +static struct swnode * +software_node_to_swnode(const struct software_node *node) +{ + struct swnode *swnode; + struct kobject *k; + + if (!node) + return NULL; + + spin_lock(&swnode_kset->list_lock); + + list_for_each_entry(k, &swnode_kset->list, entry) { + swnode = kobj_to_swnode(k); + if (swnode->node == node) + break; + swnode = NULL; + } + + spin_unlock(&swnode_kset->list_lock); + + return swnode; +} + +const struct software_node *to_software_node(struct fwnode_handle *fwnode) +{ + struct swnode *swnode = to_swnode(fwnode); + + return swnode ? swnode->node : NULL; +} +EXPORT_SYMBOL_GPL(to_software_node); + +struct fwnode_handle *software_node_fwnode(const struct software_node *node) +{ + struct swnode *swnode = software_node_to_swnode(node); + + return swnode ? &swnode->fwnode : NULL; +} +EXPORT_SYMBOL_GPL(software_node_fwnode); + /* -------------------------------------------------------------------------- */ /* property_entry processing */ @@ -383,6 +422,9 @@ property_entries_dup(const struct property_entry *properties) int i, n = 0; int ret; + if (!properties) + return NULL; + while (properties[n].name) n++; @@ -430,7 +472,7 @@ EXPORT_SYMBOL_GPL(property_entries_free); static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode) { - struct software_node *swnode = to_software_node(fwnode); + struct swnode *swnode = to_swnode(fwnode); kobject_get(&swnode->kobj); @@ -439,7 +481,7 @@ static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode) static void software_node_put(struct fwnode_handle *fwnode) { - struct software_node *swnode = to_software_node(fwnode); + struct swnode *swnode = to_swnode(fwnode); kobject_put(&swnode->kobj); } @@ -447,8 +489,9 @@ static void software_node_put(struct fwnode_handle *fwnode) static bool software_node_property_present(const struct fwnode_handle *fwnode, const char *propname) { - return !!property_entry_get(to_software_node(fwnode)->properties, - propname); + struct swnode *swnode = to_swnode(fwnode); + + return !!property_entry_get(swnode->node->properties, propname); } static int software_node_read_int_array(const struct fwnode_handle *fwnode, @@ -456,9 +499,9 @@ static int software_node_read_int_array(const struct fwnode_handle *fwnode, unsigned int elem_size, void *val, size_t nval) { - struct software_node *swnode = to_software_node(fwnode); + struct swnode *swnode = to_swnode(fwnode); - return property_entry_read_int_array(swnode->properties, propname, + return property_entry_read_int_array(swnode->node->properties, propname, elem_size, val, nval); } @@ -466,27 +509,26 @@ static int software_node_read_string_array(const struct fwnode_handle *fwnode, const char *propname, const char **val, size_t nval) { - struct software_node *swnode = to_software_node(fwnode); + struct swnode *swnode = to_swnode(fwnode); - return property_entry_read_string_array(swnode->properties, propname, - val, nval); + return property_entry_read_string_array(swnode->node->properties, + propname, val, nval); } static struct fwnode_handle * software_node_get_parent(const struct fwnode_handle *fwnode) { - struct software_node *swnode = to_software_node(fwnode); + struct swnode *swnode = to_swnode(fwnode); - return swnode ? (swnode->parent ? &swnode->parent->fwnode : NULL) : - NULL; + return swnode ? (swnode->parent ? &swnode->parent->fwnode : NULL) : NULL; } static struct fwnode_handle * software_node_get_next_child(const struct fwnode_handle *fwnode, struct fwnode_handle *child) { - struct software_node *p = to_software_node(fwnode); - struct software_node *c = to_software_node(child); + struct swnode *p = to_swnode(fwnode); + struct swnode *c = to_swnode(child); if (!p || list_empty(&p->children) || (c && list_is_last(&c->entry, &p->children))) @@ -495,7 +537,7 @@ software_node_get_next_child(const struct fwnode_handle *fwnode, if (c) c = list_next_entry(c, entry); else - c = list_first_entry(&p->children, struct software_node, entry); + c = list_first_entry(&p->children, struct swnode, entry); return &c->fwnode; } @@ -503,18 +545,14 @@ static struct fwnode_handle * software_node_get_named_child_node(const struct fwnode_handle *fwnode, const char *childname) { - struct software_node *swnode = to_software_node(fwnode); - const struct property_entry *prop; - struct software_node *child; + struct swnode *swnode = to_swnode(fwnode); + struct swnode *child; if (!swnode || list_empty(&swnode->children)) return NULL; list_for_each_entry(child, &swnode->children, entry) { - prop = property_entry_get(child->properties, "name"); - if (!prop) - continue; - if (!strcmp(childname, prop->value.str)) { + if (!strcmp(childname, kobject_name(&child->kobj))) { kobject_get(&child->kobj); return &child->fwnode; } @@ -522,6 +560,52 @@ software_node_get_named_child_node(const struct fwnode_handle *fwnode, return NULL; } +static int +software_node_get_reference_args(const struct fwnode_handle *fwnode, + const char *propname, const char *nargs_prop, + unsigned int nargs, unsigned int index, + struct fwnode_reference_args *args) +{ + struct swnode *swnode = to_swnode(fwnode); + const struct software_node_reference *ref; + const struct property_entry *prop; + struct fwnode_handle *refnode; + int i; + + if (!swnode || !swnode->node->references) + return -ENOENT; + + for (ref = swnode->node->references; ref->name; ref++) + if (!strcmp(ref->name, propname)) + break; + + if (!ref->name || index > (ref->nrefs - 1)) + return -ENOENT; + + refnode = software_node_fwnode(ref->refs[index].node); + if (!refnode) + return -ENOENT; + + if (nargs_prop) { + prop = property_entry_get(swnode->node->properties, nargs_prop); + if (!prop) + return -EINVAL; + + nargs = prop->value.u32_data; + } + + if (nargs > NR_FWNODE_REFERENCE_ARGS) + return -EINVAL; + + args->fwnode = software_node_get(refnode); + args->nargs = nargs; + + for (i = 0; i < nargs; i++) + args->args[i] = ref->refs[index].args[i]; + + return 0; +} + static const struct fwnode_operations software_node_ops = { .get = software_node_get, .put = software_node_put, @@ -531,12 +615,13 @@ static const struct fwnode_operations software_node_ops = { .get_parent = software_node_get_parent, .get_next_child_node = software_node_get_next_child, .get_named_child_node = software_node_get_named_child_node, + .get_reference_args = software_node_get_reference_args }; /* -------------------------------------------------------------------------- */ static int -software_node_register_properties(struct software_node *swnode, +software_node_register_properties(struct software_node *node, const struct property_entry *properties) { struct property_entry *props; @@ -545,24 +630,20 @@ software_node_register_properties(struct software_node *swnode, if (IS_ERR(props)) return PTR_ERR(props); - swnode->properties = props; + node->properties = props; return 0; } static void software_node_release(struct kobject *kobj) { - struct software_node *swnode = kobj_to_swnode(kobj); + struct swnode *swnode = kobj_to_swnode(kobj); - if (swnode->parent) { - ida_simple_remove(&swnode->parent->child_ids, swnode->id); - list_del(&swnode->entry); - } else { - ida_simple_remove(&swnode_root_ids, swnode->id); + if (swnode->allocated) { + property_entries_free(swnode->node->properties); + kfree(swnode->node); } - ida_destroy(&swnode->child_ids); - property_entries_free(swnode->properties); kfree(swnode); } @@ -571,70 +652,165 @@ static struct kobj_type software_node_type = { .sysfs_ops = &kobj_sysfs_ops, }; -struct fwnode_handle * -fwnode_create_software_node(const struct property_entry *properties, - const struct fwnode_handle *parent) +static struct fwnode_handle * +swnode_register(const struct software_node *node, struct swnode *parent, + unsigned int allocated) { - struct software_node *p = NULL; - struct software_node *swnode; + struct swnode *swnode; int ret; - if (parent) { - if (IS_ERR(parent)) - return ERR_CAST(parent); - if (!is_software_node(parent)) - return ERR_PTR(-EINVAL); - p = to_software_node(parent); - } - swnode = kzalloc(sizeof(*swnode), GFP_KERNEL); - if (!swnode) - return ERR_PTR(-ENOMEM); + if (!swnode) { + ret = -ENOMEM; + goto out_err; + } - ret = ida_simple_get(p ? &p->child_ids : &swnode_root_ids, 0, 0, - GFP_KERNEL); + ret = ida_simple_get(parent ? &parent->child_ids : &swnode_root_ids, + 0, 0, GFP_KERNEL); if (ret < 0) { kfree(swnode); - return ERR_PTR(ret); + goto out_err; } swnode->id = ret; + swnode->node = node; + swnode->parent = parent; + swnode->allocated = allocated; swnode->kobj.kset = swnode_kset; swnode->fwnode.ops = &software_node_ops; ida_init(&swnode->child_ids); INIT_LIST_HEAD(&swnode->entry); INIT_LIST_HEAD(&swnode->children); - swnode->parent = p; - - if (p) - list_add_tail(&swnode->entry, &p->children); - ret = kobject_init_and_add(&swnode->kobj, &software_node_type, - p ? &p->kobj : NULL, "node%d", swnode->id); + if (node->name) + ret = kobject_init_and_add(&swnode->kobj, &software_node_type, + parent ? &parent->kobj : NULL, + "%s", node->name); + else + ret = kobject_init_and_add(&swnode->kobj, &software_node_type, + parent ? &parent->kobj : NULL, + "node%d", swnode->id); if (ret) { kobject_put(&swnode->kobj); return ERR_PTR(ret); } - ret = software_node_register_properties(swnode, properties); + if (parent) + list_add_tail(&swnode->entry, &parent->children); + + kobject_uevent(&swnode->kobj, KOBJ_ADD); + return &swnode->fwnode; + +out_err: + if (allocated) + property_entries_free(node->properties); + return ERR_PTR(ret); +} + +/** + * software_node_register_nodes - Register an array of software nodes + * @nodes: Zero terminated array of software nodes to be registered + * + * Register multiple software nodes at once. + */ +int software_node_register_nodes(const struct software_node *nodes) +{ + int ret; + int i; + + for (i = 0; nodes[i].name; i++) { + ret = software_node_register(&nodes[i]); + if (ret) { + software_node_unregister_nodes(nodes); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(software_node_register_nodes); + +/** + * software_node_unregister_nodes - Unregister an array of software nodes + * @nodes: Zero terminated array of software nodes to be unregistered + * + * Unregister multiple software nodes at once. + */ +void software_node_unregister_nodes(const struct software_node *nodes) +{ + struct swnode *swnode; + int i; + + for (i = 0; nodes[i].name; i++) { + swnode = software_node_to_swnode(&nodes[i]); + if (swnode) + fwnode_remove_software_node(&swnode->fwnode); + } +} +EXPORT_SYMBOL_GPL(software_node_unregister_nodes); + +/** + * software_node_register - Register static software node + * @node: The software node to be registered + */ +int software_node_register(const struct software_node *node) +{ + struct swnode *parent = software_node_to_swnode(node->parent); + + if (software_node_to_swnode(node)) + return -EEXIST; + + return PTR_ERR_OR_ZERO(swnode_register(node, parent, 0)); +} +EXPORT_SYMBOL_GPL(software_node_register); + +struct fwnode_handle * +fwnode_create_software_node(const struct property_entry *properties, + const struct fwnode_handle *parent) +{ + struct software_node *node; + struct swnode *p = NULL; + int ret; + + if (parent) { + if (IS_ERR(parent)) + return ERR_CAST(parent); + if (!is_software_node(parent)) + return ERR_PTR(-EINVAL); + p = to_swnode(parent); + } + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return ERR_PTR(-ENOMEM); + + ret = software_node_register_properties(node, properties); if (ret) { - kobject_put(&swnode->kobj); + kfree(node); return ERR_PTR(ret); } - kobject_uevent(&swnode->kobj, KOBJ_ADD); - return &swnode->fwnode; + node->parent = p ? p->node : NULL; + + return swnode_register(node, p, 1); } EXPORT_SYMBOL_GPL(fwnode_create_software_node); void fwnode_remove_software_node(struct fwnode_handle *fwnode) { - struct software_node *swnode = to_software_node(fwnode); + struct swnode *swnode = to_swnode(fwnode); if (!swnode) return; + if (swnode->parent) { + ida_simple_remove(&swnode->parent->child_ids, swnode->id); + list_del(&swnode->entry); + } else { + ida_simple_remove(&swnode_root_ids, swnode->id); + } + kobject_put(&swnode->kobj); } EXPORT_SYMBOL_GPL(fwnode_remove_software_node); @@ -642,7 +818,7 @@ EXPORT_SYMBOL_GPL(fwnode_remove_software_node); int software_node_notify(struct device *dev, unsigned long action) { struct fwnode_handle *fwnode = dev_fwnode(dev); - struct software_node *swnode; + struct swnode *swnode; int ret; if (!fwnode) @@ -653,7 +829,7 @@ int software_node_notify(struct device *dev, unsigned long action) if (!is_software_node(fwnode)) return 0; - swnode = to_software_node(fwnode); + swnode = to_swnode(fwnode); switch (action) { case KOBJ_ADD: diff --git a/drivers/base/topology.c b/drivers/base/topology.c index 5fd9f167ecc1..4e033d4cc0dc 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -43,6 +43,9 @@ static ssize_t name##_list_show(struct device *dev, \ define_id_show_func(physical_package_id); static DEVICE_ATTR_RO(physical_package_id); +define_id_show_func(die_id); +static DEVICE_ATTR_RO(die_id); + define_id_show_func(core_id); static DEVICE_ATTR_RO(core_id); @@ -50,10 +53,22 @@ define_siblings_show_func(thread_siblings, sibling_cpumask); static DEVICE_ATTR_RO(thread_siblings); static DEVICE_ATTR_RO(thread_siblings_list); +define_siblings_show_func(core_cpus, sibling_cpumask); +static DEVICE_ATTR_RO(core_cpus); +static DEVICE_ATTR_RO(core_cpus_list); + define_siblings_show_func(core_siblings, core_cpumask); static DEVICE_ATTR_RO(core_siblings); static DEVICE_ATTR_RO(core_siblings_list); +define_siblings_show_func(die_cpus, die_cpumask); +static DEVICE_ATTR_RO(die_cpus); +static DEVICE_ATTR_RO(die_cpus_list); + +define_siblings_show_func(package_cpus, core_cpumask); +static DEVICE_ATTR_RO(package_cpus); +static DEVICE_ATTR_RO(package_cpus_list); + #ifdef CONFIG_SCHED_BOOK define_id_show_func(book_id); static DEVICE_ATTR_RO(book_id); @@ -72,11 +87,18 @@ static DEVICE_ATTR_RO(drawer_siblings_list); static struct attribute *default_attrs[] = { &dev_attr_physical_package_id.attr, + &dev_attr_die_id.attr, &dev_attr_core_id.attr, &dev_attr_thread_siblings.attr, &dev_attr_thread_siblings_list.attr, + &dev_attr_core_cpus.attr, + &dev_attr_core_cpus_list.attr, &dev_attr_core_siblings.attr, &dev_attr_core_siblings_list.attr, + &dev_attr_die_cpus.attr, + &dev_attr_die_cpus_list.attr, + &dev_attr_package_cpus.attr, + &dev_attr_package_cpus_list.attr, #ifdef CONFIG_SCHED_BOOK &dev_attr_book_id.attr, &dev_attr_book_siblings.attr, diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c index f13b48ff5f43..b3b9cd5628fd 100644 --- a/drivers/block/drbd/drbd_debugfs.c +++ b/drivers/block/drbd/drbd_debugfs.c @@ -465,35 +465,20 @@ static const struct file_operations in_flight_summary_fops = { void drbd_debugfs_resource_add(struct drbd_resource *resource) { struct dentry *dentry; - if (!drbd_debugfs_resources) - return; dentry = debugfs_create_dir(resource->name, drbd_debugfs_resources); - if (IS_ERR_OR_NULL(dentry)) - goto fail; resource->debugfs_res = dentry; dentry = debugfs_create_dir("volumes", resource->debugfs_res); - if (IS_ERR_OR_NULL(dentry)) - goto fail; resource->debugfs_res_volumes = dentry; dentry = debugfs_create_dir("connections", resource->debugfs_res); - if (IS_ERR_OR_NULL(dentry)) - goto fail; resource->debugfs_res_connections = dentry; dentry = debugfs_create_file("in_flight_summary", 0440, resource->debugfs_res, resource, &in_flight_summary_fops); - if (IS_ERR_OR_NULL(dentry)) - goto fail; resource->debugfs_res_in_flight_summary = dentry; - return; - -fail: - drbd_debugfs_resource_cleanup(resource); - drbd_err(resource, "failed to create debugfs dentry\n"); } static void drbd_debugfs_remove(struct dentry **dp) @@ -636,35 +621,22 @@ void drbd_debugfs_connection_add(struct drbd_connection *connection) { struct dentry *conns_dir = connection->resource->debugfs_res_connections; struct dentry *dentry; - if (!conns_dir) - return; /* Once we enable mutliple peers, * these connections will have descriptive names. * For now, it is just the one connection to the (only) "peer". */ dentry = debugfs_create_dir("peer", conns_dir); - if (IS_ERR_OR_NULL(dentry)) - goto fail; connection->debugfs_conn = dentry; dentry = debugfs_create_file("callback_history", 0440, connection->debugfs_conn, connection, &connection_callback_history_fops); - if (IS_ERR_OR_NULL(dentry)) - goto fail; connection->debugfs_conn_callback_history = dentry; dentry = debugfs_create_file("oldest_requests", 0440, connection->debugfs_conn, connection, &connection_oldest_requests_fops); - if (IS_ERR_OR_NULL(dentry)) - goto fail; connection->debugfs_conn_oldest_requests = dentry; - return; - -fail: - drbd_debugfs_connection_cleanup(connection); - drbd_err(connection, "failed to create debugfs dentry\n"); } void drbd_debugfs_connection_cleanup(struct drbd_connection *connection) @@ -809,8 +781,6 @@ void drbd_debugfs_device_add(struct drbd_device *device) snprintf(vnr_buf, sizeof(vnr_buf), "%u", device->vnr); dentry = debugfs_create_dir(vnr_buf, vols_dir); - if (IS_ERR_OR_NULL(dentry)) - goto fail; device->debugfs_vol = dentry; snprintf(minor_buf, sizeof(minor_buf), "%u", device->minor); @@ -819,18 +789,14 @@ void drbd_debugfs_device_add(struct drbd_device *device) if (!slink_name) goto fail; dentry = debugfs_create_symlink(minor_buf, drbd_debugfs_minors, slink_name); + device->debugfs_minor = dentry; kfree(slink_name); slink_name = NULL; - if (IS_ERR_OR_NULL(dentry)) - goto fail; - device->debugfs_minor = dentry; #define DCF(name) do { \ dentry = debugfs_create_file(#name, 0440, \ device->debugfs_vol, device, \ &device_ ## name ## _fops); \ - if (IS_ERR_OR_NULL(dentry)) \ - goto fail; \ device->debugfs_vol_ ## name = dentry; \ } while (0) @@ -864,19 +830,9 @@ void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device) struct dentry *dentry; char vnr_buf[8]; - if (!conn_dir) - return; - snprintf(vnr_buf, sizeof(vnr_buf), "%u", peer_device->device->vnr); dentry = debugfs_create_dir(vnr_buf, conn_dir); - if (IS_ERR_OR_NULL(dentry)) - goto fail; peer_device->debugfs_peer_dev = dentry; - return; - -fail: - drbd_debugfs_peer_device_cleanup(peer_device); - drbd_err(peer_device, "failed to create debugfs entries\n"); } void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device) @@ -917,35 +873,19 @@ void drbd_debugfs_cleanup(void) drbd_debugfs_remove(&drbd_debugfs_root); } -int __init drbd_debugfs_init(void) +void __init drbd_debugfs_init(void) { struct dentry *dentry; dentry = debugfs_create_dir("drbd", NULL); - if (IS_ERR_OR_NULL(dentry)) - goto fail; drbd_debugfs_root = dentry; dentry = debugfs_create_file("version", 0444, drbd_debugfs_root, NULL, &drbd_version_fops); - if (IS_ERR_OR_NULL(dentry)) - goto fail; drbd_debugfs_version = dentry; dentry = debugfs_create_dir("resources", drbd_debugfs_root); - if (IS_ERR_OR_NULL(dentry)) - goto fail; drbd_debugfs_resources = dentry; dentry = debugfs_create_dir("minors", drbd_debugfs_root); - if (IS_ERR_OR_NULL(dentry)) - goto fail; drbd_debugfs_minors = dentry; - return 0; - -fail: - drbd_debugfs_cleanup(); - if (dentry) - return PTR_ERR(dentry); - else - return -EINVAL; } diff --git a/drivers/block/drbd/drbd_debugfs.h b/drivers/block/drbd/drbd_debugfs.h index 4ecfbb3358d7..58e31cef0844 100644 --- a/drivers/block/drbd/drbd_debugfs.h +++ b/drivers/block/drbd/drbd_debugfs.h @@ -6,7 +6,7 @@ #include "drbd_int.h" #ifdef CONFIG_DEBUG_FS -int __init drbd_debugfs_init(void); +void __init drbd_debugfs_init(void); void drbd_debugfs_cleanup(void); void drbd_debugfs_resource_add(struct drbd_resource *resource); @@ -22,7 +22,7 @@ void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device); void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device); #else -static inline int __init drbd_debugfs_init(void) { return -ENODEV; } +static inline void __init drbd_debugfs_init(void) { } static inline void drbd_debugfs_cleanup(void) { } static inline void drbd_debugfs_resource_add(struct drbd_resource *resource) { } diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 31237f45247a..ddbf56014c51 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1960,7 +1960,7 @@ static inline void wake_ack_receiver(struct drbd_connection *connection) { struct task_struct *task = connection->ack_receiver.task; if (task && get_t_state(&connection->ack_receiver) == RUNNING) - force_sig(SIGXCPU, task); + send_sig(SIGXCPU, task, 1); } static inline void request_ping(struct drbd_connection *connection) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 541b31fa42b3..9bd4ddd12b25 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -465,7 +465,7 @@ void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait) smp_mb(); init_completion(&thi->stop); if (thi->task != current) - force_sig(DRBD_SIGKILL, thi->task); + send_sig(DRBD_SIGKILL, thi->task, 1); } spin_unlock_irqrestore(&thi->t_lock, flags); @@ -3009,8 +3009,7 @@ static int __init drbd_init(void) spin_lock_init(&retry.lock); INIT_LIST_HEAD(&retry.writes); - if (drbd_debugfs_init()) - pr_notice("failed to initialize debugfs -- will not be available\n"); + drbd_debugfs_init(); pr_info("initialized. " "Version: " REL_VERSION " (api:%d/proto:%d-%d)\n", diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index cdd748b8116d..5d52a2d32155 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -599,7 +599,7 @@ void conn_try_outdate_peer_async(struct drbd_connection *connection) struct task_struct *opa; kref_get(&connection->kref); - /* We may just have force_sig()'ed this thread + /* We may have just sent a signal to this thread * to get it out of some blocking network function. * Clear signals; otherwise kthread_run(), which internally uses * wait_on_completion_killable(), will mistake our pending signal diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 9fb9b312ab6b..b933a7eea52b 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3900,7 +3900,7 @@ static void __init config_types(void) if (!UDP->cmos) UDP->cmos = FLOPPY0_TYPE; drive = 1; - if (!UDP->cmos && FLOPPY1_TYPE) + if (!UDP->cmos) UDP->cmos = FLOPPY1_TYPE; /* FIXME: additional physical CMOS drive detection should go here */ diff --git a/drivers/block/loop.c b/drivers/block/loop.c index f11b7dc16e9d..44c9985f352a 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -264,20 +264,12 @@ lo_do_transfer(struct loop_device *lo, int cmd, return ret; } -static inline void loop_iov_iter_bvec(struct iov_iter *i, - unsigned int direction, const struct bio_vec *bvec, - unsigned long nr_segs, size_t count) -{ - iov_iter_bvec(i, direction, bvec, nr_segs, count); - i->type |= ITER_BVEC_FLAG_NO_REF; -} - static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos) { struct iov_iter i; ssize_t bw; - loop_iov_iter_bvec(&i, WRITE, bvec, 1, bvec->bv_len); + iov_iter_bvec(&i, WRITE, bvec, 1, bvec->bv_len); file_start_write(file); bw = vfs_iter_write(file, &i, ppos, 0); @@ -355,7 +347,7 @@ static int lo_read_simple(struct loop_device *lo, struct request *rq, ssize_t len; rq_for_each_segment(bvec, rq, iter) { - loop_iov_iter_bvec(&i, READ, &bvec, 1, bvec.bv_len); + iov_iter_bvec(&i, READ, &bvec, 1, bvec.bv_len); len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0); if (len < 0) return len; @@ -396,7 +388,7 @@ static int lo_read_transfer(struct loop_device *lo, struct request *rq, b.bv_offset = 0; b.bv_len = bvec.bv_len; - loop_iov_iter_bvec(&i, READ, &b, 1, b.bv_len); + iov_iter_bvec(&i, READ, &b, 1, b.bv_len); len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0); if (len < 0) { ret = len; @@ -563,7 +555,7 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, } atomic_set(&cmd->ref, 2); - loop_iov_iter_bvec(&iter, rw, bvec, nr_bvec, blk_rq_bytes(rq)); + iov_iter_bvec(&iter, rw, bvec, nr_bvec, blk_rq_bytes(rq)); iter.iov_offset = offset; cmd->iocb.ki_pos = pos; diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index a14b09ab3a41..964f78cfffa0 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -1577,7 +1577,6 @@ static int exec_drive_command(struct mtip_port *port, u8 *command, ATA_SECT_SIZE * xfer_sz); return -ENOMEM; } - memset(buf, 0, ATA_SECT_SIZE * xfer_sz); } /* Build the FIS. */ @@ -2776,7 +2775,6 @@ static int mtip_dma_alloc(struct driver_data *dd) &port->block1_dma, GFP_KERNEL); if (!port->block1) return -ENOMEM; - memset(port->block1, 0, BLOCK_DMA_ALLOC_SZ); /* Allocate dma memory for command list */ port->command_list = @@ -2789,7 +2787,6 @@ static int mtip_dma_alloc(struct driver_data *dd) port->block1_dma = 0; return -ENOMEM; } - memset(port->command_list, 0, AHCI_CMD_TBL_SZ); /* Setup all pointers into first DMA region */ port->rxfis = port->block1 + AHCI_RX_FIS_OFFSET; @@ -3529,8 +3526,6 @@ static int mtip_init_cmd(struct blk_mq_tag_set *set, struct request *rq, if (!cmd->command) return -ENOMEM; - memset(cmd->command, 0, CMD_DMA_ALLOC_SZ); - sg_init_table(cmd->sg, MTIP_MAX_SG); return 0; } diff --git a/drivers/block/null_blk_main.c b/drivers/block/null_blk_main.c index 447d635c79a2..99328ded60d1 100644 --- a/drivers/block/null_blk_main.c +++ b/drivers/block/null_blk_main.c @@ -327,11 +327,12 @@ static ssize_t nullb_device_power_store(struct config_item *item, set_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags); dev->power = newp; } else if (dev->power && !newp) { - mutex_lock(&lock); - dev->power = newp; - null_del_dev(dev->nullb); - mutex_unlock(&lock); - clear_bit(NULLB_DEV_FL_UP, &dev->flags); + if (test_and_clear_bit(NULLB_DEV_FL_UP, &dev->flags)) { + mutex_lock(&lock); + dev->power = newp; + null_del_dev(dev->nullb); + mutex_unlock(&lock); + } clear_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags); } @@ -1197,7 +1198,7 @@ static blk_status_t null_handle_cmd(struct nullb_cmd *cmd) if (!cmd->error && dev->zoned) { sector_t sector; unsigned int nr_sectors; - int op; + enum req_opf op; if (dev->queue_mode == NULL_Q_BIO) { op = bio_op(cmd->bio); @@ -1488,7 +1489,6 @@ static int setup_queues(struct nullb *nullb) if (!nullb->queues) return -ENOMEM; - nullb->nr_queues = 0; nullb->queue_depth = nullb->dev->hw_queue_depth; return 0; diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 7d3ad6c22ee5..51569c199a6c 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for sTec s1120 PCIe SSDs. sTec was acquired in 2013 by HGST and HGST * was acquired by Western Digital in 2012. * * Copyright 2012 sTec, Inc. * Copyright (c) 2017 Western Digital Corporation or its affiliates. - * - * This file is part of the Linux kernel, and is made available under - * the terms of the GNU General Public License version 2. */ #include <linux/kernel.h> @@ -2696,7 +2694,6 @@ static int skd_cons_skmsg(struct skd_device *skdev) (FIT_QCMD_ALIGN - 1), "not aligned: msg_buf %p mb_dma_address %pad\n", skmsg->msg_buf, &skmsg->mb_dma_address); - memset(skmsg->msg_buf, 0, SKD_N_FITMSG_BYTES); } err_out: diff --git a/drivers/block/skd_s1120.h b/drivers/block/skd_s1120.h index de35f47e953c..c30bb98c7cd2 100644 --- a/drivers/block/skd_s1120.h +++ b/drivers/block/skd_s1120.h @@ -1,9 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2012 STEC, Inc. * Copyright (c) 2017 Western Digital Corporation or its affiliates. - * - * This file is part of the Linux kernel, and is made available under - * the terms of the GNU General Public License version 2. */ diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 464c9092bc8b..5d8e0ab3f054 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Xilinx SystemACE device driver * * Copyright 2007 Secret Lab Technologies Ltd. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ /* diff --git a/drivers/bus/da8xx-mstpri.c b/drivers/bus/da8xx-mstpri.c index 9af9bcc68059..ee4c02335130 100644 --- a/drivers/bus/da8xx-mstpri.c +++ b/drivers/bus/da8xx-mstpri.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI da8xx master peripheral priority driver * @@ -5,10 +6,6 @@ * * Author: * Bartosz Golaszewski <bgolaszewski@baylibre.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/bus/qcom-ebi2.c b/drivers/bus/qcom-ebi2.c index 56b01e4344d3..03ddcf426887 100644 --- a/drivers/bus/qcom-ebi2.c +++ b/drivers/bus/qcom-ebi2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Qualcomm External Bus Interface 2 (EBI2) driver * an older version of the Qualcomm Parallel Interface Controller (QPIC) @@ -6,10 +7,6 @@ * * Author: Linus Walleij <linus.walleij@linaro.org> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * * See the device tree bindings for this block for more details on the * hardware. */ diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 308475ed4b32..b72741668c92 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -660,12 +660,6 @@ static int sysc_check_registers(struct sysc *ddata) nr_regs++; } - if (nr_regs < 1) { - dev_err(ddata->dev, "missing registers\n"); - - return -EINVAL; - } - if (nr_matches > nr_regs) { dev_err(ddata->dev, "overlapping registers: (%i/%i)", nr_regs, nr_matches); @@ -691,12 +685,18 @@ static int sysc_ioremap(struct sysc *ddata) { int size; - size = max3(ddata->offsets[SYSC_REVISION], - ddata->offsets[SYSC_SYSCONFIG], - ddata->offsets[SYSC_SYSSTATUS]); + if (ddata->offsets[SYSC_REVISION] < 0 && + ddata->offsets[SYSC_SYSCONFIG] < 0 && + ddata->offsets[SYSC_SYSSTATUS] < 0) { + size = ddata->module_size; + } else { + size = max3(ddata->offsets[SYSC_REVISION], + ddata->offsets[SYSC_SYSCONFIG], + ddata->offsets[SYSC_SYSSTATUS]); - if (size < 0 || (size + sizeof(u32)) > ddata->module_size) - return -EINVAL; + if ((size + sizeof(u32)) > ddata->module_size) + return -EINVAL; + } ddata->module_va = devm_ioremap(ddata->dev, ddata->module_pa, @@ -1128,7 +1128,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK("cpgmac", 0, 0x1200, 0x1208, 0x1204, 0x4edb1902, 0xffff00f0, 0), SYSC_QUIRK("dcan", 0, 0, -1, -1, 0xffffffff, 0xffffffff, 0), - SYSC_QUIRK("dcan", 0, 0, -1, -1, 0x00001401, 0xffffffff, 0), SYSC_QUIRK("dmic", 0, 0, 0x10, -1, 0x50010000, 0xffffffff, 0), SYSC_QUIRK("dwc3", 0, 0, 0x10, -1, 0x500a0200, 0xffffffff, 0), SYSC_QUIRK("epwmss", 0, 0, 0x4, -1, 0x47400001, 0xffffffff, 0), diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 658664a5a5aa..df1edb5ec0ad 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -1311,8 +1311,7 @@ static void ipi_handler(void *null) void global_cache_flush(void) { - if (on_each_cpu(ipi_handler, NULL, 1) != 0) - panic(PFX "timed out waiting for the other CPUs!\n"); + on_each_cpu(ipi_handler, NULL, 1); } EXPORT_SYMBOL(global_cache_flush); diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 3695773ce7c3..84d9adbb62f6 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HP zx1 AGPGART routines. * * (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P. * Bjorn Helgaas <bjorn.helgaas@hp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index 15f2e7025b78..ed3c4c42fc23 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HP Quicksilver AGP GART routines * @@ -6,11 +7,6 @@ * Based on drivers/char/agpgart/hp-agp.c which is * (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P. * Bjorn Helgaas <bjorn.helgaas@hp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 3a1e6b3ccd10..5c39f20378b8 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Intel & MS High Precision Event Timer Implementation. * @@ -5,10 +6,6 @@ * Venki Pallipadi * (c) Copyright 2004 Hewlett-Packard Development Company, L.P. * Bob Picco <robert.picco@hp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/interrupt.h> diff --git a/drivers/char/hw_random/hisi-rng.c b/drivers/char/hw_random/hisi-rng.c index 40d96572c591..c663d5dd85bb 100644 --- a/drivers/char/hw_random/hisi-rng.c +++ b/drivers/char/hw_random/hisi-rng.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 HiSilicon Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/char/hw_random/iproc-rng200.c b/drivers/char/hw_random/iproc-rng200.c index 8b5a20b35293..92be1c0ab99f 100644 --- a/drivers/char/hw_random/iproc-rng200.c +++ b/drivers/char/hw_random/iproc-rng200.c @@ -220,6 +220,7 @@ static int iproc_rng200_probe(struct platform_device *pdev) } static const struct of_device_id iproc_rng200_of_match[] = { + { .compatible = "brcm,bcm7211-rng200", }, { .compatible = "brcm,bcm7278-rng200", }, { .compatible = "brcm,iproc-rng200", }, {}, diff --git a/drivers/char/hw_random/meson-rng.c b/drivers/char/hw_random/meson-rng.c index 2e23be802a62..76e693da5dde 100644 --- a/drivers/char/hw_random/meson-rng.c +++ b/drivers/char/hw_random/meson-rng.c @@ -1,58 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * * Copyright (c) 2016 BayLibre, SAS. * Author: Neil Armstrong <narmstrong@baylibre.com> * Copyright (C) 2014 Amlogic, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * BSD LICENSE - * - * Copyright (c) 2016 BayLibre, SAS. - * Author: Neil Armstrong <narmstrong@baylibre.com> - * Copyright (C) 2014 Amlogic, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <linux/err.h> #include <linux/module.h> diff --git a/drivers/char/hw_random/st-rng.c b/drivers/char/hw_random/st-rng.c index 938ec10e733d..bd6a98b3479b 100644 --- a/drivers/char/hw_random/st-rng.c +++ b/drivers/char/hw_random/st-rng.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ST Random Number Generator Driver ST's Platforms * @@ -5,10 +6,6 @@ * Lee Jones <lee.jones@linaro.org> * * Copyright (C) 2015 STMicroelectronics (R&D) Limited - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index f615684028af..ccd1f6e0696b 100644 --- a/drivers/char/hw_random/timeriomem-rng.c +++ b/drivers/char/hw_random/timeriomem-rng.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/char/hw_random/timeriomem-rng.c * @@ -7,10 +8,6 @@ * Copyright 2005 (c) MontaVista Software, Inc. * Author: Deepak Saxena <dsaxena@plexity.net> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Overview: * This driver is useful for platforms that have an IO range that provides * periodic random data from a single IO memory address. All the platform diff --git a/drivers/char/tpm/eventlog/efi.c b/drivers/char/tpm/eventlog/efi.c index 3e44362e469c..6bb023de17f1 100644 --- a/drivers/char/tpm/eventlog/efi.c +++ b/drivers/char/tpm/eventlog/efi.c @@ -16,10 +16,13 @@ int tpm_read_log_efi(struct tpm_chip *chip) { + struct efi_tcg2_final_events_table *final_tbl = NULL; struct linux_efi_tpm_eventlog *log_tbl; struct tpm_bios_log *log; u32 log_size; u8 tpm_log_version; + void *tmp; + int ret; if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) return -ENODEV; @@ -47,15 +50,57 @@ int tpm_read_log_efi(struct tpm_chip *chip) /* malloc EventLog space */ log->bios_event_log = kmemdup(log_tbl->log, log_size, GFP_KERNEL); - if (!log->bios_event_log) - goto err_memunmap; - log->bios_event_log_end = log->bios_event_log + log_size; + if (!log->bios_event_log) { + ret = -ENOMEM; + goto out; + } + log->bios_event_log_end = log->bios_event_log + log_size; tpm_log_version = log_tbl->version; - memunmap(log_tbl); - return tpm_log_version; -err_memunmap: + ret = tpm_log_version; + + if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR || + efi_tpm_final_log_size == 0 || + tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) + goto out; + + final_tbl = memremap(efi.tpm_final_log, + sizeof(*final_tbl) + efi_tpm_final_log_size, + MEMREMAP_WB); + if (!final_tbl) { + pr_err("Could not map UEFI TPM final log\n"); + kfree(log->bios_event_log); + ret = -ENOMEM; + goto out; + } + + efi_tpm_final_log_size -= log_tbl->final_events_preboot_size; + + tmp = krealloc(log->bios_event_log, + log_size + efi_tpm_final_log_size, + GFP_KERNEL); + if (!tmp) { + kfree(log->bios_event_log); + ret = -ENOMEM; + goto out; + } + + log->bios_event_log = tmp; + + /* + * Copy any of the final events log that didn't also end up in the + * main log. Events can be logged in both if events are generated + * between GetEventLog() and ExitBootServices(). + */ + memcpy((void *)log->bios_event_log + log_size, + final_tbl->events + log_tbl->final_events_preboot_size, + efi_tpm_final_log_size); + log->bios_event_log_end = log->bios_event_log + + log_size + efi_tpm_final_log_size; + +out: + memunmap(final_tbl); memunmap(log_tbl); - return -ENOMEM; + return ret; } diff --git a/drivers/char/tpm/eventlog/tpm2.c b/drivers/char/tpm/eventlog/tpm2.c index d506362e046f..b9aeda1cbcd7 100644 --- a/drivers/char/tpm/eventlog/tpm2.c +++ b/drivers/char/tpm/eventlog/tpm2.c @@ -36,52 +36,7 @@ static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event, struct tcg_pcr_event *event_header) { - struct tcg_efi_specid_event_head *efispecid; - struct tcg_event_field *event_field; - void *marker; - void *marker_start; - u32 halg_size; - size_t size; - u16 halg; - int i; - int j; - - marker = event; - marker_start = marker; - marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type) - + sizeof(event->count); - - efispecid = (struct tcg_efi_specid_event_head *)event_header->event; - - /* Check if event is malformed. */ - if (event->count > efispecid->num_algs) - return 0; - - for (i = 0; i < event->count; i++) { - halg_size = sizeof(event->digests[i].alg_id); - memcpy(&halg, marker, halg_size); - marker = marker + halg_size; - for (j = 0; j < efispecid->num_algs; j++) { - if (halg == efispecid->digest_sizes[j].alg_id) { - marker += - efispecid->digest_sizes[j].digest_size; - break; - } - } - /* Algorithm without known length. Such event is unparseable. */ - if (j == efispecid->num_algs) - return 0; - } - - event_field = (struct tcg_event_field *)marker; - marker = marker + sizeof(event_field->event_size) - + event_field->event_size; - size = marker - marker_start; - - if ((event->event_type == 0) && (event_field->event_size == 0)) - return 0; - - return size; + return __calc_tpm2_event_size(event, event_header, false); } static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 90325e1749fb..d47ad10a35fe 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -289,15 +289,15 @@ static int tpm_class_shutdown(struct device *dev) { struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); + down_write(&chip->ops_sem); if (chip->flags & TPM_CHIP_FLAG_TPM2) { - down_write(&chip->ops_sem); if (!tpm_chip_start(chip)) { tpm2_shutdown(chip, TPM2_SU_CLEAR); tpm_chip_stop(chip); } - chip->ops = NULL; - up_write(&chip->ops_sem); } + chip->ops = NULL; + up_write(&chip->ops_sem); return 0; } diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c index 85dcf2654d11..faacbe1ffa1a 100644 --- a/drivers/char/tpm/tpm1-cmd.c +++ b/drivers/char/tpm/tpm1-cmd.c @@ -510,7 +510,7 @@ struct tpm1_get_random_out { * * Return: * * number of bytes read - * * -errno or a TPM return code otherwise + * * -errno (positive TPM return codes are masked to -EIO) */ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) { @@ -531,8 +531,11 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len), "attempting get random"); - if (rc) + if (rc) { + if (rc > 0) + rc = -EIO; goto out; + } out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE]; diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 4de49924cfc4..d103545e4055 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -297,7 +297,7 @@ struct tpm2_get_random_out { * * Return: * size of the buffer on success, - * -errno otherwise + * -errno otherwise (positive TPM return codes are masked to -EIO) */ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) { @@ -324,8 +324,11 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) offsetof(struct tpm2_get_random_out, buffer), "attempting get random"); - if (err) + if (err) { + if (err > 0) + err = -EIO; goto out; + } out = (struct tpm2_get_random_out *) &buf.data[TPM_HEADER_SIZE]; diff --git a/drivers/char/tpm/tpmrm-dev.c b/drivers/char/tpm/tpmrm-dev.c index 0c751a79bbed..7a0a7051a06f 100644 --- a/drivers/char/tpm/tpmrm-dev.c +++ b/drivers/char/tpm/tpmrm-dev.c @@ -1,7 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 James.Bottomley@HansenPartnership.com - * - * GPLv2 */ #include <linux/slab.h> #include "tpm-dev.h" diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index 4e2d00cb0d81..da5b30771418 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Implementation of the Xen vTPM device frontend * * Author: Daniel De Graaf <dgdegra@tycho.nsa.gov> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #include <linux/errno.h> #include <linux/err.h> diff --git a/drivers/clk/axis/clk-artpec6.c b/drivers/clk/axis/clk-artpec6.c index da1a073c2236..f95959ff85ac 100644 --- a/drivers/clk/axis/clk-artpec6.c +++ b/drivers/clk/axis/clk-artpec6.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ARTPEC-6 clock initialization * * Copyright 2015-2016 Axis Comunications AB. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk-provider.h> diff --git a/drivers/clk/bcm/clk-bcm53573-ilp.c b/drivers/clk/bcm/clk-bcm53573-ilp.c index 36eb3716ffb0..84f2af736ee8 100644 --- a/drivers/clk/bcm/clk-bcm53573-ilp.c +++ b/drivers/clk/bcm/clk-bcm53573-ilp.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk-provider.h> diff --git a/drivers/clk/bcm/clk-sr.c b/drivers/clk/bcm/clk-sr.c index 7b9efc0212a8..5db021685d6d 100644 --- a/drivers/clk/bcm/clk-sr.c +++ b/drivers/clk/bcm/clk-sr.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2017 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ #include <linux/err.h> diff --git a/drivers/clk/clk-axm5516.c b/drivers/clk/clk-axm5516.c index 98e0c9ba7b61..07e80fe8c310 100644 --- a/drivers/clk/clk-axm5516.c +++ b/drivers/clk/clk-axm5516.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/clk/clk-axm5516.c * @@ -5,10 +6,6 @@ * the Axxia device: PLL clock, a clock divider and a clock mux. * * Copyright (C) 2014 LSI Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/module.h> #include <linux/kernel.h> diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c index f21d9092564f..0443dfc82794 100644 --- a/drivers/clk/clk-cdce706.c +++ b/drivers/clk/clk-cdce706.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI CDCE706 programmable 3-PLL clock synthesizer driver * * Copyright (c) 2014 Cadence Design Systems Inc. * * Reference: http://www.ti.com/lit/ds/symlink/cdce706.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/clk/clk-efm32gg.c b/drivers/clk/clk-efm32gg.c index f37cf08ff7aa..85beaacb4088 100644 --- a/drivers/clk/clk-efm32gg.c +++ b/drivers/clk/clk-efm32gg.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Pengutronix * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. */ #include <linux/io.h> #include <linux/clk-provider.h> diff --git a/drivers/clk/clk-nspire.c b/drivers/clk/clk-nspire.c index f861011d5d21..6305058dd0d3 100644 --- a/drivers/clk/clk-nspire.c +++ b/drivers/clk/clk-nspire.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * */ #include <linux/clk-provider.h> diff --git a/drivers/clk/clk-pwm.c b/drivers/clk/clk-pwm.c index 02b472a1f9b0..5f0490b8f6cb 100644 --- a/drivers/clk/clk-pwm.c +++ b/drivers/clk/clk-pwm.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Philipp Zabel, Pengutronix * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * PWM (mis)used as clock output */ #include <linux/clk-provider.h> diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 4739a47ec8bd..dd93d3acc67d 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2013 Freescale Semiconductor, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * clock driver for Freescale QorIQ SoCs. */ diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index aa51756fd4d6..87b410d6e51d 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -368,7 +368,7 @@ static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index) const char *dev_id = dev ? dev_name(dev) : NULL; struct device_node *np = core->of_node; - if (np && index >= 0) + if (np && (name || index >= 0)) hw = of_clk_get_hw(np, index, name); /* diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 2afc8df8acff..0f2e3fcf0f19 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/clk/clkdev.c * * Copyright (C) 2008 Russell King. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Helper for the clk API to assist looking up a struct clk. */ #include <linux/module.h> diff --git a/drivers/clk/hisilicon/clk-hi6220-stub.c b/drivers/clk/hisilicon/clk-hi6220-stub.c index 329a09214d12..4fdee4424d82 100644 --- a/drivers/clk/hisilicon/clk-hi6220-stub.c +++ b/drivers/clk/hisilicon/clk-hi6220-stub.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Hi6220 stub clock driver * @@ -5,11 +6,6 @@ * Copyright (c) 2015 Linaro Limited. * * Author: Leo Yan <leo.yan@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/clk-provider.h> diff --git a/drivers/clk/hisilicon/clk-hi6220.c b/drivers/clk/hisilicon/clk-hi6220.c index a87809d4bd52..b2c5b6bbb1c1 100644 --- a/drivers/clk/hisilicon/clk-hi6220.c +++ b/drivers/clk/hisilicon/clk-hi6220.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Hisilicon Hi6220 clock driver * * Copyright (c) 2015 Hisilicon Limited. * * Author: Bintian Wang <bintian.wang@huawei.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c index 9f46cf9dcc65..5348bafe694f 100644 --- a/drivers/clk/hisilicon/clkdivider-hi6220.c +++ b/drivers/clk/hisilicon/clkdivider-hi6220.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Hisilicon hi6220 SoC divider clock driver * * Copyright (c) 2015 Hisilicon Limited. * * Author: Bintian Wang <bintian.wang@huawei.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/clk/imx/clk-cpu.c b/drivers/clk/imx/clk-cpu.c index ed1b7e97a0d3..00d026eb7891 100644 --- a/drivers/clk/imx/clk-cpu.c +++ b/drivers/clk/imx/clk-cpu.c @@ -1,12 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 Lucas Stach <l.stach@pengutronix.de>, Pengutronix - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html */ #include <linux/clk.h> diff --git a/drivers/clk/imx/clk-gate-exclusive.c b/drivers/clk/imx/clk-gate-exclusive.c index 3bd9dee618b2..cffa4966568d 100644 --- a/drivers/clk/imx/clk-gate-exclusive.c +++ b/drivers/clk/imx/clk-gate-exclusive.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2014 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk-provider.h> diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c index 60fc9d7a9723..ec08fda547a3 100644 --- a/drivers/clk/imx/clk-gate2.c +++ b/drivers/clk/imx/clk-gate2.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com> * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Gated clock implementation */ diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c index 203cad6c9aab..e595f559907f 100644 --- a/drivers/clk/imx/clk-imx35.c +++ b/drivers/clk/imx/clk-imx35.c @@ -1,10 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/mm.h> #include <linux/delay.h> diff --git a/drivers/clk/imx/clk-imx5.c b/drivers/clk/imx/clk-imx5.c index c85ebd74a8a5..01e079b81026 100644 --- a/drivers/clk/imx/clk-imx5.c +++ b/drivers/clk/imx/clk-imx5.c @@ -1,10 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/mm.h> #include <linux/delay.h> diff --git a/drivers/clk/imx/clk-imx6sl.c b/drivers/clk/imx/clk-imx6sl.c index e13d8814cfa4..f9f1f8a95d92 100644 --- a/drivers/clk/imx/clk-imx6sl.c +++ b/drivers/clk/imx/clk-imx6sl.c @@ -1,10 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2013-2014 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/clk.h> diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 739f64fdf1e3..206fafd299ea 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -2734,8 +2734,8 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { [CLKID_MALI_1_DIV] = &g12a_mali_1_div.hw, [CLKID_MALI_1] = &g12a_mali_1.hw, [CLKID_MALI] = &g12a_mali.hw, - [CLKID_MPLL_5OM_DIV] = &g12a_mpll_50m_div.hw, - [CLKID_MPLL_5OM] = &g12a_mpll_50m.hw, + [CLKID_MPLL_50M_DIV] = &g12a_mpll_50m_div.hw, + [CLKID_MPLL_50M] = &g12a_mpll_50m.hw, [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw, [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw, [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_premux0.hw, diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h index 39c41af70804..bcc05cd9882f 100644 --- a/drivers/clk/meson/g12a.h +++ b/drivers/clk/meson/g12a.h @@ -166,7 +166,7 @@ #define CLKID_HDMI_DIV 167 #define CLKID_MALI_0_DIV 170 #define CLKID_MALI_1_DIV 173 -#define CLKID_MPLL_5OM_DIV 176 +#define CLKID_MPLL_50M_DIV 176 #define CLKID_SYS_PLL_DIV16_EN 178 #define CLKID_SYS_PLL_DIV16 179 #define CLKID_CPU_CLK_DYN0_SEL 180 diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 37cf0f01bb5d..62cd3a7f1f65 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -1761,7 +1761,7 @@ static struct clk_regmap meson8m2_gp_pll = { }, }; -static const char * const mmeson8b_vpu_0_1_parent_names[] = { +static const char * const meson8b_vpu_0_1_parent_names[] = { "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" }; @@ -1778,8 +1778,8 @@ static struct clk_regmap meson8b_vpu_0_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_0_sel", .ops = &clk_regmap_mux_ops, - .parent_names = mmeson8b_vpu_0_1_parent_names, - .num_parents = ARRAY_SIZE(mmeson8b_vpu_0_1_parent_names), + .parent_names = meson8b_vpu_0_1_parent_names, + .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_names), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1837,8 +1837,8 @@ static struct clk_regmap meson8b_vpu_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_1_sel", .ops = &clk_regmap_mux_ops, - .parent_names = mmeson8b_vpu_0_1_parent_names, - .num_parents = ARRAY_SIZE(mmeson8b_vpu_0_1_parent_names), + .parent_names = meson8b_vpu_0_1_parent_names, + .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_names), .flags = CLK_SET_RATE_PARENT, }, }; diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c index 32c19c0f1e14..0dc478a19451 100644 --- a/drivers/clk/rockchip/clk-cpu.c +++ b/drivers/clk/rockchip/clk-cpu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 MundoReader S.L. * Author: Heiko Stuebner <heiko@sntech.de> @@ -6,10 +7,6 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Thomas Abraham <thomas.ab@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * A CPU clock is defined as a clock supplied to a CPU or a group of CPUs. * The CPU clock is typically derived from a hierarchy of clock * blocks which includes mux and divider blocks. There are a number of other diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c index 3f80bcd46074..efc4fa61fbaf 100644 --- a/drivers/clk/samsung/clk-cpu.c +++ b/drivers/clk/samsung/clk-cpu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Thomas Abraham <thomas.ab@samsung.com> @@ -5,10 +6,6 @@ * Copyright (c) 2015 Samsung Electronics Co., Ltd. * Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This file contains the utility function to register CPU clock for Samsung * Exynos platforms. A CPU clock is defined as a clock supplied to a CPU or a * group of CPUs. The CPU clock is typically derived from a hierarchy of clock diff --git a/drivers/clk/samsung/clk-cpu.h b/drivers/clk/samsung/clk-cpu.h index bd38c6aa3897..ad38cc27f3df 100644 --- a/drivers/clk/samsung/clk-cpu.h +++ b/drivers/clk/samsung/clk-cpu.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for all PLL's in Samsung platforms */ diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 8f8a0f9fc842..42b5d32c6cc7 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Author: Padmavathi Venna <padma.v@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for Audio Subsystem Clock Controller. */ diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c index ce41f36a0e29..34ccb1d23bc3 100644 --- a/drivers/clk/samsung/clk-exynos-clkout.c +++ b/drivers/clk/samsung/clk-exynos-clkout.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Tomasz Figa <t.figa@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Clock driver for Exynos clock output */ diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index facaad3c56a1..17897c7a84d4 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for Exynos3250 SoC. */ diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index d2a68a792a21..982eb02bafda 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Copyright (c) 2013 Linaro Ltd. * Author: Thomas Abraham <thomas.ab@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for all Exynos4 SoCs. */ diff --git a/drivers/clk/samsung/clk-exynos4412-isp.c b/drivers/clk/samsung/clk-exynos4412-isp.c index cfaa057035ad..4b9e73608c21 100644 --- a/drivers/clk/samsung/clk-exynos4412-isp.c +++ b/drivers/clk/samsung/clk-exynos4412-isp.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017 Samsung Electronics Co., Ltd. * Author: Marek Szyprowski <m.szyprowski@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for Exynos4412 ISP module. */ diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index c8265c4cbc4f..f2b896881768 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Copyright (c) 2013 Linaro Ltd. * Author: Thomas Abraham <thomas.ab@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for Exynos5250 SoC. */ diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c index 2cc2583abd87..e05d7323669a 100644 --- a/drivers/clk/samsung/clk-exynos5260.c +++ b/drivers/clk/samsung/clk-exynos5260.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Rahul Sharma <rahul.sharma@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for Exynos5260 SoC. */ diff --git a/drivers/clk/samsung/clk-exynos5260.h b/drivers/clk/samsung/clk-exynos5260.h index d739716d6ea1..50a5b77734b7 100644 --- a/drivers/clk/samsung/clk-exynos5260.h +++ b/drivers/clk/samsung/clk-exynos5260.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Rahul Sharma <rahul.sharma@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for Exynos5260 SoC. */ diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c index b2da2c8fa0c7..d67d67a519a4 100644 --- a/drivers/clk/samsung/clk-exynos5410.c +++ b/drivers/clk/samsung/clk-exynos5410.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Author: Tarek Dakhran <t.dakhran@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for Exynos5410 SoC. */ diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 34cce3c5898f..12d800fd9528 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Authors: Thomas Abraham <thomas.ab@samsung.com> * Chander Kashyap <k.chander@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for Exynos5420 SoC. */ diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index dae1c96de933..945d5f2ad733 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Chanwoo Choi <cw00.choi@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for Exynos5433 SoC. */ diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c index 492d51691080..87ee1bad9a9a 100644 --- a/drivers/clk/samsung/clk-exynos7.c +++ b/drivers/clk/samsung/clk-exynos7.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Naveen Krishna Ch <naveenkrishna.ch@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/clk-provider.h> diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 0c6782ceac48..ac70ad785d8e 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Copyright (c) 2013 Linaro Ltd. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This file contains the utility functions to register the pll clocks. */ diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index ca57b3dfa814..79e41c226b90 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Copyright (c) 2013 Linaro Ltd. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for all PLL's in Samsung platforms */ diff --git a/drivers/clk/samsung/clk-s3c2410-dclk.c b/drivers/clk/samsung/clk-s3c2410-dclk.c index 0117e40c1d0a..1281672cb00e 100644 --- a/drivers/clk/samsung/clk-s3c2410-dclk.c +++ b/drivers/clk/samsung/clk-s3c2410-dclk.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for s3c24xx external clock output. */ diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c index 8cb868f06257..fcf6764693cc 100644 --- a/drivers/clk/samsung/clk-s3c2410.c +++ b/drivers/clk/samsung/clk-s3c2410.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for S3C2410 and following SoCs. */ diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c index ce21b89d1eb1..a95ab5f75163 100644 --- a/drivers/clk/samsung/clk-s3c2412.c +++ b/drivers/clk/samsung/clk-s3c2412.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for S3C2412 and S3C2413. */ diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c index b2ea4dfb5b8c..5f30fe72cd51 100644 --- a/drivers/clk/samsung/clk-s3c2443.c +++ b/drivers/clk/samsung/clk-s3c2443.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for S3C2443 and following SoCs. */ diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c index 54916c7bdb06..b96d33e5eb45 100644 --- a/drivers/clk/samsung/clk-s3c64xx.c +++ b/drivers/clk/samsung/clk-s3c64xx.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Tomasz Figa <tomasz.figa at gmail.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for all S3C64xx SoCs. */ diff --git a/drivers/clk/samsung/clk-s5pv210-audss.c b/drivers/clk/samsung/clk-s5pv210-audss.c index 22b18e728b88..14985ebd043b 100644 --- a/drivers/clk/samsung/clk-s5pv210-audss.c +++ b/drivers/clk/samsung/clk-s5pv210-audss.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 Tomasz Figa <t.figa@samsung.com> * @@ -6,10 +7,6 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Author: Padmavathi Venna <padma.v@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Driver for Audio Subsystem Clock Controller of S5PV210-compatible SoCs. */ diff --git a/drivers/clk/samsung/clk-s5pv210.c b/drivers/clk/samsung/clk-s5pv210.c index 41d2337fe030..e7b68ffe36de 100644 --- a/drivers/clk/samsung/clk-s5pv210.c +++ b/drivers/clk/samsung/clk-s5pv210.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Author: Mateusz Krawczuk <m.krawczuk@partner.samsung.com> * * Based on clock drivers for S3C64xx and Exynos4 SoCs. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for all S5PC110/S5PV210 SoCs. */ diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c index 9ad546a5f74c..e544a38106dd 100644 --- a/drivers/clk/samsung/clk.c +++ b/drivers/clk/samsung/clk.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Copyright (c) 2013 Linaro Ltd. * Author: Thomas Abraham <thomas.ab@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This file includes utility functions to register clocks to common * clock framework for Samsung platforms. */ diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index 9cfaca5fbcdb..c1e1a6b2f499 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Copyright (c) 2013 Linaro Ltd. * Author: Thomas Abraham <thomas.ab@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Common Clock Framework support for all Samsung platforms */ diff --git a/drivers/clk/socfpga/clk-s10.c b/drivers/clk/socfpga/clk-s10.c index 8281dfbf38c2..5bed36e12951 100644 --- a/drivers/clk/socfpga/clk-s10.c +++ b/drivers/clk/socfpga/clk-s10.c @@ -103,9 +103,9 @@ static const struct stratix10_perip_cnt_clock s10_main_perip_cnt_clks[] = { { STRATIX10_NOC_CLK, "noc_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0, 0, 0x3C, 1}, { STRATIX10_EMAC_A_FREE_CLK, "emaca_free_clk", NULL, emaca_free_mux, ARRAY_SIZE(emaca_free_mux), - 0, 0, 4, 0xB0, 0}, + 0, 0, 2, 0xB0, 0}, { STRATIX10_EMAC_B_FREE_CLK, "emacb_free_clk", NULL, emacb_free_mux, ARRAY_SIZE(emacb_free_mux), - 0, 0, 4, 0xB0, 1}, + 0, 0, 2, 0xB0, 1}, { STRATIX10_EMAC_PTP_FREE_CLK, "emac_ptp_free_clk", NULL, emac_ptp_free_mux, ARRAY_SIZE(emac_ptp_free_mux), 0, 0, 4, 0xB0, 2}, { STRATIX10_GPIO_DB_FREE_CLK, "gpio_db_free_clk", NULL, gpio_db_free_mux, diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index 946ceb14dbf7..ca1ccdb8a3b1 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -1,10 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 STMicroelectronics R&D Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ /* diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 661a73284e9f..4d8f0422b876 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Emilio López <emilio@elopez.com.ar> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Adjustable factor-based clock implementation */ diff --git a/drivers/clk/tegra/clk-bpmp.c b/drivers/clk/tegra/clk-bpmp.c index 01dada561c10..a66263b6490d 100644 --- a/drivers/clk/tegra/clk-bpmp.c +++ b/drivers/clk/tegra/clk-bpmp.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk-provider.h> diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index e1ba62d2b1a0..ac1d27a8c650 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -3366,6 +3366,8 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA210_CLK_I2S3_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 }, { TEGRA210_CLK_I2S4_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 }, { TEGRA210_CLK_VIMCLK_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 }, + { TEGRA210_CLK_HDA, TEGRA210_CLK_PLL_P, 51000000, 0 }, + { TEGRA210_CLK_HDA2CODEC_2X, TEGRA210_CLK_PLL_P, 48000000, 0 }, /* This MUST be the last entry. */ { TEGRA210_CLK_CLK_MAX, TEGRA210_CLK_CLK_MAX, 0, 0 }, }; diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c index 339d30d64ebb..b10ed0429091 100644 --- a/drivers/clk/ti/clk-44xx.c +++ b/drivers/clk/ti/clk-44xx.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP4 Clock init * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo (t-kristo@ti.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c index a17b0c4646a1..dafef7e70ba8 100644 --- a/drivers/clk/ti/clk-54xx.c +++ b/drivers/clk/ti/clk-54xx.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP5 Clock init * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo (t-kristo@ti.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/clk/ti/clk-7xx-compat.c b/drivers/clk/ti/clk-7xx-compat.c index b3cd2296f84b..ddf7c8277946 100644 --- a/drivers/clk/ti/clk-7xx-compat.c +++ b/drivers/clk/ti/clk-7xx-compat.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * DRA7 Clock init * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo (t-kristo@ti.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c index 79186b918d87..b57fe09b428b 100644 --- a/drivers/clk/ti/clk-7xx.c +++ b/drivers/clk/ti/clk-7xx.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * DRA7 Clock init * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo (t-kristo@ti.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/clk/ti/clkctrl.c b/drivers/clk/ti/clkctrl.c index 8e834317c97d..975995eea15c 100644 --- a/drivers/clk/ti/clkctrl.c +++ b/drivers/clk/ti/clkctrl.c @@ -229,6 +229,7 @@ static struct clk_hw *_ti_omap4_clkctrl_xlate(struct of_phandle_args *clkspec, { struct omap_clkctrl_provider *provider = data; struct omap_clkctrl_clk *entry; + bool found = false; if (clkspec->args_count != 2) return ERR_PTR(-EINVAL); @@ -238,11 +239,13 @@ static struct clk_hw *_ti_omap4_clkctrl_xlate(struct of_phandle_args *clkspec, list_for_each_entry(entry, &provider->clocks, node) { if (entry->reg_offset == clkspec->args[0] && - entry->bit_offset == clkspec->args[1]) + entry->bit_offset == clkspec->args[1]) { + found = true; break; + } } - if (!entry) + if (!found) return ERR_PTR(-EINVAL); return entry->clk; diff --git a/drivers/clk/ti/clkt_dpll.c b/drivers/clk/ti/clkt_dpll.c index ce98da2c10be..87ece6cd4226 100644 --- a/drivers/clk/ti/clkt_dpll.c +++ b/drivers/clk/ti/clkt_dpll.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP2/3/4 DPLL clock functions * @@ -7,10 +8,6 @@ * Contacts: * Richard Woodruff <r-woodruff2@ti.com> * Paul Walmsley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #undef DEBUG diff --git a/drivers/clk/ti/clkt_iclk.c b/drivers/clk/ti/clkt_iclk.c index 60b583d7db33..b738ee615423 100644 --- a/drivers/clk/ti/clkt_iclk.c +++ b/drivers/clk/ti/clkt_iclk.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP2/3 interface clock control * * Copyright (C) 2011 Nokia Corporation * Paul Walmsley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #undef DEBUG diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c index 3dde6c8c3354..2490026948b4 100644 --- a/drivers/clk/ti/dpll3xxx.c +++ b/drivers/clk/ti/dpll3xxx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP3/4 - specific DPLL control functions * @@ -12,10 +13,6 @@ * * Parts of this code are based on code written by * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/clk/ti/dpll44xx.c b/drivers/clk/ti/dpll44xx.c index d7a3f7ec8d77..89c3ed1a24b8 100644 --- a/drivers/clk/ti/dpll44xx.c +++ b/drivers/clk/ti/dpll44xx.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP4-specific DPLL control functions * * Copyright (C) 2011 Texas Instruments, Inc. * Rajendra Nayak - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index dafe7a45875d..fe686f77787f 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for the ICST307 VCO clock found in the ARM Reference designs. * We wrap the custom interface from <asm/hardware/icst.h> into the generic @@ -5,10 +6,6 @@ * * Copyright (C) 2012-2015 Linus Walleij * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * TODO: when all ARM reference designs are migrated to generic clocks, the * ICST clock code from the ARM tree should probably be merged into this * file. diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c index 401558bfc409..1991f15a5db9 100644 --- a/drivers/clk/versatile/clk-impd1.c +++ b/drivers/clk/versatile/clk-impd1.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Clock driver for the ARM Integrator/IM-PD1 board * Copyright (C) 2012-2013 Linus Walleij - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk-provider.h> #include <linux/clkdev.h> diff --git a/drivers/clk/versatile/clk-versatile.c b/drivers/clk/versatile/clk-versatile.c index d6960de64d4a..90bb0b041b7a 100644 --- a/drivers/clk/versatile/clk-versatile.c +++ b/drivers/clk/versatile/clk-versatile.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Clock driver for the ARM Integrator/AP, Integrator/CP, Versatile AB and * Versatile PB boards. * Copyright (C) 2012 Linus Walleij - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk-provider.h> #include <linux/err.h> diff --git a/drivers/clk/versatile/icst.c b/drivers/clk/versatile/icst.c index de2af63a3aad..ba4b2d22ec97 100644 --- a/drivers/clk/versatile/icst.c +++ b/drivers/clk/versatile/icst.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/arch/arm/common/icst307.c * * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Support functions for calculating clocks/divisors for the ICST307 * clock generators. See http://www.idt.com/ for more information * on these devices. diff --git a/drivers/clk/versatile/icst.h b/drivers/clk/versatile/icst.h index 7519bba03b04..73a3062b4535 100644 --- a/drivers/clk/versatile/icst.h +++ b/drivers/clk/versatile/icst.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Support functions for calculating clocks/divisors for the ICST * clock generators. See http://www.idt.com/ for more information * on these devices. diff --git a/drivers/clk/x86/clk-lpt.c b/drivers/clk/x86/clk-lpt.c index 68bd3abaef2c..fbe9fd3ed948 100644 --- a/drivers/clk/x86/clk-lpt.c +++ b/drivers/clk/x86/clk-lpt.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Intel Low Power Subsystem clocks. * * Copyright (C) 2013, Intel Corporation * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> * Heikki Krogerus <heikki.krogerus@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk-provider.h> diff --git a/drivers/clk/zte/clk-zx296702.c b/drivers/clk/zte/clk-zx296702.c index 76e967c19775..e846f2a34feb 100644 --- a/drivers/clk/zte/clk-zx296702.c +++ b/drivers/clk/zte/clk-zx296702.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2014 Linaro Ltd. * Copyright (C) 2014 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk-provider.h> diff --git a/drivers/clk/zte/clk-zx296718.c b/drivers/clk/zte/clk-zx296718.c index 354dd508c516..fd6c347bec6a 100644 --- a/drivers/clk/zte/clk-zx296718.c +++ b/drivers/clk/zte/clk-zx296718.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 - 2016 ZTE Corporation. * Copyright (C) 2016 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk-provider.h> #include <linux/device.h> diff --git a/drivers/clk/zte/clk.c b/drivers/clk/zte/clk.c index b82031766ffa..8bda6d41ad3a 100644 --- a/drivers/clk/zte/clk.c +++ b/drivers/clk/zte/clk.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2014 Linaro Ltd. * Copyright (C) 2014 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk-provider.h> diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h index f1041e36bcf1..aeaf2a380ba6 100644 --- a/drivers/clk/zte/clk.h +++ b/drivers/clk/zte/clk.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2015 Linaro Ltd. * Copyright (C) 2014 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __ZTE_CLK_H diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 3300739edce4..5e9317dc3d39 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -43,6 +43,11 @@ config BCM_KONA_TIMER help Enables the support for the BCM Kona mobile timer driver. +config DAVINCI_TIMER + bool "Texas Instruments DaVinci timer driver" if COMPILE_TEST + help + Enables the support for the TI DaVinci timer driver. + config DIGICOLOR_TIMER bool "Digicolor timer driver" if COMPILE_TEST select CLKSRC_MMIO @@ -140,7 +145,7 @@ config TEGRA_TIMER bool "Tegra timer driver" if COMPILE_TEST select CLKSRC_MMIO select TIMER_OF - depends on ARM || ARM64 + depends on ARCH_TEGRA || COMPILE_TEST help Enables support for the Tegra driver. @@ -617,6 +622,13 @@ config CLKSRC_IMX_TPM Enable this option to use IMX Timer/PWM Module (TPM) timer as clocksource. +config TIMER_IMX_SYS_CTR + bool "i.MX system counter timer" if COMPILE_TEST + select TIMER_OF + help + Enable this option to use i.MX system counter timer as a + clockevent. + config CLKSRC_ST_LPC bool "Low power clocksource found in the LPC" if COMPILE_TEST select TIMER_OF if OF diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 236858fa7fbf..2e7936e7833f 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o obj-$(CONFIG_EM_TIMER_STI) += em_sti.o obj-$(CONFIG_CLKBLD_I8253) += i8253.o obj-$(CONFIG_CLKSRC_MMIO) += mmio.o +obj-$(CONFIG_DAVINCI_TIMER) += timer-davinci.o obj-$(CONFIG_DIGICOLOR_TIMER) += timer-digicolor.o obj-$(CONFIG_OMAP_DM_TIMER) += timer-ti-dm.o obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o @@ -36,7 +37,7 @@ obj-$(CONFIG_U300_TIMER) += timer-u300.o obj-$(CONFIG_SUN4I_TIMER) += timer-sun4i.o obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o obj-$(CONFIG_MESON6_TIMER) += timer-meson6.o -obj-$(CONFIG_TEGRA_TIMER) += timer-tegra20.o +obj-$(CONFIG_TEGRA_TIMER) += timer-tegra.o obj-$(CONFIG_VT8500_TIMER) += timer-vt8500.o obj-$(CONFIG_NSPIRE_TIMER) += timer-zevio.o obj-$(CONFIG_BCM_KONA_TIMER) += bcm_kona_timer.o @@ -74,6 +75,7 @@ obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o obj-$(CONFIG_CLKSRC_TANGO_XTAL) += timer-tango-xtal.o obj-$(CONFIG_CLKSRC_IMX_GPT) += timer-imx-gpt.o obj-$(CONFIG_CLKSRC_IMX_TPM) += timer-imx-tpm.o +obj-$(CONFIG_TIMER_IMX_SYS_CTR) += timer-imx-sysctr.o obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o obj-$(CONFIG_H8300_TMR8) += h8300_timer8.o obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o @@ -84,3 +86,4 @@ obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o +obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 1961e3539b57..eb596ff9e7bb 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/clocksource/acpi_pm.c * @@ -12,8 +13,6 @@ * * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c, * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4. - * - * This file is licensed under the GPL v2. */ #include <linux/acpi_pmtmr.h> diff --git a/drivers/clocksource/arc_timer.c b/drivers/clocksource/arc_timer.c index b28970ca4a7a..b29b5a75333e 100644 --- a/drivers/clocksource/arc_timer.c +++ b/drivers/clocksource/arc_timer.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016-17 Synopsys, Inc. (www.synopsys.com) * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /* ARC700 has two 32bit independent prog Timers: TIMER0 and TIMER1, Each can be @@ -16,6 +13,7 @@ */ #include <linux/interrupt.h> +#include <linux/bits.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/clocksource.h> @@ -142,7 +140,7 @@ static u64 arc_read_rtc(struct clocksource *cs) l = read_aux_reg(AUX_RTC_LOW); h = read_aux_reg(AUX_RTC_HIGH); status = read_aux_reg(AUX_RTC_CTRL); - } while (!(status & _BITUL(31))); + } while (!(status & BIT(31))); return (((u64)h) << 32) | l; } diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 5c69c9a9a6a4..9a5464c625b4 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/clocksource/arm_arch_timer.c * * Copyright (C) 2011 ARM Ltd. * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "arch_timer: " fmt @@ -804,14 +801,7 @@ static void arch_timer_evtstrm_enable(int divider) cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT) | ARCH_TIMER_VIRT_EVT_EN; arch_timer_set_cntkctl(cntkctl); -#ifdef CONFIG_ARM64 - cpu_set_named_feature(EVTSTRM); -#else - elf_hwcap |= HWCAP_EVTSTRM; -#endif -#ifdef CONFIG_COMPAT - compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM; -#endif + arch_timer_set_evtstrm_feature(); cpumask_set_cpu(smp_processor_id(), &evtstrm_available); } @@ -1040,11 +1030,7 @@ static int arch_timer_cpu_pm_notify(struct notifier_block *self, } else if (action == CPU_PM_ENTER_FAILED || action == CPU_PM_EXIT) { arch_timer_set_cntkctl(__this_cpu_read(saved_cntkctl)); -#ifdef CONFIG_ARM64 - if (cpu_have_named_feature(EVTSTRM)) -#else - if (elf_hwcap & HWCAP_EVTSTRM) -#endif + if (arch_timer_have_evtstrm_feature()) cpumask_set_cpu(smp_processor_id(), &evtstrm_available); } return NOTIFY_OK; diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c index 095bb965f621..88b2d38a7a61 100644 --- a/drivers/clocksource/arm_global_timer.c +++ b/drivers/clocksource/arm_global_timer.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/clocksource/arm_global_timer.c * * Copyright (C) 2013 STMicroelectronics (R&D) Limited. * Author: Stuart Menefy <stuart.menefy@st.com> * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> diff --git a/drivers/clocksource/dummy_timer.c b/drivers/clocksource/dummy_timer.c index 01f3f5a59bc6..6cee6dce5605 100644 --- a/drivers/clocksource/dummy_timer.c +++ b/drivers/clocksource/dummy_timer.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/clocksource/dummy_timer.c * * Copyright (C) 2013 ARM Ltd. * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clockchips.h> #include <linux/cpu.h> diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c index 1f5f734e4919..654766538f93 100644 --- a/drivers/clocksource/dw_apb_timer.c +++ b/drivers/clocksource/dw_apb_timer.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * (C) Copyright 2009 Intel Corporation * Author: Jacob Pan (jacob.jun.pan@intel.com) * * Shared with ARM platforms, Jamie Iles, Picochip 2011 * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Support for the Synopsys DesignWare APB Timers. */ #include <linux/dw_apb_timer.h> diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c index db410acd8964..8c28b127759f 100644 --- a/drivers/clocksource/dw_apb_timer_of.c +++ b/drivers/clocksource/dw_apb_timer_of.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Altera Corporation * Copyright (c) 2011 Picochip Ltd., Jamie Iles * * Modified from mach-picoxcell/time.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/delay.h> #include <linux/dw_apb_timer.h> diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 34bd250d46c6..74cb299f5089 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* linux/arch/arm/mach-exynos4/mct.c * * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * * EXYNOS4 MCT(Multi-Core Timer) support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/interrupt.h> @@ -209,7 +206,7 @@ static void exynos4_frc_resume(struct clocksource *cs) static struct clocksource mct_frc = { .name = "mct-frc", - .rating = 400, + .rating = 450, /* use value higher than ARM arch timer */ .read = exynos4_frc_read, .mask = CLOCKSOURCE_MASK(32), .flags = CLOCK_SOURCE_IS_CONTINUOUS, @@ -464,7 +461,7 @@ static int exynos4_mct_starting_cpu(unsigned int cpu) evt->set_state_oneshot_stopped = set_state_shutdown; evt->tick_resume = set_state_shutdown; evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; - evt->rating = 450; + evt->rating = 500; /* use value higher than ARM arch timer */ exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET); diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c new file mode 100644 index 000000000000..ba2c79e6a0ee --- /dev/null +++ b/drivers/clocksource/hyperv_timer.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Clocksource driver for the synthetic counter and timers + * provided by the Hyper-V hypervisor to guest VMs, as described + * in the Hyper-V Top Level Functional Spec (TLFS). This driver + * is instruction set architecture independent. + * + * Copyright (C) 2019, Microsoft, Inc. + * + * Author: Michael Kelley <mikelley@microsoft.com> + */ + +#include <linux/percpu.h> +#include <linux/cpumask.h> +#include <linux/clockchips.h> +#include <linux/clocksource.h> +#include <linux/sched_clock.h> +#include <linux/mm.h> +#include <clocksource/hyperv_timer.h> +#include <asm/hyperv-tlfs.h> +#include <asm/mshyperv.h> + +static struct clock_event_device __percpu *hv_clock_event; + +/* + * If false, we're using the old mechanism for stimer0 interrupts + * where it sends a VMbus message when it expires. The old + * mechanism is used when running on older versions of Hyper-V + * that don't support Direct Mode. While Hyper-V provides + * four stimer's per CPU, Linux uses only stimer0. + */ +static bool direct_mode_enabled; + +static int stimer0_irq; +static int stimer0_vector; +static int stimer0_message_sint; + +/* + * ISR for when stimer0 is operating in Direct Mode. Direct Mode + * does not use VMbus or any VMbus messages, so process here and not + * in the VMbus driver code. + */ +void hv_stimer0_isr(void) +{ + struct clock_event_device *ce; + + ce = this_cpu_ptr(hv_clock_event); + ce->event_handler(ce); +} +EXPORT_SYMBOL_GPL(hv_stimer0_isr); + +static int hv_ce_set_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + u64 current_tick; + + current_tick = hyperv_cs->read(NULL); + current_tick += delta; + hv_init_timer(0, current_tick); + return 0; +} + +static int hv_ce_shutdown(struct clock_event_device *evt) +{ + hv_init_timer(0, 0); + hv_init_timer_config(0, 0); + if (direct_mode_enabled) + hv_disable_stimer0_percpu_irq(stimer0_irq); + + return 0; +} + +static int hv_ce_set_oneshot(struct clock_event_device *evt) +{ + union hv_stimer_config timer_cfg; + + timer_cfg.as_uint64 = 0; + timer_cfg.enable = 1; + timer_cfg.auto_enable = 1; + if (direct_mode_enabled) { + /* + * When it expires, the timer will directly interrupt + * on the specified hardware vector/IRQ. + */ + timer_cfg.direct_mode = 1; + timer_cfg.apic_vector = stimer0_vector; + hv_enable_stimer0_percpu_irq(stimer0_irq); + } else { + /* + * When it expires, the timer will generate a VMbus message, + * to be handled by the normal VMbus interrupt handler. + */ + timer_cfg.direct_mode = 0; + timer_cfg.sintx = stimer0_message_sint; + } + hv_init_timer_config(0, timer_cfg.as_uint64); + return 0; +} + +/* + * hv_stimer_init - Per-cpu initialization of the clockevent + */ +void hv_stimer_init(unsigned int cpu) +{ + struct clock_event_device *ce; + + /* + * Synthetic timers are always available except on old versions of + * Hyper-V on x86. In that case, just return as Linux will use a + * clocksource based on emulated PIT or LAPIC timer hardware. + */ + if (!(ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE)) + return; + + ce = per_cpu_ptr(hv_clock_event, cpu); + ce->name = "Hyper-V clockevent"; + ce->features = CLOCK_EVT_FEAT_ONESHOT; + ce->cpumask = cpumask_of(cpu); + ce->rating = 1000; + ce->set_state_shutdown = hv_ce_shutdown; + ce->set_state_oneshot = hv_ce_set_oneshot; + ce->set_next_event = hv_ce_set_next_event; + + clockevents_config_and_register(ce, + HV_CLOCK_HZ, + HV_MIN_DELTA_TICKS, + HV_MAX_MAX_DELTA_TICKS); +} +EXPORT_SYMBOL_GPL(hv_stimer_init); + +/* + * hv_stimer_cleanup - Per-cpu cleanup of the clockevent + */ +void hv_stimer_cleanup(unsigned int cpu) +{ + struct clock_event_device *ce; + + /* Turn off clockevent device */ + if (ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE) { + ce = per_cpu_ptr(hv_clock_event, cpu); + hv_ce_shutdown(ce); + } +} +EXPORT_SYMBOL_GPL(hv_stimer_cleanup); + +/* hv_stimer_alloc - Global initialization of the clockevent and stimer0 */ +int hv_stimer_alloc(int sint) +{ + int ret; + + hv_clock_event = alloc_percpu(struct clock_event_device); + if (!hv_clock_event) + return -ENOMEM; + + direct_mode_enabled = ms_hyperv.misc_features & + HV_STIMER_DIRECT_MODE_AVAILABLE; + if (direct_mode_enabled) { + ret = hv_setup_stimer0_irq(&stimer0_irq, &stimer0_vector, + hv_stimer0_isr); + if (ret) { + free_percpu(hv_clock_event); + hv_clock_event = NULL; + return ret; + } + } + + stimer0_message_sint = sint; + return 0; +} +EXPORT_SYMBOL_GPL(hv_stimer_alloc); + +/* hv_stimer_free - Free global resources allocated by hv_stimer_alloc() */ +void hv_stimer_free(void) +{ + if (direct_mode_enabled && (stimer0_irq != 0)) { + hv_remove_stimer0_irq(stimer0_irq); + stimer0_irq = 0; + } + free_percpu(hv_clock_event); + hv_clock_event = NULL; +} +EXPORT_SYMBOL_GPL(hv_stimer_free); + +/* + * Do a global cleanup of clockevents for the cases of kexec and + * vmbus exit + */ +void hv_stimer_global_cleanup(void) +{ + int cpu; + struct clock_event_device *ce; + + if (ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE) { + for_each_present_cpu(cpu) { + ce = per_cpu_ptr(hv_clock_event, cpu); + clockevents_unbind_device(ce, cpu); + } + } + hv_stimer_free(); +} +EXPORT_SYMBOL_GPL(hv_stimer_global_cleanup); + +/* + * Code and definitions for the Hyper-V clocksources. Two + * clocksources are defined: one that reads the Hyper-V defined MSR, and + * the other that uses the TSC reference page feature as defined in the + * TLFS. The MSR version is for compatibility with old versions of + * Hyper-V and 32-bit x86. The TSC reference page version is preferred. + */ + +struct clocksource *hyperv_cs; +EXPORT_SYMBOL_GPL(hyperv_cs); + +#ifdef CONFIG_HYPERV_TSCPAGE + +static struct ms_hyperv_tsc_page *tsc_pg; + +struct ms_hyperv_tsc_page *hv_get_tsc_page(void) +{ + return tsc_pg; +} +EXPORT_SYMBOL_GPL(hv_get_tsc_page); + +static u64 notrace read_hv_sched_clock_tsc(void) +{ + u64 current_tick = hv_read_tsc_page(tsc_pg); + + if (current_tick == U64_MAX) + hv_get_time_ref_count(current_tick); + + return current_tick; +} + +static u64 read_hv_clock_tsc(struct clocksource *arg) +{ + return read_hv_sched_clock_tsc(); +} + +static struct clocksource hyperv_cs_tsc = { + .name = "hyperv_clocksource_tsc_page", + .rating = 400, + .read = read_hv_clock_tsc, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; +#endif + +static u64 notrace read_hv_sched_clock_msr(void) +{ + u64 current_tick; + /* + * Read the partition counter to get the current tick count. This count + * is set to 0 when the partition is created and is incremented in + * 100 nanosecond units. + */ + hv_get_time_ref_count(current_tick); + return current_tick; +} + +static u64 read_hv_clock_msr(struct clocksource *arg) +{ + return read_hv_sched_clock_msr(); +} + +static struct clocksource hyperv_cs_msr = { + .name = "hyperv_clocksource_msr", + .rating = 400, + .read = read_hv_clock_msr, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +#ifdef CONFIG_HYPERV_TSCPAGE +static bool __init hv_init_tsc_clocksource(void) +{ + u64 tsc_msr; + phys_addr_t phys_addr; + + if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE)) + return false; + + tsc_pg = vmalloc(PAGE_SIZE); + if (!tsc_pg) + return false; + + hyperv_cs = &hyperv_cs_tsc; + phys_addr = page_to_phys(vmalloc_to_page(tsc_pg)); + + /* + * The Hyper-V TLFS specifies to preserve the value of reserved + * bits in registers. So read the existing value, preserve the + * low order 12 bits, and add in the guest physical address + * (which already has at least the low 12 bits set to zero since + * it is page aligned). Also set the "enable" bit, which is bit 0. + */ + hv_get_reference_tsc(tsc_msr); + tsc_msr &= GENMASK_ULL(11, 0); + tsc_msr = tsc_msr | 0x1 | (u64)phys_addr; + hv_set_reference_tsc(tsc_msr); + + hv_set_clocksource_vdso(hyperv_cs_tsc); + clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100); + + /* sched_clock_register is needed on ARM64 but is a no-op on x86 */ + sched_clock_register(read_hv_sched_clock_tsc, 64, HV_CLOCK_HZ); + return true; +} +#else +static bool __init hv_init_tsc_clocksource(void) +{ + return false; +} +#endif + + +void __init hv_init_clocksource(void) +{ + /* + * Try to set up the TSC page clocksource. If it succeeds, we're + * done. Otherwise, set up the MSR clocksoruce. At least one of + * these will always be available except on very old versions of + * Hyper-V on x86. In that case we won't have a Hyper-V + * clocksource, but Linux will still run with a clocksource based + * on the emulated PIT or LAPIC timer. + */ + if (hv_init_tsc_clocksource()) + return; + + if (!(ms_hyperv.features & HV_MSR_TIME_REF_COUNT_AVAILABLE)) + return; + + hyperv_cs = &hyperv_cs_msr; + clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100); + + /* sched_clock_register is needed on ARM64 but is a no-op on x86 */ + sched_clock_register(read_hv_sched_clock_msr, 64, HV_CLOCK_HZ); +} +EXPORT_SYMBOL_GPL(hv_init_clocksource); diff --git a/drivers/clocksource/mmio.c b/drivers/clocksource/mmio.c index 4c4df981d8cc..9de751531831 100644 --- a/drivers/clocksource/mmio.c +++ b/drivers/clocksource/mmio.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic MMIO clocksource support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clocksource.h> #include <linux/errno.h> diff --git a/drivers/clocksource/mps2-timer.c b/drivers/clocksource/mps2-timer.c index aa4d63af8706..2e64d984c83a 100644 --- a/drivers/clocksource/mps2-timer.c +++ b/drivers/clocksource/mps2-timer.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 ARM Limited * * Author: Vladimir Murzin <vladimir.murzin@arm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index 19b336c9b417..3f7fa8c01367 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2008 STMicroelectronics * Copyright (C) 2010 Alessandro Rubini * Copyright (C) 2010 Linus Walleij for ST-Ericsson - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. */ #include <linux/init.h> #include <linux/interrupt.h> diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 6d5d126357c2..895f53eb5771 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * samsung - Common hr-timer support (s3c and s5p) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/interrupt.h> diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c index 2fab18fae4fc..b4f264ed1937 100644 --- a/drivers/clocksource/timer-atmel-pit.c +++ b/drivers/clocksource/timer-atmel-pit.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * at91sam926x_time.c - Periodic Interval Timer (PIT) for at91sam926x * * Copyright (C) 2005-2006 M. Amine SAYA, ATMEL Rousset, France * Revision 2005 M. Nicolas Diremdjian, ATMEL Rousset, France * Converted to ClockSource/ClockEvents by David Brownell. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "AT91: PIT: " fmt diff --git a/drivers/clocksource/timer-davinci.c b/drivers/clocksource/timer-davinci.c new file mode 100644 index 000000000000..62745c962049 --- /dev/null +++ b/drivers/clocksource/timer-davinci.c @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * TI DaVinci clocksource driver + * + * Copyright (C) 2019 Texas Instruments + * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> + * (with tiny parts adopted from code by Kevin Hilman <khilman@baylibre.com>) + */ + +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/sched_clock.h> + +#include <clocksource/timer-davinci.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt "\n", __func__ + +#define DAVINCI_TIMER_REG_TIM12 0x10 +#define DAVINCI_TIMER_REG_TIM34 0x14 +#define DAVINCI_TIMER_REG_PRD12 0x18 +#define DAVINCI_TIMER_REG_PRD34 0x1c +#define DAVINCI_TIMER_REG_TCR 0x20 +#define DAVINCI_TIMER_REG_TGCR 0x24 + +#define DAVINCI_TIMER_TIMMODE_MASK GENMASK(3, 2) +#define DAVINCI_TIMER_RESET_MASK GENMASK(1, 0) +#define DAVINCI_TIMER_TIMMODE_32BIT_UNCHAINED BIT(2) +#define DAVINCI_TIMER_UNRESET GENMASK(1, 0) + +#define DAVINCI_TIMER_ENAMODE_MASK GENMASK(1, 0) +#define DAVINCI_TIMER_ENAMODE_DISABLED 0x00 +#define DAVINCI_TIMER_ENAMODE_ONESHOT BIT(0) +#define DAVINCI_TIMER_ENAMODE_PERIODIC BIT(1) + +#define DAVINCI_TIMER_ENAMODE_SHIFT_TIM12 6 +#define DAVINCI_TIMER_ENAMODE_SHIFT_TIM34 22 + +#define DAVINCI_TIMER_MIN_DELTA 0x01 +#define DAVINCI_TIMER_MAX_DELTA 0xfffffffe + +#define DAVINCI_TIMER_CLKSRC_BITS 32 + +#define DAVINCI_TIMER_TGCR_DEFAULT \ + (DAVINCI_TIMER_TIMMODE_32BIT_UNCHAINED | DAVINCI_TIMER_UNRESET) + +struct davinci_clockevent { + struct clock_event_device dev; + void __iomem *base; + unsigned int cmp_off; +}; + +/* + * This must be globally accessible by davinci_timer_read_sched_clock(), so + * let's keep it here. + */ +static struct { + struct clocksource dev; + void __iomem *base; + unsigned int tim_off; +} davinci_clocksource; + +static struct davinci_clockevent * +to_davinci_clockevent(struct clock_event_device *clockevent) +{ + return container_of(clockevent, struct davinci_clockevent, dev); +} + +static unsigned int +davinci_clockevent_read(struct davinci_clockevent *clockevent, + unsigned int reg) +{ + return readl_relaxed(clockevent->base + reg); +} + +static void davinci_clockevent_write(struct davinci_clockevent *clockevent, + unsigned int reg, unsigned int val) +{ + writel_relaxed(val, clockevent->base + reg); +} + +static void davinci_tim12_shutdown(void __iomem *base) +{ + unsigned int tcr; + + tcr = DAVINCI_TIMER_ENAMODE_DISABLED << + DAVINCI_TIMER_ENAMODE_SHIFT_TIM12; + /* + * This function is only ever called if we're using both timer + * halves. In this case TIM34 runs in periodic mode and we must + * not modify it. + */ + tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC << + DAVINCI_TIMER_ENAMODE_SHIFT_TIM34; + + writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR); +} + +static void davinci_tim12_set_oneshot(void __iomem *base) +{ + unsigned int tcr; + + tcr = DAVINCI_TIMER_ENAMODE_ONESHOT << + DAVINCI_TIMER_ENAMODE_SHIFT_TIM12; + /* Same as above. */ + tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC << + DAVINCI_TIMER_ENAMODE_SHIFT_TIM34; + + writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR); +} + +static int davinci_clockevent_shutdown(struct clock_event_device *dev) +{ + struct davinci_clockevent *clockevent; + + clockevent = to_davinci_clockevent(dev); + + davinci_tim12_shutdown(clockevent->base); + + return 0; +} + +static int davinci_clockevent_set_oneshot(struct clock_event_device *dev) +{ + struct davinci_clockevent *clockevent = to_davinci_clockevent(dev); + + davinci_clockevent_write(clockevent, DAVINCI_TIMER_REG_TIM12, 0x0); + + davinci_tim12_set_oneshot(clockevent->base); + + return 0; +} + +static int +davinci_clockevent_set_next_event_std(unsigned long cycles, + struct clock_event_device *dev) +{ + struct davinci_clockevent *clockevent = to_davinci_clockevent(dev); + + davinci_clockevent_shutdown(dev); + + davinci_clockevent_write(clockevent, DAVINCI_TIMER_REG_TIM12, 0x0); + davinci_clockevent_write(clockevent, DAVINCI_TIMER_REG_PRD12, cycles); + + davinci_clockevent_set_oneshot(dev); + + return 0; +} + +static int +davinci_clockevent_set_next_event_cmp(unsigned long cycles, + struct clock_event_device *dev) +{ + struct davinci_clockevent *clockevent = to_davinci_clockevent(dev); + unsigned int curr_time; + + curr_time = davinci_clockevent_read(clockevent, + DAVINCI_TIMER_REG_TIM12); + davinci_clockevent_write(clockevent, + clockevent->cmp_off, curr_time + cycles); + + return 0; +} + +static irqreturn_t davinci_timer_irq_timer(int irq, void *data) +{ + struct davinci_clockevent *clockevent = data; + + if (!clockevent_state_oneshot(&clockevent->dev)) + davinci_tim12_shutdown(clockevent->base); + + clockevent->dev.event_handler(&clockevent->dev); + + return IRQ_HANDLED; +} + +static u64 notrace davinci_timer_read_sched_clock(void) +{ + return readl_relaxed(davinci_clocksource.base + + davinci_clocksource.tim_off); +} + +static u64 davinci_clocksource_read(struct clocksource *dev) +{ + return davinci_timer_read_sched_clock(); +} + +/* + * Standard use-case: we're using tim12 for clockevent and tim34 for + * clocksource. The default is making the former run in oneshot mode + * and the latter in periodic mode. + */ +static void davinci_clocksource_init_tim34(void __iomem *base) +{ + int tcr; + + tcr = DAVINCI_TIMER_ENAMODE_PERIODIC << + DAVINCI_TIMER_ENAMODE_SHIFT_TIM34; + tcr |= DAVINCI_TIMER_ENAMODE_ONESHOT << + DAVINCI_TIMER_ENAMODE_SHIFT_TIM12; + + writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM34); + writel_relaxed(UINT_MAX, base + DAVINCI_TIMER_REG_PRD34); + writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR); +} + +/* + * Special use-case on da830: the DSP may use tim34. We're using tim12 for + * both clocksource and clockevent. We set tim12 to periodic and don't touch + * tim34. + */ +static void davinci_clocksource_init_tim12(void __iomem *base) +{ + unsigned int tcr; + + tcr = DAVINCI_TIMER_ENAMODE_PERIODIC << + DAVINCI_TIMER_ENAMODE_SHIFT_TIM12; + + writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM12); + writel_relaxed(UINT_MAX, base + DAVINCI_TIMER_REG_PRD12); + writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR); +} + +static void davinci_timer_init(void __iomem *base) +{ + /* Set clock to internal mode and disable it. */ + writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TCR); + /* + * Reset both 32-bit timers, set no prescaler for timer 34, set the + * timer to dual 32-bit unchained mode, unreset both 32-bit timers. + */ + writel_relaxed(DAVINCI_TIMER_TGCR_DEFAULT, + base + DAVINCI_TIMER_REG_TGCR); + /* Init both counters to zero. */ + writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM12); + writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM34); +} + +int __init davinci_timer_register(struct clk *clk, + const struct davinci_timer_cfg *timer_cfg) +{ + struct davinci_clockevent *clockevent; + unsigned int tick_rate; + void __iomem *base; + int rv; + + rv = clk_prepare_enable(clk); + if (rv) { + pr_err("Unable to prepare and enable the timer clock"); + return rv; + } + + if (!request_mem_region(timer_cfg->reg.start, + resource_size(&timer_cfg->reg), + "davinci-timer")) { + pr_err("Unable to request memory region"); + return -EBUSY; + } + + base = ioremap(timer_cfg->reg.start, resource_size(&timer_cfg->reg)); + if (!base) { + pr_err("Unable to map the register range"); + return -ENOMEM; + } + + davinci_timer_init(base); + tick_rate = clk_get_rate(clk); + + clockevent = kzalloc(sizeof(*clockevent), GFP_KERNEL | __GFP_NOFAIL); + if (!clockevent) { + pr_err("Error allocating memory for clockevent data"); + return -ENOMEM; + } + + clockevent->dev.name = "tim12"; + clockevent->dev.features = CLOCK_EVT_FEAT_ONESHOT; + clockevent->dev.cpumask = cpumask_of(0); + clockevent->base = base; + + if (timer_cfg->cmp_off) { + clockevent->cmp_off = timer_cfg->cmp_off; + clockevent->dev.set_next_event = + davinci_clockevent_set_next_event_cmp; + } else { + clockevent->dev.set_next_event = + davinci_clockevent_set_next_event_std; + clockevent->dev.set_state_oneshot = + davinci_clockevent_set_oneshot; + clockevent->dev.set_state_shutdown = + davinci_clockevent_shutdown; + } + + rv = request_irq(timer_cfg->irq[DAVINCI_TIMER_CLOCKEVENT_IRQ].start, + davinci_timer_irq_timer, IRQF_TIMER, + "clockevent/tim12", clockevent); + if (rv) { + pr_err("Unable to request the clockevent interrupt"); + return rv; + } + + clockevents_config_and_register(&clockevent->dev, tick_rate, + DAVINCI_TIMER_MIN_DELTA, + DAVINCI_TIMER_MAX_DELTA); + + davinci_clocksource.dev.rating = 300; + davinci_clocksource.dev.read = davinci_clocksource_read; + davinci_clocksource.dev.mask = + CLOCKSOURCE_MASK(DAVINCI_TIMER_CLKSRC_BITS); + davinci_clocksource.dev.flags = CLOCK_SOURCE_IS_CONTINUOUS; + davinci_clocksource.base = base; + + if (timer_cfg->cmp_off) { + davinci_clocksource.dev.name = "tim12"; + davinci_clocksource.tim_off = DAVINCI_TIMER_REG_TIM12; + davinci_clocksource_init_tim12(base); + } else { + davinci_clocksource.dev.name = "tim34"; + davinci_clocksource.tim_off = DAVINCI_TIMER_REG_TIM34; + davinci_clocksource_init_tim34(base); + } + + rv = clocksource_register_hz(&davinci_clocksource.dev, tick_rate); + if (rv) { + pr_err("Unable to register clocksource"); + return rv; + } + + sched_clock_register(davinci_timer_read_sched_clock, + DAVINCI_TIMER_CLKSRC_BITS, tick_rate); + + return 0; +} + +static int __init of_davinci_timer_register(struct device_node *np) +{ + struct davinci_timer_cfg timer_cfg = { }; + struct clk *clk; + int rv; + + rv = of_address_to_resource(np, 0, &timer_cfg.reg); + if (rv) { + pr_err("Unable to get the register range for timer"); + return rv; + } + + rv = of_irq_to_resource_table(np, timer_cfg.irq, + DAVINCI_TIMER_NUM_IRQS); + if (rv != DAVINCI_TIMER_NUM_IRQS) { + pr_err("Unable to get the interrupts for timer"); + return rv; + } + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_err("Unable to get the timer clock"); + return PTR_ERR(clk); + } + + rv = davinci_timer_register(clk, &timer_cfg); + if (rv) + clk_put(clk); + + return rv; +} +TIMER_OF_DECLARE(davinci_timer, "ti,da830-timer", of_davinci_timer_register); diff --git a/drivers/clocksource/timer-efm32.c b/drivers/clocksource/timer-efm32.c index 257e810ec1ad..5a22cb079ad3 100644 --- a/drivers/clocksource/timer-efm32.c +++ b/drivers/clocksource/timer-efm32.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Pengutronix * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/clocksource/timer-imx-sysctr.c b/drivers/clocksource/timer-imx-sysctr.c new file mode 100644 index 000000000000..fd7d68066efb --- /dev/null +++ b/drivers/clocksource/timer-imx-sysctr.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright 2017-2019 NXP + +#include <linux/interrupt.h> +#include <linux/clockchips.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> + +#include "timer-of.h" + +#define CMP_OFFSET 0x10000 + +#define CNTCV_LO 0x8 +#define CNTCV_HI 0xc +#define CMPCV_LO (CMP_OFFSET + 0x20) +#define CMPCV_HI (CMP_OFFSET + 0x24) +#define CMPCR (CMP_OFFSET + 0x2c) + +#define SYS_CTR_EN 0x1 +#define SYS_CTR_IRQ_MASK 0x2 + +static void __iomem *sys_ctr_base; +static u32 cmpcr; + +static void sysctr_timer_enable(bool enable) +{ + writel(enable ? cmpcr | SYS_CTR_EN : cmpcr, sys_ctr_base + CMPCR); +} + +static void sysctr_irq_acknowledge(void) +{ + /* + * clear the enable bit(EN =0) will clear + * the status bit(ISTAT = 0), then the interrupt + * signal will be negated(acknowledged). + */ + sysctr_timer_enable(false); +} + +static inline u64 sysctr_read_counter(void) +{ + u32 cnt_hi, tmp_hi, cnt_lo; + + do { + cnt_hi = readl_relaxed(sys_ctr_base + CNTCV_HI); + cnt_lo = readl_relaxed(sys_ctr_base + CNTCV_LO); + tmp_hi = readl_relaxed(sys_ctr_base + CNTCV_HI); + } while (tmp_hi != cnt_hi); + + return ((u64) cnt_hi << 32) | cnt_lo; +} + +static int sysctr_set_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + u32 cmp_hi, cmp_lo; + u64 next; + + sysctr_timer_enable(false); + + next = sysctr_read_counter(); + + next += delta; + + cmp_hi = (next >> 32) & 0x00fffff; + cmp_lo = next & 0xffffffff; + + writel_relaxed(cmp_hi, sys_ctr_base + CMPCV_HI); + writel_relaxed(cmp_lo, sys_ctr_base + CMPCV_LO); + + sysctr_timer_enable(true); + + return 0; +} + +static int sysctr_set_state_oneshot(struct clock_event_device *evt) +{ + return 0; +} + +static int sysctr_set_state_shutdown(struct clock_event_device *evt) +{ + sysctr_timer_enable(false); + + return 0; +} + +static irqreturn_t sysctr_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + sysctr_irq_acknowledge(); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static struct timer_of to_sysctr = { + .flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE, + .clkevt = { + .name = "i.MX system counter timer", + .features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_DYNIRQ, + .set_state_oneshot = sysctr_set_state_oneshot, + .set_next_event = sysctr_set_next_event, + .set_state_shutdown = sysctr_set_state_shutdown, + .rating = 200, + }, + .of_irq = { + .handler = sysctr_timer_interrupt, + .flags = IRQF_TIMER | IRQF_IRQPOLL, + }, + .of_clk = { + .name = "per", + }, +}; + +static void __init sysctr_clockevent_init(void) +{ + to_sysctr.clkevt.cpumask = cpumask_of(0); + + clockevents_config_and_register(&to_sysctr.clkevt, + timer_of_rate(&to_sysctr), + 0xff, 0x7fffffff); +} + +static int __init sysctr_timer_init(struct device_node *np) +{ + int ret = 0; + + ret = timer_of_init(np, &to_sysctr); + if (ret) + return ret; + + sys_ctr_base = timer_of_base(&to_sysctr); + cmpcr = readl(sys_ctr_base + CMPCR); + cmpcr &= ~SYS_CTR_EN; + + sysctr_clockevent_init(); + + return 0; +} +TIMER_OF_DECLARE(sysctr_timer, "nxp,sysctr-timer", sysctr_timer_init); diff --git a/drivers/clocksource/timer-ixp4xx.c b/drivers/clocksource/timer-ixp4xx.c index 5c2190b654cd..9396745e1c17 100644 --- a/drivers/clocksource/timer-ixp4xx.c +++ b/drivers/clocksource/timer-ixp4xx.c @@ -75,14 +75,19 @@ to_ixp4xx_timer(struct clock_event_device *evt) return container_of(evt, struct ixp4xx_timer, clkevt); } -static u64 notrace ixp4xx_read_sched_clock(void) +static unsigned long ixp4xx_read_timer(void) { return __raw_readl(local_ixp4xx_timer->base + IXP4XX_OSTS_OFFSET); } +static u64 notrace ixp4xx_read_sched_clock(void) +{ + return ixp4xx_read_timer(); +} + static u64 ixp4xx_clocksource_read(struct clocksource *c) { - return __raw_readl(local_ixp4xx_timer->base + IXP4XX_OSTS_OFFSET); + return ixp4xx_read_timer(); } static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id) @@ -224,6 +229,13 @@ static __init int ixp4xx_timer_register(void __iomem *base, sched_clock_register(ixp4xx_read_sched_clock, 32, timer_freq); +#ifdef CONFIG_ARM + /* Also use this timer for delays */ + tmr->delay_timer.read_current_timer = ixp4xx_read_timer; + tmr->delay_timer.freq = timer_freq; + register_current_timer_delay(&tmr->delay_timer); +#endif + return 0; } diff --git a/drivers/clocksource/timer-keystone.c b/drivers/clocksource/timer-keystone.c index f5b2eda30bf3..fea8a4f85669 100644 --- a/drivers/clocksource/timer-keystone.c +++ b/drivers/clocksource/timer-keystone.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Keystone broadcast clock-event * * Copyright 2013 Texas Instruments, Inc. * * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/clk.h> diff --git a/drivers/clocksource/timer-meson6.c b/drivers/clocksource/timer-meson6.c index 84bd9479c3f8..9e8b467c71da 100644 --- a/drivers/clocksource/timer-meson6.c +++ b/drivers/clocksource/timer-meson6.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Amlogic Meson6 SoCs timer handling. * * Copyright (C) 2014 Carlo Caione <carlo@caione.org> * * Based on code from Amlogic, Inc - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/bitfield.h> diff --git a/drivers/clocksource/timer-pxa.c b/drivers/clocksource/timer-pxa.c index 395837938301..913a5d354a1f 100644 --- a/drivers/clocksource/timer-pxa.c +++ b/drivers/clocksource/timer-pxa.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-pxa/time.c * @@ -6,10 +7,6 @@ * * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001 * by MontaVista Software, Inc. (Nico, your code rocks!) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/clocksource/timer-rockchip.c b/drivers/clocksource/timer-rockchip.c index 33f370dbd0d6..1f95d0aca08f 100644 --- a/drivers/clocksource/timer-rockchip.c +++ b/drivers/clocksource/timer-rockchip.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Rockchip timer support * * Copyright (C) Daniel Lezcano <daniel.lezcano@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> #include <linux/clockchips.h> diff --git a/drivers/clocksource/timer-tegra.c b/drivers/clocksource/timer-tegra.c new file mode 100644 index 000000000000..e9635c25eef4 --- /dev/null +++ b/drivers/clocksource/timer-tegra.c @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2010 Google, Inc. + * + * Author: + * Colin Cross <ccross@google.com> + */ + +#define pr_fmt(fmt) "tegra-timer: " fmt + +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/cpu.h> +#include <linux/cpumask.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/percpu.h> +#include <linux/sched_clock.h> +#include <linux/time.h> + +#include "timer-of.h" + +#define RTC_SECONDS 0x08 +#define RTC_SHADOW_SECONDS 0x0c +#define RTC_MILLISECONDS 0x10 + +#define TIMERUS_CNTR_1US 0x10 +#define TIMERUS_USEC_CFG 0x14 +#define TIMERUS_CNTR_FREEZE 0x4c + +#define TIMER_PTV 0x0 +#define TIMER_PTV_EN BIT(31) +#define TIMER_PTV_PER BIT(30) +#define TIMER_PCR 0x4 +#define TIMER_PCR_INTR_CLR BIT(30) + +#define TIMER1_BASE 0x00 +#define TIMER2_BASE 0x08 +#define TIMER3_BASE 0x50 +#define TIMER4_BASE 0x58 +#define TIMER10_BASE 0x90 + +#define TIMER1_IRQ_IDX 0 +#define TIMER10_IRQ_IDX 10 + +#define TIMER_1MHz 1000000 + +static u32 usec_config; +static void __iomem *timer_reg_base; + +static int tegra_timer_set_next_event(unsigned long cycles, + struct clock_event_device *evt) +{ + void __iomem *reg_base = timer_of_base(to_timer_of(evt)); + + /* + * Tegra's timer uses n+1 scheme for the counter, i.e. timer will + * fire after one tick if 0 is loaded. + * + * The minimum and maximum numbers of oneshot ticks are defined + * by clockevents_config_and_register(1, 0x1fffffff + 1) invocation + * below in the code. Hence the cycles (ticks) can't be outside of + * a range supportable by hardware. + */ + writel_relaxed(TIMER_PTV_EN | (cycles - 1), reg_base + TIMER_PTV); + + return 0; +} + +static int tegra_timer_shutdown(struct clock_event_device *evt) +{ + void __iomem *reg_base = timer_of_base(to_timer_of(evt)); + + writel_relaxed(0, reg_base + TIMER_PTV); + + return 0; +} + +static int tegra_timer_set_periodic(struct clock_event_device *evt) +{ + void __iomem *reg_base = timer_of_base(to_timer_of(evt)); + unsigned long period = timer_of_period(to_timer_of(evt)); + + writel_relaxed(TIMER_PTV_EN | TIMER_PTV_PER | (period - 1), + reg_base + TIMER_PTV); + + return 0; +} + +static irqreturn_t tegra_timer_isr(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + void __iomem *reg_base = timer_of_base(to_timer_of(evt)); + + writel_relaxed(TIMER_PCR_INTR_CLR, reg_base + TIMER_PCR); + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static void tegra_timer_suspend(struct clock_event_device *evt) +{ + void __iomem *reg_base = timer_of_base(to_timer_of(evt)); + + writel_relaxed(TIMER_PCR_INTR_CLR, reg_base + TIMER_PCR); +} + +static void tegra_timer_resume(struct clock_event_device *evt) +{ + writel_relaxed(usec_config, timer_reg_base + TIMERUS_USEC_CFG); +} + +static DEFINE_PER_CPU(struct timer_of, tegra_to) = { + .flags = TIMER_OF_CLOCK | TIMER_OF_BASE, + + .clkevt = { + .name = "tegra_timer", + .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, + .set_next_event = tegra_timer_set_next_event, + .set_state_shutdown = tegra_timer_shutdown, + .set_state_periodic = tegra_timer_set_periodic, + .set_state_oneshot = tegra_timer_shutdown, + .tick_resume = tegra_timer_shutdown, + .suspend = tegra_timer_suspend, + .resume = tegra_timer_resume, + }, +}; + +static int tegra_timer_setup(unsigned int cpu) +{ + struct timer_of *to = per_cpu_ptr(&tegra_to, cpu); + + writel_relaxed(0, timer_of_base(to) + TIMER_PTV); + writel_relaxed(TIMER_PCR_INTR_CLR, timer_of_base(to) + TIMER_PCR); + + irq_force_affinity(to->clkevt.irq, cpumask_of(cpu)); + enable_irq(to->clkevt.irq); + + /* + * Tegra's timer uses n+1 scheme for the counter, i.e. timer will + * fire after one tick if 0 is loaded and thus minimum number of + * ticks is 1. In result both of the clocksource's tick limits are + * higher than a minimum and maximum that hardware register can + * take by 1, this is then taken into account by set_next_event + * callback. + */ + clockevents_config_and_register(&to->clkevt, timer_of_rate(to), + 1, /* min */ + 0x1fffffff + 1); /* max 29 bits + 1 */ + + return 0; +} + +static int tegra_timer_stop(unsigned int cpu) +{ + struct timer_of *to = per_cpu_ptr(&tegra_to, cpu); + + to->clkevt.set_state_shutdown(&to->clkevt); + disable_irq_nosync(to->clkevt.irq); + + return 0; +} + +static u64 notrace tegra_read_sched_clock(void) +{ + return readl_relaxed(timer_reg_base + TIMERUS_CNTR_1US); +} + +#ifdef CONFIG_ARM +static unsigned long tegra_delay_timer_read_counter_long(void) +{ + return readl_relaxed(timer_reg_base + TIMERUS_CNTR_1US); +} + +static struct delay_timer tegra_delay_timer = { + .read_current_timer = tegra_delay_timer_read_counter_long, + .freq = TIMER_1MHz, +}; +#endif + +static struct timer_of suspend_rtc_to = { + .flags = TIMER_OF_BASE | TIMER_OF_CLOCK, +}; + +/* + * tegra_rtc_read - Reads the Tegra RTC registers + * Care must be taken that this function is not called while the + * tegra_rtc driver could be executing to avoid race conditions + * on the RTC shadow register + */ +static u64 tegra_rtc_read_ms(struct clocksource *cs) +{ + void __iomem *reg_base = timer_of_base(&suspend_rtc_to); + + u32 ms = readl_relaxed(reg_base + RTC_MILLISECONDS); + u32 s = readl_relaxed(reg_base + RTC_SHADOW_SECONDS); + + return (u64)s * MSEC_PER_SEC + ms; +} + +static struct clocksource suspend_rtc_clocksource = { + .name = "tegra_suspend_timer", + .rating = 200, + .read = tegra_rtc_read_ms, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP, +}; + +static inline unsigned int tegra_base_for_cpu(int cpu, bool tegra20) +{ + if (tegra20) { + switch (cpu) { + case 0: + return TIMER1_BASE; + case 1: + return TIMER2_BASE; + case 2: + return TIMER3_BASE; + default: + return TIMER4_BASE; + } + } + + return TIMER10_BASE + cpu * 8; +} + +static inline unsigned int tegra_irq_idx_for_cpu(int cpu, bool tegra20) +{ + if (tegra20) + return TIMER1_IRQ_IDX + cpu; + + return TIMER10_IRQ_IDX + cpu; +} + +static inline unsigned long tegra_rate_for_timer(struct timer_of *to, + bool tegra20) +{ + /* + * TIMER1-9 are fixed to 1MHz, TIMER10-13 are running off the + * parent clock. + */ + if (tegra20) + return TIMER_1MHz; + + return timer_of_rate(to); +} + +static int __init tegra_init_timer(struct device_node *np, bool tegra20, + int rating) +{ + struct timer_of *to; + int cpu, ret; + + to = this_cpu_ptr(&tegra_to); + ret = timer_of_init(np, to); + if (ret) + goto out; + + timer_reg_base = timer_of_base(to); + + /* + * Configure microsecond timers to have 1MHz clock + * Config register is 0xqqww, where qq is "dividend", ww is "divisor" + * Uses n+1 scheme + */ + switch (timer_of_rate(to)) { + case 12000000: + usec_config = 0x000b; /* (11+1)/(0+1) */ + break; + case 12800000: + usec_config = 0x043f; /* (63+1)/(4+1) */ + break; + case 13000000: + usec_config = 0x000c; /* (12+1)/(0+1) */ + break; + case 16800000: + usec_config = 0x0453; /* (83+1)/(4+1) */ + break; + case 19200000: + usec_config = 0x045f; /* (95+1)/(4+1) */ + break; + case 26000000: + usec_config = 0x0019; /* (25+1)/(0+1) */ + break; + case 38400000: + usec_config = 0x04bf; /* (191+1)/(4+1) */ + break; + case 48000000: + usec_config = 0x002f; /* (47+1)/(0+1) */ + break; + default: + ret = -EINVAL; + goto out; + } + + writel_relaxed(usec_config, timer_reg_base + TIMERUS_USEC_CFG); + + for_each_possible_cpu(cpu) { + struct timer_of *cpu_to = per_cpu_ptr(&tegra_to, cpu); + unsigned long flags = IRQF_TIMER | IRQF_NOBALANCING; + unsigned long rate = tegra_rate_for_timer(to, tegra20); + unsigned int base = tegra_base_for_cpu(cpu, tegra20); + unsigned int idx = tegra_irq_idx_for_cpu(cpu, tegra20); + unsigned int irq = irq_of_parse_and_map(np, idx); + + if (!irq) { + pr_err("failed to map irq for cpu%d\n", cpu); + ret = -EINVAL; + goto out_irq; + } + + cpu_to->clkevt.irq = irq; + cpu_to->clkevt.rating = rating; + cpu_to->clkevt.cpumask = cpumask_of(cpu); + cpu_to->of_base.base = timer_reg_base + base; + cpu_to->of_clk.period = rate / HZ; + cpu_to->of_clk.rate = rate; + + irq_set_status_flags(cpu_to->clkevt.irq, IRQ_NOAUTOEN); + + ret = request_irq(cpu_to->clkevt.irq, tegra_timer_isr, flags, + cpu_to->clkevt.name, &cpu_to->clkevt); + if (ret) { + pr_err("failed to set up irq for cpu%d: %d\n", + cpu, ret); + irq_dispose_mapping(cpu_to->clkevt.irq); + cpu_to->clkevt.irq = 0; + goto out_irq; + } + } + + sched_clock_register(tegra_read_sched_clock, 32, TIMER_1MHz); + + ret = clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US, + "timer_us", TIMER_1MHz, 300, 32, + clocksource_mmio_readl_up); + if (ret) + pr_err("failed to register clocksource: %d\n", ret); + +#ifdef CONFIG_ARM + register_current_timer_delay(&tegra_delay_timer); +#endif + + ret = cpuhp_setup_state(CPUHP_AP_TEGRA_TIMER_STARTING, + "AP_TEGRA_TIMER_STARTING", tegra_timer_setup, + tegra_timer_stop); + if (ret) + pr_err("failed to set up cpu hp state: %d\n", ret); + + return ret; + +out_irq: + for_each_possible_cpu(cpu) { + struct timer_of *cpu_to; + + cpu_to = per_cpu_ptr(&tegra_to, cpu); + if (cpu_to->clkevt.irq) { + free_irq(cpu_to->clkevt.irq, &cpu_to->clkevt); + irq_dispose_mapping(cpu_to->clkevt.irq); + } + } + + to->of_base.base = timer_reg_base; +out: + timer_of_cleanup(to); + + return ret; +} + +static int __init tegra210_init_timer(struct device_node *np) +{ + /* + * Arch-timer can't survive across power cycle of CPU core and + * after CPUPORESET signal due to a system design shortcoming, + * hence tegra-timer is more preferable on Tegra210. + */ + return tegra_init_timer(np, false, 460); +} +TIMER_OF_DECLARE(tegra210_timer, "nvidia,tegra210-timer", tegra210_init_timer); + +static int __init tegra20_init_timer(struct device_node *np) +{ + int rating; + + /* + * Tegra20 and Tegra30 have Cortex A9 CPU that has a TWD timer, + * that timer runs off the CPU clock and hence is subjected to + * a jitter caused by DVFS clock rate changes. Tegra-timer is + * more preferable for older Tegra's, while later SoC generations + * have arch-timer as a main per-CPU timer and it is not affected + * by DVFS changes. + */ + if (of_machine_is_compatible("nvidia,tegra20") || + of_machine_is_compatible("nvidia,tegra30")) + rating = 460; + else + rating = 330; + + return tegra_init_timer(np, true, rating); +} +TIMER_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); + +static int __init tegra20_init_rtc(struct device_node *np) +{ + int ret; + + ret = timer_of_init(np, &suspend_rtc_to); + if (ret) + return ret; + + return clocksource_register_hz(&suspend_rtc_clocksource, 1000); +} +TIMER_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); diff --git a/drivers/clocksource/timer-tegra20.c b/drivers/clocksource/timer-tegra20.c deleted file mode 100644 index 1e7ece279730..000000000000 --- a/drivers/clocksource/timer-tegra20.c +++ /dev/null @@ -1,379 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2010 Google, Inc. - * - * Author: - * Colin Cross <ccross@google.com> - */ - -#include <linux/clk.h> -#include <linux/clockchips.h> -#include <linux/cpu.h> -#include <linux/cpumask.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/interrupt.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/percpu.h> -#include <linux/sched_clock.h> -#include <linux/time.h> - -#include "timer-of.h" - -#ifdef CONFIG_ARM -#include <asm/mach/time.h> -#endif - -#define RTC_SECONDS 0x08 -#define RTC_SHADOW_SECONDS 0x0c -#define RTC_MILLISECONDS 0x10 - -#define TIMERUS_CNTR_1US 0x10 -#define TIMERUS_USEC_CFG 0x14 -#define TIMERUS_CNTR_FREEZE 0x4c - -#define TIMER_PTV 0x0 -#define TIMER_PTV_EN BIT(31) -#define TIMER_PTV_PER BIT(30) -#define TIMER_PCR 0x4 -#define TIMER_PCR_INTR_CLR BIT(30) - -#ifdef CONFIG_ARM -#define TIMER_CPU0 0x50 /* TIMER3 */ -#else -#define TIMER_CPU0 0x90 /* TIMER10 */ -#define TIMER10_IRQ_IDX 10 -#define IRQ_IDX_FOR_CPU(cpu) (TIMER10_IRQ_IDX + cpu) -#endif -#define TIMER_BASE_FOR_CPU(cpu) (TIMER_CPU0 + (cpu) * 8) - -static u32 usec_config; -static void __iomem *timer_reg_base; -#ifdef CONFIG_ARM -static struct delay_timer tegra_delay_timer; -#endif - -static int tegra_timer_set_next_event(unsigned long cycles, - struct clock_event_device *evt) -{ - void __iomem *reg_base = timer_of_base(to_timer_of(evt)); - - writel(TIMER_PTV_EN | - ((cycles > 1) ? (cycles - 1) : 0), /* n+1 scheme */ - reg_base + TIMER_PTV); - - return 0; -} - -static int tegra_timer_shutdown(struct clock_event_device *evt) -{ - void __iomem *reg_base = timer_of_base(to_timer_of(evt)); - - writel(0, reg_base + TIMER_PTV); - - return 0; -} - -static int tegra_timer_set_periodic(struct clock_event_device *evt) -{ - void __iomem *reg_base = timer_of_base(to_timer_of(evt)); - - writel(TIMER_PTV_EN | TIMER_PTV_PER | - ((timer_of_rate(to_timer_of(evt)) / HZ) - 1), - reg_base + TIMER_PTV); - - return 0; -} - -static irqreturn_t tegra_timer_isr(int irq, void *dev_id) -{ - struct clock_event_device *evt = (struct clock_event_device *)dev_id; - void __iomem *reg_base = timer_of_base(to_timer_of(evt)); - - writel(TIMER_PCR_INTR_CLR, reg_base + TIMER_PCR); - evt->event_handler(evt); - - return IRQ_HANDLED; -} - -static void tegra_timer_suspend(struct clock_event_device *evt) -{ - void __iomem *reg_base = timer_of_base(to_timer_of(evt)); - - writel(TIMER_PCR_INTR_CLR, reg_base + TIMER_PCR); -} - -static void tegra_timer_resume(struct clock_event_device *evt) -{ - writel(usec_config, timer_reg_base + TIMERUS_USEC_CFG); -} - -#ifdef CONFIG_ARM64 -static DEFINE_PER_CPU(struct timer_of, tegra_to) = { - .flags = TIMER_OF_CLOCK | TIMER_OF_BASE, - - .clkevt = { - .name = "tegra_timer", - .rating = 460, - .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .set_next_event = tegra_timer_set_next_event, - .set_state_shutdown = tegra_timer_shutdown, - .set_state_periodic = tegra_timer_set_periodic, - .set_state_oneshot = tegra_timer_shutdown, - .tick_resume = tegra_timer_shutdown, - .suspend = tegra_timer_suspend, - .resume = tegra_timer_resume, - }, -}; - -static int tegra_timer_setup(unsigned int cpu) -{ - struct timer_of *to = per_cpu_ptr(&tegra_to, cpu); - - irq_force_affinity(to->clkevt.irq, cpumask_of(cpu)); - enable_irq(to->clkevt.irq); - - clockevents_config_and_register(&to->clkevt, timer_of_rate(to), - 1, /* min */ - 0x1fffffff); /* 29 bits */ - - return 0; -} - -static int tegra_timer_stop(unsigned int cpu) -{ - struct timer_of *to = per_cpu_ptr(&tegra_to, cpu); - - to->clkevt.set_state_shutdown(&to->clkevt); - disable_irq_nosync(to->clkevt.irq); - - return 0; -} -#else /* CONFIG_ARM */ -static struct timer_of tegra_to = { - .flags = TIMER_OF_CLOCK | TIMER_OF_BASE | TIMER_OF_IRQ, - - .clkevt = { - .name = "tegra_timer", - .rating = 300, - .features = CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_DYNIRQ, - .set_next_event = tegra_timer_set_next_event, - .set_state_shutdown = tegra_timer_shutdown, - .set_state_periodic = tegra_timer_set_periodic, - .set_state_oneshot = tegra_timer_shutdown, - .tick_resume = tegra_timer_shutdown, - .suspend = tegra_timer_suspend, - .resume = tegra_timer_resume, - .cpumask = cpu_possible_mask, - }, - - .of_irq = { - .index = 2, - .flags = IRQF_TIMER | IRQF_TRIGGER_HIGH, - .handler = tegra_timer_isr, - }, -}; - -static u64 notrace tegra_read_sched_clock(void) -{ - return readl(timer_reg_base + TIMERUS_CNTR_1US); -} - -static unsigned long tegra_delay_timer_read_counter_long(void) -{ - return readl(timer_reg_base + TIMERUS_CNTR_1US); -} - -static struct timer_of suspend_rtc_to = { - .flags = TIMER_OF_BASE | TIMER_OF_CLOCK, -}; - -/* - * tegra_rtc_read - Reads the Tegra RTC registers - * Care must be taken that this funciton is not called while the - * tegra_rtc driver could be executing to avoid race conditions - * on the RTC shadow register - */ -static u64 tegra_rtc_read_ms(struct clocksource *cs) -{ - u32 ms = readl(timer_of_base(&suspend_rtc_to) + RTC_MILLISECONDS); - u32 s = readl(timer_of_base(&suspend_rtc_to) + RTC_SHADOW_SECONDS); - return (u64)s * MSEC_PER_SEC + ms; -} - -static struct clocksource suspend_rtc_clocksource = { - .name = "tegra_suspend_timer", - .rating = 200, - .read = tegra_rtc_read_ms, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP, -}; -#endif - -static int tegra_timer_common_init(struct device_node *np, struct timer_of *to) -{ - int ret = 0; - - ret = timer_of_init(np, to); - if (ret < 0) - goto out; - - timer_reg_base = timer_of_base(to); - - /* - * Configure microsecond timers to have 1MHz clock - * Config register is 0xqqww, where qq is "dividend", ww is "divisor" - * Uses n+1 scheme - */ - switch (timer_of_rate(to)) { - case 12000000: - usec_config = 0x000b; /* (11+1)/(0+1) */ - break; - case 12800000: - usec_config = 0x043f; /* (63+1)/(4+1) */ - break; - case 13000000: - usec_config = 0x000c; /* (12+1)/(0+1) */ - break; - case 16800000: - usec_config = 0x0453; /* (83+1)/(4+1) */ - break; - case 19200000: - usec_config = 0x045f; /* (95+1)/(4+1) */ - break; - case 26000000: - usec_config = 0x0019; /* (25+1)/(0+1) */ - break; - case 38400000: - usec_config = 0x04bf; /* (191+1)/(4+1) */ - break; - case 48000000: - usec_config = 0x002f; /* (47+1)/(0+1) */ - break; - default: - ret = -EINVAL; - goto out; - } - - writel(usec_config, timer_of_base(to) + TIMERUS_USEC_CFG); - -out: - return ret; -} - -#ifdef CONFIG_ARM64 -static int __init tegra_init_timer(struct device_node *np) -{ - int cpu, ret = 0; - struct timer_of *to; - - to = this_cpu_ptr(&tegra_to); - ret = tegra_timer_common_init(np, to); - if (ret < 0) - goto out; - - for_each_possible_cpu(cpu) { - struct timer_of *cpu_to; - - cpu_to = per_cpu_ptr(&tegra_to, cpu); - cpu_to->of_base.base = timer_reg_base + TIMER_BASE_FOR_CPU(cpu); - cpu_to->of_clk.rate = timer_of_rate(to); - cpu_to->clkevt.cpumask = cpumask_of(cpu); - cpu_to->clkevt.irq = - irq_of_parse_and_map(np, IRQ_IDX_FOR_CPU(cpu)); - if (!cpu_to->clkevt.irq) { - pr_err("%s: can't map IRQ for CPU%d\n", - __func__, cpu); - ret = -EINVAL; - goto out; - } - - irq_set_status_flags(cpu_to->clkevt.irq, IRQ_NOAUTOEN); - ret = request_irq(cpu_to->clkevt.irq, tegra_timer_isr, - IRQF_TIMER | IRQF_NOBALANCING, - cpu_to->clkevt.name, &cpu_to->clkevt); - if (ret) { - pr_err("%s: cannot setup irq %d for CPU%d\n", - __func__, cpu_to->clkevt.irq, cpu); - ret = -EINVAL; - goto out_irq; - } - } - - cpuhp_setup_state(CPUHP_AP_TEGRA_TIMER_STARTING, - "AP_TEGRA_TIMER_STARTING", tegra_timer_setup, - tegra_timer_stop); - - return ret; -out_irq: - for_each_possible_cpu(cpu) { - struct timer_of *cpu_to; - - cpu_to = per_cpu_ptr(&tegra_to, cpu); - if (cpu_to->clkevt.irq) { - free_irq(cpu_to->clkevt.irq, &cpu_to->clkevt); - irq_dispose_mapping(cpu_to->clkevt.irq); - } - } -out: - timer_of_cleanup(to); - return ret; -} -#else /* CONFIG_ARM */ -static int __init tegra_init_timer(struct device_node *np) -{ - int ret = 0; - - ret = tegra_timer_common_init(np, &tegra_to); - if (ret < 0) - goto out; - - tegra_to.of_base.base = timer_reg_base + TIMER_BASE_FOR_CPU(0); - tegra_to.of_clk.rate = 1000000; /* microsecond timer */ - - sched_clock_register(tegra_read_sched_clock, 32, - timer_of_rate(&tegra_to)); - ret = clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US, - "timer_us", timer_of_rate(&tegra_to), - 300, 32, clocksource_mmio_readl_up); - if (ret) { - pr_err("Failed to register clocksource\n"); - goto out; - } - - tegra_delay_timer.read_current_timer = - tegra_delay_timer_read_counter_long; - tegra_delay_timer.freq = timer_of_rate(&tegra_to); - register_current_timer_delay(&tegra_delay_timer); - - clockevents_config_and_register(&tegra_to.clkevt, - timer_of_rate(&tegra_to), - 0x1, - 0x1fffffff); - - return ret; -out: - timer_of_cleanup(&tegra_to); - - return ret; -} - -static int __init tegra20_init_rtc(struct device_node *np) -{ - int ret; - - ret = timer_of_init(np, &suspend_rtc_to); - if (ret) - return ret; - - clocksource_register_hz(&suspend_rtc_clocksource, 1000); - - return 0; -} -TIMER_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); -#endif -TIMER_OF_DECLARE(tegra210_timer, "nvidia,tegra210-timer", tegra_init_timer); -TIMER_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra_init_timer); diff --git a/drivers/clocksource/timer-zevio.c b/drivers/clocksource/timer-zevio.c index 6127e8062a71..c0041561f1be 100644 --- a/drivers/clocksource/timer-zevio.c +++ b/drivers/clocksource/timer-zevio.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/clocksource/zevio-timer.c * * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * */ #include <linux/io.h> diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index 138ecd8a8fbd..2967d0a9ff91 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -51,6 +51,7 @@ config STM32_LPTIMER_CNT config FTM_QUADDEC tristate "Flex Timer Module Quadrature decoder driver" + depends on HAS_IOMEM && OF help Select this option to enable the Flex Timer Quadrature decoder driver. diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index f8129edc145e..56c31a78c692 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -93,6 +93,15 @@ config ARM_IMX6Q_CPUFREQ If in doubt, say N. +config ARM_IMX_CPUFREQ_DT + tristate "Freescale i.MX8M cpufreq support" + depends on ARCH_MXC && CPUFREQ_DT + help + This adds cpufreq driver support for Freescale i.MX8M series SoCs, + based on cpufreq-dt. + + If in doubt, say N. + config ARM_KIRKWOOD_CPUFREQ def_bool MACH_KIRKWOOD help @@ -133,6 +142,14 @@ config ARM_QCOM_CPUFREQ_HW The driver implements the cpufreq interface for this HW engine. Say Y if you want to support CPUFreq HW. +config ARM_RASPBERRYPI_CPUFREQ + tristate "Raspberry Pi cpufreq support" + depends on CLK_RASPBERRYPI || COMPILE_TEST + help + This adds the CPUFreq driver for Raspberry Pi + + If in doubt, say N. + config ARM_S3C_CPUFREQ bool help diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 689b26c6f949..5a6c70d26c98 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o +obj-$(CONFIG_ARM_IMX_CPUFREQ_DT) += imx-cpufreq-dt.o obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o obj-$(CONFIG_ARM_MEDIATEK_CPUFREQ) += mediatek-cpufreq.o obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o @@ -64,6 +65,7 @@ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o +obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o diff --git a/drivers/cpufreq/amd_freq_sensitivity.c b/drivers/cpufreq/amd_freq_sensitivity.c index 6927a8c0e748..e2df9d112106 100644 --- a/drivers/cpufreq/amd_freq_sensitivity.c +++ b/drivers/cpufreq/amd_freq_sensitivity.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * amd_freq_sensitivity.c: AMD frequency sensitivity feedback powersave bias * for the ondemand governor. @@ -5,10 +6,6 @@ * Copyright (C) 2013 Advanced Micro Devices, Inc. * * Author: Jacob Shin <jacob.shin@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c index 0df16eb1eb3c..aa0f06dec959 100644 --- a/drivers/cpufreq/armada-37xx-cpufreq.c +++ b/drivers/cpufreq/armada-37xx-cpufreq.c @@ -257,7 +257,7 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base, static void __init armada37xx_cpufreq_avs_setup(struct regmap *base, struct armada_37xx_dvfs *dvfs) { - unsigned int avs_val = 0, freq; + unsigned int avs_val = 0; int load_level = 0; if (base == NULL) @@ -275,8 +275,6 @@ static void __init armada37xx_cpufreq_avs_setup(struct regmap *base, for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++) { - freq = dvfs->cpu_freq_max / dvfs->divider[load_level]; - avs_val = dvfs->avs[load_level]; regmap_update_bits(base, ARMADA_37XX_AVS_VSET(load_level-1), ARMADA_37XX_AVS_VDD_MASK << ARMADA_37XX_AVS_HIGH_VDD_LIMIT | diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c index e6f9cbe5835f..77b0e5d0fb13 100644 --- a/drivers/cpufreq/brcmstb-avs-cpufreq.c +++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c @@ -384,12 +384,12 @@ static int brcm_avs_set_pstate(struct private_data *priv, unsigned int pstate) return __issue_avs_command(priv, AVS_CMD_SET_PSTATE, true, args); } -static unsigned long brcm_avs_get_voltage(void __iomem *base) +static u32 brcm_avs_get_voltage(void __iomem *base) { return readl(base + AVS_MBOX_VOLTAGE1); } -static unsigned long brcm_avs_get_frequency(void __iomem *base) +static u32 brcm_avs_get_frequency(void __iomem *base) { return readl(base + AVS_MBOX_FREQUENCY) * 1000; /* in kHz */ } @@ -446,8 +446,8 @@ static bool brcm_avs_is_firmware_loaded(struct private_data *priv) rc = brcm_avs_get_pmap(priv, NULL); magic = readl(priv->base + AVS_MBOX_MAGIC); - return (magic == AVS_FIRMWARE_MAGIC) && (rc != -ENOTSUPP) && - (rc != -EINVAL); + return (magic == AVS_FIRMWARE_MAGIC) && ((rc != -ENOTSUPP) || + (rc != -EINVAL)); } static unsigned int brcm_avs_cpufreq_get(unsigned int cpu) @@ -653,14 +653,14 @@ static ssize_t show_brcm_avs_voltage(struct cpufreq_policy *policy, char *buf) { struct private_data *priv = policy->driver_data; - return sprintf(buf, "0x%08lx\n", brcm_avs_get_voltage(priv->base)); + return sprintf(buf, "0x%08x\n", brcm_avs_get_voltage(priv->base)); } static ssize_t show_brcm_avs_frequency(struct cpufreq_policy *policy, char *buf) { struct private_data *priv = policy->driver_data; - return sprintf(buf, "0x%08lx\n", brcm_avs_get_frequency(priv->base)); + return sprintf(buf, "0x%08x\n", brcm_avs_get_frequency(priv->base)); } cpufreq_freq_attr_ro(brcm_avs_pstate); diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index 47729a22c159..03dc4244ab00 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Linaro. * Viresh Kumar <viresh.kumar@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> @@ -40,7 +37,6 @@ static const struct of_device_id whitelist[] __initconst = { { .compatible = "fsl,imx27", }, { .compatible = "fsl,imx51", }, { .compatible = "fsl,imx53", }, - { .compatible = "fsl,imx7d", }, { .compatible = "marvell,berlin", }, { .compatible = "marvell,pxa250", }, @@ -108,6 +104,10 @@ static const struct of_device_id blacklist[] __initconst = { { .compatible = "calxeda,highbank", }, { .compatible = "calxeda,ecx-2000", }, + { .compatible = "fsl,imx7d", }, + { .compatible = "fsl,imx8mq", }, + { .compatible = "fsl,imx8mm", }, + { .compatible = "marvell,armadaxp", }, { .compatible = "mediatek,mt2701", }, diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index bde28878725b..d2b5f062a07b 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Freescale Semiconductor, Inc. * * Copyright (C) 2014 Linaro. * Viresh Kumar <viresh.kumar@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/cpufreq/cpufreq-dt.h b/drivers/cpufreq/cpufreq-dt.h index d5aeea13433e..a5a45b547d0b 100644 --- a/drivers/cpufreq/cpufreq-dt.h +++ b/drivers/cpufreq/cpufreq-dt.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2016 Linaro * Viresh Kumar <viresh.kumar@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __CPUFREQ_DT_H__ diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 85ff958e01f1..0a9f675f2af4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/cpufreq/cpufreq.c * @@ -9,10 +10,6 @@ * Added handling for CPU hotplug * Feb 2006 - Jacob Shin <jacob.shin@amd.com> * Fix handling for CPU hotplug -- affected CPUs - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -359,12 +356,10 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy, * which is not equal to what the cpufreq core thinks is * "old frequency". */ - if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { - if (policy->cur && (policy->cur != freqs->old)) { - pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n", - freqs->old, policy->cur); - freqs->old = policy->cur; - } + if (policy->cur && policy->cur != freqs->old) { + pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n", + freqs->old, policy->cur); + freqs->old = policy->cur; } srcu_notifier_call_chain(&cpufreq_transition_notifier_list, @@ -634,7 +629,7 @@ static int cpufreq_parse_policy(char *str_governor, } /** - * cpufreq_parse_governor - parse a governor string only for !setpolicy + * cpufreq_parse_governor - parse a governor string only for has_target() */ static int cpufreq_parse_governor(char *str_governor, struct cpufreq_policy *policy) @@ -1117,13 +1112,25 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cp return ret; } +static void refresh_frequency_limits(struct cpufreq_policy *policy) +{ + struct cpufreq_policy new_policy = *policy; + + pr_debug("updating policy for CPU %u\n", policy->cpu); + + new_policy.min = policy->user_policy.min; + new_policy.max = policy->user_policy.max; + + cpufreq_set_policy(policy, &new_policy); +} + static void handle_update(struct work_struct *work) { struct cpufreq_policy *policy = container_of(work, struct cpufreq_policy, update); - unsigned int cpu = policy->cpu; - pr_debug("handle_update for cpu %u called\n", cpu); - cpufreq_update_policy(cpu); + + pr_debug("handle_update for cpu %u called\n", policy->cpu); + refresh_frequency_limits(policy); } static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu) @@ -1303,7 +1310,7 @@ static int cpufreq_online(unsigned int cpu) policy->max = policy->user_policy.max; } - if (cpufreq_driver->get && !cpufreq_driver->setpolicy) { + if (cpufreq_driver->get && has_target()) { policy->cur = cpufreq_driver->get(policy->cpu); if (!policy->cur) { pr_err("%s: ->get() failed\n", __func__); @@ -1378,8 +1385,7 @@ static int cpufreq_online(unsigned int cpu) if (cpufreq_driver->ready) cpufreq_driver->ready(policy); - if (IS_ENABLED(CONFIG_CPU_THERMAL) && - cpufreq_driver->flags & CPUFREQ_IS_COOLING_DEV) + if (cpufreq_thermal_control_enabled(cpufreq_driver)) policy->cdev = of_cpufreq_cooling_register(policy); pr_debug("initialization complete\n"); @@ -1469,8 +1475,7 @@ static int cpufreq_offline(unsigned int cpu) goto unlock; } - if (IS_ENABLED(CONFIG_CPU_THERMAL) && - cpufreq_driver->flags & CPUFREQ_IS_COOLING_DEV) { + if (cpufreq_thermal_control_enabled(cpufreq_driver)) { cpufreq_cooling_unregister(policy->cdev); policy->cdev = NULL; } @@ -1549,6 +1554,30 @@ static void cpufreq_out_of_sync(struct cpufreq_policy *policy, cpufreq_freq_transition_end(policy, &freqs, 0); } +static unsigned int cpufreq_verify_current_freq(struct cpufreq_policy *policy, bool update) +{ + unsigned int new_freq; + + new_freq = cpufreq_driver->get(policy->cpu); + if (!new_freq) + return 0; + + /* + * If fast frequency switching is used with the given policy, the check + * against policy->cur is pointless, so skip it in that case. + */ + if (policy->fast_switch_enabled || !has_target()) + return new_freq; + + if (policy->cur != new_freq) { + cpufreq_out_of_sync(policy, new_freq); + if (update) + schedule_work(&policy->update); + } + + return new_freq; +} + /** * cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur * @cpu: CPU number @@ -1604,31 +1633,10 @@ EXPORT_SYMBOL(cpufreq_quick_get_max); static unsigned int __cpufreq_get(struct cpufreq_policy *policy) { - unsigned int ret_freq = 0; - if (unlikely(policy_is_inactive(policy))) - return ret_freq; - - ret_freq = cpufreq_driver->get(policy->cpu); - - /* - * If fast frequency switching is used with the given policy, the check - * against policy->cur is pointless, so skip it in that case too. - */ - if (policy->fast_switch_enabled) - return ret_freq; - - if (ret_freq && policy->cur && - !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { - /* verify no discrepancy between actual and - saved value exists */ - if (unlikely(ret_freq != policy->cur)) { - cpufreq_out_of_sync(policy, ret_freq); - schedule_work(&policy->update); - } - } + return 0; - return ret_freq; + return cpufreq_verify_current_freq(policy, true); } /** @@ -1655,24 +1663,6 @@ unsigned int cpufreq_get(unsigned int cpu) } EXPORT_SYMBOL(cpufreq_get); -static unsigned int cpufreq_update_current_freq(struct cpufreq_policy *policy) -{ - unsigned int new_freq; - - new_freq = cpufreq_driver->get(policy->cpu); - if (!new_freq) - return 0; - - if (!policy->cur) { - pr_debug("cpufreq: Driver did not initialize current freq\n"); - policy->cur = new_freq; - } else if (policy->cur != new_freq && has_target()) { - cpufreq_out_of_sync(policy, new_freq); - } - - return new_freq; -} - static struct subsys_interface cpufreq_interface = { .name = "cpufreq", .subsys = &cpu_subsys, @@ -2153,8 +2143,8 @@ static int cpufreq_start_governor(struct cpufreq_policy *policy) pr_debug("%s: for CPU %u\n", __func__, policy->cpu); - if (cpufreq_driver->get && !cpufreq_driver->setpolicy) - cpufreq_update_current_freq(policy); + if (cpufreq_driver->get) + cpufreq_verify_current_freq(policy, false); if (policy->governor->start) { ret = policy->governor->start(policy); @@ -2395,7 +2385,6 @@ int cpufreq_set_policy(struct cpufreq_policy *policy, void cpufreq_update_policy(unsigned int cpu) { struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu); - struct cpufreq_policy new_policy; if (!policy) return; @@ -2404,16 +2393,11 @@ void cpufreq_update_policy(unsigned int cpu) * BIOS might change freq behind our back * -> ask driver for current freq and notify governors about a change */ - if (cpufreq_driver->get && !cpufreq_driver->setpolicy && - (cpufreq_suspended || WARN_ON(!cpufreq_update_current_freq(policy)))) + if (cpufreq_driver->get && has_target() && + (cpufreq_suspended || WARN_ON(!cpufreq_verify_current_freq(policy, false)))) goto unlock; - pr_debug("updating policy for CPU %u\n", cpu); - memcpy(&new_policy, policy, sizeof(*policy)); - new_policy.min = policy->user_policy.min; - new_policy.max = policy->user_policy.max; - - cpufreq_set_policy(policy, &new_policy); + refresh_frequency_limits(policy); unlock: cpufreq_cpu_release(policy); diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 4268f87e99fc..b66e81c06a57 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/cpufreq/cpufreq_conservative.c * @@ -5,10 +6,6 @@ * (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>. * Jun Nakajima <jun.nakajima@intel.com> * (C) 2009 Alexander Clouter <alex@digriz.org.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/slab.h> diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 9d1d9bf02710..4bb054d0cb43 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/cpufreq/cpufreq_governor.c * @@ -8,10 +9,6 @@ * (C) 2003 Jun Nakajima <jun.nakajima@intel.com> * (C) 2009 Alexander Clouter <alex@digriz.org.uk> * (c) 2012 Viresh Kumar <viresh.kumar@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 8463f5def0f5..c56773c25757 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * drivers/cpufreq/cpufreq_governor.h * @@ -8,10 +9,6 @@ * (C) 2003 Jun Nakajima <jun.nakajima@intel.com> * (C) 2009 Alexander Clouter <alex@digriz.org.uk> * (c) 2012 Viresh Kumar <viresh.kumar@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _CPUFREQ_GOVERNOR_H diff --git a/drivers/cpufreq/cpufreq_governor_attr_set.c b/drivers/cpufreq/cpufreq_governor_attr_set.c index 52841f807a7e..66b05a326910 100644 --- a/drivers/cpufreq/cpufreq_governor_attr_set.c +++ b/drivers/cpufreq/cpufreq_governor_attr_set.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Abstract code for CPUFreq governor tunable sysfs attributes. * * Copyright (C) 2016, Intel Corporation * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "cpufreq_governor.h" diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 6b423eebfd5d..dced033875bf 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/cpufreq/cpufreq_ondemand.c * * Copyright (C) 2001 Russell King * (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>. * Jun Nakajima <jun.nakajima@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/cpufreq/cpufreq_ondemand.h b/drivers/cpufreq/cpufreq_ondemand.h index 640ea4e97106..1af8e5c4b86f 100644 --- a/drivers/cpufreq/cpufreq_ondemand.h +++ b/drivers/cpufreq/cpufreq_ondemand.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Header file for CPUFreq ondemand governor and related code. * * Copyright (C) 2016, Intel Corporation * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "cpufreq_governor.h" diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c index dafb679adc58..aaa04dfcacd9 100644 --- a/drivers/cpufreq/cpufreq_performance.c +++ b/drivers/cpufreq/cpufreq_performance.c @@ -1,13 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/cpufreq/cpufreq_performance.c * * Copyright (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c index 78a651038faf..c143dc237d87 100644 --- a/drivers/cpufreq/cpufreq_powersave.c +++ b/drivers/cpufreq/cpufreq_powersave.c @@ -1,13 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/cpufreq/cpufreq_powersave.c * * Copyright (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 08b192eb22c6..f9bcf0f3ea30 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/cpufreq/cpufreq_stats.c * * Copyright (C) 2003-2004 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>. * (C) 2004 Zou Nan hai <nanhai.zou@intel.com>. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/cpu.h> diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index bd897e3e134d..cbd81c58cb8f 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/cpufreq/cpufreq_userspace.c * * Copyright (C) 2001 Russell King * (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c index 940fe85db97a..3de48ae60c29 100644 --- a/drivers/cpufreq/davinci-cpufreq.c +++ b/drivers/cpufreq/davinci-cpufreq.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * CPU frequency scaling for DaVinci * @@ -13,10 +14,6 @@ * Copyright (C) 2007-2008 Texas Instruments, Inc. * Updated to support OMAP3 * Rajendra Nayak <rnayak@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/types.h> #include <linux/cpufreq.h> diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index e7be0af3199f..ded427e0a488 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/cpufreq/freq_table.c * * Copyright (C) 2002 - 2003 Dominik Brodowski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c index 8f52a06664e3..e97b5733aa24 100644 --- a/drivers/cpufreq/gx-suspmod.c +++ b/drivers/cpufreq/gx-suspmod.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Cyrix MediaGX and NatSemi Geode Suspend Modulation * (C) 2002 Zwane Mwaikambo <zwane@commfireservices.com> * (C) 2002 Hiroshi Miura <miura@da-cha.org> * All Rights Reserved * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation - * * The author(s) of this software shall not be held liable for damages * of any nature resulting due to the use of this software. This * software is provided AS-IS with no warranties. @@ -48,7 +45,6 @@ * off_duration = (freq * DURATION) / stock_freq * on_duration = DURATION - off_duration * - * *--------------------------------------------------------------------------- * * ChangeLog: diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c index 1608f7105c9f..5a7f6dafcddb 100644 --- a/drivers/cpufreq/highbank-cpufreq.c +++ b/drivers/cpufreq/highbank-cpufreq.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Calxeda, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This driver provides the clk notifier callbacks that are used when * the cpufreq-dt driver changes to frequency to alert the highbank * EnergyCore Management Engine (ECME) about the need to change diff --git a/drivers/cpufreq/imx-cpufreq-dt.c b/drivers/cpufreq/imx-cpufreq-dt.c new file mode 100644 index 000000000000..b54fd26ea7df --- /dev/null +++ b/drivers/cpufreq/imx-cpufreq-dt.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 NXP + */ + +#include <linux/cpu.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/nvmem-consumer.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_opp.h> +#include <linux/slab.h> + +#define OCOTP_CFG3_SPEED_GRADE_SHIFT 8 +#define OCOTP_CFG3_SPEED_GRADE_MASK (0x3 << 8) +#define OCOTP_CFG3_MKT_SEGMENT_SHIFT 6 +#define OCOTP_CFG3_MKT_SEGMENT_MASK (0x3 << 6) + +/* cpufreq-dt device registered by imx-cpufreq-dt */ +static struct platform_device *cpufreq_dt_pdev; +static struct opp_table *cpufreq_opp_table; + +static int imx_cpufreq_dt_probe(struct platform_device *pdev) +{ + struct device *cpu_dev = get_cpu_device(0); + u32 cell_value, supported_hw[2]; + int speed_grade, mkt_segment; + int ret; + + ret = nvmem_cell_read_u32(cpu_dev, "speed_grade", &cell_value); + if (ret) + return ret; + + speed_grade = (cell_value & OCOTP_CFG3_SPEED_GRADE_MASK) >> OCOTP_CFG3_SPEED_GRADE_SHIFT; + mkt_segment = (cell_value & OCOTP_CFG3_MKT_SEGMENT_MASK) >> OCOTP_CFG3_MKT_SEGMENT_SHIFT; + + /* + * Early samples without fuses written report "0 0" which means + * consumer segment and minimum speed grading. + * + * According to datasheet minimum speed grading is not supported for + * consumer parts so clamp to 1 to avoid warning for "no OPPs" + * + * Applies to 8mq and 8mm. + */ + if (mkt_segment == 0 && speed_grade == 0 && ( + of_machine_is_compatible("fsl,imx8mm") || + of_machine_is_compatible("fsl,imx8mq"))) + speed_grade = 1; + + supported_hw[0] = BIT(speed_grade); + supported_hw[1] = BIT(mkt_segment); + dev_info(&pdev->dev, "cpu speed grade %d mkt segment %d supported-hw %#x %#x\n", + speed_grade, mkt_segment, supported_hw[0], supported_hw[1]); + + cpufreq_opp_table = dev_pm_opp_set_supported_hw(cpu_dev, supported_hw, 2); + if (IS_ERR(cpufreq_opp_table)) { + ret = PTR_ERR(cpufreq_opp_table); + dev_err(&pdev->dev, "Failed to set supported opp: %d\n", ret); + return ret; + } + + cpufreq_dt_pdev = platform_device_register_data( + &pdev->dev, "cpufreq-dt", -1, NULL, 0); + if (IS_ERR(cpufreq_dt_pdev)) { + dev_pm_opp_put_supported_hw(cpufreq_opp_table); + ret = PTR_ERR(cpufreq_dt_pdev); + dev_err(&pdev->dev, "Failed to register cpufreq-dt: %d\n", ret); + return ret; + } + + return 0; +} + +static int imx_cpufreq_dt_remove(struct platform_device *pdev) +{ + platform_device_unregister(cpufreq_dt_pdev); + dev_pm_opp_put_supported_hw(cpufreq_opp_table); + + return 0; +} + +static struct platform_driver imx_cpufreq_dt_driver = { + .probe = imx_cpufreq_dt_probe, + .remove = imx_cpufreq_dt_remove, + .driver = { + .name = "imx-cpufreq-dt", + }, +}; +module_platform_driver(imx_cpufreq_dt_driver); + +MODULE_ALIAS("platform:imx-cpufreq-dt"); +MODULE_DESCRIPTION("Freescale i.MX cpufreq speed grading driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index 3e17560b1efe..47ccfa6b17b7 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c index a94355723ef8..f5220b3d4ec5 100644 --- a/drivers/cpufreq/maple-cpufreq.c +++ b/drivers/cpufreq/maple-cpufreq.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Dmitry Eremin-Solenikov * Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org> * and Markus Demleitner <msdemlei@cl.uni-heidelberg.de> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This driver adds basic cpufreq support for SMU & 970FX based G5 Macs, * that is iMac G5 and latest single CPU desktop. */ diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 68052b74d28f..29643f06a3c3 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * CPU frequency scaling for OMAP using OPP information * @@ -8,10 +9,6 @@ * * Copyright (C) 2007-2011 Texas Instruments, Inc. * - OMAP3/4 support by Rajendra Nayak, Santosh Shilimkar - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index 1e5e64643c3a..fdc767fdbe6a 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -582,10 +582,10 @@ static int __init pcc_cpufreq_init(void) /* Skip initialization if another cpufreq driver is there. */ if (cpufreq_get_current_driver()) - return 0; + return -EEXIST; if (acpi_disabled) - return 0; + return -ENODEV; ret = pcc_cpufreq_probe(); if (ret) { diff --git a/drivers/cpufreq/pmac32-cpufreq.c b/drivers/cpufreq/pmac32-cpufreq.c index 9b4ce2eb8222..650104d729f3 100644 --- a/drivers/cpufreq/pmac32-cpufreq.c +++ b/drivers/cpufreq/pmac32-cpufreq.c @@ -1,16 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org> * Copyright (C) 2004 John Steele Scott <toojays@toojays.net> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * TODO: Need a big cleanup here. Basically, we need to have different * cpufreq_driver structures for the different type of HW instead of the * current mess. We also need to better deal with the detection of the * type of machine. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/cpufreq/pmac64-cpufreq.c b/drivers/cpufreq/pmac64-cpufreq.c index 1d32a863332d..1af3492a000d 100644 --- a/drivers/cpufreq/pmac64-cpufreq.c +++ b/drivers/cpufreq/pmac64-cpufreq.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org> * and Markus Demleitner <msdemlei@cl.uni-heidelberg.de> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This driver adds basic cpufreq support for SMU & 970FX based G5 Macs, * that is iMac G5 and latest single CPU desktop. */ diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c index 71b640c8c1a5..8e436dc75c8b 100644 --- a/drivers/cpufreq/qoriq-cpufreq.c +++ b/drivers/cpufreq/qoriq-cpufreq.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2013 Freescale Semiconductor, Inc. * * CPU Frequency Scaling driver for Freescale QorIQ SoCs. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/cpufreq/raspberrypi-cpufreq.c b/drivers/cpufreq/raspberrypi-cpufreq.c new file mode 100644 index 000000000000..2bc7d9734272 --- /dev/null +++ b/drivers/cpufreq/raspberrypi-cpufreq.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Raspberry Pi cpufreq driver + * + * Copyright (C) 2019, Nicolas Saenz Julienne <nsaenzjulienne@suse.de> + */ + +#include <linux/clk.h> +#include <linux/cpu.h> +#include <linux/cpufreq.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_opp.h> + +#define RASPBERRYPI_FREQ_INTERVAL 100000000 + +static struct platform_device *cpufreq_dt; + +static int raspberrypi_cpufreq_probe(struct platform_device *pdev) +{ + struct device *cpu_dev; + unsigned long min, max; + unsigned long rate; + struct clk *clk; + int ret; + + cpu_dev = get_cpu_device(0); + if (!cpu_dev) { + pr_err("Cannot get CPU for cpufreq driver\n"); + return -ENODEV; + } + + clk = clk_get(cpu_dev, NULL); + if (IS_ERR(clk)) { + dev_err(cpu_dev, "Cannot get clock for CPU0\n"); + return PTR_ERR(clk); + } + + /* + * The max and min frequencies are configurable in the Raspberry Pi + * firmware, so we query them at runtime. + */ + min = roundup(clk_round_rate(clk, 0), RASPBERRYPI_FREQ_INTERVAL); + max = roundup(clk_round_rate(clk, ULONG_MAX), RASPBERRYPI_FREQ_INTERVAL); + clk_put(clk); + + for (rate = min; rate <= max; rate += RASPBERRYPI_FREQ_INTERVAL) { + ret = dev_pm_opp_add(cpu_dev, rate, 0); + if (ret) + goto remove_opp; + } + + cpufreq_dt = platform_device_register_simple("cpufreq-dt", -1, NULL, 0); + ret = PTR_ERR_OR_ZERO(cpufreq_dt); + if (ret) { + dev_err(cpu_dev, "Failed to create platform device, %d\n", ret); + goto remove_opp; + } + + return 0; + +remove_opp: + dev_pm_opp_remove_all_dynamic(cpu_dev); + + return ret; +} + +static int raspberrypi_cpufreq_remove(struct platform_device *pdev) +{ + struct device *cpu_dev; + + cpu_dev = get_cpu_device(0); + if (cpu_dev) + dev_pm_opp_remove_all_dynamic(cpu_dev); + + platform_device_unregister(cpufreq_dt); + + return 0; +} + +/* + * Since the driver depends on clk-raspberrypi, which may return EPROBE_DEFER, + * all the activity is performed in the probe, which may be defered as well. + */ +static struct platform_driver raspberrypi_cpufreq_driver = { + .driver = { + .name = "raspberrypi-cpufreq", + }, + .probe = raspberrypi_cpufreq_probe, + .remove = raspberrypi_cpufreq_remove, +}; +module_platform_driver(raspberrypi_cpufreq_driver); + +MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de"); +MODULE_DESCRIPTION("Raspberry Pi cpufreq driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:raspberrypi-cpufreq"); diff --git a/drivers/cpufreq/s3c2410-cpufreq.c b/drivers/cpufreq/s3c2410-cpufreq.c index b8e5da8e188b..0c4f2ccd7e22 100644 --- a/drivers/cpufreq/s3c2410-cpufreq.c +++ b/drivers/cpufreq/s3c2410-cpufreq.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2006-2008 Simtec Electronics * http://armlinux.simtec.co.uk/ * Ben Dooks <ben@simtec.co.uk> * * S3C2410 CPU Frequency scaling - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> diff --git a/drivers/cpufreq/s3c2412-cpufreq.c b/drivers/cpufreq/s3c2412-cpufreq.c index b04b6f02bbdc..53385a9ab957 100644 --- a/drivers/cpufreq/s3c2412-cpufreq.c +++ b/drivers/cpufreq/s3c2412-cpufreq.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008 Simtec Electronics * http://armlinux.simtec.co.uk/ * Ben Dooks <ben@simtec.co.uk> * * S3C2412 CPU Frequency scalling - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c index 5b2db3c6568f..f7ff1ed7fef1 100644 --- a/drivers/cpufreq/s3c2416-cpufreq.c +++ b/drivers/cpufreq/s3c2416-cpufreq.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * S3C2416/2450 CPUfreq Support * @@ -6,10 +7,6 @@ * based on s3c64xx_cpufreq.c * * Copyright 2009 Wolfson Microelectronics plc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/cpufreq/s3c2440-cpufreq.c b/drivers/cpufreq/s3c2440-cpufreq.c index d2f67b7a20dd..3f772ba8896e 100644 --- a/drivers/cpufreq/s3c2440-cpufreq.c +++ b/drivers/cpufreq/s3c2440-cpufreq.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2006-2009 Simtec Electronics * http://armlinux.simtec.co.uk/ @@ -5,10 +6,6 @@ * Vincent Sanders <vince@simtec.co.uk> * * S3C2440/S3C2442 CPU Frequency scaling - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c b/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c index 0df87b6480fe..290e3539d03e 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c +++ b/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2009 Simtec Electronics * http://armlinux.simtec.co.uk/ * Ben Dooks <ben@simtec.co.uk> * * S3C24XX CPU Frequency scaling - debugfs status support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index 3b291a2b0cb3..ed0e713b1b57 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2006-2008 Simtec Electronics * http://armlinux.simtec.co.uk/ * Ben Dooks <ben@simtec.co.uk> * * S3C24XX CPU Frequency scaling - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c index 0cb9040eca49..37df2d892eb0 100644 --- a/drivers/cpufreq/s3c64xx-cpufreq.c +++ b/drivers/cpufreq/s3c64xx-cpufreq.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2009 Wolfson Microelectronics plc * * S3C64xx CPUfreq Support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "cpufreq: " fmt diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 5b4289460bc9..e5cb17d4be7b 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2010 Samsung Electronics Co., Ltd. * http://www.samsung.com * * CPU frequency scaling for S5PC110/S5PV210 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -481,7 +478,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) arm_volt, arm_volt_max); } - printk(KERN_DEBUG "Perf changed[L%d]\n", index); + pr_debug("Perf changed[L%d]\n", index); exit: mutex_unlock(&set_freq_lock); diff --git a/drivers/cpufreq/sa1110-cpufreq.c b/drivers/cpufreq/sa1110-cpufreq.c index 66e5fb088ecc..dab54e051c0e 100644 --- a/drivers/cpufreq/sa1110-cpufreq.c +++ b/drivers/cpufreq/sa1110-cpufreq.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/arch/arm/mach-sa1100/cpu-sa1110.c * * Copyright (C) 2001 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Note: there are two erratas that apply to the SA1110 here: * 7 - SDRAM auto-power-up failure (rev A0) * 13 - Corruption of internal register reads/writes following diff --git a/drivers/cpufreq/sfi-cpufreq.c b/drivers/cpufreq/sfi-cpufreq.c index 978770432b13..45cfdf67cf03 100644 --- a/drivers/cpufreq/sfi-cpufreq.c +++ b/drivers/cpufreq/sfi-cpufreq.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SFI Performance States Driver * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * * Author: Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com> * Author: Srinidhi Kasagar <srinidhi.kasagar@intel.com> */ diff --git a/drivers/cpufreq/unicore2-cpufreq.c b/drivers/cpufreq/unicore2-cpufreq.c index db62d9844751..707dbc1b7ac8 100644 --- a/drivers/cpufreq/unicore2-cpufreq.c +++ b/drivers/cpufreq/unicore2-cpufreq.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * clock scaling for the UniCore-II * @@ -5,10 +6,6 @@ * * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> * Copyright (C) 2001-2010 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c index 3a407a3ef22b..5bcd82c35dcf 100644 --- a/drivers/cpuidle/cpuidle-arm.c +++ b/drivers/cpuidle/cpuidle-arm.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ARM/ARM64 generic CPU idle driver. * * Copyright (C) 2014 ARM Ltd. * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "CPUidle arm: " fmt diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c index b44476a1b7ad..7f8ddc04342d 100644 --- a/drivers/cpuidle/cpuidle-big_little.c +++ b/drivers/cpuidle/cpuidle-big_little.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 ARM/Linaro * @@ -5,10 +6,6 @@ * Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> * Nicolas Pitre <nicolas.pitre@linaro.org> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Maintainer: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> * Maintainer: Daniel Lezcano <daniel.lezcano@linaro.org> */ diff --git a/drivers/cpuidle/cpuidle-exynos.c b/drivers/cpuidle/cpuidle-exynos.c index f7199a35cbb6..b2b5666e0515 100644 --- a/drivers/cpuidle/cpuidle-exynos.c +++ b/drivers/cpuidle/cpuidle-exynos.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. * http://www.samsung.com @@ -5,10 +6,6 @@ * Coupled cpuidle support based on the work of: * Colin Cross <ccross@android.com> * Daniel Lezcano <daniel.lezcano@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/cpuidle.h> diff --git a/drivers/cpuidle/cpuidle-ux500.c b/drivers/cpuidle/cpuidle-ux500.c index 7941a090bea6..a2d34be17a09 100644 --- a/drivers/cpuidle/cpuidle-ux500.c +++ b/drivers/cpuidle/cpuidle-ux500.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012 Linaro : Daniel Lezcano <daniel.lezcano@linaro.org> (IBM) * * Based on the work of Rickard Andersson <rickard.andersson@stericsson.com> * and Jonas Aaberg <jonas.aberg@stericsson.com>. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c index add9569636b5..d06d21a9525d 100644 --- a/drivers/cpuidle/dt_idle_states.c +++ b/drivers/cpuidle/dt_idle_states.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * DT idle states parsing code. * * Copyright (C) 2014 ARM Ltd. * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "DT idle-states: " fmt diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 0af08081e305..603413f28fa3 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -520,10 +520,13 @@ config CRYPTO_DEV_ATMEL_SHA To compile this driver as a module, choose M here: the module will be called atmel-sha. +config CRYPTO_DEV_ATMEL_I2C + tristate + config CRYPTO_DEV_ATMEL_ECC tristate "Support for Microchip / Atmel ECC hw accelerator" - depends on ARCH_AT91 || COMPILE_TEST depends on I2C + select CRYPTO_DEV_ATMEL_I2C select CRYPTO_ECDH select CRC16 help @@ -534,6 +537,21 @@ config CRYPTO_DEV_ATMEL_ECC To compile this driver as a module, choose M here: the module will be called atmel-ecc. +config CRYPTO_DEV_ATMEL_SHA204A + tristate "Support for Microchip / Atmel SHA accelerator and RNG" + depends on I2C + select CRYPTO_DEV_ATMEL_I2C + select HW_RANDOM + select CRC16 + help + Microhip / Atmel SHA accelerator and RNG. + Select this if you want to use the Microchip / Atmel SHA204A + module as a random number generator. (Other functions of the + chip are currently not exposed by this driver) + + To compile this driver as a module, choose M here: the module + will be called atmel-sha204a. + config CRYPTO_DEV_CCP bool "Support for AMD Secure Processor" depends on ((X86 && PCI) || (ARM64 && (OF_ADDRESS || ACPI))) && HAS_IOMEM diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index a23a7197fcd7..afc4753b5d28 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -2,7 +2,9 @@ obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o +obj-$(CONFIG_CRYPTO_DEV_ATMEL_I2C) += atmel-i2c.o obj-$(CONFIG_CRYPTO_DEV_ATMEL_ECC) += atmel-ecc.o +obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA204A) += atmel-sha204a.o obj-$(CONFIG_CRYPTO_DEV_CAVIUM_ZIP) += cavium/ obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/ obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/ diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c index 49f3e0ce242c..cbfc607282f4 100644 --- a/drivers/crypto/amcc/crypto4xx_alg.c +++ b/drivers/crypto/amcc/crypto4xx_alg.c @@ -67,12 +67,16 @@ static void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm, } static inline int crypto4xx_crypt(struct skcipher_request *req, - const unsigned int ivlen, bool decrypt) + const unsigned int ivlen, bool decrypt, + bool check_blocksize) { struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher); __le32 iv[AES_IV_SIZE]; + if (check_blocksize && !IS_ALIGNED(req->cryptlen, AES_BLOCK_SIZE)) + return -EINVAL; + if (ivlen) crypto4xx_memcpy_to_le32(iv, req->iv, ivlen); @@ -81,24 +85,34 @@ static inline int crypto4xx_crypt(struct skcipher_request *req, ctx->sa_len, 0, NULL); } -int crypto4xx_encrypt_noiv(struct skcipher_request *req) +int crypto4xx_encrypt_noiv_block(struct skcipher_request *req) +{ + return crypto4xx_crypt(req, 0, false, true); +} + +int crypto4xx_encrypt_iv_stream(struct skcipher_request *req) +{ + return crypto4xx_crypt(req, AES_IV_SIZE, false, false); +} + +int crypto4xx_decrypt_noiv_block(struct skcipher_request *req) { - return crypto4xx_crypt(req, 0, false); + return crypto4xx_crypt(req, 0, true, true); } -int crypto4xx_encrypt_iv(struct skcipher_request *req) +int crypto4xx_decrypt_iv_stream(struct skcipher_request *req) { - return crypto4xx_crypt(req, AES_IV_SIZE, false); + return crypto4xx_crypt(req, AES_IV_SIZE, true, false); } -int crypto4xx_decrypt_noiv(struct skcipher_request *req) +int crypto4xx_encrypt_iv_block(struct skcipher_request *req) { - return crypto4xx_crypt(req, 0, true); + return crypto4xx_crypt(req, AES_IV_SIZE, false, true); } -int crypto4xx_decrypt_iv(struct skcipher_request *req) +int crypto4xx_decrypt_iv_block(struct skcipher_request *req) { - return crypto4xx_crypt(req, AES_IV_SIZE, true); + return crypto4xx_crypt(req, AES_IV_SIZE, true, true); } /** @@ -269,8 +283,8 @@ crypto4xx_ctr_crypt(struct skcipher_request *req, bool encrypt) return ret; } - return encrypt ? crypto4xx_encrypt_iv(req) - : crypto4xx_decrypt_iv(req); + return encrypt ? crypto4xx_encrypt_iv_stream(req) + : crypto4xx_decrypt_iv_stream(req); } static int crypto4xx_sk_setup_fallback(struct crypto4xx_ctx *ctx, diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 16d911aaa508..de5e9352e920 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -182,7 +182,6 @@ static u32 crypto4xx_build_pdr(struct crypto4xx_device *dev) dev->pdr_pa); return -ENOMEM; } - memset(dev->pdr, 0, sizeof(struct ce_pd) * PPC4XX_NUM_PD); dev->shadow_sa_pool = dma_alloc_coherent(dev->core_dev->device, sizeof(union shadow_sa_buf) * PPC4XX_NUM_PD, &dev->shadow_sa_pool_pa, @@ -1210,8 +1209,8 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_IV_SIZE, .setkey = crypto4xx_setkey_aes_cbc, - .encrypt = crypto4xx_encrypt_iv, - .decrypt = crypto4xx_decrypt_iv, + .encrypt = crypto4xx_encrypt_iv_block, + .decrypt = crypto4xx_decrypt_iv_block, .init = crypto4xx_sk_init, .exit = crypto4xx_sk_exit, } }, @@ -1222,7 +1221,7 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = AES_BLOCK_SIZE, + .cra_blocksize = 1, .cra_ctxsize = sizeof(struct crypto4xx_ctx), .cra_module = THIS_MODULE, }, @@ -1230,8 +1229,8 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_IV_SIZE, .setkey = crypto4xx_setkey_aes_cfb, - .encrypt = crypto4xx_encrypt_iv, - .decrypt = crypto4xx_decrypt_iv, + .encrypt = crypto4xx_encrypt_iv_stream, + .decrypt = crypto4xx_decrypt_iv_stream, .init = crypto4xx_sk_init, .exit = crypto4xx_sk_exit, } }, @@ -1243,7 +1242,7 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { .cra_flags = CRYPTO_ALG_NEED_FALLBACK | CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = AES_BLOCK_SIZE, + .cra_blocksize = 1, .cra_ctxsize = sizeof(struct crypto4xx_ctx), .cra_module = THIS_MODULE, }, @@ -1263,7 +1262,7 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = AES_BLOCK_SIZE, + .cra_blocksize = 1, .cra_ctxsize = sizeof(struct crypto4xx_ctx), .cra_module = THIS_MODULE, }, @@ -1290,8 +1289,8 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .setkey = crypto4xx_setkey_aes_ecb, - .encrypt = crypto4xx_encrypt_noiv, - .decrypt = crypto4xx_decrypt_noiv, + .encrypt = crypto4xx_encrypt_noiv_block, + .decrypt = crypto4xx_decrypt_noiv_block, .init = crypto4xx_sk_init, .exit = crypto4xx_sk_exit, } }, @@ -1302,7 +1301,7 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = AES_BLOCK_SIZE, + .cra_blocksize = 1, .cra_ctxsize = sizeof(struct crypto4xx_ctx), .cra_module = THIS_MODULE, }, @@ -1310,8 +1309,8 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_IV_SIZE, .setkey = crypto4xx_setkey_aes_ofb, - .encrypt = crypto4xx_encrypt_iv, - .decrypt = crypto4xx_decrypt_iv, + .encrypt = crypto4xx_encrypt_iv_stream, + .decrypt = crypto4xx_decrypt_iv_stream, .init = crypto4xx_sk_init, .exit = crypto4xx_sk_exit, } }, diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h index ca1c25c40c23..6b6841359190 100644 --- a/drivers/crypto/amcc/crypto4xx_core.h +++ b/drivers/crypto/amcc/crypto4xx_core.h @@ -173,10 +173,12 @@ int crypto4xx_setkey_rfc3686(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen); int crypto4xx_encrypt_ctr(struct skcipher_request *req); int crypto4xx_decrypt_ctr(struct skcipher_request *req); -int crypto4xx_encrypt_iv(struct skcipher_request *req); -int crypto4xx_decrypt_iv(struct skcipher_request *req); -int crypto4xx_encrypt_noiv(struct skcipher_request *req); -int crypto4xx_decrypt_noiv(struct skcipher_request *req); +int crypto4xx_encrypt_iv_stream(struct skcipher_request *req); +int crypto4xx_decrypt_iv_stream(struct skcipher_request *req); +int crypto4xx_encrypt_iv_block(struct skcipher_request *req); +int crypto4xx_decrypt_iv_block(struct skcipher_request *req); +int crypto4xx_encrypt_noiv_block(struct skcipher_request *req); +int crypto4xx_decrypt_noiv_block(struct skcipher_request *req); int crypto4xx_rfc3686_encrypt(struct skcipher_request *req); int crypto4xx_rfc3686_decrypt(struct skcipher_request *req); int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm); diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c index ba00e4563ca0..ff02cc05affb 100644 --- a/drivers/crypto/atmel-ecc.c +++ b/drivers/crypto/atmel-ecc.c @@ -6,8 +6,6 @@ * Author: Tudor Ambarus <tudor.ambarus@microchip.com> */ -#include <linux/bitrev.h> -#include <linux/crc16.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> @@ -23,42 +21,11 @@ #include <crypto/internal/kpp.h> #include <crypto/ecdh.h> #include <crypto/kpp.h> -#include "atmel-ecc.h" - -/* Used for binding tfm objects to i2c clients. */ -struct atmel_ecc_driver_data { - struct list_head i2c_client_list; - spinlock_t i2c_list_lock; -} ____cacheline_aligned; +#include "atmel-i2c.h" static struct atmel_ecc_driver_data driver_data; /** - * atmel_ecc_i2c_client_priv - i2c_client private data - * @client : pointer to i2c client device - * @i2c_client_list_node: part of i2c_client_list - * @lock : lock for sending i2c commands - * @wake_token : wake token array of zeros - * @wake_token_sz : size in bytes of the wake_token - * @tfm_count : number of active crypto transformations on i2c client - * - * Reads and writes from/to the i2c client are sequential. The first byte - * transmitted to the device is treated as the byte size. Any attempt to send - * more than this number of bytes will cause the device to not ACK those bytes. - * After the host writes a single command byte to the input buffer, reads are - * prohibited until after the device completes command execution. Use a mutex - * when sending i2c commands. - */ -struct atmel_ecc_i2c_client_priv { - struct i2c_client *client; - struct list_head i2c_client_list_node; - struct mutex lock; - u8 wake_token[WAKE_TOKEN_MAX_SIZE]; - size_t wake_token_sz; - atomic_t tfm_count ____cacheline_aligned; -}; - -/** * atmel_ecdh_ctx - transformation context * @client : pointer to i2c client device * @fallback : used for unsupported curves or when user wants to use its own @@ -80,188 +47,12 @@ struct atmel_ecdh_ctx { bool do_fallback; }; -/** - * atmel_ecc_work_data - data structure representing the work - * @ctx : transformation context. - * @cbk : pointer to a callback function to be invoked upon completion of this - * request. This has the form: - * callback(struct atmel_ecc_work_data *work_data, void *areq, u8 status) - * where: - * @work_data: data structure representing the work - * @areq : optional pointer to an argument passed with the original - * request. - * @status : status returned from the i2c client device or i2c error. - * @areq: optional pointer to a user argument for use at callback time. - * @work: describes the task to be executed. - * @cmd : structure used for communicating with the device. - */ -struct atmel_ecc_work_data { - struct atmel_ecdh_ctx *ctx; - void (*cbk)(struct atmel_ecc_work_data *work_data, void *areq, - int status); - void *areq; - struct work_struct work; - struct atmel_ecc_cmd cmd; -}; - -static u16 atmel_ecc_crc16(u16 crc, const u8 *buffer, size_t len) -{ - return cpu_to_le16(bitrev16(crc16(crc, buffer, len))); -} - -/** - * atmel_ecc_checksum() - Generate 16-bit CRC as required by ATMEL ECC. - * CRC16 verification of the count, opcode, param1, param2 and data bytes. - * The checksum is saved in little-endian format in the least significant - * two bytes of the command. CRC polynomial is 0x8005 and the initial register - * value should be zero. - * - * @cmd : structure used for communicating with the device. - */ -static void atmel_ecc_checksum(struct atmel_ecc_cmd *cmd) -{ - u8 *data = &cmd->count; - size_t len = cmd->count - CRC_SIZE; - u16 *crc16 = (u16 *)(data + len); - - *crc16 = atmel_ecc_crc16(0, data, len); -} - -static void atmel_ecc_init_read_cmd(struct atmel_ecc_cmd *cmd) -{ - cmd->word_addr = COMMAND; - cmd->opcode = OPCODE_READ; - /* - * Read the word from Configuration zone that contains the lock bytes - * (UserExtra, Selector, LockValue, LockConfig). - */ - cmd->param1 = CONFIG_ZONE; - cmd->param2 = DEVICE_LOCK_ADDR; - cmd->count = READ_COUNT; - - atmel_ecc_checksum(cmd); - - cmd->msecs = MAX_EXEC_TIME_READ; - cmd->rxsize = READ_RSP_SIZE; -} - -static void atmel_ecc_init_genkey_cmd(struct atmel_ecc_cmd *cmd, u16 keyid) -{ - cmd->word_addr = COMMAND; - cmd->count = GENKEY_COUNT; - cmd->opcode = OPCODE_GENKEY; - cmd->param1 = GENKEY_MODE_PRIVATE; - /* a random private key will be generated and stored in slot keyID */ - cmd->param2 = cpu_to_le16(keyid); - - atmel_ecc_checksum(cmd); - - cmd->msecs = MAX_EXEC_TIME_GENKEY; - cmd->rxsize = GENKEY_RSP_SIZE; -} - -static int atmel_ecc_init_ecdh_cmd(struct atmel_ecc_cmd *cmd, - struct scatterlist *pubkey) -{ - size_t copied; - - cmd->word_addr = COMMAND; - cmd->count = ECDH_COUNT; - cmd->opcode = OPCODE_ECDH; - cmd->param1 = ECDH_PREFIX_MODE; - /* private key slot */ - cmd->param2 = cpu_to_le16(DATA_SLOT_2); - - /* - * The device only supports NIST P256 ECC keys. The public key size will - * always be the same. Use a macro for the key size to avoid unnecessary - * computations. - */ - copied = sg_copy_to_buffer(pubkey, - sg_nents_for_len(pubkey, - ATMEL_ECC_PUBKEY_SIZE), - cmd->data, ATMEL_ECC_PUBKEY_SIZE); - if (copied != ATMEL_ECC_PUBKEY_SIZE) - return -EINVAL; - - atmel_ecc_checksum(cmd); - - cmd->msecs = MAX_EXEC_TIME_ECDH; - cmd->rxsize = ECDH_RSP_SIZE; - - return 0; -} - -/* - * After wake and after execution of a command, there will be error, status, or - * result bytes in the device's output register that can be retrieved by the - * system. When the length of that group is four bytes, the codes returned are - * detailed in error_list. - */ -static int atmel_ecc_status(struct device *dev, u8 *status) -{ - size_t err_list_len = ARRAY_SIZE(error_list); - int i; - u8 err_id = status[1]; - - if (*status != STATUS_SIZE) - return 0; - - if (err_id == STATUS_WAKE_SUCCESSFUL || err_id == STATUS_NOERR) - return 0; - - for (i = 0; i < err_list_len; i++) - if (error_list[i].value == err_id) - break; - - /* if err_id is not in the error_list then ignore it */ - if (i != err_list_len) { - dev_err(dev, "%02x: %s:\n", err_id, error_list[i].error_text); - return err_id; - } - - return 0; -} - -static int atmel_ecc_wakeup(struct i2c_client *client) -{ - struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); - u8 status[STATUS_RSP_SIZE]; - int ret; - - /* - * The device ignores any levels or transitions on the SCL pin when the - * device is idle, asleep or during waking up. Don't check for error - * when waking up the device. - */ - i2c_master_send(client, i2c_priv->wake_token, i2c_priv->wake_token_sz); - - /* - * Wait to wake the device. Typical execution times for ecdh and genkey - * are around tens of milliseconds. Delta is chosen to 50 microseconds. - */ - usleep_range(TWHI_MIN, TWHI_MAX); - - ret = i2c_master_recv(client, status, STATUS_SIZE); - if (ret < 0) - return ret; - - return atmel_ecc_status(&client->dev, status); -} - -static int atmel_ecc_sleep(struct i2c_client *client) -{ - u8 sleep = SLEEP_TOKEN; - - return i2c_master_send(client, &sleep, 1); -} - -static void atmel_ecdh_done(struct atmel_ecc_work_data *work_data, void *areq, +static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq, int status) { struct kpp_request *req = areq; struct atmel_ecdh_ctx *ctx = work_data->ctx; - struct atmel_ecc_cmd *cmd = &work_data->cmd; + struct atmel_i2c_cmd *cmd = &work_data->cmd; size_t copied, n_sz; if (status) @@ -282,82 +73,6 @@ free_work_data: kpp_request_complete(req, status); } -/* - * atmel_ecc_send_receive() - send a command to the device and receive its - * response. - * @client: i2c client device - * @cmd : structure used to communicate with the device - * - * After the device receives a Wake token, a watchdog counter starts within the - * device. After the watchdog timer expires, the device enters sleep mode - * regardless of whether some I/O transmission or command execution is in - * progress. If a command is attempted when insufficient time remains prior to - * watchdog timer execution, the device will return the watchdog timeout error - * code without attempting to execute the command. There is no way to reset the - * counter other than to put the device into sleep or idle mode and then - * wake it up again. - */ -static int atmel_ecc_send_receive(struct i2c_client *client, - struct atmel_ecc_cmd *cmd) -{ - struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); - int ret; - - mutex_lock(&i2c_priv->lock); - - ret = atmel_ecc_wakeup(client); - if (ret) - goto err; - - /* send the command */ - ret = i2c_master_send(client, (u8 *)cmd, cmd->count + WORD_ADDR_SIZE); - if (ret < 0) - goto err; - - /* delay the appropriate amount of time for command to execute */ - msleep(cmd->msecs); - - /* receive the response */ - ret = i2c_master_recv(client, cmd->data, cmd->rxsize); - if (ret < 0) - goto err; - - /* put the device into low-power mode */ - ret = atmel_ecc_sleep(client); - if (ret < 0) - goto err; - - mutex_unlock(&i2c_priv->lock); - return atmel_ecc_status(&client->dev, cmd->data); -err: - mutex_unlock(&i2c_priv->lock); - return ret; -} - -static void atmel_ecc_work_handler(struct work_struct *work) -{ - struct atmel_ecc_work_data *work_data = - container_of(work, struct atmel_ecc_work_data, work); - struct atmel_ecc_cmd *cmd = &work_data->cmd; - struct i2c_client *client = work_data->ctx->client; - int status; - - status = atmel_ecc_send_receive(client, cmd); - work_data->cbk(work_data, work_data->areq, status); -} - -static void atmel_ecc_enqueue(struct atmel_ecc_work_data *work_data, - void (*cbk)(struct atmel_ecc_work_data *work_data, - void *areq, int status), - void *areq) -{ - work_data->cbk = (void *)cbk; - work_data->areq = areq; - - INIT_WORK(&work_data->work, atmel_ecc_work_handler); - schedule_work(&work_data->work); -} - static unsigned int atmel_ecdh_supported_curve(unsigned int curve_id) { if (curve_id == ECC_CURVE_NIST_P256) @@ -374,7 +89,7 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, unsigned int len) { struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); - struct atmel_ecc_cmd *cmd; + struct atmel_i2c_cmd *cmd; void *public_key; struct ecdh params; int ret = -ENOMEM; @@ -412,9 +127,9 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, ctx->do_fallback = false; ctx->curve_id = params.curve_id; - atmel_ecc_init_genkey_cmd(cmd, DATA_SLOT_2); + atmel_i2c_init_genkey_cmd(cmd, DATA_SLOT_2); - ret = atmel_ecc_send_receive(ctx->client, cmd); + ret = atmel_i2c_send_receive(ctx->client, cmd); if (ret) goto free_public_key; @@ -444,6 +159,9 @@ static int atmel_ecdh_generate_public_key(struct kpp_request *req) return crypto_kpp_generate_public_key(req); } + if (!ctx->public_key) + return -EINVAL; + /* might want less than we've got */ nbytes = min_t(size_t, ATMEL_ECC_PUBKEY_SIZE, req->dst_len); @@ -461,7 +179,7 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req) { struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); - struct atmel_ecc_work_data *work_data; + struct atmel_i2c_work_data *work_data; gfp_t gfp; int ret; @@ -482,12 +200,13 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req) return -ENOMEM; work_data->ctx = ctx; + work_data->client = ctx->client; - ret = atmel_ecc_init_ecdh_cmd(&work_data->cmd, req->src); + ret = atmel_i2c_init_ecdh_cmd(&work_data->cmd, req->src); if (ret) goto free_work_data; - atmel_ecc_enqueue(work_data, atmel_ecdh_done, req); + atmel_i2c_enqueue(work_data, atmel_ecdh_done, req); return -EINPROGRESS; @@ -498,7 +217,7 @@ free_work_data: static struct i2c_client *atmel_ecc_i2c_client_alloc(void) { - struct atmel_ecc_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL; + struct atmel_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL; struct i2c_client *client = ERR_PTR(-ENODEV); int min_tfm_cnt = INT_MAX; int tfm_cnt; @@ -533,7 +252,7 @@ static struct i2c_client *atmel_ecc_i2c_client_alloc(void) static void atmel_ecc_i2c_client_free(struct i2c_client *client) { - struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); + struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); atomic_dec(&i2c_priv->tfm_count); } @@ -604,96 +323,18 @@ static struct kpp_alg atmel_ecdh = { }, }; -static inline size_t atmel_ecc_wake_token_sz(u32 bus_clk_rate) -{ - u32 no_of_bits = DIV_ROUND_UP(TWLO_USEC * bus_clk_rate, USEC_PER_SEC); - - /* return the size of the wake_token in bytes */ - return DIV_ROUND_UP(no_of_bits, 8); -} - -static int device_sanity_check(struct i2c_client *client) -{ - struct atmel_ecc_cmd *cmd; - int ret; - - cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - atmel_ecc_init_read_cmd(cmd); - - ret = atmel_ecc_send_receive(client, cmd); - if (ret) - goto free_cmd; - - /* - * It is vital that the Configuration, Data and OTP zones be locked - * prior to release into the field of the system containing the device. - * Failure to lock these zones may permit modification of any secret - * keys and may lead to other security problems. - */ - if (cmd->data[LOCK_CONFIG_IDX] || cmd->data[LOCK_VALUE_IDX]) { - dev_err(&client->dev, "Configuration or Data and OTP zones are unlocked!\n"); - ret = -ENOTSUPP; - } - - /* fall through */ -free_cmd: - kfree(cmd); - return ret; -} - static int atmel_ecc_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct atmel_ecc_i2c_client_priv *i2c_priv; - struct device *dev = &client->dev; + struct atmel_i2c_client_priv *i2c_priv; int ret; - u32 bus_clk_rate; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - dev_err(dev, "I2C_FUNC_I2C not supported\n"); - return -ENODEV; - } - ret = of_property_read_u32(client->adapter->dev.of_node, - "clock-frequency", &bus_clk_rate); - if (ret) { - dev_err(dev, "of: failed to read clock-frequency property\n"); - return ret; - } - - if (bus_clk_rate > 1000000L) { - dev_err(dev, "%d exceeds maximum supported clock frequency (1MHz)\n", - bus_clk_rate); - return -EINVAL; - } - - i2c_priv = devm_kmalloc(dev, sizeof(*i2c_priv), GFP_KERNEL); - if (!i2c_priv) - return -ENOMEM; - - i2c_priv->client = client; - mutex_init(&i2c_priv->lock); - - /* - * WAKE_TOKEN_MAX_SIZE was calculated for the maximum bus_clk_rate - - * 1MHz. The previous bus_clk_rate check ensures us that wake_token_sz - * will always be smaller than or equal to WAKE_TOKEN_MAX_SIZE. - */ - i2c_priv->wake_token_sz = atmel_ecc_wake_token_sz(bus_clk_rate); - - memset(i2c_priv->wake_token, 0, sizeof(i2c_priv->wake_token)); - - atomic_set(&i2c_priv->tfm_count, 0); - - i2c_set_clientdata(client, i2c_priv); - - ret = device_sanity_check(client); + ret = atmel_i2c_probe(client, id); if (ret) return ret; + i2c_priv = i2c_get_clientdata(client); + spin_lock(&driver_data.i2c_list_lock); list_add_tail(&i2c_priv->i2c_client_list_node, &driver_data.i2c_client_list); @@ -705,10 +346,10 @@ static int atmel_ecc_probe(struct i2c_client *client, list_del(&i2c_priv->i2c_client_list_node); spin_unlock(&driver_data.i2c_list_lock); - dev_err(dev, "%s alg registration failed\n", + dev_err(&client->dev, "%s alg registration failed\n", atmel_ecdh.base.cra_driver_name); } else { - dev_info(dev, "atmel ecc algorithms registered in /proc/crypto\n"); + dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n"); } return ret; @@ -716,7 +357,7 @@ static int atmel_ecc_probe(struct i2c_client *client, static int atmel_ecc_remove(struct i2c_client *client) { - struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); + struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); /* Return EBUSY if i2c client already allocated. */ if (atomic_read(&i2c_priv->tfm_count)) { diff --git a/drivers/crypto/atmel-ecc.h b/drivers/crypto/atmel-ecc.h deleted file mode 100644 index 643a3b947338..000000000000 --- a/drivers/crypto/atmel-ecc.h +++ /dev/null @@ -1,116 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2017, Microchip Technology Inc. - * Author: Tudor Ambarus <tudor.ambarus@microchip.com> - */ - -#ifndef __ATMEL_ECC_H__ -#define __ATMEL_ECC_H__ - -#define ATMEL_ECC_PRIORITY 300 - -#define COMMAND 0x03 /* packet function */ -#define SLEEP_TOKEN 0x01 -#define WAKE_TOKEN_MAX_SIZE 8 - -/* Definitions of Data and Command sizes */ -#define WORD_ADDR_SIZE 1 -#define COUNT_SIZE 1 -#define CRC_SIZE 2 -#define CMD_OVERHEAD_SIZE (COUNT_SIZE + CRC_SIZE) - -/* size in bytes of the n prime */ -#define ATMEL_ECC_NIST_P256_N_SIZE 32 -#define ATMEL_ECC_PUBKEY_SIZE (2 * ATMEL_ECC_NIST_P256_N_SIZE) - -#define STATUS_RSP_SIZE 4 -#define ECDH_RSP_SIZE (32 + CMD_OVERHEAD_SIZE) -#define GENKEY_RSP_SIZE (ATMEL_ECC_PUBKEY_SIZE + \ - CMD_OVERHEAD_SIZE) -#define READ_RSP_SIZE (4 + CMD_OVERHEAD_SIZE) -#define MAX_RSP_SIZE GENKEY_RSP_SIZE - -/** - * atmel_ecc_cmd - structure used for communicating with the device. - * @word_addr: indicates the function of the packet sent to the device. This - * byte should have a value of COMMAND for normal operation. - * @count : number of bytes to be transferred to (or from) the device. - * @opcode : the command code. - * @param1 : the first parameter; always present. - * @param2 : the second parameter; always present. - * @data : optional remaining input data. Includes a 2-byte CRC. - * @rxsize : size of the data received from i2c client. - * @msecs : command execution time in milliseconds - */ -struct atmel_ecc_cmd { - u8 word_addr; - u8 count; - u8 opcode; - u8 param1; - u16 param2; - u8 data[MAX_RSP_SIZE]; - u8 msecs; - u16 rxsize; -} __packed; - -/* Status/Error codes */ -#define STATUS_SIZE 0x04 -#define STATUS_NOERR 0x00 -#define STATUS_WAKE_SUCCESSFUL 0x11 - -static const struct { - u8 value; - const char *error_text; -} error_list[] = { - { 0x01, "CheckMac or Verify miscompare" }, - { 0x03, "Parse Error" }, - { 0x05, "ECC Fault" }, - { 0x0F, "Execution Error" }, - { 0xEE, "Watchdog about to expire" }, - { 0xFF, "CRC or other communication error" }, -}; - -/* Definitions for eeprom organization */ -#define CONFIG_ZONE 0 - -/* Definitions for Indexes common to all commands */ -#define RSP_DATA_IDX 1 /* buffer index of data in response */ -#define DATA_SLOT_2 2 /* used for ECDH private key */ - -/* Definitions for the device lock state */ -#define DEVICE_LOCK_ADDR 0x15 -#define LOCK_VALUE_IDX (RSP_DATA_IDX + 2) -#define LOCK_CONFIG_IDX (RSP_DATA_IDX + 3) - -/* - * Wake High delay to data communication (microseconds). SDA should be stable - * high for this entire duration. - */ -#define TWHI_MIN 1500 -#define TWHI_MAX 1550 - -/* Wake Low duration */ -#define TWLO_USEC 60 - -/* Command execution time (milliseconds) */ -#define MAX_EXEC_TIME_ECDH 58 -#define MAX_EXEC_TIME_GENKEY 115 -#define MAX_EXEC_TIME_READ 1 - -/* Command opcode */ -#define OPCODE_ECDH 0x43 -#define OPCODE_GENKEY 0x40 -#define OPCODE_READ 0x02 - -/* Definitions for the READ Command */ -#define READ_COUNT 7 - -/* Definitions for the GenKey Command */ -#define GENKEY_COUNT 7 -#define GENKEY_MODE_PRIVATE 0x04 - -/* Definitions for the ECDH Command */ -#define ECDH_COUNT 71 -#define ECDH_PREFIX_MODE 0x00 - -#endif /* __ATMEL_ECC_H__ */ diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c new file mode 100644 index 000000000000..dc876fab2882 --- /dev/null +++ b/drivers/crypto/atmel-i2c.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip / Atmel ECC (I2C) driver. + * + * Copyright (c) 2017, Microchip Technology Inc. + * Author: Tudor Ambarus <tudor.ambarus@microchip.com> + */ + +#include <linux/bitrev.h> +#include <linux/crc16.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/scatterlist.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include "atmel-i2c.h" + +/** + * atmel_i2c_checksum() - Generate 16-bit CRC as required by ATMEL ECC. + * CRC16 verification of the count, opcode, param1, param2 and data bytes. + * The checksum is saved in little-endian format in the least significant + * two bytes of the command. CRC polynomial is 0x8005 and the initial register + * value should be zero. + * + * @cmd : structure used for communicating with the device. + */ +static void atmel_i2c_checksum(struct atmel_i2c_cmd *cmd) +{ + u8 *data = &cmd->count; + size_t len = cmd->count - CRC_SIZE; + __le16 *__crc16 = (__le16 *)(data + len); + + *__crc16 = cpu_to_le16(bitrev16(crc16(0, data, len))); +} + +void atmel_i2c_init_read_cmd(struct atmel_i2c_cmd *cmd) +{ + cmd->word_addr = COMMAND; + cmd->opcode = OPCODE_READ; + /* + * Read the word from Configuration zone that contains the lock bytes + * (UserExtra, Selector, LockValue, LockConfig). + */ + cmd->param1 = CONFIG_ZONE; + cmd->param2 = cpu_to_le16(DEVICE_LOCK_ADDR); + cmd->count = READ_COUNT; + + atmel_i2c_checksum(cmd); + + cmd->msecs = MAX_EXEC_TIME_READ; + cmd->rxsize = READ_RSP_SIZE; +} +EXPORT_SYMBOL(atmel_i2c_init_read_cmd); + +void atmel_i2c_init_random_cmd(struct atmel_i2c_cmd *cmd) +{ + cmd->word_addr = COMMAND; + cmd->opcode = OPCODE_RANDOM; + cmd->param1 = 0; + cmd->param2 = 0; + cmd->count = RANDOM_COUNT; + + atmel_i2c_checksum(cmd); + + cmd->msecs = MAX_EXEC_TIME_RANDOM; + cmd->rxsize = RANDOM_RSP_SIZE; +} +EXPORT_SYMBOL(atmel_i2c_init_random_cmd); + +void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid) +{ + cmd->word_addr = COMMAND; + cmd->count = GENKEY_COUNT; + cmd->opcode = OPCODE_GENKEY; + cmd->param1 = GENKEY_MODE_PRIVATE; + /* a random private key will be generated and stored in slot keyID */ + cmd->param2 = cpu_to_le16(keyid); + + atmel_i2c_checksum(cmd); + + cmd->msecs = MAX_EXEC_TIME_GENKEY; + cmd->rxsize = GENKEY_RSP_SIZE; +} +EXPORT_SYMBOL(atmel_i2c_init_genkey_cmd); + +int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd, + struct scatterlist *pubkey) +{ + size_t copied; + + cmd->word_addr = COMMAND; + cmd->count = ECDH_COUNT; + cmd->opcode = OPCODE_ECDH; + cmd->param1 = ECDH_PREFIX_MODE; + /* private key slot */ + cmd->param2 = cpu_to_le16(DATA_SLOT_2); + + /* + * The device only supports NIST P256 ECC keys. The public key size will + * always be the same. Use a macro for the key size to avoid unnecessary + * computations. + */ + copied = sg_copy_to_buffer(pubkey, + sg_nents_for_len(pubkey, + ATMEL_ECC_PUBKEY_SIZE), + cmd->data, ATMEL_ECC_PUBKEY_SIZE); + if (copied != ATMEL_ECC_PUBKEY_SIZE) + return -EINVAL; + + atmel_i2c_checksum(cmd); + + cmd->msecs = MAX_EXEC_TIME_ECDH; + cmd->rxsize = ECDH_RSP_SIZE; + + return 0; +} +EXPORT_SYMBOL(atmel_i2c_init_ecdh_cmd); + +/* + * After wake and after execution of a command, there will be error, status, or + * result bytes in the device's output register that can be retrieved by the + * system. When the length of that group is four bytes, the codes returned are + * detailed in error_list. + */ +static int atmel_i2c_status(struct device *dev, u8 *status) +{ + size_t err_list_len = ARRAY_SIZE(error_list); + int i; + u8 err_id = status[1]; + + if (*status != STATUS_SIZE) + return 0; + + if (err_id == STATUS_WAKE_SUCCESSFUL || err_id == STATUS_NOERR) + return 0; + + for (i = 0; i < err_list_len; i++) + if (error_list[i].value == err_id) + break; + + /* if err_id is not in the error_list then ignore it */ + if (i != err_list_len) { + dev_err(dev, "%02x: %s:\n", err_id, error_list[i].error_text); + return err_id; + } + + return 0; +} + +static int atmel_i2c_wakeup(struct i2c_client *client) +{ + struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); + u8 status[STATUS_RSP_SIZE]; + int ret; + + /* + * The device ignores any levels or transitions on the SCL pin when the + * device is idle, asleep or during waking up. Don't check for error + * when waking up the device. + */ + i2c_master_send(client, i2c_priv->wake_token, i2c_priv->wake_token_sz); + + /* + * Wait to wake the device. Typical execution times for ecdh and genkey + * are around tens of milliseconds. Delta is chosen to 50 microseconds. + */ + usleep_range(TWHI_MIN, TWHI_MAX); + + ret = i2c_master_recv(client, status, STATUS_SIZE); + if (ret < 0) + return ret; + + return atmel_i2c_status(&client->dev, status); +} + +static int atmel_i2c_sleep(struct i2c_client *client) +{ + u8 sleep = SLEEP_TOKEN; + + return i2c_master_send(client, &sleep, 1); +} + +/* + * atmel_i2c_send_receive() - send a command to the device and receive its + * response. + * @client: i2c client device + * @cmd : structure used to communicate with the device + * + * After the device receives a Wake token, a watchdog counter starts within the + * device. After the watchdog timer expires, the device enters sleep mode + * regardless of whether some I/O transmission or command execution is in + * progress. If a command is attempted when insufficient time remains prior to + * watchdog timer execution, the device will return the watchdog timeout error + * code without attempting to execute the command. There is no way to reset the + * counter other than to put the device into sleep or idle mode and then + * wake it up again. + */ +int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd) +{ + struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); + int ret; + + mutex_lock(&i2c_priv->lock); + + ret = atmel_i2c_wakeup(client); + if (ret) + goto err; + + /* send the command */ + ret = i2c_master_send(client, (u8 *)cmd, cmd->count + WORD_ADDR_SIZE); + if (ret < 0) + goto err; + + /* delay the appropriate amount of time for command to execute */ + msleep(cmd->msecs); + + /* receive the response */ + ret = i2c_master_recv(client, cmd->data, cmd->rxsize); + if (ret < 0) + goto err; + + /* put the device into low-power mode */ + ret = atmel_i2c_sleep(client); + if (ret < 0) + goto err; + + mutex_unlock(&i2c_priv->lock); + return atmel_i2c_status(&client->dev, cmd->data); +err: + mutex_unlock(&i2c_priv->lock); + return ret; +} +EXPORT_SYMBOL(atmel_i2c_send_receive); + +static void atmel_i2c_work_handler(struct work_struct *work) +{ + struct atmel_i2c_work_data *work_data = + container_of(work, struct atmel_i2c_work_data, work); + struct atmel_i2c_cmd *cmd = &work_data->cmd; + struct i2c_client *client = work_data->client; + int status; + + status = atmel_i2c_send_receive(client, cmd); + work_data->cbk(work_data, work_data->areq, status); +} + +void atmel_i2c_enqueue(struct atmel_i2c_work_data *work_data, + void (*cbk)(struct atmel_i2c_work_data *work_data, + void *areq, int status), + void *areq) +{ + work_data->cbk = (void *)cbk; + work_data->areq = areq; + + INIT_WORK(&work_data->work, atmel_i2c_work_handler); + schedule_work(&work_data->work); +} +EXPORT_SYMBOL(atmel_i2c_enqueue); + +static inline size_t atmel_i2c_wake_token_sz(u32 bus_clk_rate) +{ + u32 no_of_bits = DIV_ROUND_UP(TWLO_USEC * bus_clk_rate, USEC_PER_SEC); + + /* return the size of the wake_token in bytes */ + return DIV_ROUND_UP(no_of_bits, 8); +} + +static int device_sanity_check(struct i2c_client *client) +{ + struct atmel_i2c_cmd *cmd; + int ret; + + cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + atmel_i2c_init_read_cmd(cmd); + + ret = atmel_i2c_send_receive(client, cmd); + if (ret) + goto free_cmd; + + /* + * It is vital that the Configuration, Data and OTP zones be locked + * prior to release into the field of the system containing the device. + * Failure to lock these zones may permit modification of any secret + * keys and may lead to other security problems. + */ + if (cmd->data[LOCK_CONFIG_IDX] || cmd->data[LOCK_VALUE_IDX]) { + dev_err(&client->dev, "Configuration or Data and OTP zones are unlocked!\n"); + ret = -ENOTSUPP; + } + + /* fall through */ +free_cmd: + kfree(cmd); + return ret; +} + +int atmel_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct atmel_i2c_client_priv *i2c_priv; + struct device *dev = &client->dev; + int ret; + u32 bus_clk_rate; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(dev, "I2C_FUNC_I2C not supported\n"); + return -ENODEV; + } + + bus_clk_rate = i2c_acpi_find_bus_speed(&client->adapter->dev); + if (!bus_clk_rate) { + ret = device_property_read_u32(&client->adapter->dev, + "clock-frequency", &bus_clk_rate); + if (ret) { + dev_err(dev, "failed to read clock-frequency property\n"); + return ret; + } + } + + if (bus_clk_rate > 1000000L) { + dev_err(dev, "%d exceeds maximum supported clock frequency (1MHz)\n", + bus_clk_rate); + return -EINVAL; + } + + i2c_priv = devm_kmalloc(dev, sizeof(*i2c_priv), GFP_KERNEL); + if (!i2c_priv) + return -ENOMEM; + + i2c_priv->client = client; + mutex_init(&i2c_priv->lock); + + /* + * WAKE_TOKEN_MAX_SIZE was calculated for the maximum bus_clk_rate - + * 1MHz. The previous bus_clk_rate check ensures us that wake_token_sz + * will always be smaller than or equal to WAKE_TOKEN_MAX_SIZE. + */ + i2c_priv->wake_token_sz = atmel_i2c_wake_token_sz(bus_clk_rate); + + memset(i2c_priv->wake_token, 0, sizeof(i2c_priv->wake_token)); + + atomic_set(&i2c_priv->tfm_count, 0); + + i2c_set_clientdata(client, i2c_priv); + + ret = device_sanity_check(client); + if (ret) + return ret; + + return 0; +} +EXPORT_SYMBOL(atmel_i2c_probe); + +MODULE_AUTHOR("Tudor Ambarus <tudor.ambarus@microchip.com>"); +MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h new file mode 100644 index 000000000000..21860b99c3e3 --- /dev/null +++ b/drivers/crypto/atmel-i2c.h @@ -0,0 +1,197 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, Microchip Technology Inc. + * Author: Tudor Ambarus <tudor.ambarus@microchip.com> + */ + +#ifndef __ATMEL_I2C_H__ +#define __ATMEL_I2C_H__ + +#include <linux/hw_random.h> +#include <linux/types.h> + +#define ATMEL_ECC_PRIORITY 300 + +#define COMMAND 0x03 /* packet function */ +#define SLEEP_TOKEN 0x01 +#define WAKE_TOKEN_MAX_SIZE 8 + +/* Definitions of Data and Command sizes */ +#define WORD_ADDR_SIZE 1 +#define COUNT_SIZE 1 +#define CRC_SIZE 2 +#define CMD_OVERHEAD_SIZE (COUNT_SIZE + CRC_SIZE) + +/* size in bytes of the n prime */ +#define ATMEL_ECC_NIST_P256_N_SIZE 32 +#define ATMEL_ECC_PUBKEY_SIZE (2 * ATMEL_ECC_NIST_P256_N_SIZE) + +#define STATUS_RSP_SIZE 4 +#define ECDH_RSP_SIZE (32 + CMD_OVERHEAD_SIZE) +#define GENKEY_RSP_SIZE (ATMEL_ECC_PUBKEY_SIZE + \ + CMD_OVERHEAD_SIZE) +#define READ_RSP_SIZE (4 + CMD_OVERHEAD_SIZE) +#define RANDOM_RSP_SIZE (32 + CMD_OVERHEAD_SIZE) +#define MAX_RSP_SIZE GENKEY_RSP_SIZE + +/** + * atmel_i2c_cmd - structure used for communicating with the device. + * @word_addr: indicates the function of the packet sent to the device. This + * byte should have a value of COMMAND for normal operation. + * @count : number of bytes to be transferred to (or from) the device. + * @opcode : the command code. + * @param1 : the first parameter; always present. + * @param2 : the second parameter; always present. + * @data : optional remaining input data. Includes a 2-byte CRC. + * @rxsize : size of the data received from i2c client. + * @msecs : command execution time in milliseconds + */ +struct atmel_i2c_cmd { + u8 word_addr; + u8 count; + u8 opcode; + u8 param1; + __le16 param2; + u8 data[MAX_RSP_SIZE]; + u8 msecs; + u16 rxsize; +} __packed; + +/* Status/Error codes */ +#define STATUS_SIZE 0x04 +#define STATUS_NOERR 0x00 +#define STATUS_WAKE_SUCCESSFUL 0x11 + +static const struct { + u8 value; + const char *error_text; +} error_list[] = { + { 0x01, "CheckMac or Verify miscompare" }, + { 0x03, "Parse Error" }, + { 0x05, "ECC Fault" }, + { 0x0F, "Execution Error" }, + { 0xEE, "Watchdog about to expire" }, + { 0xFF, "CRC or other communication error" }, +}; + +/* Definitions for eeprom organization */ +#define CONFIG_ZONE 0 + +/* Definitions for Indexes common to all commands */ +#define RSP_DATA_IDX 1 /* buffer index of data in response */ +#define DATA_SLOT_2 2 /* used for ECDH private key */ + +/* Definitions for the device lock state */ +#define DEVICE_LOCK_ADDR 0x15 +#define LOCK_VALUE_IDX (RSP_DATA_IDX + 2) +#define LOCK_CONFIG_IDX (RSP_DATA_IDX + 3) + +/* + * Wake High delay to data communication (microseconds). SDA should be stable + * high for this entire duration. + */ +#define TWHI_MIN 1500 +#define TWHI_MAX 1550 + +/* Wake Low duration */ +#define TWLO_USEC 60 + +/* Command execution time (milliseconds) */ +#define MAX_EXEC_TIME_ECDH 58 +#define MAX_EXEC_TIME_GENKEY 115 +#define MAX_EXEC_TIME_READ 1 +#define MAX_EXEC_TIME_RANDOM 50 + +/* Command opcode */ +#define OPCODE_ECDH 0x43 +#define OPCODE_GENKEY 0x40 +#define OPCODE_READ 0x02 +#define OPCODE_RANDOM 0x1b + +/* Definitions for the READ Command */ +#define READ_COUNT 7 + +/* Definitions for the RANDOM Command */ +#define RANDOM_COUNT 7 + +/* Definitions for the GenKey Command */ +#define GENKEY_COUNT 7 +#define GENKEY_MODE_PRIVATE 0x04 + +/* Definitions for the ECDH Command */ +#define ECDH_COUNT 71 +#define ECDH_PREFIX_MODE 0x00 + +/* Used for binding tfm objects to i2c clients. */ +struct atmel_ecc_driver_data { + struct list_head i2c_client_list; + spinlock_t i2c_list_lock; +} ____cacheline_aligned; + +/** + * atmel_i2c_client_priv - i2c_client private data + * @client : pointer to i2c client device + * @i2c_client_list_node: part of i2c_client_list + * @lock : lock for sending i2c commands + * @wake_token : wake token array of zeros + * @wake_token_sz : size in bytes of the wake_token + * @tfm_count : number of active crypto transformations on i2c client + * + * Reads and writes from/to the i2c client are sequential. The first byte + * transmitted to the device is treated as the byte size. Any attempt to send + * more than this number of bytes will cause the device to not ACK those bytes. + * After the host writes a single command byte to the input buffer, reads are + * prohibited until after the device completes command execution. Use a mutex + * when sending i2c commands. + */ +struct atmel_i2c_client_priv { + struct i2c_client *client; + struct list_head i2c_client_list_node; + struct mutex lock; + u8 wake_token[WAKE_TOKEN_MAX_SIZE]; + size_t wake_token_sz; + atomic_t tfm_count ____cacheline_aligned; + struct hwrng hwrng; +}; + +/** + * atmel_i2c_work_data - data structure representing the work + * @ctx : transformation context. + * @cbk : pointer to a callback function to be invoked upon completion of this + * request. This has the form: + * callback(struct atmel_i2c_work_data *work_data, void *areq, u8 status) + * where: + * @work_data: data structure representing the work + * @areq : optional pointer to an argument passed with the original + * request. + * @status : status returned from the i2c client device or i2c error. + * @areq: optional pointer to a user argument for use at callback time. + * @work: describes the task to be executed. + * @cmd : structure used for communicating with the device. + */ +struct atmel_i2c_work_data { + void *ctx; + struct i2c_client *client; + void (*cbk)(struct atmel_i2c_work_data *work_data, void *areq, + int status); + void *areq; + struct work_struct work; + struct atmel_i2c_cmd cmd; +}; + +int atmel_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); + +void atmel_i2c_enqueue(struct atmel_i2c_work_data *work_data, + void (*cbk)(struct atmel_i2c_work_data *work_data, + void *areq, int status), + void *areq); + +int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd); + +void atmel_i2c_init_read_cmd(struct atmel_i2c_cmd *cmd); +void atmel_i2c_init_random_cmd(struct atmel_i2c_cmd *cmd); +void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid); +int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd, + struct scatterlist *pubkey); + +#endif /* __ATMEL_I2C_H__ */ diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c new file mode 100644 index 000000000000..ea0d2068ea4f --- /dev/null +++ b/drivers/crypto/atmel-sha204a.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip / Atmel SHA204A (I2C) driver. + * + * Copyright (c) 2019 Linaro, Ltd. <ard.biesheuvel@linaro.org> + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/scatterlist.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include "atmel-i2c.h" + +static void atmel_sha204a_rng_done(struct atmel_i2c_work_data *work_data, + void *areq, int status) +{ + struct atmel_i2c_client_priv *i2c_priv = work_data->ctx; + struct hwrng *rng = areq; + + if (status) + dev_warn_ratelimited(&i2c_priv->client->dev, + "i2c transaction failed (%d)\n", + status); + + rng->priv = (unsigned long)work_data; + atomic_dec(&i2c_priv->tfm_count); +} + +static int atmel_sha204a_rng_read_nonblocking(struct hwrng *rng, void *data, + size_t max) +{ + struct atmel_i2c_client_priv *i2c_priv; + struct atmel_i2c_work_data *work_data; + + i2c_priv = container_of(rng, struct atmel_i2c_client_priv, hwrng); + + /* keep maximum 1 asynchronous read in flight at any time */ + if (!atomic_add_unless(&i2c_priv->tfm_count, 1, 1)) + return 0; + + if (rng->priv) { + work_data = (struct atmel_i2c_work_data *)rng->priv; + max = min(sizeof(work_data->cmd.data), max); + memcpy(data, &work_data->cmd.data, max); + rng->priv = 0; + } else { + work_data = kmalloc(sizeof(*work_data), GFP_ATOMIC); + if (!work_data) + return -ENOMEM; + + work_data->ctx = i2c_priv; + work_data->client = i2c_priv->client; + + max = 0; + } + + atmel_i2c_init_random_cmd(&work_data->cmd); + atmel_i2c_enqueue(work_data, atmel_sha204a_rng_done, rng); + + return max; +} + +static int atmel_sha204a_rng_read(struct hwrng *rng, void *data, size_t max, + bool wait) +{ + struct atmel_i2c_client_priv *i2c_priv; + struct atmel_i2c_cmd cmd; + int ret; + + if (!wait) + return atmel_sha204a_rng_read_nonblocking(rng, data, max); + + i2c_priv = container_of(rng, struct atmel_i2c_client_priv, hwrng); + + atmel_i2c_init_random_cmd(&cmd); + + ret = atmel_i2c_send_receive(i2c_priv->client, &cmd); + if (ret) + return ret; + + max = min(sizeof(cmd.data), max); + memcpy(data, cmd.data, max); + + return max; +} + +static int atmel_sha204a_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct atmel_i2c_client_priv *i2c_priv; + int ret; + + ret = atmel_i2c_probe(client, id); + if (ret) + return ret; + + i2c_priv = i2c_get_clientdata(client); + + memset(&i2c_priv->hwrng, 0, sizeof(i2c_priv->hwrng)); + + i2c_priv->hwrng.name = dev_name(&client->dev); + i2c_priv->hwrng.read = atmel_sha204a_rng_read; + i2c_priv->hwrng.quality = 1024; + + ret = hwrng_register(&i2c_priv->hwrng); + if (ret) + dev_warn(&client->dev, "failed to register RNG (%d)\n", ret); + + return ret; +} + +static int atmel_sha204a_remove(struct i2c_client *client) +{ + struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); + + if (atomic_read(&i2c_priv->tfm_count)) { + dev_err(&client->dev, "Device is busy\n"); + return -EBUSY; + } + + if (i2c_priv->hwrng.priv) + kfree((void *)i2c_priv->hwrng.priv); + hwrng_unregister(&i2c_priv->hwrng); + + return 0; +} + +static const struct of_device_id atmel_sha204a_dt_ids[] = { + { .compatible = "atmel,atsha204a", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids); + +static const struct i2c_device_id atmel_sha204a_id[] = { + { "atsha204a", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, atmel_sha204a_id); + +static struct i2c_driver atmel_sha204a_driver = { + .probe = atmel_sha204a_probe, + .remove = atmel_sha204a_remove, + .id_table = atmel_sha204a_id, + + .driver.name = "atmel-sha204a", + .driver.of_match_table = of_match_ptr(atmel_sha204a_dt_ids), +}; + +static int __init atmel_sha204a_init(void) +{ + return i2c_add_driver(&atmel_sha204a_driver); +} + +static void __exit atmel_sha204a_exit(void) +{ + flush_scheduled_work(); + i2c_del_driver(&atmel_sha204a_driver); +} + +module_init(atmel_sha204a_init); +module_exit(atmel_sha204a_exit); + +MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c index 25f8d3913ceb..869602fcfd96 100644 --- a/drivers/crypto/bcm/cipher.c +++ b/drivers/crypto/bcm/cipher.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ #include <linux/err.h> @@ -96,7 +85,7 @@ MODULE_PARM_DESC(aead_pri, "Priority for AEAD algos"); * 0x70 - ring 2 * 0x78 - ring 3 */ -char BCMHEADER[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28 }; +static char BCMHEADER[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28 }; /* * Some SPU hw does not use BCM header on SPU messages. So BCM_HDR_LEN * is set dynamically after reading SPU type from device tree. @@ -2094,7 +2083,7 @@ static int __ahash_init(struct ahash_request *req) * Return: true if incremental hashing is not supported * false otherwise */ -bool spu_no_incr_hash(struct iproc_ctx_s *ctx) +static bool spu_no_incr_hash(struct iproc_ctx_s *ctx) { struct spu_hw *spu = &iproc_priv.spu; @@ -4820,7 +4809,7 @@ static int spu_dt_read(struct platform_device *pdev) return 0; } -int bcm_spu_probe(struct platform_device *pdev) +static int bcm_spu_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct spu_hw *spu = &iproc_priv.spu; @@ -4864,7 +4853,7 @@ failure: return err; } -int bcm_spu_remove(struct platform_device *pdev) +static int bcm_spu_remove(struct platform_device *pdev) { int i; struct device *dev = &pdev->dev; diff --git a/drivers/crypto/bcm/cipher.h b/drivers/crypto/bcm/cipher.h index f6da49758954..766452b24d0a 100644 --- a/drivers/crypto/bcm/cipher.h +++ b/drivers/crypto/bcm/cipher.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ #ifndef _CIPHER_H diff --git a/drivers/crypto/bcm/spu.c b/drivers/crypto/bcm/spu.c index 2baf6d7f2c1d..e7562e9bf396 100644 --- a/drivers/crypto/bcm/spu.c +++ b/drivers/crypto/bcm/spu.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ #include <linux/kernel.h> diff --git a/drivers/crypto/bcm/spu.h b/drivers/crypto/bcm/spu.h index aa6fc38db263..b247bc5b9354 100644 --- a/drivers/crypto/bcm/spu.h +++ b/drivers/crypto/bcm/spu.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ /* diff --git a/drivers/crypto/bcm/spu2.c b/drivers/crypto/bcm/spu2.c index bf7ac621c591..2add51024575 100644 --- a/drivers/crypto/bcm/spu2.c +++ b/drivers/crypto/bcm/spu2.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ /* @@ -49,21 +38,21 @@ enum spu2_proto_sel { SPU2_DTLS_AEAD = 10 }; -char *spu2_cipher_type_names[] = { "None", "AES128", "AES192", "AES256", +static char *spu2_cipher_type_names[] = { "None", "AES128", "AES192", "AES256", "DES", "3DES" }; -char *spu2_cipher_mode_names[] = { "ECB", "CBC", "CTR", "CFB", "OFB", "XTS", - "CCM", "GCM" +static char *spu2_cipher_mode_names[] = { "ECB", "CBC", "CTR", "CFB", "OFB", + "XTS", "CCM", "GCM" }; -char *spu2_hash_type_names[] = { "None", "AES128", "AES192", "AES256", +static char *spu2_hash_type_names[] = { "None", "AES128", "AES192", "AES256", "Reserved", "Reserved", "MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512", "SHA512/224", "SHA512/256", "SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512" }; -char *spu2_hash_mode_names[] = { "CMAC", "CBC-MAC", "XCBC-MAC", "HMAC", +static char *spu2_hash_mode_names[] = { "CMAC", "CBC-MAC", "XCBC-MAC", "HMAC", "Rabin", "CCM", "GCM", "Reserved" }; diff --git a/drivers/crypto/bcm/spu2.h b/drivers/crypto/bcm/spu2.h index ab1f59934828..03af6c38df7f 100644 --- a/drivers/crypto/bcm/spu2.h +++ b/drivers/crypto/bcm/spu2.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ /* diff --git a/drivers/crypto/bcm/spum.h b/drivers/crypto/bcm/spum.h index d0a5b5828638..6116ad1dd26e 100644 --- a/drivers/crypto/bcm/spum.h +++ b/drivers/crypto/bcm/spum.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ /* diff --git a/drivers/crypto/bcm/util.c b/drivers/crypto/bcm/util.c index 91ec56399d84..cd7504101acd 100644 --- a/drivers/crypto/bcm/util.c +++ b/drivers/crypto/bcm/util.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ #include <linux/debugfs.h> diff --git a/drivers/crypto/bcm/util.h b/drivers/crypto/bcm/util.h index 15c60356518a..a89b2b9c1f52 100644 --- a/drivers/crypto/bcm/util.h +++ b/drivers/crypto/bcm/util.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ #ifndef _UTIL_H diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index 577c9844b322..3720ddabb507 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -2,6 +2,12 @@ config CRYPTO_DEV_FSL_CAAM_COMMON tristate +config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC + tristate + +config CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC + tristate + config CRYPTO_DEV_FSL_CAAM tristate "Freescale CAAM-Multicore platform driver backend" depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE @@ -25,7 +31,7 @@ config CRYPTO_DEV_FSL_CAAM_DEBUG Selecting this will enable printing of various debug information in the CAAM driver. -config CRYPTO_DEV_FSL_CAAM_JR +menuconfig CRYPTO_DEV_FSL_CAAM_JR tristate "Freescale CAAM Job Ring driver backend" default y help @@ -86,8 +92,9 @@ config CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD threshold. Range is 1-65535. config CRYPTO_DEV_FSL_CAAM_CRYPTO_API - tristate "Register algorithm implementations with the Crypto API" + bool "Register algorithm implementations with the Crypto API" default y + select CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC select CRYPTO_AEAD select CRYPTO_AUTHENC select CRYPTO_BLKCIPHER @@ -97,13 +104,11 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API scatterlist crypto API (such as the linux native IPSec stack) to the SEC4 via job ring. - To compile this as a module, choose M here: the module - will be called caamalg. - config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI - tristate "Queue Interface as Crypto API backend" + bool "Queue Interface as Crypto API backend" depends on FSL_DPAA && NET default y + select CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC select CRYPTO_AUTHENC select CRYPTO_BLKCIPHER help @@ -114,33 +119,26 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI assigned to the kernel should also be more than the number of job rings. - To compile this as a module, choose M here: the module - will be called caamalg_qi. - config CRYPTO_DEV_FSL_CAAM_AHASH_API - tristate "Register hash algorithm implementations with Crypto API" + bool "Register hash algorithm implementations with Crypto API" default y + select CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC select CRYPTO_HASH help Selecting this will offload ahash for users of the scatterlist crypto API to the SEC4 via job ring. - To compile this as a module, choose M here: the module - will be called caamhash. - config CRYPTO_DEV_FSL_CAAM_PKC_API - tristate "Register public key cryptography implementations with Crypto API" + bool "Register public key cryptography implementations with Crypto API" default y select CRYPTO_RSA help Selecting this will allow SEC Public key support for RSA. Supported cryptographic primitives: encryption, decryption, signature and verification. - To compile this as a module, choose M here: the module - will be called caam_pkc. config CRYPTO_DEV_FSL_CAAM_RNG_API - tristate "Register caam device for hwrng API" + bool "Register caam device for hwrng API" default y select CRYPTO_RNG select HW_RANDOM @@ -148,9 +146,6 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API Selecting this will register the SEC4 hardware rng to the hw_random API for suppying the kernel entropy pool. - To compile this as a module, choose M here: the module - will be called caamrng. - endif # CRYPTO_DEV_FSL_CAAM_JR endif # CRYPTO_DEV_FSL_CAAM @@ -160,6 +155,8 @@ config CRYPTO_DEV_FSL_DPAA2_CAAM depends on FSL_MC_DPIO depends on NETDEVICES select CRYPTO_DEV_FSL_CAAM_COMMON + select CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC + select CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC select CRYPTO_BLKCIPHER select CRYPTO_AUTHENC select CRYPTO_AEAD @@ -171,12 +168,3 @@ config CRYPTO_DEV_FSL_DPAA2_CAAM To compile this as a module, choose M here: the module will be called dpaa2_caam. - -config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC - def_tristate (CRYPTO_DEV_FSL_CAAM_CRYPTO_API || \ - CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI || \ - CRYPTO_DEV_FSL_DPAA2_CAAM) - -config CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC - def_tristate (CRYPTO_DEV_FSL_CAAM_AHASH_API || \ - CRYPTO_DEV_FSL_DPAA2_CAAM) diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile index 7bbfd06a11ff..9ab4e81ea21e 100644 --- a/drivers/crypto/caam/Makefile +++ b/drivers/crypto/caam/Makefile @@ -11,20 +11,20 @@ ccflags-y += -DVERSION=\"\" obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON) += error.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o -obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o -obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC) += caamalg_desc.o -obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC) += caamhash_desc.o -obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o -obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caam_pkc.o -caam-objs := ctrl.o -caam_jr-objs := jr.o key_gen.o -caam_pkc-y := caampkc.o pkc_desc.o +caam-y := ctrl.o +caam_jr-y := jr.o key_gen.o +caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o +caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o +caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o +caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o +caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caampkc.o pkc_desc.o + +caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += qi.o ifneq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI),) ccflags-y += -DCONFIG_CAAM_QI - caam-objs += qi.o endif obj-$(CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM) += dpaa2_caam.o diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index c0ece44f303b..43f18253e5b6 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -77,13 +77,6 @@ #define DESC_MAX_USED_BYTES (CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN) #define DESC_MAX_USED_LEN (DESC_MAX_USED_BYTES / CAAM_CMD_SZ) -#ifdef DEBUG -/* for print_hex_dumps with line references */ -#define debug(format, arg...) printk(format, arg) -#else -#define debug(format, arg...) -#endif - struct caam_alg_entry { int class1_alg_type; int class2_alg_type; @@ -583,13 +576,11 @@ static int aead_setkey(struct crypto_aead *aead, if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) goto badkey; -#ifdef DEBUG - printk(KERN_ERR "keylen %d enckeylen %d authkeylen %d\n", + dev_dbg(jrdev, "keylen %d enckeylen %d authkeylen %d\n", keys.authkeylen + keys.enckeylen, keys.enckeylen, keys.authkeylen); - print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif + print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); /* * If DKP is supported, use it in the shared descriptor to generate @@ -623,11 +614,10 @@ static int aead_setkey(struct crypto_aead *aead, memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen); dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad + keys.enckeylen, ctx->dir); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, - ctx->adata.keylen_pad + keys.enckeylen, 1); -#endif + + print_hex_dump_debug("ctx.key@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->adata.keylen_pad + keys.enckeylen, 1); skip_split_key: ctx->cdata.keylen = keys.enckeylen; @@ -678,10 +668,8 @@ static int gcm_setkey(struct crypto_aead *aead, struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif + print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, ctx->dir); @@ -699,10 +687,8 @@ static int rfc4106_setkey(struct crypto_aead *aead, if (keylen < 4) return -EINVAL; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif + print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); @@ -725,10 +711,8 @@ static int rfc4543_setkey(struct crypto_aead *aead, if (keylen < 4) return -EINVAL; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif + print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); @@ -757,10 +741,8 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, OP_ALG_AAI_CTR_MOD128); const bool is_rfc3686 = alg->caam.rfc3686; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif + print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); /* * AES-CTR needs to load IV in CONTEXT1 reg * at an offset of 128bits (16bytes) @@ -916,7 +898,7 @@ static void caam_unmap(struct device *dev, struct scatterlist *src, } if (iv_dma) - dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE); + dma_unmap_single(dev, iv_dma, ivsize, DMA_BIDIRECTIONAL); if (sec4_sg_bytes) dma_unmap_single(dev, sec4_sg_dma, sec4_sg_bytes, DMA_TO_DEVICE); @@ -949,9 +931,7 @@ static void aead_encrypt_done(struct device *jrdev, u32 *desc, u32 err, struct aead_request *req = context; struct aead_edesc *edesc; -#ifdef DEBUG - dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); -#endif + dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct aead_edesc, hw_desc[0]); @@ -971,9 +951,7 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err, struct aead_request *req = context; struct aead_edesc *edesc; -#ifdef DEBUG - dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); -#endif + dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct aead_edesc, hw_desc[0]); @@ -1001,33 +979,32 @@ static void skcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); int ivsize = crypto_skcipher_ivsize(skcipher); -#ifdef DEBUG - dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); -#endif + dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct skcipher_edesc, hw_desc[0]); if (err) caam_jr_strstatus(jrdev, err); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->iv, - edesc->src_nents > 1 ? 100 : ivsize, 1); -#endif - caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->dst, - edesc->dst_nents > 1 ? 100 : req->cryptlen, 1); - skcipher_unmap(jrdev, edesc, req); /* * The crypto API expects us to set the IV (req->iv) to the last - * ciphertext block. This is used e.g. by the CTS mode. + * ciphertext block (CBC mode) or last counter (CTR mode). + * This is used e.g. by the CTS mode. */ - if (ivsize) - scatterwalk_map_and_copy(req->iv, req->dst, req->cryptlen - - ivsize, ivsize, 0); + if (ivsize) { + memcpy(req->iv, (u8 *)edesc->sec4_sg + edesc->sec4_sg_bytes, + ivsize); + + print_hex_dump_debug("dstiv @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->iv, + edesc->src_nents > 1 ? 100 : ivsize, 1); + } + + caam_dump_sg("dst @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->dst, + edesc->dst_nents > 1 ? 100 : req->cryptlen, 1); kfree(edesc); @@ -1039,26 +1016,35 @@ static void skcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, { struct skcipher_request *req = context; struct skcipher_edesc *edesc; -#ifdef DEBUG struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); int ivsize = crypto_skcipher_ivsize(skcipher); - dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); -#endif + dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct skcipher_edesc, hw_desc[0]); if (err) caam_jr_strstatus(jrdev, err); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1); -#endif - caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ", + skcipher_unmap(jrdev, edesc, req); + + /* + * The crypto API expects us to set the IV (req->iv) to the last + * ciphertext block (CBC mode) or last counter (CTR mode). + * This is used e.g. by the CTS mode. + */ + if (ivsize) { + memcpy(req->iv, (u8 *)edesc->sec4_sg + edesc->sec4_sg_bytes, + ivsize); + + print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->iv, + ivsize, 1); + } + + caam_dump_sg("dst @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->dst, edesc->dst_nents > 1 ? 100 : req->cryptlen, 1); - skcipher_unmap(jrdev, edesc, req); kfree(edesc); skcipher_request_complete(req, err); @@ -1106,6 +1092,7 @@ static void init_aead_job(struct aead_request *req, if (unlikely(req->src != req->dst)) { if (!edesc->mapped_dst_nents) { dst_dma = 0; + out_options = 0; } else if (edesc->mapped_dst_nents == 1) { dst_dma = sg_dma_address(req->dst); out_options = 0; @@ -1249,6 +1236,7 @@ static void init_skcipher_job(struct skcipher_request *req, { struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); + struct device *jrdev = ctx->jrdev; int ivsize = crypto_skcipher_ivsize(skcipher); u32 *desc = edesc->hw_desc; u32 *sh_desc; @@ -1256,13 +1244,12 @@ static void init_skcipher_job(struct skcipher_request *req, dma_addr_t src_dma, dst_dma, ptr; int len, sec4_sg_index = 0; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1); - pr_err("asked=%d, cryptlen%d\n", + print_hex_dump_debug("presciv@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1); + dev_dbg(jrdev, "asked=%d, cryptlen%d\n", (int)edesc->src_nents > 1 ? 100 : req->cryptlen, req->cryptlen); -#endif - caam_dump_sg(KERN_ERR, "src @" __stringify(__LINE__)": ", + + caam_dump_sg("src @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->src, edesc->src_nents > 1 ? 100 : req->cryptlen, 1); @@ -1285,7 +1272,7 @@ static void init_skcipher_job(struct skcipher_request *req, if (likely(req->src == req->dst)) { dst_dma = src_dma + !!ivsize * sizeof(struct sec4_sg_entry); out_options = in_options; - } else if (edesc->mapped_dst_nents == 1) { + } else if (!ivsize && edesc->mapped_dst_nents == 1) { dst_dma = sg_dma_address(req->dst); } else { dst_dma = edesc->sec4_sg_dma + sec4_sg_index * @@ -1293,7 +1280,7 @@ static void init_skcipher_job(struct skcipher_request *req, out_options = LDST_SGF; } - append_seq_out_ptr(desc, dst_dma, req->cryptlen, out_options); + append_seq_out_ptr(desc, dst_dma, req->cryptlen + ivsize, out_options); } /* @@ -1309,37 +1296,36 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; + int src_len, dst_len = 0; struct aead_edesc *edesc; int sec4_sg_index, sec4_sg_len, sec4_sg_bytes; unsigned int authsize = ctx->authsize; if (unlikely(req->dst != req->src)) { - src_nents = sg_nents_for_len(req->src, req->assoclen + - req->cryptlen); + src_len = req->assoclen + req->cryptlen; + dst_len = src_len + (encrypt ? authsize : (-authsize)); + + src_nents = sg_nents_for_len(req->src, src_len); if (unlikely(src_nents < 0)) { dev_err(jrdev, "Insufficient bytes (%d) in src S/G\n", - req->assoclen + req->cryptlen); + src_len); return ERR_PTR(src_nents); } - dst_nents = sg_nents_for_len(req->dst, req->assoclen + - req->cryptlen + - (encrypt ? authsize : - (-authsize))); + dst_nents = sg_nents_for_len(req->dst, dst_len); if (unlikely(dst_nents < 0)) { dev_err(jrdev, "Insufficient bytes (%d) in dst S/G\n", - req->assoclen + req->cryptlen + - (encrypt ? authsize : (-authsize))); + dst_len); return ERR_PTR(dst_nents); } } else { - src_nents = sg_nents_for_len(req->src, req->assoclen + - req->cryptlen + - (encrypt ? authsize : 0)); + src_len = req->assoclen + req->cryptlen + + (encrypt ? authsize : 0); + + src_nents = sg_nents_for_len(req->src, src_len); if (unlikely(src_nents < 0)) { dev_err(jrdev, "Insufficient bytes (%d) in src S/G\n", - req->assoclen + req->cryptlen + - (encrypt ? authsize : 0)); + src_len); return ERR_PTR(src_nents); } } @@ -1380,8 +1366,16 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, } } + /* + * HW reads 4 S/G entries at a time; make sure the reads don't go beyond + * the end of the table by allocating more S/G entries. + */ sec4_sg_len = mapped_src_nents > 1 ? mapped_src_nents : 0; - sec4_sg_len += mapped_dst_nents > 1 ? mapped_dst_nents : 0; + if (mapped_dst_nents > 1) + sec4_sg_len += pad_sg_nents(mapped_dst_nents); + else + sec4_sg_len = pad_sg_nents(sec4_sg_len); + sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry); /* allocate space for base edesc and hw desc commands, link tables */ @@ -1403,12 +1397,12 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, sec4_sg_index = 0; if (mapped_src_nents > 1) { - sg_to_sec4_sg_last(req->src, mapped_src_nents, + sg_to_sec4_sg_last(req->src, src_len, edesc->sec4_sg + sec4_sg_index, 0); sec4_sg_index += mapped_src_nents; } if (mapped_dst_nents > 1) { - sg_to_sec4_sg_last(req->dst, mapped_dst_nents, + sg_to_sec4_sg_last(req->dst, dst_len, edesc->sec4_sg + sec4_sg_index, 0); } @@ -1446,11 +1440,10 @@ static int gcm_encrypt(struct aead_request *req) /* Create and submit job descriptor */ init_gcm_job(req, edesc, all_contig, true); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, - desc_bytes(edesc->hw_desc), 1); -#endif + + print_hex_dump_debug("aead jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, + desc_bytes(edesc->hw_desc), 1); desc = edesc->hw_desc; ret = caam_jr_enqueue(jrdev, desc, aead_encrypt_done, req); @@ -1556,11 +1549,10 @@ static int aead_encrypt(struct aead_request *req) /* Create and submit job descriptor */ init_authenc_job(req, edesc, all_contig, true); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, - desc_bytes(edesc->hw_desc), 1); -#endif + + print_hex_dump_debug("aead jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, + desc_bytes(edesc->hw_desc), 1); desc = edesc->hw_desc; ret = caam_jr_enqueue(jrdev, desc, aead_encrypt_done, req); @@ -1591,11 +1583,10 @@ static int gcm_decrypt(struct aead_request *req) /* Create and submit job descriptor*/ init_gcm_job(req, edesc, all_contig, false); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, - desc_bytes(edesc->hw_desc), 1); -#endif + + print_hex_dump_debug("aead jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, + desc_bytes(edesc->hw_desc), 1); desc = edesc->hw_desc; ret = caam_jr_enqueue(jrdev, desc, aead_decrypt_done, req); @@ -1627,7 +1618,7 @@ static int aead_decrypt(struct aead_request *req) u32 *desc; int ret = 0; - caam_dump_sg(KERN_ERR, "dec src@" __stringify(__LINE__)": ", + caam_dump_sg("dec src@" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->src, req->assoclen + req->cryptlen, 1); @@ -1639,11 +1630,10 @@ static int aead_decrypt(struct aead_request *req) /* Create and submit job descriptor*/ init_authenc_job(req, edesc, all_contig, false); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, - desc_bytes(edesc->hw_desc), 1); -#endif + + print_hex_dump_debug("aead jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, + desc_bytes(edesc->hw_desc), 1); desc = edesc->hw_desc; ret = caam_jr_enqueue(jrdev, desc, aead_decrypt_done, req); @@ -1719,7 +1709,29 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req, else sec4_sg_ents = mapped_src_nents + !!ivsize; dst_sg_idx = sec4_sg_ents; - sec4_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0; + + /* + * Input, output HW S/G tables: [IV, src][dst, IV] + * IV entries point to the same buffer + * If src == dst, S/G entries are reused (S/G tables overlap) + * + * HW reads 4 S/G entries at a time; make sure the reads don't go beyond + * the end of the table by allocating more S/G entries. Logic: + * if (output S/G) + * pad output S/G, if needed + * else if (input S/G) ... + * pad input S/G, if needed + */ + if (ivsize || mapped_dst_nents > 1) { + if (req->src == req->dst) + sec4_sg_ents = !!ivsize + pad_sg_nents(sec4_sg_ents); + else + sec4_sg_ents += pad_sg_nents(mapped_dst_nents + + !!ivsize); + } else { + sec4_sg_ents = pad_sg_nents(sec4_sg_ents); + } + sec4_sg_bytes = sec4_sg_ents * sizeof(struct sec4_sg_entry); /* @@ -1744,10 +1756,10 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req, /* Make sure IV is located in a DMAable area */ if (ivsize) { - iv = (u8 *)edesc->hw_desc + desc_bytes + sec4_sg_bytes; + iv = (u8 *)edesc->sec4_sg + sec4_sg_bytes; memcpy(iv, req->iv, ivsize); - iv_dma = dma_map_single(jrdev, iv, ivsize, DMA_TO_DEVICE); + iv_dma = dma_map_single(jrdev, iv, ivsize, DMA_BIDIRECTIONAL); if (dma_mapping_error(jrdev, iv_dma)) { dev_err(jrdev, "unable to map IV\n"); caam_unmap(jrdev, req->src, req->dst, src_nents, @@ -1759,13 +1771,20 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req, dma_to_sec4_sg_one(edesc->sec4_sg, iv_dma, ivsize, 0); } if (dst_sg_idx) - sg_to_sec4_sg_last(req->src, mapped_src_nents, edesc->sec4_sg + - !!ivsize, 0); + sg_to_sec4_sg(req->src, req->cryptlen, edesc->sec4_sg + + !!ivsize, 0); - if (mapped_dst_nents > 1) { - sg_to_sec4_sg_last(req->dst, mapped_dst_nents, - edesc->sec4_sg + dst_sg_idx, 0); - } + if (req->src != req->dst && (ivsize || mapped_dst_nents > 1)) + sg_to_sec4_sg(req->dst, req->cryptlen, edesc->sec4_sg + + dst_sg_idx, 0); + + if (ivsize) + dma_to_sec4_sg_one(edesc->sec4_sg + dst_sg_idx + + mapped_dst_nents, iv_dma, ivsize, 0); + + if (ivsize || mapped_dst_nents > 1) + sg_to_sec4_set_last(edesc->sec4_sg + dst_sg_idx + + mapped_dst_nents); if (sec4_sg_bytes) { edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, @@ -1782,11 +1801,9 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req, edesc->iv_dma = iv_dma; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "skcipher sec4_sg@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg, - sec4_sg_bytes, 1); -#endif + print_hex_dump_debug("skcipher sec4_sg@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg, + sec4_sg_bytes, 1); return edesc; } @@ -1807,11 +1824,11 @@ static int skcipher_encrypt(struct skcipher_request *req) /* Create and submit job descriptor*/ init_skcipher_job(req, edesc, true); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "skcipher jobdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, - desc_bytes(edesc->hw_desc), 1); -#endif + + print_hex_dump_debug("skcipher jobdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, + desc_bytes(edesc->hw_desc), 1); + desc = edesc->hw_desc; ret = caam_jr_enqueue(jrdev, desc, skcipher_encrypt_done, req); @@ -1830,7 +1847,6 @@ static int skcipher_decrypt(struct skcipher_request *req) struct skcipher_edesc *edesc; struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); - int ivsize = crypto_skcipher_ivsize(skcipher); struct device *jrdev = ctx->jrdev; u32 *desc; int ret = 0; @@ -1840,22 +1856,13 @@ static int skcipher_decrypt(struct skcipher_request *req) if (IS_ERR(edesc)) return PTR_ERR(edesc); - /* - * The crypto API expects us to set the IV (req->iv) to the last - * ciphertext block. - */ - if (ivsize) - scatterwalk_map_and_copy(req->iv, req->src, req->cryptlen - - ivsize, ivsize, 0); - /* Create and submit job descriptor*/ init_skcipher_job(req, edesc, false); desc = edesc->hw_desc; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "skcipher jobdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, - desc_bytes(edesc->hw_desc), 1); -#endif + + print_hex_dump_debug("skcipher jobdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, + desc_bytes(edesc->hw_desc), 1); ret = caam_jr_enqueue(jrdev, desc, skcipher_decrypt_done, req); if (!ret) { @@ -3444,7 +3451,7 @@ static void caam_aead_exit(struct crypto_aead *tfm) caam_exit_common(crypto_aead_ctx(tfm)); } -static void __exit caam_algapi_exit(void) +void caam_algapi_exit(void) { int i; @@ -3489,43 +3496,15 @@ static void caam_aead_alg_init(struct caam_aead_alg *t_alg) alg->exit = caam_aead_exit; } -static int __init caam_algapi_init(void) +int caam_algapi_init(struct device *ctrldev) { - struct device_node *dev_node; - struct platform_device *pdev; - struct caam_drv_private *priv; + struct caam_drv_private *priv = dev_get_drvdata(ctrldev); int i = 0, err = 0; u32 aes_vid, aes_inst, des_inst, md_vid, md_inst, ccha_inst, ptha_inst; u32 arc4_inst; unsigned int md_limit = SHA512_DIGEST_SIZE; bool registered = false, gcm_support; - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) { - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); - if (!dev_node) - return -ENODEV; - } - - pdev = of_find_device_by_node(dev_node); - if (!pdev) { - of_node_put(dev_node); - return -ENODEV; - } - - priv = dev_get_drvdata(&pdev->dev); - of_node_put(dev_node); - - /* - * If priv is NULL, it's probably because the caam driver wasn't - * properly initialized (e.g. RNG4 init failed). Thus, bail out here. - */ - if (!priv) { - err = -ENODEV; - goto out_put_dev; - } - - /* * Register crypto algorithms the device supports. * First, detect presence and attributes of DES, AES, and MD blocks. @@ -3668,14 +3647,5 @@ static int __init caam_algapi_init(void) if (registered) pr_info("caam algorithms registered in /proc/crypto\n"); -out_put_dev: - put_device(&pdev->dev); return err; } - -module_init(caam_algapi_init); -module_exit(caam_algapi_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("FSL CAAM support for crypto API"); -MODULE_AUTHOR("Freescale Semiconductor - NMG/STC"); diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c index 1e1a376edc2f..72531837571e 100644 --- a/drivers/crypto/caam/caamalg_desc.c +++ b/drivers/crypto/caam/caamalg_desc.c @@ -33,12 +33,11 @@ static inline void append_dec_op1(u32 *desc, u32 type) } jump_cmd = append_jump(desc, JUMP_TEST_ALL | JUMP_COND_SHRD); - append_operation(desc, type | OP_ALG_AS_INITFINAL | - OP_ALG_DECRYPT); + append_operation(desc, type | OP_ALG_AS_INIT | OP_ALG_DECRYPT); uncond_jump_cmd = append_jump(desc, JUMP_TEST_ALL); set_jump_tgt_here(desc, jump_cmd); - append_operation(desc, type | OP_ALG_AS_INITFINAL | - OP_ALG_DECRYPT | OP_ALG_AAI_DK); + append_operation(desc, type | OP_ALG_AS_INIT | OP_ALG_DECRYPT | + OP_ALG_AAI_DK); set_jump_tgt_here(desc, uncond_jump_cmd); } @@ -115,11 +114,9 @@ void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata, append_seq_store(desc, icvsize, LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_CONTEXT); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "aead null enc shdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("aead null enc shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); } EXPORT_SYMBOL(cnstr_shdsc_aead_null_encap); @@ -204,11 +201,9 @@ void cnstr_shdsc_aead_null_decap(u32 * const desc, struct alginfo *adata, append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "aead null dec shdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("aead null dec shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); } EXPORT_SYMBOL(cnstr_shdsc_aead_null_decap); @@ -358,10 +353,9 @@ void cnstr_shdsc_aead_encap(u32 * const desc, struct alginfo *cdata, append_seq_store(desc, icvsize, LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_CONTEXT); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead enc shdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("aead enc shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); } EXPORT_SYMBOL(cnstr_shdsc_aead_encap); @@ -475,10 +469,9 @@ void cnstr_shdsc_aead_decap(u32 * const desc, struct alginfo *cdata, append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead dec shdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("aead dec shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); } EXPORT_SYMBOL(cnstr_shdsc_aead_decap); @@ -613,11 +606,9 @@ copy_iv: append_seq_store(desc, icvsize, LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_CONTEXT); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "aead givenc shdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("aead givenc shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); } EXPORT_SYMBOL(cnstr_shdsc_aead_givencap); @@ -742,10 +733,9 @@ void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata, append_seq_store(desc, icvsize, LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "gcm enc shdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("gcm enc shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); } EXPORT_SYMBOL(cnstr_shdsc_gcm_encap); @@ -838,10 +828,9 @@ void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata, append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "gcm dec shdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("gcm dec shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); } EXPORT_SYMBOL(cnstr_shdsc_gcm_decap); @@ -933,11 +922,9 @@ void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata, append_seq_store(desc, icvsize, LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "rfc4106 enc shdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("rfc4106 enc shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); } EXPORT_SYMBOL(cnstr_shdsc_rfc4106_encap); @@ -1030,11 +1017,9 @@ void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata, append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "rfc4106 dec shdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("rfc4106 dec shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); } EXPORT_SYMBOL(cnstr_shdsc_rfc4106_decap); @@ -1115,11 +1100,9 @@ void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata, append_seq_store(desc, icvsize, LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "rfc4543 enc shdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("rfc4543 enc shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); } EXPORT_SYMBOL(cnstr_shdsc_rfc4543_encap); @@ -1205,11 +1188,9 @@ void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata, append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "rfc4543 dec shdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("rfc4543 dec shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); } EXPORT_SYMBOL(cnstr_shdsc_rfc4543_decap); @@ -1410,17 +1391,21 @@ void cnstr_shdsc_skcipher_encap(u32 * const desc, struct alginfo *cdata, LDST_OFFSET_SHIFT)); /* Load operation */ - append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + append_operation(desc, cdata->algtype | OP_ALG_AS_INIT | OP_ALG_ENCRYPT); /* Perform operation */ skcipher_append_src_dst(desc); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "skcipher enc shdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + /* Store IV */ + if (ivsize) + append_seq_store(desc, ivsize, LDST_SRCDST_BYTE_CONTEXT | + LDST_CLASS_1_CCB | (ctx1_iv_off << + LDST_OFFSET_SHIFT)); + + print_hex_dump_debug("skcipher enc shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); } EXPORT_SYMBOL(cnstr_shdsc_skcipher_encap); @@ -1479,7 +1464,7 @@ void cnstr_shdsc_skcipher_decap(u32 * const desc, struct alginfo *cdata, /* Choose operation */ if (ctx1_iv_off) - append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + append_operation(desc, cdata->algtype | OP_ALG_AS_INIT | OP_ALG_DECRYPT); else append_dec_op1(desc, cdata->algtype); @@ -1487,11 +1472,15 @@ void cnstr_shdsc_skcipher_decap(u32 * const desc, struct alginfo *cdata, /* Perform operation */ skcipher_append_src_dst(desc); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "skcipher dec shdesc@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + /* Store IV */ + if (ivsize) + append_seq_store(desc, ivsize, LDST_SRCDST_BYTE_CONTEXT | + LDST_CLASS_1_CCB | (ctx1_iv_off << + LDST_OFFSET_SHIFT)); + + print_hex_dump_debug("skcipher dec shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); } EXPORT_SYMBOL(cnstr_shdsc_skcipher_decap); @@ -1538,11 +1527,13 @@ void cnstr_shdsc_xts_skcipher_encap(u32 * const desc, struct alginfo *cdata) /* Perform operation */ skcipher_append_src_dst(desc); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "xts skcipher enc shdesc@" __stringify(__LINE__) ": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + /* Store upper 8B of IV */ + append_seq_store(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB | + (0x20 << LDST_OFFSET_SHIFT)); + + print_hex_dump_debug("xts skcipher enc shdesc@" __stringify(__LINE__) + ": ", DUMP_PREFIX_ADDRESS, 16, 4, + desc, desc_bytes(desc), 1); } EXPORT_SYMBOL(cnstr_shdsc_xts_skcipher_encap); @@ -1588,11 +1579,13 @@ void cnstr_shdsc_xts_skcipher_decap(u32 * const desc, struct alginfo *cdata) /* Perform operation */ skcipher_append_src_dst(desc); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "xts skcipher dec shdesc@" __stringify(__LINE__) ": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + /* Store upper 8B of IV */ + append_seq_store(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB | + (0x20 << LDST_OFFSET_SHIFT)); + + print_hex_dump_debug("xts skcipher dec shdesc@" __stringify(__LINE__) + ": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); } EXPORT_SYMBOL(cnstr_shdsc_xts_skcipher_decap); diff --git a/drivers/crypto/caam/caamalg_desc.h b/drivers/crypto/caam/caamalg_desc.h index d5ca42ff961a..da4a4ee60c80 100644 --- a/drivers/crypto/caam/caamalg_desc.h +++ b/drivers/crypto/caam/caamalg_desc.h @@ -44,9 +44,9 @@ #define DESC_SKCIPHER_BASE (3 * CAAM_CMD_SZ) #define DESC_SKCIPHER_ENC_LEN (DESC_SKCIPHER_BASE + \ - 20 * CAAM_CMD_SZ) + 21 * CAAM_CMD_SZ) #define DESC_SKCIPHER_DEC_LEN (DESC_SKCIPHER_BASE + \ - 15 * CAAM_CMD_SZ) + 16 * CAAM_CMD_SZ) void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata, unsigned int icvsize, int era); diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c index d290d6b41825..32f0f8a72067 100644 --- a/drivers/crypto/caam/caamalg_qi.c +++ b/drivers/crypto/caam/caamalg_qi.c @@ -4,7 +4,7 @@ * Based on caamalg.c * * Copyright 2013-2016 Freescale Semiconductor, Inc. - * Copyright 2016-2018 NXP + * Copyright 2016-2019 NXP */ #include "compat.h" @@ -214,13 +214,11 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key, if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) goto badkey; -#ifdef DEBUG - dev_err(jrdev, "keylen %d enckeylen %d authkeylen %d\n", + dev_dbg(jrdev, "keylen %d enckeylen %d authkeylen %d\n", keys.authkeylen + keys.enckeylen, keys.enckeylen, keys.authkeylen); - print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif + print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); /* * If DKP is supported, use it in the shared descriptor to generate @@ -237,7 +235,7 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key, memcpy(ctx->key, keys.authkey, keys.authkeylen); memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen); - dma_sync_single_for_device(jrdev, ctx->key_dma, + dma_sync_single_for_device(jrdev->parent, ctx->key_dma, ctx->adata.keylen_pad + keys.enckeylen, ctx->dir); goto skip_split_key; @@ -251,8 +249,9 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key, /* postpend encryption key to auth split key */ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen); - dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad + - keys.enckeylen, ctx->dir); + dma_sync_single_for_device(jrdev->parent, ctx->key_dma, + ctx->adata.keylen_pad + keys.enckeylen, + ctx->dir); #ifdef DEBUG print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, @@ -386,13 +385,12 @@ static int gcm_setkey(struct crypto_aead *aead, struct device *jrdev = ctx->jrdev; int ret; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif + print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); - dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, ctx->dir); + dma_sync_single_for_device(jrdev->parent, ctx->key_dma, keylen, + ctx->dir); ctx->cdata.keylen = keylen; ret = gcm_set_sh_desc(aead); @@ -485,10 +483,8 @@ static int rfc4106_setkey(struct crypto_aead *aead, if (keylen < 4) return -EINVAL; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif + print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); /* @@ -496,8 +492,8 @@ static int rfc4106_setkey(struct crypto_aead *aead, * in the nonce. Update the AES key length. */ ctx->cdata.keylen = keylen - 4; - dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen, - ctx->dir); + dma_sync_single_for_device(jrdev->parent, ctx->key_dma, + ctx->cdata.keylen, ctx->dir); ret = rfc4106_set_sh_desc(aead); if (ret) @@ -589,10 +585,8 @@ static int rfc4543_setkey(struct crypto_aead *aead, if (keylen < 4) return -EINVAL; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif + print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); memcpy(ctx->key, key, keylen); /* @@ -600,8 +594,8 @@ static int rfc4543_setkey(struct crypto_aead *aead, * in the nonce. Update the AES key length. */ ctx->cdata.keylen = keylen - 4; - dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen, - ctx->dir); + dma_sync_single_for_device(jrdev->parent, ctx->key_dma, + ctx->cdata.keylen, ctx->dir); ret = rfc4543_set_sh_desc(aead); if (ret) @@ -644,10 +638,9 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, const bool is_rfc3686 = alg->caam.rfc3686; int ret = 0; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif + print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + /* * AES-CTR needs to load IV in CONTEXT1 reg * at an offset of 128bits (16bytes) @@ -838,7 +831,8 @@ static struct caam_drv_ctx *get_drv_ctx(struct caam_ctx *ctx, static void caam_unmap(struct device *dev, struct scatterlist *src, struct scatterlist *dst, int src_nents, int dst_nents, dma_addr_t iv_dma, int ivsize, - dma_addr_t qm_sg_dma, int qm_sg_bytes) + enum dma_data_direction iv_dir, dma_addr_t qm_sg_dma, + int qm_sg_bytes) { if (dst != src) { if (src_nents) @@ -850,7 +844,7 @@ static void caam_unmap(struct device *dev, struct scatterlist *src, } if (iv_dma) - dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE); + dma_unmap_single(dev, iv_dma, ivsize, iv_dir); if (qm_sg_bytes) dma_unmap_single(dev, qm_sg_dma, qm_sg_bytes, DMA_TO_DEVICE); } @@ -863,7 +857,8 @@ static void aead_unmap(struct device *dev, int ivsize = crypto_aead_ivsize(aead); caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, - edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes); + edesc->iv_dma, ivsize, DMA_TO_DEVICE, edesc->qm_sg_dma, + edesc->qm_sg_bytes); dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE); } @@ -874,7 +869,8 @@ static void skcipher_unmap(struct device *dev, struct skcipher_edesc *edesc, int ivsize = crypto_skcipher_ivsize(skcipher); caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, - edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes); + edesc->iv_dma, ivsize, DMA_BIDIRECTIONAL, edesc->qm_sg_dma, + edesc->qm_sg_bytes); } static void aead_done(struct caam_drv_req *drv_req, u32 status) @@ -924,6 +920,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; + int src_len, dst_len = 0; struct aead_edesc *edesc; dma_addr_t qm_sg_dma, iv_dma = 0; int ivsize = 0; @@ -945,13 +942,13 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, } if (likely(req->src == req->dst)) { - src_nents = sg_nents_for_len(req->src, req->assoclen + - req->cryptlen + - (encrypt ? authsize : 0)); + src_len = req->assoclen + req->cryptlen + + (encrypt ? authsize : 0); + + src_nents = sg_nents_for_len(req->src, src_len); if (unlikely(src_nents < 0)) { dev_err(qidev, "Insufficient bytes (%d) in src S/G\n", - req->assoclen + req->cryptlen + - (encrypt ? authsize : 0)); + src_len); qi_cache_free(edesc); return ERR_PTR(src_nents); } @@ -964,23 +961,21 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, return ERR_PTR(-ENOMEM); } } else { - src_nents = sg_nents_for_len(req->src, req->assoclen + - req->cryptlen); + src_len = req->assoclen + req->cryptlen; + dst_len = src_len + (encrypt ? authsize : (-authsize)); + + src_nents = sg_nents_for_len(req->src, src_len); if (unlikely(src_nents < 0)) { dev_err(qidev, "Insufficient bytes (%d) in src S/G\n", - req->assoclen + req->cryptlen); + src_len); qi_cache_free(edesc); return ERR_PTR(src_nents); } - dst_nents = sg_nents_for_len(req->dst, req->assoclen + - req->cryptlen + - (encrypt ? authsize : - (-authsize))); + dst_nents = sg_nents_for_len(req->dst, dst_len); if (unlikely(dst_nents < 0)) { dev_err(qidev, "Insufficient bytes (%d) in dst S/G\n", - req->assoclen + req->cryptlen + - (encrypt ? authsize : (-authsize))); + dst_len); qi_cache_free(edesc); return ERR_PTR(dst_nents); } @@ -1019,9 +1014,24 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, /* * Create S/G table: req->assoclen, [IV,] req->src [, req->dst]. * Input is not contiguous. + * HW reads 4 S/G entries at a time; make sure the reads don't go beyond + * the end of the table by allocating more S/G entries. Logic: + * if (src != dst && output S/G) + * pad output S/G, if needed + * else if (src == dst && S/G) + * overlapping S/Gs; pad one of them + * else if (input S/G) ... + * pad input S/G, if needed */ - qm_sg_ents = 1 + !!ivsize + mapped_src_nents + - (mapped_dst_nents > 1 ? mapped_dst_nents : 0); + qm_sg_ents = 1 + !!ivsize + mapped_src_nents; + if (mapped_dst_nents > 1) + qm_sg_ents += pad_sg_nents(mapped_dst_nents); + else if ((req->src == req->dst) && (mapped_src_nents > 1)) + qm_sg_ents = max(pad_sg_nents(qm_sg_ents), + 1 + !!ivsize + pad_sg_nents(mapped_src_nents)); + else + qm_sg_ents = pad_sg_nents(qm_sg_ents); + sg_table = &edesc->sgt[0]; qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); if (unlikely(offsetof(struct aead_edesc, sgt) + qm_sg_bytes + ivsize > @@ -1029,7 +1039,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n", qm_sg_ents, ivsize); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0); + 0, DMA_NONE, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -1044,7 +1054,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, if (dma_mapping_error(qidev, iv_dma)) { dev_err(qidev, "unable to map IV\n"); caam_unmap(qidev, req->src, req->dst, src_nents, - dst_nents, 0, 0, 0, 0); + dst_nents, 0, 0, DMA_NONE, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -1063,7 +1073,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, if (dma_mapping_error(qidev, edesc->assoclen_dma)) { dev_err(qidev, "unable to map assoclen\n"); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, 0, 0); + iv_dma, ivsize, DMA_TO_DEVICE, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -1074,19 +1084,18 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, dma_to_qm_sg_one(sg_table + qm_sg_index, iv_dma, ivsize, 0); qm_sg_index++; } - sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0); + sg_to_qm_sg_last(req->src, src_len, sg_table + qm_sg_index, 0); qm_sg_index += mapped_src_nents; if (mapped_dst_nents > 1) - sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + - qm_sg_index, 0); + sg_to_qm_sg_last(req->dst, dst_len, sg_table + qm_sg_index, 0); qm_sg_dma = dma_map_single(qidev, sg_table, qm_sg_bytes, DMA_TO_DEVICE); if (dma_mapping_error(qidev, qm_sg_dma)) { dev_err(qidev, "unable to map S/G table\n"); dma_unmap_single(qidev, edesc->assoclen_dma, 4, DMA_TO_DEVICE); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, 0, 0); + iv_dma, ivsize, DMA_TO_DEVICE, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -1109,7 +1118,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, dma_to_qm_sg_one_ext(&fd_sgt[0], qm_sg_dma + (1 + !!ivsize) * sizeof(*sg_table), out_len, 0); - } else if (mapped_dst_nents == 1) { + } else if (mapped_dst_nents <= 1) { dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->dst), out_len, 0); } else { @@ -1182,33 +1191,28 @@ static void skcipher_done(struct caam_drv_req *drv_req, u32 status) struct device *qidev = caam_ctx->qidev; int ivsize = crypto_skcipher_ivsize(skcipher); -#ifdef DEBUG - dev_err(qidev, "%s %d: status 0x%x\n", __func__, __LINE__, status); -#endif + dev_dbg(qidev, "%s %d: status 0x%x\n", __func__, __LINE__, status); edesc = container_of(drv_req, typeof(*edesc), drv_req); if (status) caam_jr_strstatus(qidev, status); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "dstiv @" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->iv, - edesc->src_nents > 1 ? 100 : ivsize, 1); - caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ", + print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->iv, + edesc->src_nents > 1 ? 100 : ivsize, 1); + caam_dump_sg("dst @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->dst, edesc->dst_nents > 1 ? 100 : req->cryptlen, 1); -#endif skcipher_unmap(qidev, edesc, req); /* * The crypto API expects us to set the IV (req->iv) to the last - * ciphertext block. This is used e.g. by the CTS mode. + * ciphertext block (CBC mode) or last counter (CTR mode). + * This is used e.g. by the CTS mode. */ - if (edesc->drv_req.drv_ctx->op_type == ENCRYPT) - scatterwalk_map_and_copy(req->iv, req->dst, req->cryptlen - - ivsize, ivsize, 0); + memcpy(req->iv, (u8 *)&edesc->sgt[0] + edesc->qm_sg_bytes, ivsize); qi_cache_free(edesc); skcipher_request_complete(req, status); @@ -1276,14 +1280,26 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req, qm_sg_ents = 1 + mapped_src_nents; dst_sg_idx = qm_sg_ents; - qm_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0; + /* + * Input, output HW S/G tables: [IV, src][dst, IV] + * IV entries point to the same buffer + * If src == dst, S/G entries are reused (S/G tables overlap) + * + * HW reads 4 S/G entries at a time; make sure the reads don't go beyond + * the end of the table by allocating more S/G entries. + */ + if (req->src != req->dst) + qm_sg_ents += pad_sg_nents(mapped_dst_nents + 1); + else + qm_sg_ents = 1 + pad_sg_nents(qm_sg_ents); + qm_sg_bytes = qm_sg_ents * sizeof(struct qm_sg_entry); if (unlikely(offsetof(struct skcipher_edesc, sgt) + qm_sg_bytes + ivsize > CAAM_QI_MEMCACHE_SIZE)) { dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n", qm_sg_ents, ivsize); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0); + 0, DMA_NONE, 0, 0); return ERR_PTR(-ENOMEM); } @@ -1292,7 +1308,7 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req, if (unlikely(!edesc)) { dev_err(qidev, "could not allocate extended descriptor\n"); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0); + 0, DMA_NONE, 0, 0); return ERR_PTR(-ENOMEM); } @@ -1301,11 +1317,11 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req, iv = (u8 *)(sg_table + qm_sg_ents); memcpy(iv, req->iv, ivsize); - iv_dma = dma_map_single(qidev, iv, ivsize, DMA_TO_DEVICE); + iv_dma = dma_map_single(qidev, iv, ivsize, DMA_BIDIRECTIONAL); if (dma_mapping_error(qidev, iv_dma)) { dev_err(qidev, "unable to map IV\n"); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0); + 0, DMA_NONE, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -1319,18 +1335,20 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req, edesc->drv_req.drv_ctx = drv_ctx; dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0); - sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + 1, 0); + sg_to_qm_sg(req->src, req->cryptlen, sg_table + 1, 0); - if (mapped_dst_nents > 1) - sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + - dst_sg_idx, 0); + if (req->src != req->dst) + sg_to_qm_sg(req->dst, req->cryptlen, sg_table + dst_sg_idx, 0); + + dma_to_qm_sg_one(sg_table + dst_sg_idx + mapped_dst_nents, iv_dma, + ivsize, 0); edesc->qm_sg_dma = dma_map_single(qidev, sg_table, edesc->qm_sg_bytes, DMA_TO_DEVICE); if (dma_mapping_error(qidev, edesc->qm_sg_dma)) { dev_err(qidev, "unable to map S/G table\n"); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, 0, 0); + iv_dma, ivsize, DMA_BIDIRECTIONAL, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -1340,16 +1358,14 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req, dma_to_qm_sg_one_last_ext(&fd_sgt[1], edesc->qm_sg_dma, ivsize + req->cryptlen, 0); - if (req->src == req->dst) { + if (req->src == req->dst) dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + - sizeof(*sg_table), req->cryptlen, 0); - } else if (mapped_dst_nents > 1) { + sizeof(*sg_table), req->cryptlen + ivsize, + 0); + else dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + dst_sg_idx * - sizeof(*sg_table), req->cryptlen, 0); - } else { - dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->dst), - req->cryptlen, 0); - } + sizeof(*sg_table), req->cryptlen + ivsize, + 0); return edesc; } @@ -1359,7 +1375,6 @@ static inline int skcipher_crypt(struct skcipher_request *req, bool encrypt) struct skcipher_edesc *edesc; struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); - int ivsize = crypto_skcipher_ivsize(skcipher); int ret; if (unlikely(caam_congested)) @@ -1370,14 +1385,6 @@ static inline int skcipher_crypt(struct skcipher_request *req, bool encrypt) if (IS_ERR(edesc)) return PTR_ERR(edesc); - /* - * The crypto API expects us to set the IV (req->iv) to the last - * ciphertext block. - */ - if (!encrypt) - scatterwalk_map_and_copy(req->iv, req->src, req->cryptlen - - ivsize, ivsize, 0); - ret = caam_qi_enqueue(ctx->qidev, &edesc->drv_req); if (!ret) { ret = -EINPROGRESS; @@ -2382,6 +2389,7 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam, bool uses_dkp) { struct caam_drv_private *priv; + struct device *dev; /* * distribute tfms across job rings to ensure in-order @@ -2393,16 +2401,17 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam, return PTR_ERR(ctx->jrdev); } - priv = dev_get_drvdata(ctx->jrdev->parent); + dev = ctx->jrdev->parent; + priv = dev_get_drvdata(dev); if (priv->era >= 6 && uses_dkp) ctx->dir = DMA_BIDIRECTIONAL; else ctx->dir = DMA_TO_DEVICE; - ctx->key_dma = dma_map_single(ctx->jrdev, ctx->key, sizeof(ctx->key), + ctx->key_dma = dma_map_single(dev, ctx->key, sizeof(ctx->key), ctx->dir); - if (dma_mapping_error(ctx->jrdev, ctx->key_dma)) { - dev_err(ctx->jrdev, "unable to map key\n"); + if (dma_mapping_error(dev, ctx->key_dma)) { + dev_err(dev, "unable to map key\n"); caam_jr_free(ctx->jrdev); return -ENOMEM; } @@ -2411,7 +2420,7 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam, ctx->cdata.algtype = OP_TYPE_CLASS1_ALG | caam->class1_alg_type; ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam->class2_alg_type; - ctx->qidev = priv->qidev; + ctx->qidev = dev; spin_lock_init(&ctx->lock); ctx->drv_ctx[ENCRYPT] = NULL; @@ -2445,7 +2454,8 @@ static void caam_exit_common(struct caam_ctx *ctx) caam_drv_ctx_rel(ctx->drv_ctx[ENCRYPT]); caam_drv_ctx_rel(ctx->drv_ctx[DECRYPT]); - dma_unmap_single(ctx->jrdev, ctx->key_dma, sizeof(ctx->key), ctx->dir); + dma_unmap_single(ctx->jrdev->parent, ctx->key_dma, sizeof(ctx->key), + ctx->dir); caam_jr_free(ctx->jrdev); } @@ -2460,7 +2470,7 @@ static void caam_aead_exit(struct crypto_aead *tfm) caam_exit_common(crypto_aead_ctx(tfm)); } -static void __exit caam_qi_algapi_exit(void) +void caam_qi_algapi_exit(void) { int i; @@ -2505,45 +2515,17 @@ static void caam_aead_alg_init(struct caam_aead_alg *t_alg) alg->exit = caam_aead_exit; } -static int __init caam_qi_algapi_init(void) +int caam_qi_algapi_init(struct device *ctrldev) { - struct device_node *dev_node; - struct platform_device *pdev; - struct device *ctrldev; - struct caam_drv_private *priv; + struct caam_drv_private *priv = dev_get_drvdata(ctrldev); int i = 0, err = 0; u32 aes_vid, aes_inst, des_inst, md_vid, md_inst; unsigned int md_limit = SHA512_DIGEST_SIZE; bool registered = false; - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) { - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); - if (!dev_node) - return -ENODEV; - } - - pdev = of_find_device_by_node(dev_node); - of_node_put(dev_node); - if (!pdev) - return -ENODEV; - - ctrldev = &pdev->dev; - priv = dev_get_drvdata(ctrldev); - - /* - * If priv is NULL, it's probably because the caam driver wasn't - * properly initialized (e.g. RNG4 init failed). Thus, bail out here. - */ - if (!priv || !priv->qi_present) { - err = -ENODEV; - goto out_put_dev; - } - if (caam_dpaa2) { dev_info(ctrldev, "caam/qi frontend driver not suitable for DPAA 2.x, aborting...\n"); - err = -ENODEV; - goto out_put_dev; + return -ENODEV; } /* @@ -2598,7 +2580,7 @@ static int __init caam_qi_algapi_init(void) err = crypto_register_skcipher(&t_alg->skcipher); if (err) { - dev_warn(priv->qidev, "%s alg registration failed\n", + dev_warn(ctrldev, "%s alg registration failed\n", t_alg->skcipher.base.cra_driver_name); continue; } @@ -2654,16 +2636,7 @@ static int __init caam_qi_algapi_init(void) } if (registered) - dev_info(priv->qidev, "algorithms registered in /proc/crypto\n"); + dev_info(ctrldev, "algorithms registered in /proc/crypto\n"); -out_put_dev: - put_device(ctrldev); return err; } - -module_init(caam_qi_algapi_init); -module_exit(caam_qi_algapi_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Support for crypto API using CAAM-QI backend"); -MODULE_AUTHOR("Freescale Semiconductor"); diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c index 2b2980a8a9b9..06bf32c32cbd 100644 --- a/drivers/crypto/caam/caamalg_qi2.c +++ b/drivers/crypto/caam/caamalg_qi2.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* * Copyright 2015-2016 Freescale Semiconductor Inc. - * Copyright 2017-2018 NXP + * Copyright 2017-2019 NXP */ #include "compat.h" @@ -140,7 +140,8 @@ static struct caam_request *to_caam_req(struct crypto_async_request *areq) static void caam_unmap(struct device *dev, struct scatterlist *src, struct scatterlist *dst, int src_nents, int dst_nents, dma_addr_t iv_dma, int ivsize, - dma_addr_t qm_sg_dma, int qm_sg_bytes) + enum dma_data_direction iv_dir, dma_addr_t qm_sg_dma, + int qm_sg_bytes) { if (dst != src) { if (src_nents) @@ -152,7 +153,7 @@ static void caam_unmap(struct device *dev, struct scatterlist *src, } if (iv_dma) - dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE); + dma_unmap_single(dev, iv_dma, ivsize, iv_dir); if (qm_sg_bytes) dma_unmap_single(dev, qm_sg_dma, qm_sg_bytes, DMA_TO_DEVICE); @@ -371,6 +372,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; + int src_len, dst_len = 0; struct aead_edesc *edesc; dma_addr_t qm_sg_dma, iv_dma = 0; int ivsize = 0; @@ -387,23 +389,21 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, } if (unlikely(req->dst != req->src)) { - src_nents = sg_nents_for_len(req->src, req->assoclen + - req->cryptlen); + src_len = req->assoclen + req->cryptlen; + dst_len = src_len + (encrypt ? authsize : (-authsize)); + + src_nents = sg_nents_for_len(req->src, src_len); if (unlikely(src_nents < 0)) { dev_err(dev, "Insufficient bytes (%d) in src S/G\n", - req->assoclen + req->cryptlen); + src_len); qi_cache_free(edesc); return ERR_PTR(src_nents); } - dst_nents = sg_nents_for_len(req->dst, req->assoclen + - req->cryptlen + - (encrypt ? authsize : - (-authsize))); + dst_nents = sg_nents_for_len(req->dst, dst_len); if (unlikely(dst_nents < 0)) { dev_err(dev, "Insufficient bytes (%d) in dst S/G\n", - req->assoclen + req->cryptlen + - (encrypt ? authsize : (-authsize))); + dst_len); qi_cache_free(edesc); return ERR_PTR(dst_nents); } @@ -434,13 +434,13 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, mapped_dst_nents = 0; } } else { - src_nents = sg_nents_for_len(req->src, req->assoclen + - req->cryptlen + - (encrypt ? authsize : 0)); + src_len = req->assoclen + req->cryptlen + + (encrypt ? authsize : 0); + + src_nents = sg_nents_for_len(req->src, src_len); if (unlikely(src_nents < 0)) { dev_err(dev, "Insufficient bytes (%d) in src S/G\n", - req->assoclen + req->cryptlen + - (encrypt ? authsize : 0)); + src_len); qi_cache_free(edesc); return ERR_PTR(src_nents); } @@ -460,9 +460,25 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, /* * Create S/G table: req->assoclen, [IV,] req->src [, req->dst]. * Input is not contiguous. + * HW reads 4 S/G entries at a time; make sure the reads don't go beyond + * the end of the table by allocating more S/G entries. Logic: + * if (src != dst && output S/G) + * pad output S/G, if needed + * else if (src == dst && S/G) + * overlapping S/Gs; pad one of them + * else if (input S/G) ... + * pad input S/G, if needed */ - qm_sg_nents = 1 + !!ivsize + mapped_src_nents + - (mapped_dst_nents > 1 ? mapped_dst_nents : 0); + qm_sg_nents = 1 + !!ivsize + mapped_src_nents; + if (mapped_dst_nents > 1) + qm_sg_nents += pad_sg_nents(mapped_dst_nents); + else if ((req->src == req->dst) && (mapped_src_nents > 1)) + qm_sg_nents = max(pad_sg_nents(qm_sg_nents), + 1 + !!ivsize + + pad_sg_nents(mapped_src_nents)); + else + qm_sg_nents = pad_sg_nents(qm_sg_nents); + sg_table = &edesc->sgt[0]; qm_sg_bytes = qm_sg_nents * sizeof(*sg_table); if (unlikely(offsetof(struct aead_edesc, sgt) + qm_sg_bytes + ivsize > @@ -470,7 +486,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, dev_err(dev, "No space for %d S/G entries and/or %dB IV\n", qm_sg_nents, ivsize); caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0); + 0, DMA_NONE, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -485,7 +501,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, if (dma_mapping_error(dev, iv_dma)) { dev_err(dev, "unable to map IV\n"); caam_unmap(dev, req->src, req->dst, src_nents, - dst_nents, 0, 0, 0, 0); + dst_nents, 0, 0, DMA_NONE, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -509,7 +525,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, if (dma_mapping_error(dev, edesc->assoclen_dma)) { dev_err(dev, "unable to map assoclen\n"); caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, 0, 0); + iv_dma, ivsize, DMA_TO_DEVICE, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -520,19 +536,18 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, dma_to_qm_sg_one(sg_table + qm_sg_index, iv_dma, ivsize, 0); qm_sg_index++; } - sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0); + sg_to_qm_sg_last(req->src, src_len, sg_table + qm_sg_index, 0); qm_sg_index += mapped_src_nents; if (mapped_dst_nents > 1) - sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + - qm_sg_index, 0); + sg_to_qm_sg_last(req->dst, dst_len, sg_table + qm_sg_index, 0); qm_sg_dma = dma_map_single(dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE); if (dma_mapping_error(dev, qm_sg_dma)) { dev_err(dev, "unable to map S/G table\n"); dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE); caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, 0, 0); + iv_dma, ivsize, DMA_TO_DEVICE, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -559,6 +574,14 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, dpaa2_fl_set_addr(out_fle, qm_sg_dma + (1 + !!ivsize) * sizeof(*sg_table)); } + } else if (!mapped_dst_nents) { + /* + * crypto engine requires the output entry to be present when + * "frame list" FD is used. + * Since engine does not support FMT=2'b11 (unused entry type), + * leaving out_fle zeroized is the best option. + */ + goto skip_out_fle; } else if (mapped_dst_nents == 1) { dpaa2_fl_set_format(out_fle, dpaa2_fl_single); dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst)); @@ -570,6 +593,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, dpaa2_fl_set_len(out_fle, out_len); +skip_out_fle: return edesc; } @@ -1077,14 +1101,26 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req) qm_sg_ents = 1 + mapped_src_nents; dst_sg_idx = qm_sg_ents; - qm_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0; + /* + * Input, output HW S/G tables: [IV, src][dst, IV] + * IV entries point to the same buffer + * If src == dst, S/G entries are reused (S/G tables overlap) + * + * HW reads 4 S/G entries at a time; make sure the reads don't go beyond + * the end of the table by allocating more S/G entries. + */ + if (req->src != req->dst) + qm_sg_ents += pad_sg_nents(mapped_dst_nents + 1); + else + qm_sg_ents = 1 + pad_sg_nents(qm_sg_ents); + qm_sg_bytes = qm_sg_ents * sizeof(struct dpaa2_sg_entry); if (unlikely(offsetof(struct skcipher_edesc, sgt) + qm_sg_bytes + ivsize > CAAM_QI_MEMCACHE_SIZE)) { dev_err(dev, "No space for %d S/G entries and/or %dB IV\n", qm_sg_ents, ivsize); caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0); + 0, DMA_NONE, 0, 0); return ERR_PTR(-ENOMEM); } @@ -1093,7 +1129,7 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req) if (unlikely(!edesc)) { dev_err(dev, "could not allocate extended descriptor\n"); caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0); + 0, DMA_NONE, 0, 0); return ERR_PTR(-ENOMEM); } @@ -1102,11 +1138,11 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req) iv = (u8 *)(sg_table + qm_sg_ents); memcpy(iv, req->iv, ivsize); - iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE); + iv_dma = dma_map_single(dev, iv, ivsize, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, iv_dma)) { dev_err(dev, "unable to map IV\n"); caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0); + 0, DMA_NONE, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -1117,18 +1153,20 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req) edesc->qm_sg_bytes = qm_sg_bytes; dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0); - sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + 1, 0); + sg_to_qm_sg(req->src, req->cryptlen, sg_table + 1, 0); - if (mapped_dst_nents > 1) - sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + - dst_sg_idx, 0); + if (req->src != req->dst) + sg_to_qm_sg(req->dst, req->cryptlen, sg_table + dst_sg_idx, 0); + + dma_to_qm_sg_one(sg_table + dst_sg_idx + mapped_dst_nents, iv_dma, + ivsize, 0); edesc->qm_sg_dma = dma_map_single(dev, sg_table, edesc->qm_sg_bytes, DMA_TO_DEVICE); if (dma_mapping_error(dev, edesc->qm_sg_dma)) { dev_err(dev, "unable to map S/G table\n"); caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, 0, 0); + iv_dma, ivsize, DMA_BIDIRECTIONAL, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -1136,23 +1174,19 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req) memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); dpaa2_fl_set_final(in_fle, true); dpaa2_fl_set_len(in_fle, req->cryptlen + ivsize); - dpaa2_fl_set_len(out_fle, req->cryptlen); + dpaa2_fl_set_len(out_fle, req->cryptlen + ivsize); dpaa2_fl_set_format(in_fle, dpaa2_fl_sg); dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma); - if (req->src == req->dst) { - dpaa2_fl_set_format(out_fle, dpaa2_fl_sg); + dpaa2_fl_set_format(out_fle, dpaa2_fl_sg); + + if (req->src == req->dst) dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma + sizeof(*sg_table)); - } else if (mapped_dst_nents > 1) { - dpaa2_fl_set_format(out_fle, dpaa2_fl_sg); + else dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma + dst_sg_idx * sizeof(*sg_table)); - } else { - dpaa2_fl_set_format(out_fle, dpaa2_fl_single); - dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst)); - } return edesc; } @@ -1164,7 +1198,8 @@ static void aead_unmap(struct device *dev, struct aead_edesc *edesc, int ivsize = crypto_aead_ivsize(aead); caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, - edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes); + edesc->iv_dma, ivsize, DMA_TO_DEVICE, edesc->qm_sg_dma, + edesc->qm_sg_bytes); dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE); } @@ -1175,7 +1210,8 @@ static void skcipher_unmap(struct device *dev, struct skcipher_edesc *edesc, int ivsize = crypto_skcipher_ivsize(skcipher); caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, - edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes); + edesc->iv_dma, ivsize, DMA_BIDIRECTIONAL, edesc->qm_sg_dma, + edesc->qm_sg_bytes); } static void aead_encrypt_done(void *cbk_ctx, u32 status) @@ -1324,7 +1360,7 @@ static void skcipher_encrypt_done(void *cbk_ctx, u32 status) print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->iv, edesc->src_nents > 1 ? 100 : ivsize, 1); - caam_dump_sg(KERN_DEBUG, "dst @" __stringify(__LINE__)": ", + caam_dump_sg("dst @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->dst, edesc->dst_nents > 1 ? 100 : req->cryptlen, 1); @@ -1332,10 +1368,10 @@ static void skcipher_encrypt_done(void *cbk_ctx, u32 status) /* * The crypto API expects us to set the IV (req->iv) to the last - * ciphertext block. This is used e.g. by the CTS mode. + * ciphertext block (CBC mode) or last counter (CTR mode). + * This is used e.g. by the CTS mode. */ - scatterwalk_map_and_copy(req->iv, req->dst, req->cryptlen - ivsize, - ivsize, 0); + memcpy(req->iv, (u8 *)&edesc->sgt[0] + edesc->qm_sg_bytes, ivsize); qi_cache_free(edesc); skcipher_request_complete(req, ecode); @@ -1362,11 +1398,19 @@ static void skcipher_decrypt_done(void *cbk_ctx, u32 status) print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->iv, edesc->src_nents > 1 ? 100 : ivsize, 1); - caam_dump_sg(KERN_DEBUG, "dst @" __stringify(__LINE__)": ", + caam_dump_sg("dst @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->dst, edesc->dst_nents > 1 ? 100 : req->cryptlen, 1); skcipher_unmap(ctx->dev, edesc, req); + + /* + * The crypto API expects us to set the IV (req->iv) to the last + * ciphertext block (CBC mode) or last counter (CTR mode). + * This is used e.g. by the CTS mode. + */ + memcpy(req->iv, (u8 *)&edesc->sgt[0] + edesc->qm_sg_bytes, ivsize); + qi_cache_free(edesc); skcipher_request_complete(req, ecode); } @@ -1405,7 +1449,6 @@ static int skcipher_decrypt(struct skcipher_request *req) struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); struct caam_request *caam_req = skcipher_request_ctx(req); - int ivsize = crypto_skcipher_ivsize(skcipher); int ret; /* allocate extended descriptor */ @@ -1413,13 +1456,6 @@ static int skcipher_decrypt(struct skcipher_request *req) if (IS_ERR(edesc)) return PTR_ERR(edesc); - /* - * The crypto API expects us to set the IV (req->iv) to the last - * ciphertext block. - */ - scatterwalk_map_and_copy(req->iv, req->src, req->cryptlen - ivsize, - ivsize, 0); - caam_req->flc = &ctx->flc[DECRYPT]; caam_req->flc_dma = ctx->flc_dma[DECRYPT]; caam_req->cbk = skcipher_decrypt_done; @@ -3380,9 +3416,9 @@ static int ahash_update_ctx(struct ahash_request *req) if (to_hash) { struct dpaa2_sg_entry *sg_table; + int src_len = req->nbytes - *next_buflen; - src_nents = sg_nents_for_len(req->src, - req->nbytes - (*next_buflen)); + src_nents = sg_nents_for_len(req->src, src_len); if (src_nents < 0) { dev_err(ctx->dev, "Invalid number of src SG.\n"); return src_nents; @@ -3409,7 +3445,7 @@ static int ahash_update_ctx(struct ahash_request *req) edesc->src_nents = src_nents; qm_sg_src_index = 1 + (*buflen ? 1 : 0); - qm_sg_bytes = (qm_sg_src_index + mapped_nents) * + qm_sg_bytes = pad_sg_nents(qm_sg_src_index + mapped_nents) * sizeof(*sg_table); sg_table = &edesc->sgt[0]; @@ -3423,7 +3459,7 @@ static int ahash_update_ctx(struct ahash_request *req) goto unmap_ctx; if (mapped_nents) { - sg_to_qm_sg_last(req->src, mapped_nents, + sg_to_qm_sg_last(req->src, src_len, sg_table + qm_sg_src_index, 0); if (*next_buflen) scatterwalk_map_and_copy(next_buf, req->src, @@ -3494,7 +3530,7 @@ static int ahash_final_ctx(struct ahash_request *req) gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; int buflen = *current_buflen(state); - int qm_sg_bytes, qm_sg_src_index; + int qm_sg_bytes; int digestsize = crypto_ahash_digestsize(ahash); struct ahash_edesc *edesc; struct dpaa2_sg_entry *sg_table; @@ -3505,8 +3541,7 @@ static int ahash_final_ctx(struct ahash_request *req) if (!edesc) return -ENOMEM; - qm_sg_src_index = 1 + (buflen ? 1 : 0); - qm_sg_bytes = qm_sg_src_index * sizeof(*sg_table); + qm_sg_bytes = pad_sg_nents(1 + (buflen ? 1 : 0)) * sizeof(*sg_table); sg_table = &edesc->sgt[0]; ret = ctx_map_to_qm_sg(ctx->dev, state, ctx->ctx_len, sg_table, @@ -3518,7 +3553,7 @@ static int ahash_final_ctx(struct ahash_request *req) if (ret) goto unmap_ctx; - dpaa2_sg_set_final(sg_table + qm_sg_src_index - 1, true); + dpaa2_sg_set_final(sg_table + (buflen ? 1 : 0), true); edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE); @@ -3599,7 +3634,8 @@ static int ahash_finup_ctx(struct ahash_request *req) edesc->src_nents = src_nents; qm_sg_src_index = 1 + (buflen ? 1 : 0); - qm_sg_bytes = (qm_sg_src_index + mapped_nents) * sizeof(*sg_table); + qm_sg_bytes = pad_sg_nents(qm_sg_src_index + mapped_nents) * + sizeof(*sg_table); sg_table = &edesc->sgt[0]; ret = ctx_map_to_qm_sg(ctx->dev, state, ctx->ctx_len, sg_table, @@ -3611,7 +3647,7 @@ static int ahash_finup_ctx(struct ahash_request *req) if (ret) goto unmap_ctx; - sg_to_qm_sg_last(req->src, mapped_nents, sg_table + qm_sg_src_index, 0); + sg_to_qm_sg_last(req->src, req->nbytes, sg_table + qm_sg_src_index, 0); edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE); @@ -3696,8 +3732,8 @@ static int ahash_digest(struct ahash_request *req) int qm_sg_bytes; struct dpaa2_sg_entry *sg_table = &edesc->sgt[0]; - qm_sg_bytes = mapped_nents * sizeof(*sg_table); - sg_to_qm_sg_last(req->src, mapped_nents, sg_table, 0); + qm_sg_bytes = pad_sg_nents(mapped_nents) * sizeof(*sg_table); + sg_to_qm_sg_last(req->src, req->nbytes, sg_table, 0); edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE); if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) { @@ -3840,9 +3876,9 @@ static int ahash_update_no_ctx(struct ahash_request *req) if (to_hash) { struct dpaa2_sg_entry *sg_table; + int src_len = req->nbytes - *next_buflen; - src_nents = sg_nents_for_len(req->src, - req->nbytes - *next_buflen); + src_nents = sg_nents_for_len(req->src, src_len); if (src_nents < 0) { dev_err(ctx->dev, "Invalid number of src SG.\n"); return src_nents; @@ -3868,14 +3904,15 @@ static int ahash_update_no_ctx(struct ahash_request *req) } edesc->src_nents = src_nents; - qm_sg_bytes = (1 + mapped_nents) * sizeof(*sg_table); + qm_sg_bytes = pad_sg_nents(1 + mapped_nents) * + sizeof(*sg_table); sg_table = &edesc->sgt[0]; ret = buf_map_to_qm_sg(ctx->dev, sg_table, state); if (ret) goto unmap_ctx; - sg_to_qm_sg_last(req->src, mapped_nents, sg_table + 1, 0); + sg_to_qm_sg_last(req->src, src_len, sg_table + 1, 0); if (*next_buflen) scatterwalk_map_and_copy(next_buf, req->src, @@ -3987,14 +4024,14 @@ static int ahash_finup_no_ctx(struct ahash_request *req) } edesc->src_nents = src_nents; - qm_sg_bytes = (2 + mapped_nents) * sizeof(*sg_table); + qm_sg_bytes = pad_sg_nents(2 + mapped_nents) * sizeof(*sg_table); sg_table = &edesc->sgt[0]; ret = buf_map_to_qm_sg(ctx->dev, sg_table, state); if (ret) goto unmap; - sg_to_qm_sg_last(req->src, mapped_nents, sg_table + 1, 0); + sg_to_qm_sg_last(req->src, req->nbytes, sg_table + 1, 0); edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE); @@ -4064,9 +4101,9 @@ static int ahash_update_first(struct ahash_request *req) if (to_hash) { struct dpaa2_sg_entry *sg_table; + int src_len = req->nbytes - *next_buflen; - src_nents = sg_nents_for_len(req->src, - req->nbytes - (*next_buflen)); + src_nents = sg_nents_for_len(req->src, src_len); if (src_nents < 0) { dev_err(ctx->dev, "Invalid number of src SG.\n"); return src_nents; @@ -4101,8 +4138,9 @@ static int ahash_update_first(struct ahash_request *req) if (mapped_nents > 1) { int qm_sg_bytes; - sg_to_qm_sg_last(req->src, mapped_nents, sg_table, 0); - qm_sg_bytes = mapped_nents * sizeof(*sg_table); + sg_to_qm_sg_last(req->src, src_len, sg_table, 0); + qm_sg_bytes = pad_sg_nents(mapped_nents) * + sizeof(*sg_table); edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE); diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 7205d9f4029e..e4ac5d591ad6 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -82,14 +82,6 @@ #define HASH_MSG_LEN 8 #define MAX_CTX_LEN (HASH_MSG_LEN + SHA512_DIGEST_SIZE) -#ifdef DEBUG -/* for print_hex_dumps with line references */ -#define debug(format, arg...) printk(format, arg) -#else -#define debug(format, arg...) -#endif - - static struct list_head hash_list; /* ahash per-session context */ @@ -243,11 +235,10 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) ctx->ctx_len, true, ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma, desc_bytes(desc), ctx->dir); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "ahash update shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + + print_hex_dump_debug("ahash update shdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); /* ahash_update_first shared descriptor */ desc = ctx->sh_desc_update_first; @@ -255,11 +246,9 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) ctx->ctx_len, false, ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, desc_bytes(desc), ctx->dir); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "ahash update first shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("ahash update first shdesc@"__stringify(__LINE__) + ": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); /* ahash_final shared descriptor */ desc = ctx->sh_desc_fin; @@ -267,11 +256,10 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) ctx->ctx_len, true, ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, desc_bytes(desc), ctx->dir); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ahash final shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif + + print_hex_dump_debug("ahash final shdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); /* ahash_digest shared descriptor */ desc = ctx->sh_desc_digest; @@ -279,12 +267,10 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) ctx->ctx_len, false, ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, desc_bytes(desc), ctx->dir); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "ahash digest shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif + + print_hex_dump_debug("ahash digest shdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); return 0; } @@ -328,9 +314,9 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash) ctx->ctx_len, ctx->key_dma); dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, desc_bytes(desc), ctx->dir); - print_hex_dump_debug("axcbc update first shdesc@" __stringify(__LINE__)" : ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), - 1); + print_hex_dump_debug("axcbc update first shdesc@" __stringify(__LINE__) + " : ", DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); /* shared descriptor for ahash_digest */ desc = ctx->sh_desc_digest; @@ -377,8 +363,8 @@ static int acmac_set_sh_desc(struct crypto_ahash *ahash) ctx->ctx_len, 0); dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, desc_bytes(desc), ctx->dir); - print_hex_dump_debug("acmac update first shdesc@" __stringify(__LINE__)" : ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, + print_hex_dump_debug("acmac update first shdesc@" __stringify(__LINE__) + " : ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); /* shared descriptor for ahash_digest */ @@ -429,12 +415,11 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, u32 *keylen, u8 *key, append_seq_store(desc, digestsize, LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_CONTEXT); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "key_in@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, *keylen, 1); - print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("key_in@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, *keylen, 1); + print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); result.err = 0; init_completion(&result.completion); @@ -444,11 +429,10 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, u32 *keylen, u8 *key, /* in progress */ wait_for_completion(&result.completion); ret = result.err; -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "digested key@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, digestsize, 1); -#endif + + print_hex_dump_debug("digested key@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, + digestsize, 1); } dma_unmap_single(jrdev, key_dma, *keylen, DMA_BIDIRECTIONAL); @@ -463,15 +447,14 @@ static int ahash_setkey(struct crypto_ahash *ahash, const u8 *key, unsigned int keylen) { struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct device *jrdev = ctx->jrdev; int blocksize = crypto_tfm_alg_blocksize(&ahash->base); int digestsize = crypto_ahash_digestsize(ahash); struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctx->jrdev->parent); int ret; u8 *hashed_key = NULL; -#ifdef DEBUG - printk(KERN_ERR "keylen %d\n", keylen); -#endif + dev_dbg(jrdev, "keylen %d\n", keylen); if (keylen > blocksize) { hashed_key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA); @@ -600,11 +583,9 @@ static void ahash_done(struct device *jrdev, u32 *desc, u32 err, struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); int digestsize = crypto_ahash_digestsize(ahash); struct caam_hash_state *state = ahash_request_ctx(req); -#ifdef DEBUG struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); - dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); -#endif + dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); if (err) @@ -614,11 +595,9 @@ static void ahash_done(struct device *jrdev, u32 *desc, u32 err, memcpy(req->result, state->caam_ctx, digestsize); kfree(edesc); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, - ctx->ctx_len, 1); -#endif + print_hex_dump_debug("ctx@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, + ctx->ctx_len, 1); req->base.complete(&req->base, err); } @@ -631,11 +610,9 @@ static void ahash_done_bi(struct device *jrdev, u32 *desc, u32 err, struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); struct caam_hash_state *state = ahash_request_ctx(req); -#ifdef DEBUG int digestsize = crypto_ahash_digestsize(ahash); - dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); -#endif + dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); if (err) @@ -645,15 +622,13 @@ static void ahash_done_bi(struct device *jrdev, u32 *desc, u32 err, switch_buf(state); kfree(edesc); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, - ctx->ctx_len, 1); + print_hex_dump_debug("ctx@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, + ctx->ctx_len, 1); if (req->result) - print_hex_dump(KERN_ERR, "result@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->result, - digestsize, 1); -#endif + print_hex_dump_debug("result@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->result, + digestsize, 1); req->base.complete(&req->base, err); } @@ -666,11 +641,9 @@ static void ahash_done_ctx_src(struct device *jrdev, u32 *desc, u32 err, struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); int digestsize = crypto_ahash_digestsize(ahash); struct caam_hash_state *state = ahash_request_ctx(req); -#ifdef DEBUG struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); - dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); -#endif + dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); if (err) @@ -680,11 +653,9 @@ static void ahash_done_ctx_src(struct device *jrdev, u32 *desc, u32 err, memcpy(req->result, state->caam_ctx, digestsize); kfree(edesc); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, - ctx->ctx_len, 1); -#endif + print_hex_dump_debug("ctx@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, + ctx->ctx_len, 1); req->base.complete(&req->base, err); } @@ -697,11 +668,9 @@ static void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err, struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); struct caam_hash_state *state = ahash_request_ctx(req); -#ifdef DEBUG int digestsize = crypto_ahash_digestsize(ahash); - dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); -#endif + dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); if (err) @@ -711,15 +680,13 @@ static void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err, switch_buf(state); kfree(edesc); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, - ctx->ctx_len, 1); + print_hex_dump_debug("ctx@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, + ctx->ctx_len, 1); if (req->result) - print_hex_dump(KERN_ERR, "result@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->result, - digestsize, 1); -#endif + print_hex_dump_debug("result@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->result, + digestsize, 1); req->base.complete(&req->base, err); } @@ -759,9 +726,10 @@ static int ahash_edesc_add_src(struct caam_hash_ctx *ctx, if (nents > 1 || first_sg) { struct sec4_sg_entry *sg = edesc->sec4_sg; - unsigned int sgsize = sizeof(*sg) * (first_sg + nents); + unsigned int sgsize = sizeof(*sg) * + pad_sg_nents(first_sg + nents); - sg_to_sec4_sg_last(req->src, nents, sg + first_sg, 0); + sg_to_sec4_sg_last(req->src, to_hash, sg + first_sg, 0); src_dma = dma_map_single(ctx->jrdev, sg, sgsize, DMA_TO_DEVICE); if (dma_mapping_error(ctx->jrdev, src_dma)) { @@ -819,8 +787,10 @@ static int ahash_update_ctx(struct ahash_request *req) } if (to_hash) { - src_nents = sg_nents_for_len(req->src, - req->nbytes - (*next_buflen)); + int pad_nents; + int src_len = req->nbytes - *next_buflen; + + src_nents = sg_nents_for_len(req->src, src_len); if (src_nents < 0) { dev_err(jrdev, "Invalid number of src SG.\n"); return src_nents; @@ -838,15 +808,14 @@ static int ahash_update_ctx(struct ahash_request *req) } sec4_sg_src_index = 1 + (*buflen ? 1 : 0); - sec4_sg_bytes = (sec4_sg_src_index + mapped_nents) * - sizeof(struct sec4_sg_entry); + pad_nents = pad_sg_nents(sec4_sg_src_index + mapped_nents); + sec4_sg_bytes = pad_nents * sizeof(struct sec4_sg_entry); /* * allocate space for base edesc and hw desc commands, * link tables */ - edesc = ahash_edesc_alloc(ctx, sec4_sg_src_index + mapped_nents, - ctx->sh_desc_update, + edesc = ahash_edesc_alloc(ctx, pad_nents, ctx->sh_desc_update, ctx->sh_desc_update_dma, flags); if (!edesc) { dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE); @@ -866,7 +835,7 @@ static int ahash_update_ctx(struct ahash_request *req) goto unmap_ctx; if (mapped_nents) - sg_to_sec4_sg_last(req->src, mapped_nents, + sg_to_sec4_sg_last(req->src, src_len, edesc->sec4_sg + sec4_sg_src_index, 0); else @@ -893,11 +862,9 @@ static int ahash_update_ctx(struct ahash_request *req) append_seq_out_ptr(desc, state->ctx_dma, ctx->ctx_len, 0); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif + print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); ret = caam_jr_enqueue(jrdev, desc, ahash_done_bi, req); if (ret) @@ -910,13 +877,12 @@ static int ahash_update_ctx(struct ahash_request *req) *buflen = *next_buflen; *next_buflen = last_buflen; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "buf@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1); - print_hex_dump(KERN_ERR, "next buf@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, next_buf, - *next_buflen, 1); -#endif + + print_hex_dump_debug("buf@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1); + print_hex_dump_debug("next buf@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, next_buf, + *next_buflen, 1); return ret; unmap_ctx: @@ -935,18 +901,17 @@ static int ahash_final_ctx(struct ahash_request *req) GFP_KERNEL : GFP_ATOMIC; int buflen = *current_buflen(state); u32 *desc; - int sec4_sg_bytes, sec4_sg_src_index; + int sec4_sg_bytes; int digestsize = crypto_ahash_digestsize(ahash); struct ahash_edesc *edesc; int ret; - sec4_sg_src_index = 1 + (buflen ? 1 : 0); - sec4_sg_bytes = sec4_sg_src_index * sizeof(struct sec4_sg_entry); + sec4_sg_bytes = pad_sg_nents(1 + (buflen ? 1 : 0)) * + sizeof(struct sec4_sg_entry); /* allocate space for base edesc and hw desc commands, link tables */ - edesc = ahash_edesc_alloc(ctx, sec4_sg_src_index, - ctx->sh_desc_fin, ctx->sh_desc_fin_dma, - flags); + edesc = ahash_edesc_alloc(ctx, 4, ctx->sh_desc_fin, + ctx->sh_desc_fin_dma, flags); if (!edesc) return -ENOMEM; @@ -963,7 +928,7 @@ static int ahash_final_ctx(struct ahash_request *req) if (ret) goto unmap_ctx; - sg_to_sec4_set_last(edesc->sec4_sg + sec4_sg_src_index - 1); + sg_to_sec4_set_last(edesc->sec4_sg + (buflen ? 1 : 0)); edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, sec4_sg_bytes, DMA_TO_DEVICE); @@ -977,10 +942,9 @@ static int ahash_final_ctx(struct ahash_request *req) LDST_SGF); append_seq_out_ptr(desc, state->ctx_dma, digestsize, 0); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_src, req); if (ret) @@ -1058,10 +1022,9 @@ static int ahash_finup_ctx(struct ahash_request *req) append_seq_out_ptr(desc, state->ctx_dma, digestsize, 0); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_src, req); if (ret) @@ -1135,10 +1098,9 @@ static int ahash_digest(struct ahash_request *req) return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); ret = caam_jr_enqueue(jrdev, desc, ahash_done, req); if (!ret) { @@ -1190,10 +1152,9 @@ static int ahash_final_no_ctx(struct ahash_request *req) if (ret) goto unmap; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); ret = caam_jr_enqueue(jrdev, desc, ahash_done, req); if (!ret) { @@ -1246,8 +1207,10 @@ static int ahash_update_no_ctx(struct ahash_request *req) } if (to_hash) { - src_nents = sg_nents_for_len(req->src, - req->nbytes - *next_buflen); + int pad_nents; + int src_len = req->nbytes - *next_buflen; + + src_nents = sg_nents_for_len(req->src, src_len); if (src_nents < 0) { dev_err(jrdev, "Invalid number of src SG.\n"); return src_nents; @@ -1264,14 +1227,14 @@ static int ahash_update_no_ctx(struct ahash_request *req) mapped_nents = 0; } - sec4_sg_bytes = (1 + mapped_nents) * - sizeof(struct sec4_sg_entry); + pad_nents = pad_sg_nents(1 + mapped_nents); + sec4_sg_bytes = pad_nents * sizeof(struct sec4_sg_entry); /* * allocate space for base edesc and hw desc commands, * link tables */ - edesc = ahash_edesc_alloc(ctx, 1 + mapped_nents, + edesc = ahash_edesc_alloc(ctx, pad_nents, ctx->sh_desc_update_first, ctx->sh_desc_update_first_dma, flags); @@ -1287,8 +1250,7 @@ static int ahash_update_no_ctx(struct ahash_request *req) if (ret) goto unmap_ctx; - sg_to_sec4_sg_last(req->src, mapped_nents, - edesc->sec4_sg + 1, 0); + sg_to_sec4_sg_last(req->src, src_len, edesc->sec4_sg + 1, 0); if (*next_buflen) { scatterwalk_map_and_copy(next_buf, req->src, @@ -1313,11 +1275,9 @@ static int ahash_update_no_ctx(struct ahash_request *req) if (ret) goto unmap_ctx; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif + print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_dst, req); if (ret) @@ -1333,13 +1293,12 @@ static int ahash_update_no_ctx(struct ahash_request *req) *buflen = *next_buflen; *next_buflen = 0; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "buf@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1); - print_hex_dump(KERN_ERR, "next buf@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, next_buf, - *next_buflen, 1); -#endif + + print_hex_dump_debug("buf@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1); + print_hex_dump_debug("next buf@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen, + 1); return ret; unmap_ctx: @@ -1414,10 +1373,9 @@ static int ahash_finup_no_ctx(struct ahash_request *req) if (ret) goto unmap; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); ret = caam_jr_enqueue(jrdev, desc, ahash_done, req); if (!ret) { @@ -1517,11 +1475,9 @@ static int ahash_update_first(struct ahash_request *req) if (ret) goto unmap_ctx; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif + print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_dst, req); if (ret) @@ -1539,11 +1495,10 @@ static int ahash_update_first(struct ahash_request *req) req->nbytes, 0); switch_buf(state); } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "next buf@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, next_buf, - *next_buflen, 1); -#endif + + print_hex_dump_debug("next buf@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen, + 1); return ret; unmap_ctx: @@ -1930,7 +1885,7 @@ static void caam_hash_cra_exit(struct crypto_tfm *tfm) caam_jr_free(ctx->jrdev); } -static void __exit caam_algapi_hash_exit(void) +void caam_algapi_hash_exit(void) { struct caam_hash_alg *t_alg, *n; @@ -1988,40 +1943,13 @@ caam_hash_alloc(struct caam_hash_template *template, return t_alg; } -static int __init caam_algapi_hash_init(void) +int caam_algapi_hash_init(struct device *ctrldev) { - struct device_node *dev_node; - struct platform_device *pdev; int i = 0, err = 0; - struct caam_drv_private *priv; + struct caam_drv_private *priv = dev_get_drvdata(ctrldev); unsigned int md_limit = SHA512_DIGEST_SIZE; u32 md_inst, md_vid; - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) { - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); - if (!dev_node) - return -ENODEV; - } - - pdev = of_find_device_by_node(dev_node); - if (!pdev) { - of_node_put(dev_node); - return -ENODEV; - } - - priv = dev_get_drvdata(&pdev->dev); - of_node_put(dev_node); - - /* - * If priv is NULL, it's probably because the caam driver wasn't - * properly initialized (e.g. RNG4 init failed). Thus, bail out here. - */ - if (!priv) { - err = -ENODEV; - goto out_put_dev; - } - /* * Register crypto algorithms the device supports. First, identify * presence and attributes of MD block. @@ -2042,10 +1970,8 @@ static int __init caam_algapi_hash_init(void) * Skip registration of any hashing algorithms if MD block * is not present. */ - if (!md_inst) { - err = -ENODEV; - goto out_put_dev; - } + if (!md_inst) + return -ENODEV; /* Limit digest size based on LP256 */ if (md_vid == CHA_VER_VID_MD_LP256) @@ -2102,14 +2028,5 @@ static int __init caam_algapi_hash_init(void) list_add_tail(&t_alg->entry, &hash_list); } -out_put_dev: - put_device(&pdev->dev); return err; } - -module_init(caam_algapi_hash_init); -module_exit(caam_algapi_hash_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("FSL CAAM support for ahash functions of crypto API"); -MODULE_AUTHOR("Freescale Semiconductor - NMG"); diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c index fe24485274e1..80574106af29 100644 --- a/drivers/crypto/caam/caampkc.c +++ b/drivers/crypto/caam/caampkc.c @@ -3,7 +3,7 @@ * caam - Freescale FSL CAAM support for Public Key Cryptography * * Copyright 2016 Freescale Semiconductor, Inc. - * Copyright 2018 NXP + * Copyright 2018-2019 NXP * * There is no Shared Descriptor for PKC so that the Job Descriptor must carry * all the desired key parameters, input and output pointers. @@ -24,12 +24,18 @@ sizeof(struct rsa_priv_f2_pdb)) #define DESC_RSA_PRIV_F3_LEN (2 * CAAM_CMD_SZ + \ sizeof(struct rsa_priv_f3_pdb)) +#define CAAM_RSA_MAX_INPUT_SIZE 512 /* for a 4096-bit modulus */ + +/* buffer filled with zeros, used for padding */ +static u8 *zero_buffer; static void rsa_io_unmap(struct device *dev, struct rsa_edesc *edesc, struct akcipher_request *req) { + struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req); + dma_unmap_sg(dev, req->dst, edesc->dst_nents, DMA_FROM_DEVICE); - dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE); + dma_unmap_sg(dev, req_ctx->fixup_src, edesc->src_nents, DMA_TO_DEVICE); if (edesc->sec4_sg_bytes) dma_unmap_single(dev, edesc->sec4_sg_dma, edesc->sec4_sg_bytes, @@ -168,6 +174,13 @@ static void rsa_priv_f3_done(struct device *dev, u32 *desc, u32 err, akcipher_request_complete(req, err); } +/** + * Count leading zeros, need it to strip, from a given scatterlist + * + * @sgl : scatterlist to count zeros from + * @nbytes: number of zeros, in bytes, to strip + * @flags : operation flags + */ static int caam_rsa_count_leading_zeros(struct scatterlist *sgl, unsigned int nbytes, unsigned int flags) @@ -187,7 +200,8 @@ static int caam_rsa_count_leading_zeros(struct scatterlist *sgl, lzeros = 0; len = 0; while (nbytes > 0) { - while (len && !*buff) { + /* do not strip more than given bytes */ + while (len && !*buff && lzeros < nbytes) { lzeros++; len--; buff++; @@ -218,6 +232,7 @@ static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req, struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); struct device *dev = ctx->dev; struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req); + struct caam_rsa_key *key = &ctx->key; struct rsa_edesc *edesc; gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; @@ -225,22 +240,45 @@ static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req, int sgc; int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes; int src_nents, dst_nents; + unsigned int diff_size = 0; int lzeros; - lzeros = caam_rsa_count_leading_zeros(req->src, req->src_len, sg_flags); - if (lzeros < 0) - return ERR_PTR(lzeros); - - req->src_len -= lzeros; - req->src = scatterwalk_ffwd(req_ctx->src, req->src, lzeros); + if (req->src_len > key->n_sz) { + /* + * strip leading zeros and + * return the number of zeros to skip + */ + lzeros = caam_rsa_count_leading_zeros(req->src, req->src_len - + key->n_sz, sg_flags); + if (lzeros < 0) + return ERR_PTR(lzeros); + + req_ctx->fixup_src = scatterwalk_ffwd(req_ctx->src, req->src, + lzeros); + req_ctx->fixup_src_len = req->src_len - lzeros; + } else { + /* + * input src is less then n key modulus, + * so there will be zero padding + */ + diff_size = key->n_sz - req->src_len; + req_ctx->fixup_src = req->src; + req_ctx->fixup_src_len = req->src_len; + } - src_nents = sg_nents_for_len(req->src, req->src_len); + src_nents = sg_nents_for_len(req_ctx->fixup_src, + req_ctx->fixup_src_len); dst_nents = sg_nents_for_len(req->dst, req->dst_len); - if (src_nents > 1) - sec4_sg_len = src_nents; + if (!diff_size && src_nents == 1) + sec4_sg_len = 0; /* no need for an input hw s/g table */ + else + sec4_sg_len = src_nents + !!diff_size; + sec4_sg_index = sec4_sg_len; if (dst_nents > 1) - sec4_sg_len += dst_nents; + sec4_sg_len += pad_sg_nents(dst_nents); + else + sec4_sg_len = pad_sg_nents(sec4_sg_len); sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry); @@ -250,7 +288,7 @@ static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req, if (!edesc) return ERR_PTR(-ENOMEM); - sgc = dma_map_sg(dev, req->src, src_nents, DMA_TO_DEVICE); + sgc = dma_map_sg(dev, req_ctx->fixup_src, src_nents, DMA_TO_DEVICE); if (unlikely(!sgc)) { dev_err(dev, "unable to map source\n"); goto src_fail; @@ -263,14 +301,16 @@ static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req, } edesc->sec4_sg = (void *)edesc + sizeof(*edesc) + desclen; + if (diff_size) + dma_to_sec4_sg_one(edesc->sec4_sg, ctx->padding_dma, diff_size, + 0); + + if (sec4_sg_index) + sg_to_sec4_sg_last(req_ctx->fixup_src, req_ctx->fixup_src_len, + edesc->sec4_sg + !!diff_size, 0); - sec4_sg_index = 0; - if (src_nents > 1) { - sg_to_sec4_sg_last(req->src, src_nents, edesc->sec4_sg, 0); - sec4_sg_index += src_nents; - } if (dst_nents > 1) - sg_to_sec4_sg_last(req->dst, dst_nents, + sg_to_sec4_sg_last(req->dst, req->dst_len, edesc->sec4_sg + sec4_sg_index, 0); /* Save nents for later use in Job Descriptor */ @@ -289,12 +329,16 @@ static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req, edesc->sec4_sg_bytes = sec4_sg_bytes; + print_hex_dump_debug("caampkc sec4_sg@" __stringify(__LINE__) ": ", + DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg, + edesc->sec4_sg_bytes, 1); + return edesc; sec4_sg_fail: dma_unmap_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE); dst_fail: - dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE); + dma_unmap_sg(dev, req_ctx->fixup_src, src_nents, DMA_TO_DEVICE); src_fail: kfree(edesc); return ERR_PTR(-ENOMEM); @@ -304,6 +348,7 @@ static int set_rsa_pub_pdb(struct akcipher_request *req, struct rsa_edesc *edesc) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req); struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); struct caam_rsa_key *key = &ctx->key; struct device *dev = ctx->dev; @@ -328,7 +373,7 @@ static int set_rsa_pub_pdb(struct akcipher_request *req, pdb->f_dma = edesc->sec4_sg_dma; sec4_sg_index += edesc->src_nents; } else { - pdb->f_dma = sg_dma_address(req->src); + pdb->f_dma = sg_dma_address(req_ctx->fixup_src); } if (edesc->dst_nents > 1) { @@ -340,7 +385,7 @@ static int set_rsa_pub_pdb(struct akcipher_request *req, } pdb->sgf |= (key->e_sz << RSA_PDB_E_SHIFT) | key->n_sz; - pdb->f_len = req->src_len; + pdb->f_len = req_ctx->fixup_src_len; return 0; } @@ -373,7 +418,9 @@ static int set_rsa_priv_f1_pdb(struct akcipher_request *req, pdb->g_dma = edesc->sec4_sg_dma; sec4_sg_index += edesc->src_nents; } else { - pdb->g_dma = sg_dma_address(req->src); + struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req); + + pdb->g_dma = sg_dma_address(req_ctx->fixup_src); } if (edesc->dst_nents > 1) { @@ -436,7 +483,9 @@ static int set_rsa_priv_f2_pdb(struct akcipher_request *req, pdb->g_dma = edesc->sec4_sg_dma; sec4_sg_index += edesc->src_nents; } else { - pdb->g_dma = sg_dma_address(req->src); + struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req); + + pdb->g_dma = sg_dma_address(req_ctx->fixup_src); } if (edesc->dst_nents > 1) { @@ -523,7 +572,9 @@ static int set_rsa_priv_f3_pdb(struct akcipher_request *req, pdb->g_dma = edesc->sec4_sg_dma; sec4_sg_index += edesc->src_nents; } else { - pdb->g_dma = sg_dma_address(req->src); + struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req); + + pdb->g_dma = sg_dma_address(req_ctx->fixup_src); } if (edesc->dst_nents > 1) { @@ -978,6 +1029,15 @@ static int caam_rsa_init_tfm(struct crypto_akcipher *tfm) return PTR_ERR(ctx->dev); } + ctx->padding_dma = dma_map_single(ctx->dev, zero_buffer, + CAAM_RSA_MAX_INPUT_SIZE - 1, + DMA_TO_DEVICE); + if (dma_mapping_error(ctx->dev, ctx->padding_dma)) { + dev_err(ctx->dev, "unable to map padding\n"); + caam_jr_free(ctx->dev); + return -ENOMEM; + } + return 0; } @@ -987,6 +1047,8 @@ static void caam_rsa_exit_tfm(struct crypto_akcipher *tfm) struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); struct caam_rsa_key *key = &ctx->key; + dma_unmap_single(ctx->dev, ctx->padding_dma, CAAM_RSA_MAX_INPUT_SIZE - + 1, DMA_TO_DEVICE); caam_rsa_free_key(key); caam_jr_free(ctx->dev); } @@ -1010,41 +1072,12 @@ static struct akcipher_alg caam_rsa = { }; /* Public Key Cryptography module initialization handler */ -static int __init caam_pkc_init(void) +int caam_pkc_init(struct device *ctrldev) { - struct device_node *dev_node; - struct platform_device *pdev; - struct device *ctrldev; - struct caam_drv_private *priv; + struct caam_drv_private *priv = dev_get_drvdata(ctrldev); u32 pk_inst; int err; - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) { - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); - if (!dev_node) - return -ENODEV; - } - - pdev = of_find_device_by_node(dev_node); - if (!pdev) { - of_node_put(dev_node); - return -ENODEV; - } - - ctrldev = &pdev->dev; - priv = dev_get_drvdata(ctrldev); - of_node_put(dev_node); - - /* - * If priv is NULL, it's probably because the caam driver wasn't - * properly initialized (e.g. RNG4 init failed). Thus, bail out here. - */ - if (!priv) { - err = -ENODEV; - goto out_put_dev; - } - /* Determine public key hardware accelerator presence. */ if (priv->era < 10) pk_inst = (rd_reg32(&priv->ctrl->perfmon.cha_num_ls) & @@ -1053,31 +1086,29 @@ static int __init caam_pkc_init(void) pk_inst = rd_reg32(&priv->ctrl->vreg.pkha) & CHA_VER_NUM_MASK; /* Do not register algorithms if PKHA is not present. */ - if (!pk_inst) { - err = -ENODEV; - goto out_put_dev; - } + if (!pk_inst) + return 0; + + /* allocate zero buffer, used for padding input */ + zero_buffer = kzalloc(CAAM_RSA_MAX_INPUT_SIZE - 1, GFP_DMA | + GFP_KERNEL); + if (!zero_buffer) + return -ENOMEM; err = crypto_register_akcipher(&caam_rsa); - if (err) + if (err) { + kfree(zero_buffer); dev_warn(ctrldev, "%s alg registration failed\n", caam_rsa.base.cra_driver_name); - else + } else { dev_info(ctrldev, "caam pkc algorithms registered in /proc/crypto\n"); + } -out_put_dev: - put_device(ctrldev); return err; } -static void __exit caam_pkc_exit(void) +void caam_pkc_exit(void) { + kfree(zero_buffer); crypto_unregister_akcipher(&caam_rsa); } - -module_init(caam_pkc_init); -module_exit(caam_pkc_exit); - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_DESCRIPTION("FSL CAAM support for PKC functions of crypto API"); -MODULE_AUTHOR("Freescale Semiconductor"); diff --git a/drivers/crypto/caam/caampkc.h b/drivers/crypto/caam/caampkc.h index 82645bcf8b27..2c488c9a3812 100644 --- a/drivers/crypto/caam/caampkc.h +++ b/drivers/crypto/caam/caampkc.h @@ -89,18 +89,25 @@ struct caam_rsa_key { * caam_rsa_ctx - per session context. * @key : RSA key in DMA zone * @dev : device structure + * @padding_dma : dma address of padding, for adding it to the input */ struct caam_rsa_ctx { struct caam_rsa_key key; struct device *dev; + dma_addr_t padding_dma; + }; /** * caam_rsa_req_ctx - per request context. - * @src: input scatterlist (stripped of leading zeros) + * @src : input scatterlist (stripped of leading zeros) + * @fixup_src : input scatterlist (that might be stripped of leading zeros) + * @fixup_src_len : length of the fixup_src input scatterlist */ struct caam_rsa_req_ctx { struct scatterlist src[2]; + struct scatterlist *fixup_src; + unsigned int fixup_src_len; }; /** diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index 95eb5402c59f..561bcb535184 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -3,7 +3,7 @@ * caam - Freescale FSL CAAM support for hw_random * * Copyright 2011 Freescale Semiconductor, Inc. - * Copyright 2018 NXP + * Copyright 2018-2019 NXP * * Based on caamalg.c crypto API driver. * @@ -113,10 +113,8 @@ static void rng_done(struct device *jrdev, u32 *desc, u32 err, void *context) /* Buffer refilled, invalidate cache */ dma_sync_single_for_cpu(jrdev, bd->addr, RN_BUF_SIZE, DMA_FROM_DEVICE); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "rng refreshed buf@: ", - DUMP_PREFIX_ADDRESS, 16, 4, bd->buf, RN_BUF_SIZE, 1); -#endif + print_hex_dump_debug("rng refreshed buf@: ", DUMP_PREFIX_ADDRESS, 16, 4, + bd->buf, RN_BUF_SIZE, 1); } static inline int submit_job(struct caam_rng_ctx *ctx, int to_current) @@ -209,10 +207,10 @@ static inline int rng_create_sh_desc(struct caam_rng_ctx *ctx) dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "rng shdesc@: ", DUMP_PREFIX_ADDRESS, 16, 4, - desc, desc_bytes(desc), 1); -#endif + + print_hex_dump_debug("rng shdesc@: ", DUMP_PREFIX_ADDRESS, 16, 4, + desc, desc_bytes(desc), 1); + return 0; } @@ -233,10 +231,10 @@ static inline int rng_create_job_desc(struct caam_rng_ctx *ctx, int buf_id) } append_seq_out_ptr_intlen(desc, bd->addr, RN_BUF_SIZE, 0); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "rng job desc@: ", DUMP_PREFIX_ADDRESS, 16, 4, - desc, desc_bytes(desc), 1); -#endif + + print_hex_dump_debug("rng job desc@: ", DUMP_PREFIX_ADDRESS, 16, 4, + desc, desc_bytes(desc), 1); + return 0; } @@ -296,47 +294,20 @@ static struct hwrng caam_rng = { .read = caam_read, }; -static void __exit caam_rng_exit(void) +void caam_rng_exit(void) { caam_jr_free(rng_ctx->jrdev); hwrng_unregister(&caam_rng); kfree(rng_ctx); } -static int __init caam_rng_init(void) +int caam_rng_init(struct device *ctrldev) { struct device *dev; - struct device_node *dev_node; - struct platform_device *pdev; - struct caam_drv_private *priv; u32 rng_inst; + struct caam_drv_private *priv = dev_get_drvdata(ctrldev); int err; - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) { - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); - if (!dev_node) - return -ENODEV; - } - - pdev = of_find_device_by_node(dev_node); - if (!pdev) { - of_node_put(dev_node); - return -ENODEV; - } - - priv = dev_get_drvdata(&pdev->dev); - of_node_put(dev_node); - - /* - * If priv is NULL, it's probably because the caam driver wasn't - * properly initialized (e.g. RNG4 init failed). Thus, bail out here. - */ - if (!priv) { - err = -ENODEV; - goto out_put_dev; - } - /* Check for an instantiated RNG before registration */ if (priv->era < 10) rng_inst = (rd_reg32(&priv->ctrl->perfmon.cha_num_ls) & @@ -344,16 +315,13 @@ static int __init caam_rng_init(void) else rng_inst = rd_reg32(&priv->ctrl->vreg.rng) & CHA_VER_NUM_MASK; - if (!rng_inst) { - err = -ENODEV; - goto out_put_dev; - } + if (!rng_inst) + return 0; dev = caam_jr_alloc(); if (IS_ERR(dev)) { pr_err("Job Ring Device allocation for transform failed\n"); - err = PTR_ERR(dev); - goto out_put_dev; + return PTR_ERR(dev); } rng_ctx = kmalloc(sizeof(*rng_ctx), GFP_DMA | GFP_KERNEL); if (!rng_ctx) { @@ -364,7 +332,6 @@ static int __init caam_rng_init(void) if (err) goto free_rng_ctx; - put_device(&pdev->dev); dev_info(dev, "registering rng-caam\n"); return hwrng_register(&caam_rng); @@ -372,14 +339,5 @@ free_rng_ctx: kfree(rng_ctx); free_caam_alloc: caam_jr_free(dev); -out_put_dev: - put_device(&pdev->dev); return err; } - -module_init(caam_rng_init); -module_exit(caam_rng_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("FSL CAAM support for hw_random API"); -MODULE_AUTHOR("Freescale Semiconductor - NMG"); diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index fec39c35c877..4e43ca4d3656 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -3,7 +3,7 @@ * Controller-level driver, kernel property detection, initialization * * Copyright 2008-2012 Freescale Semiconductor, Inc. - * Copyright 2018 NXP + * Copyright 2018-2019 NXP */ #include <linux/device.h> @@ -323,8 +323,8 @@ static int caam_remove(struct platform_device *pdev) of_platform_depopulate(ctrldev); #ifdef CONFIG_CAAM_QI - if (ctrlpriv->qidev) - caam_qi_shutdown(ctrlpriv->qidev); + if (ctrlpriv->qi_init) + caam_qi_shutdown(ctrldev); #endif /* @@ -540,7 +540,8 @@ static int caam_probe(struct platform_device *pdev) ctrlpriv->caam_ipg = clk; if (!of_machine_is_compatible("fsl,imx7d") && - !of_machine_is_compatible("fsl,imx7s")) { + !of_machine_is_compatible("fsl,imx7s") && + !of_machine_is_compatible("fsl,imx7ulp")) { clk = caam_drv_identify_clk(&pdev->dev, "mem"); if (IS_ERR(clk)) { ret = PTR_ERR(clk); @@ -562,7 +563,8 @@ static int caam_probe(struct platform_device *pdev) if (!of_machine_is_compatible("fsl,imx6ul") && !of_machine_is_compatible("fsl,imx7d") && - !of_machine_is_compatible("fsl,imx7s")) { + !of_machine_is_compatible("fsl,imx7s") && + !of_machine_is_compatible("fsl,imx7ulp")) { clk = caam_drv_identify_clk(&pdev->dev, "emi_slow"); if (IS_ERR(clk)) { ret = PTR_ERR(clk); @@ -702,12 +704,7 @@ static int caam_probe(struct platform_device *pdev) } ctrlpriv->era = caam_get_era(ctrl); - - ret = of_platform_populate(nprop, caam_match, NULL, dev); - if (ret) { - dev_err(dev, "JR platform devices creation error\n"); - goto iounmap_ctrl; - } + ctrlpriv->domain = iommu_get_domain_for_dev(dev); #ifdef CONFIG_DEBUG_FS /* @@ -721,19 +718,6 @@ static int caam_probe(struct platform_device *pdev) ctrlpriv->ctl = debugfs_create_dir("ctl", ctrlpriv->dfs_root); #endif - ring = 0; - for_each_available_child_of_node(nprop, np) - if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") || - of_device_is_compatible(np, "fsl,sec4.0-job-ring")) { - ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *) - ((__force uint8_t *)ctrl + - (ring + JR_BLOCK_NUMBER) * - BLOCK_OFFSET - ); - ctrlpriv->total_jobrs++; - ring++; - } - /* Check to see if (DPAA 1.x) QI present. If so, enable */ ctrlpriv->qi_present = !!(comp_params & CTPR_MS_QI_MASK); if (ctrlpriv->qi_present && !caam_dpaa2) { @@ -752,6 +736,25 @@ static int caam_probe(struct platform_device *pdev) #endif } + ret = of_platform_populate(nprop, caam_match, NULL, dev); + if (ret) { + dev_err(dev, "JR platform devices creation error\n"); + goto shutdown_qi; + } + + ring = 0; + for_each_available_child_of_node(nprop, np) + if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") || + of_device_is_compatible(np, "fsl,sec4.0-job-ring")) { + ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *) + ((__force uint8_t *)ctrl + + (ring + JR_BLOCK_NUMBER) * + BLOCK_OFFSET + ); + ctrlpriv->total_jobrs++; + ring++; + } + /* If no QI and no rings specified, quit and go home */ if ((!ctrlpriv->qi_present) && (!ctrlpriv->total_jobrs)) { dev_err(dev, "no queues configured, terminating\n"); @@ -898,6 +901,11 @@ caam_remove: caam_remove(pdev); return ret; +shutdown_qi: +#ifdef CONFIG_CAAM_QI + if (ctrlpriv->qi_init) + caam_qi_shutdown(dev); +#endif iounmap_ctrl: iounmap(ctrl); disable_caam_emi_slow: diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h index 2980b8ef1fb1..5988a26a2441 100644 --- a/drivers/crypto/caam/desc_constr.h +++ b/drivers/crypto/caam/desc_constr.h @@ -3,6 +3,7 @@ * caam descriptor construction helper functions * * Copyright 2008-2012 Freescale Semiconductor, Inc. + * Copyright 2019 NXP */ #ifndef DESC_CONSTR_H @@ -37,6 +38,16 @@ extern bool caam_little_end; +/* + * HW fetches 4 S/G table entries at a time, irrespective of how many entries + * are in the table. It's SW's responsibility to make sure these accesses + * do not have side effects. + */ +static inline int pad_sg_nents(int sg_nents) +{ + return ALIGN(sg_nents, 4); +} + static inline int desc_len(u32 * const desc) { return caam32_to_cpu(*desc) & HDR_DESCLEN_MASK; diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c index 4da844e4b61d..4f0d45865aa2 100644 --- a/drivers/crypto/caam/error.c +++ b/drivers/crypto/caam/error.c @@ -13,7 +13,7 @@ #ifdef DEBUG #include <linux/highmem.h> -void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type, +void caam_dump_sg(const char *prefix_str, int prefix_type, int rowsize, int groupsize, struct scatterlist *sg, size_t tlen, bool ascii) { @@ -35,15 +35,15 @@ void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type, buf = it_page + it->offset; len = min_t(size_t, tlen, it->length); - print_hex_dump(level, prefix_str, prefix_type, rowsize, - groupsize, buf, len, ascii); + print_hex_dump_debug(prefix_str, prefix_type, rowsize, + groupsize, buf, len, ascii); tlen -= len; kunmap_atomic(it_page); } } #else -void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type, +void caam_dump_sg(const char *prefix_str, int prefix_type, int rowsize, int groupsize, struct scatterlist *sg, size_t tlen, bool ascii) {} diff --git a/drivers/crypto/caam/error.h b/drivers/crypto/caam/error.h index 8c6b83e02a70..d9726e66edbf 100644 --- a/drivers/crypto/caam/error.h +++ b/drivers/crypto/caam/error.h @@ -17,7 +17,7 @@ void caam_strstatus(struct device *dev, u32 status, bool qi_v2); #define caam_jr_strstatus(jrdev, status) caam_strstatus(jrdev, status, false) #define caam_qi2_strstatus(qidev, status) caam_strstatus(qidev, status, true) -void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type, +void caam_dump_sg(const char *prefix_str, int prefix_type, int rowsize, int groupsize, struct scatterlist *sg, size_t tlen, bool ascii); diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h index 3392615dc91b..6af84bbc612c 100644 --- a/drivers/crypto/caam/intern.h +++ b/drivers/crypto/caam/intern.h @@ -4,7 +4,7 @@ * Private/internal definitions between modules * * Copyright 2008-2011 Freescale Semiconductor, Inc. - * + * Copyright 2019 NXP */ #ifndef INTERN_H @@ -63,10 +63,6 @@ struct caam_drv_private_jr { * Driver-private storage for a single CAAM block instance */ struct caam_drv_private { -#ifdef CONFIG_CAAM_QI - struct device *qidev; -#endif - /* Physical-presence section */ struct caam_ctrl __iomem *ctrl; /* controller region */ struct caam_deco __iomem *deco; /* DECO/CCB views */ @@ -74,12 +70,17 @@ struct caam_drv_private { struct caam_queue_if __iomem *qi; /* QI control region */ struct caam_job_ring __iomem *jr[4]; /* JobR's register space */ + struct iommu_domain *domain; + /* * Detected geometry block. Filled in from device tree if powerpc, * or from register-based version detection code */ u8 total_jobrs; /* Total Job Rings in device */ u8 qi_present; /* Nonzero if QI present in device */ +#ifdef CONFIG_CAAM_QI + u8 qi_init; /* Nonzero if QI has been initialized */ +#endif u8 mc_en; /* Nonzero if MC f/w is active */ int secvio_irq; /* Security violation interrupt number */ int virt_en; /* Virtualization enabled in CAAM */ @@ -107,8 +108,95 @@ struct caam_drv_private { #endif }; -void caam_jr_algapi_init(struct device *dev); -void caam_jr_algapi_remove(struct device *dev); +#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API + +int caam_algapi_init(struct device *dev); +void caam_algapi_exit(void); + +#else + +static inline int caam_algapi_init(struct device *dev) +{ + return 0; +} + +static inline void caam_algapi_exit(void) +{ +} + +#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API */ + +#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API + +int caam_algapi_hash_init(struct device *dev); +void caam_algapi_hash_exit(void); + +#else + +static inline int caam_algapi_hash_init(struct device *dev) +{ + return 0; +} + +static inline void caam_algapi_hash_exit(void) +{ +} + +#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API */ + +#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API + +int caam_pkc_init(struct device *dev); +void caam_pkc_exit(void); + +#else + +static inline int caam_pkc_init(struct device *dev) +{ + return 0; +} + +static inline void caam_pkc_exit(void) +{ +} + +#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API */ + +#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API + +int caam_rng_init(struct device *dev); +void caam_rng_exit(void); + +#else + +static inline int caam_rng_init(struct device *dev) +{ + return 0; +} + +static inline void caam_rng_exit(void) +{ +} + +#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API */ + +#ifdef CONFIG_CAAM_QI + +int caam_qi_algapi_init(struct device *dev); +void caam_qi_algapi_exit(void); + +#else + +static inline int caam_qi_algapi_init(struct device *dev) +{ + return 0; +} + +static inline void caam_qi_algapi_exit(void) +{ +} + +#endif /* CONFIG_CAAM_QI */ #ifdef CONFIG_DEBUG_FS static int caam_debugfs_u64_get(void *data, u64 *val) diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index 1de2562d0982..cea811fed320 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -4,6 +4,7 @@ * JobR backend functionality * * Copyright 2008-2012 Freescale Semiconductor, Inc. + * Copyright 2019 NXP */ #include <linux/of_irq.h> @@ -23,6 +24,43 @@ struct jr_driver_data { } ____cacheline_aligned; static struct jr_driver_data driver_data; +static DEFINE_MUTEX(algs_lock); +static unsigned int active_devs; + +static void register_algs(struct device *dev) +{ + mutex_lock(&algs_lock); + + if (++active_devs != 1) + goto algs_unlock; + + caam_algapi_init(dev); + caam_algapi_hash_init(dev); + caam_pkc_init(dev); + caam_rng_init(dev); + caam_qi_algapi_init(dev); + +algs_unlock: + mutex_unlock(&algs_lock); +} + +static void unregister_algs(void) +{ + mutex_lock(&algs_lock); + + if (--active_devs != 0) + goto algs_unlock; + + caam_qi_algapi_exit(); + + caam_rng_exit(); + caam_pkc_exit(); + caam_algapi_hash_exit(); + caam_algapi_exit(); + +algs_unlock: + mutex_unlock(&algs_lock); +} static int caam_reset_hw_jr(struct device *dev) { @@ -109,6 +147,9 @@ static int caam_jr_remove(struct platform_device *pdev) return -EBUSY; } + /* Unregister JR-based RNG & crypto algorithms */ + unregister_algs(); + /* Remove the node from Physical JobR list maintained by driver */ spin_lock(&driver_data.jr_alloc_lock); list_del(&jrpriv->list_node); @@ -541,6 +582,8 @@ static int caam_jr_probe(struct platform_device *pdev) atomic_set(&jrpriv->tfm_count, 0); + register_algs(jrdev->parent); + return 0; } diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c index 8d0713fae6ac..48dd3536060d 100644 --- a/drivers/crypto/caam/key_gen.c +++ b/drivers/crypto/caam/key_gen.c @@ -16,9 +16,7 @@ void split_key_done(struct device *dev, u32 *desc, u32 err, { struct split_key_result *res = context; -#ifdef DEBUG - dev_err(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err); -#endif + dev_dbg(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err); if (err) caam_jr_strstatus(dev, err); @@ -55,12 +53,10 @@ int gen_split_key(struct device *jrdev, u8 *key_out, adata->keylen_pad = split_key_pad_len(adata->algtype & OP_ALG_ALGSEL_MASK); -#ifdef DEBUG - dev_err(jrdev, "split keylen %d split keylen padded %d\n", + dev_dbg(jrdev, "split keylen %d split keylen padded %d\n", adata->keylen, adata->keylen_pad); - print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key_in, keylen, 1); -#endif + print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key_in, keylen, 1); if (adata->keylen_pad > max_keylen) return -EINVAL; @@ -102,10 +98,9 @@ int gen_split_key(struct device *jrdev, u8 *key_out, append_fifo_store(desc, dma_addr, adata->keylen, LDST_CLASS_2_CCB | FIFOST_TYPE_SPLIT_KEK); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif + print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); result.err = 0; init_completion(&result.completion); @@ -115,11 +110,10 @@ int gen_split_key(struct device *jrdev, u8 *key_out, /* in progress */ wait_for_completion(&result.completion); ret = result.err; -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key_out, - adata->keylen_pad, 1); -#endif + + print_hex_dump_debug("ctx.key@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key_out, + adata->keylen_pad, 1); } dma_unmap_single(jrdev, dma_addr, adata->keylen_pad, DMA_BIDIRECTIONAL); diff --git a/drivers/crypto/caam/qi.c b/drivers/crypto/caam/qi.c index 9f08f84cca59..0fe618e3804a 100644 --- a/drivers/crypto/caam/qi.c +++ b/drivers/crypto/caam/qi.c @@ -4,7 +4,7 @@ * Queue Interface backend functionality * * Copyright 2013-2016 Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2017, 2019 NXP */ #include <linux/cpumask.h> @@ -18,6 +18,7 @@ #include "desc_constr.h" #define PREHDR_RSLS_SHIFT 31 +#define PREHDR_ABS BIT(25) /* * Use a reasonable backlog of frames (per CPU) as congestion threshold, @@ -58,11 +59,9 @@ static DEFINE_PER_CPU(int, last_cpu); /* * caam_qi_priv - CAAM QI backend private params * @cgr: QMan congestion group - * @qi_pdev: platform device for QI backend */ struct caam_qi_priv { struct qman_cgr cgr; - struct platform_device *qi_pdev; }; static struct caam_qi_priv qipriv ____cacheline_aligned; @@ -95,6 +94,16 @@ static u64 times_congested; */ static struct kmem_cache *qi_cache; +static void *caam_iova_to_virt(struct iommu_domain *domain, + dma_addr_t iova_addr) +{ + phys_addr_t phys_addr; + + phys_addr = domain ? iommu_iova_to_phys(domain, iova_addr) : iova_addr; + + return phys_to_virt(phys_addr); +} + int caam_qi_enqueue(struct device *qidev, struct caam_drv_req *req) { struct qm_fd fd; @@ -135,6 +144,7 @@ static void caam_fq_ern_cb(struct qman_portal *qm, struct qman_fq *fq, const struct qm_fd *fd; struct caam_drv_req *drv_req; struct device *qidev = &(raw_cpu_ptr(&pcpu_qipriv)->net_dev.dev); + struct caam_drv_private *priv = dev_get_drvdata(qidev); fd = &msg->ern.fd; @@ -143,7 +153,7 @@ static void caam_fq_ern_cb(struct qman_portal *qm, struct qman_fq *fq, return; } - drv_req = (struct caam_drv_req *)phys_to_virt(qm_fd_addr_get64(fd)); + drv_req = caam_iova_to_virt(priv->domain, qm_fd_addr_get64(fd)); if (!drv_req) { dev_err(qidev, "Can't find original request for CAAM response\n"); @@ -346,6 +356,7 @@ int caam_drv_ctx_update(struct caam_drv_ctx *drv_ctx, u32 *sh_desc) */ drv_ctx->prehdr[0] = cpu_to_caam32((1 << PREHDR_RSLS_SHIFT) | num_words); + drv_ctx->prehdr[1] = cpu_to_caam32(PREHDR_ABS); memcpy(drv_ctx->sh_desc, sh_desc, desc_bytes(sh_desc)); dma_sync_single_for_device(qidev, drv_ctx->context_a, sizeof(drv_ctx->sh_desc) + @@ -401,6 +412,7 @@ struct caam_drv_ctx *caam_drv_ctx_init(struct device *qidev, */ drv_ctx->prehdr[0] = cpu_to_caam32((1 << PREHDR_RSLS_SHIFT) | num_words); + drv_ctx->prehdr[1] = cpu_to_caam32(PREHDR_ABS); memcpy(drv_ctx->sh_desc, sh_desc, desc_bytes(sh_desc)); size = sizeof(drv_ctx->prehdr) + sizeof(drv_ctx->sh_desc); hwdesc = dma_map_single(qidev, drv_ctx->prehdr, size, @@ -488,7 +500,7 @@ EXPORT_SYMBOL(caam_drv_ctx_rel); void caam_qi_shutdown(struct device *qidev) { int i; - struct caam_qi_priv *priv = dev_get_drvdata(qidev); + struct caam_qi_priv *priv = &qipriv; const cpumask_t *cpus = qman_affine_cpus(); for_each_cpu(i, cpus) { @@ -506,8 +518,6 @@ void caam_qi_shutdown(struct device *qidev) qman_release_cgrid(priv->cgr.cgrid); kmem_cache_destroy(qi_cache); - - platform_device_unregister(priv->qi_pdev); } static void cgr_cb(struct qman_portal *qm, struct qman_cgr *cgr, int congested) @@ -550,6 +560,7 @@ static enum qman_cb_dqrr_result caam_rsp_fq_dqrr_cb(struct qman_portal *p, struct caam_drv_req *drv_req; const struct qm_fd *fd; struct device *qidev = &(raw_cpu_ptr(&pcpu_qipriv)->net_dev.dev); + struct caam_drv_private *priv = dev_get_drvdata(qidev); u32 status; if (caam_qi_napi_schedule(p, caam_napi)) @@ -572,7 +583,7 @@ static enum qman_cb_dqrr_result caam_rsp_fq_dqrr_cb(struct qman_portal *p, return qman_cb_dqrr_consume; } - drv_req = (struct caam_drv_req *)phys_to_virt(qm_fd_addr_get64(fd)); + drv_req = caam_iova_to_virt(priv->domain, qm_fd_addr_get64(fd)); if (unlikely(!drv_req)) { dev_err(qidev, "Can't find original request for caam response\n"); @@ -692,33 +703,17 @@ static void free_rsp_fqs(void) int caam_qi_init(struct platform_device *caam_pdev) { int err, i; - struct platform_device *qi_pdev; struct device *ctrldev = &caam_pdev->dev, *qidev; struct caam_drv_private *ctrlpriv; const cpumask_t *cpus = qman_affine_cpus(); - static struct platform_device_info qi_pdev_info = { - .name = "caam_qi", - .id = PLATFORM_DEVID_NONE - }; - - qi_pdev_info.parent = ctrldev; - qi_pdev_info.dma_mask = dma_get_mask(ctrldev); - qi_pdev = platform_device_register_full(&qi_pdev_info); - if (IS_ERR(qi_pdev)) - return PTR_ERR(qi_pdev); - set_dma_ops(&qi_pdev->dev, get_dma_ops(ctrldev)); ctrlpriv = dev_get_drvdata(ctrldev); - qidev = &qi_pdev->dev; - - qipriv.qi_pdev = qi_pdev; - dev_set_drvdata(qidev, &qipriv); + qidev = ctrldev; /* Initialize the congestion detection */ err = init_cgr(qidev); if (err) { dev_err(qidev, "CGR initialization failed: %d\n", err); - platform_device_unregister(qi_pdev); return err; } @@ -727,7 +722,6 @@ int caam_qi_init(struct platform_device *caam_pdev) if (err) { dev_err(qidev, "Can't allocate CAAM response FQs: %d\n", err); free_rsp_fqs(); - platform_device_unregister(qi_pdev); return err; } @@ -750,15 +744,11 @@ int caam_qi_init(struct platform_device *caam_pdev) napi_enable(irqtask); } - /* Hook up QI device to parent controlling caam device */ - ctrlpriv->qidev = qidev; - qi_cache = kmem_cache_create("caamqicache", CAAM_QI_MEMCACHE_SIZE, 0, SLAB_CACHE_DMA, NULL); if (!qi_cache) { dev_err(qidev, "Can't allocate CAAM cache\n"); free_rsp_fqs(); - platform_device_unregister(qi_pdev); return -ENOMEM; } @@ -766,6 +756,8 @@ int caam_qi_init(struct platform_device *caam_pdev) debugfs_create_file("qi_congested", 0444, ctrlpriv->ctl, ×_congested, &caam_fops_u64_ro); #endif + + ctrlpriv->qi_init = 1; dev_info(qidev, "Linux CAAM Queue I/F driver initialised\n"); return 0; } diff --git a/drivers/crypto/caam/sg_sw_qm.h b/drivers/crypto/caam/sg_sw_qm.h index b3e1aaaeffea..d56cc7efbc13 100644 --- a/drivers/crypto/caam/sg_sw_qm.h +++ b/drivers/crypto/caam/sg_sw_qm.h @@ -54,15 +54,19 @@ static inline void dma_to_qm_sg_one_last_ext(struct qm_sg_entry *qm_sg_ptr, * but does not have final bit; instead, returns last entry */ static inline struct qm_sg_entry * -sg_to_qm_sg(struct scatterlist *sg, int sg_count, +sg_to_qm_sg(struct scatterlist *sg, int len, struct qm_sg_entry *qm_sg_ptr, u16 offset) { - while (sg_count && sg) { - dma_to_qm_sg_one(qm_sg_ptr, sg_dma_address(sg), - sg_dma_len(sg), offset); + int ent_len; + + while (len) { + ent_len = min_t(int, sg_dma_len(sg), len); + + dma_to_qm_sg_one(qm_sg_ptr, sg_dma_address(sg), ent_len, + offset); qm_sg_ptr++; sg = sg_next(sg); - sg_count--; + len -= ent_len; } return qm_sg_ptr - 1; } @@ -71,10 +75,10 @@ sg_to_qm_sg(struct scatterlist *sg, int sg_count, * convert scatterlist to h/w link table format * scatterlist must have been previously dma mapped */ -static inline void sg_to_qm_sg_last(struct scatterlist *sg, int sg_count, +static inline void sg_to_qm_sg_last(struct scatterlist *sg, int len, struct qm_sg_entry *qm_sg_ptr, u16 offset) { - qm_sg_ptr = sg_to_qm_sg(sg, sg_count, qm_sg_ptr, offset); + qm_sg_ptr = sg_to_qm_sg(sg, len, qm_sg_ptr, offset); qm_sg_entry_set_f(qm_sg_ptr, qm_sg_entry_get_len(qm_sg_ptr)); } diff --git a/drivers/crypto/caam/sg_sw_qm2.h b/drivers/crypto/caam/sg_sw_qm2.h index c9378402a5f8..b8b737d2b0ea 100644 --- a/drivers/crypto/caam/sg_sw_qm2.h +++ b/drivers/crypto/caam/sg_sw_qm2.h @@ -25,15 +25,19 @@ static inline void dma_to_qm_sg_one(struct dpaa2_sg_entry *qm_sg_ptr, * but does not have final bit; instead, returns last entry */ static inline struct dpaa2_sg_entry * -sg_to_qm_sg(struct scatterlist *sg, int sg_count, +sg_to_qm_sg(struct scatterlist *sg, int len, struct dpaa2_sg_entry *qm_sg_ptr, u16 offset) { - while (sg_count && sg) { - dma_to_qm_sg_one(qm_sg_ptr, sg_dma_address(sg), - sg_dma_len(sg), offset); + int ent_len; + + while (len) { + ent_len = min_t(int, sg_dma_len(sg), len); + + dma_to_qm_sg_one(qm_sg_ptr, sg_dma_address(sg), ent_len, + offset); qm_sg_ptr++; sg = sg_next(sg); - sg_count--; + len -= ent_len; } return qm_sg_ptr - 1; } @@ -42,11 +46,11 @@ sg_to_qm_sg(struct scatterlist *sg, int sg_count, * convert scatterlist to h/w link table format * scatterlist must have been previously dma mapped */ -static inline void sg_to_qm_sg_last(struct scatterlist *sg, int sg_count, +static inline void sg_to_qm_sg_last(struct scatterlist *sg, int len, struct dpaa2_sg_entry *qm_sg_ptr, u16 offset) { - qm_sg_ptr = sg_to_qm_sg(sg, sg_count, qm_sg_ptr, offset); + qm_sg_ptr = sg_to_qm_sg(sg, len, qm_sg_ptr, offset); dpaa2_sg_set_final(qm_sg_ptr, true); } diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h index dbfa9fce33e0..07e1ee99273b 100644 --- a/drivers/crypto/caam/sg_sw_sec4.h +++ b/drivers/crypto/caam/sg_sw_sec4.h @@ -35,11 +35,9 @@ static inline void dma_to_sec4_sg_one(struct sec4_sg_entry *sec4_sg_ptr, sec4_sg_ptr->bpid_offset = cpu_to_caam32(offset & SEC4_SG_OFFSET_MASK); } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "sec4_sg_ptr@: ", - DUMP_PREFIX_ADDRESS, 16, 4, sec4_sg_ptr, - sizeof(struct sec4_sg_entry), 1); -#endif + + print_hex_dump_debug("sec4_sg_ptr@: ", DUMP_PREFIX_ADDRESS, 16, 4, + sec4_sg_ptr, sizeof(struct sec4_sg_entry), 1); } /* @@ -47,15 +45,19 @@ static inline void dma_to_sec4_sg_one(struct sec4_sg_entry *sec4_sg_ptr, * but does not have final bit; instead, returns last entry */ static inline struct sec4_sg_entry * -sg_to_sec4_sg(struct scatterlist *sg, int sg_count, +sg_to_sec4_sg(struct scatterlist *sg, int len, struct sec4_sg_entry *sec4_sg_ptr, u16 offset) { - while (sg_count) { - dma_to_sec4_sg_one(sec4_sg_ptr, sg_dma_address(sg), - sg_dma_len(sg), offset); + int ent_len; + + while (len) { + ent_len = min_t(int, sg_dma_len(sg), len); + + dma_to_sec4_sg_one(sec4_sg_ptr, sg_dma_address(sg), ent_len, + offset); sec4_sg_ptr++; sg = sg_next(sg); - sg_count--; + len -= ent_len; } return sec4_sg_ptr - 1; } @@ -72,11 +74,11 @@ static inline void sg_to_sec4_set_last(struct sec4_sg_entry *sec4_sg_ptr) * convert scatterlist to h/w link table format * scatterlist must have been previously dma mapped */ -static inline void sg_to_sec4_sg_last(struct scatterlist *sg, int sg_count, +static inline void sg_to_sec4_sg_last(struct scatterlist *sg, int len, struct sec4_sg_entry *sec4_sg_ptr, u16 offset) { - sec4_sg_ptr = sg_to_sec4_sg(sg, sg_count, sec4_sg_ptr, offset); + sec4_sg_ptr = sg_to_sec4_sg(sg, len, sec4_sg_ptr, offset); sg_to_sec4_set_last(sec4_sg_ptr); } diff --git a/drivers/crypto/cavium/cpt/cptvf_algs.c b/drivers/crypto/cavium/cpt/cptvf_algs.c index e9f4704494fb..ff3cb1f8f2b6 100644 --- a/drivers/crypto/cavium/cpt/cptvf_algs.c +++ b/drivers/crypto/cavium/cpt/cptvf_algs.c @@ -7,7 +7,6 @@ #include <crypto/aes.h> #include <crypto/algapi.h> #include <crypto/authenc.h> -#include <crypto/crypto_wq.h> #include <crypto/des.h> #include <crypto/xts.h> #include <linux/crypto.h> diff --git a/drivers/crypto/cavium/nitrox/nitrox_debugfs.h b/drivers/crypto/cavium/nitrox/nitrox_debugfs.h index f177b79bbab0..09c4cf2513fb 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_debugfs.h +++ b/drivers/crypto/cavium/nitrox/nitrox_debugfs.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __NITROX_DEBUGFS_H #define __NITROX_DEBUGFS_H diff --git a/drivers/crypto/cavium/nitrox/nitrox_mbx.h b/drivers/crypto/cavium/nitrox/nitrox_mbx.h index 5008399775a9..7c93d0282174 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_mbx.h +++ b/drivers/crypto/cavium/nitrox/nitrox_mbx.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __NITROX_MBX_H #define __NITROX_MBX_H diff --git a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c index f6e252c1d6fb..bb7219d36b2c 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c +++ b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Cryptographic Coprocessor (CCP) AES CMAC crypto API support * * Copyright (C) 2013,2018 Advanced Micro Devices, Inc. * * Author: Tom Lendacky <thomas.lendacky@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/ccp/ccp-crypto-aes-galois.c b/drivers/crypto/ccp/ccp-crypto-aes-galois.c index ca1f0d780b61..f9fec2ddf56a 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes-galois.c +++ b/drivers/crypto/ccp/ccp-crypto-aes-galois.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Cryptographic Coprocessor (CCP) AES GCM crypto API support * * Copyright (C) 2016,2017 Advanced Micro Devices, Inc. * * Author: Gary R Hook <gary.hook@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/ccp/ccp-crypto-aes-xts.c b/drivers/crypto/ccp/ccp-crypto-aes-xts.c index ca4630b8395f..783ba75e0618 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes-xts.c +++ b/drivers/crypto/ccp/ccp-crypto-aes-xts.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Cryptographic Coprocessor (CCP) AES XTS crypto API support * @@ -5,10 +6,6 @@ * * Author: Gary R Hook <gary.hook@amd.com> * Author: Tom Lendacky <thomas.lendacky@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c index 89291c15015c..58c6dddfc5e1 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes.c +++ b/drivers/crypto/ccp/ccp-crypto-aes.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Cryptographic Coprocessor (CCP) AES crypto API support * - * Copyright (C) 2013,2016 Advanced Micro Devices, Inc. + * Copyright (C) 2013-2019 Advanced Micro Devices, Inc. * * Author: Tom Lendacky <thomas.lendacky@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> @@ -79,8 +76,7 @@ static int ccp_aes_crypt(struct ablkcipher_request *req, bool encrypt) return -EINVAL; if (((ctx->u.aes.mode == CCP_AES_MODE_ECB) || - (ctx->u.aes.mode == CCP_AES_MODE_CBC) || - (ctx->u.aes.mode == CCP_AES_MODE_CFB)) && + (ctx->u.aes.mode == CCP_AES_MODE_CBC)) && (req->nbytes & (AES_BLOCK_SIZE - 1))) return -EINVAL; @@ -291,7 +287,7 @@ static struct ccp_aes_def aes_algs[] = { .version = CCP_VERSION(3, 0), .name = "cfb(aes)", .driver_name = "cfb-aes-ccp", - .blocksize = AES_BLOCK_SIZE, + .blocksize = 1, .ivsize = AES_BLOCK_SIZE, .alg_defaults = &ccp_aes_defaults, }, diff --git a/drivers/crypto/ccp/ccp-crypto-des3.c b/drivers/crypto/ccp/ccp-crypto-des3.c index 91482ffcac59..5f05f834c7cd 100644 --- a/drivers/crypto/ccp/ccp-crypto-des3.c +++ b/drivers/crypto/ccp/ccp-crypto-des3.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Cryptographic Coprocessor (CCP) DES3 crypto API support * * Copyright (C) 2016,2017 Advanced Micro Devices, Inc. * * Author: Gary R Hook <ghook@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/ccp/ccp-crypto-main.c b/drivers/crypto/ccp/ccp-crypto-main.c index b95d19974aa6..818096490829 100644 --- a/drivers/crypto/ccp/ccp-crypto-main.c +++ b/drivers/crypto/ccp/ccp-crypto-main.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Cryptographic Coprocessor (CCP) crypto API support * * Copyright (C) 2013,2017 Advanced Micro Devices, Inc. * * Author: Tom Lendacky <thomas.lendacky@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/ccp/ccp-crypto-rsa.c b/drivers/crypto/ccp/ccp-crypto-rsa.c index a2570c0c8cdc..649c91d60401 100644 --- a/drivers/crypto/ccp/ccp-crypto-rsa.c +++ b/drivers/crypto/ccp/ccp-crypto-rsa.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Cryptographic Coprocessor (CCP) RSA crypto API support * * Copyright (C) 2017 Advanced Micro Devices, Inc. * * Author: Gary R Hook <gary.hook@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/ccp/ccp-crypto-sha.c b/drivers/crypto/ccp/ccp-crypto-sha.c index 3e10573f589e..453b9797f93f 100644 --- a/drivers/crypto/ccp/ccp-crypto-sha.c +++ b/drivers/crypto/ccp/ccp-crypto-sha.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Cryptographic Coprocessor (CCP) SHA crypto API support * @@ -5,10 +6,6 @@ * * Author: Tom Lendacky <thomas.lendacky@amd.com> * Author: Gary R Hook <gary.hook@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/ccp/ccp-crypto.h b/drivers/crypto/ccp/ccp-crypto.h index 28819e11db96..622b34c17643 100644 --- a/drivers/crypto/ccp/ccp-crypto.h +++ b/drivers/crypto/ccp/ccp-crypto.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AMD Cryptographic Coprocessor (CCP) crypto API support * * Copyright (C) 2013,2017 Advanced Micro Devices, Inc. * * Author: Tom Lendacky <thomas.lendacky@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __CCP_CRYPTO_H__ diff --git a/drivers/crypto/ccp/ccp-debugfs.c b/drivers/crypto/ccp/ccp-debugfs.c index 4bd26af7098d..a1055554b47a 100644 --- a/drivers/crypto/ccp/ccp-debugfs.c +++ b/drivers/crypto/ccp/ccp-debugfs.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Cryptographic Coprocessor (CCP) driver * * Copyright (C) 2017 Advanced Micro Devices, Inc. * * Author: Gary R Hook <gary.hook@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/debugfs.h> diff --git a/drivers/crypto/ccp/ccp-dev-v3.c b/drivers/crypto/ccp/ccp-dev-v3.c index 240bebbcb8ac..2b7d47ed5c74 100644 --- a/drivers/crypto/ccp/ccp-dev-v3.c +++ b/drivers/crypto/ccp/ccp-dev-v3.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Cryptographic Coprocessor (CCP) driver * @@ -5,10 +6,6 @@ * * Author: Tom Lendacky <thomas.lendacky@amd.com> * Author: Gary R Hook <gary.hook@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/ccp/ccp-dev-v5.c b/drivers/crypto/ccp/ccp-dev-v5.c index c9bfd4f439ce..217e41bbadaf 100644 --- a/drivers/crypto/ccp/ccp-dev-v5.c +++ b/drivers/crypto/ccp/ccp-dev-v5.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Cryptographic Coprocessor (CCP) driver * * Copyright (C) 2016,2017 Advanced Micro Devices, Inc. * * Author: Gary R Hook <gary.hook@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c index 1b5035d56288..f79eede71c62 100644 --- a/drivers/crypto/ccp/ccp-dev.c +++ b/drivers/crypto/ccp/ccp-dev.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Cryptographic Coprocessor (CCP) driver * @@ -5,10 +6,6 @@ * * Author: Tom Lendacky <thomas.lendacky@amd.com> * Author: Gary R Hook <gary.hook@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> @@ -35,56 +32,62 @@ struct ccp_tasklet_data { }; /* Human-readable error strings */ +#define CCP_MAX_ERROR_CODE 64 static char *ccp_error_codes[] = { "", - "ERR 01: ILLEGAL_ENGINE", - "ERR 02: ILLEGAL_KEY_ID", - "ERR 03: ILLEGAL_FUNCTION_TYPE", - "ERR 04: ILLEGAL_FUNCTION_MODE", - "ERR 05: ILLEGAL_FUNCTION_ENCRYPT", - "ERR 06: ILLEGAL_FUNCTION_SIZE", - "ERR 07: Zlib_MISSING_INIT_EOM", - "ERR 08: ILLEGAL_FUNCTION_RSVD", - "ERR 09: ILLEGAL_BUFFER_LENGTH", - "ERR 10: VLSB_FAULT", - "ERR 11: ILLEGAL_MEM_ADDR", - "ERR 12: ILLEGAL_MEM_SEL", - "ERR 13: ILLEGAL_CONTEXT_ID", - "ERR 14: ILLEGAL_KEY_ADDR", - "ERR 15: 0xF Reserved", - "ERR 16: Zlib_ILLEGAL_MULTI_QUEUE", - "ERR 17: Zlib_ILLEGAL_JOBID_CHANGE", - "ERR 18: CMD_TIMEOUT", - "ERR 19: IDMA0_AXI_SLVERR", - "ERR 20: IDMA0_AXI_DECERR", - "ERR 21: 0x15 Reserved", - "ERR 22: IDMA1_AXI_SLAVE_FAULT", - "ERR 23: IDMA1_AIXI_DECERR", - "ERR 24: 0x18 Reserved", - "ERR 25: ZLIBVHB_AXI_SLVERR", - "ERR 26: ZLIBVHB_AXI_DECERR", - "ERR 27: 0x1B Reserved", - "ERR 27: ZLIB_UNEXPECTED_EOM", - "ERR 27: ZLIB_EXTRA_DATA", - "ERR 30: ZLIB_BTYPE", - "ERR 31: ZLIB_UNDEFINED_SYMBOL", - "ERR 32: ZLIB_UNDEFINED_DISTANCE_S", - "ERR 33: ZLIB_CODE_LENGTH_SYMBOL", - "ERR 34: ZLIB _VHB_ILLEGAL_FETCH", - "ERR 35: ZLIB_UNCOMPRESSED_LEN", - "ERR 36: ZLIB_LIMIT_REACHED", - "ERR 37: ZLIB_CHECKSUM_MISMATCH0", - "ERR 38: ODMA0_AXI_SLVERR", - "ERR 39: ODMA0_AXI_DECERR", - "ERR 40: 0x28 Reserved", - "ERR 41: ODMA1_AXI_SLVERR", - "ERR 42: ODMA1_AXI_DECERR", - "ERR 43: LSB_PARITY_ERR", + "ILLEGAL_ENGINE", + "ILLEGAL_KEY_ID", + "ILLEGAL_FUNCTION_TYPE", + "ILLEGAL_FUNCTION_MODE", + "ILLEGAL_FUNCTION_ENCRYPT", + "ILLEGAL_FUNCTION_SIZE", + "Zlib_MISSING_INIT_EOM", + "ILLEGAL_FUNCTION_RSVD", + "ILLEGAL_BUFFER_LENGTH", + "VLSB_FAULT", + "ILLEGAL_MEM_ADDR", + "ILLEGAL_MEM_SEL", + "ILLEGAL_CONTEXT_ID", + "ILLEGAL_KEY_ADDR", + "0xF Reserved", + "Zlib_ILLEGAL_MULTI_QUEUE", + "Zlib_ILLEGAL_JOBID_CHANGE", + "CMD_TIMEOUT", + "IDMA0_AXI_SLVERR", + "IDMA0_AXI_DECERR", + "0x15 Reserved", + "IDMA1_AXI_SLAVE_FAULT", + "IDMA1_AIXI_DECERR", + "0x18 Reserved", + "ZLIBVHB_AXI_SLVERR", + "ZLIBVHB_AXI_DECERR", + "0x1B Reserved", + "ZLIB_UNEXPECTED_EOM", + "ZLIB_EXTRA_DATA", + "ZLIB_BTYPE", + "ZLIB_UNDEFINED_SYMBOL", + "ZLIB_UNDEFINED_DISTANCE_S", + "ZLIB_CODE_LENGTH_SYMBOL", + "ZLIB _VHB_ILLEGAL_FETCH", + "ZLIB_UNCOMPRESSED_LEN", + "ZLIB_LIMIT_REACHED", + "ZLIB_CHECKSUM_MISMATCH0", + "ODMA0_AXI_SLVERR", + "ODMA0_AXI_DECERR", + "0x28 Reserved", + "ODMA1_AXI_SLVERR", + "ODMA1_AXI_DECERR", }; -void ccp_log_error(struct ccp_device *d, int e) +void ccp_log_error(struct ccp_device *d, unsigned int e) { - dev_err(d->dev, "CCP error: %s (0x%x)\n", ccp_error_codes[e], e); + if (WARN_ON(e >= CCP_MAX_ERROR_CODE)) + return; + + if (e < ARRAY_SIZE(ccp_error_codes)) + dev_err(d->dev, "CCP error %d: %s\n", e, ccp_error_codes[e]); + else + dev_err(d->dev, "CCP error %d: Unknown Error\n", e); } /* List of CCPs, CCP count, read-write access lock, and access functions diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h index 6810b65c1939..5e624920fd99 100644 --- a/drivers/crypto/ccp/ccp-dev.h +++ b/drivers/crypto/ccp/ccp-dev.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AMD Cryptographic Coprocessor (CCP) driver * @@ -5,10 +6,6 @@ * * Author: Tom Lendacky <thomas.lendacky@amd.com> * Author: Gary R Hook <gary.hook@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __CCP_DEV_H__ @@ -632,7 +629,7 @@ struct ccp5_desc { void ccp_add_device(struct ccp_device *ccp); void ccp_del_device(struct ccp_device *ccp); -extern void ccp_log_error(struct ccp_device *, int); +extern void ccp_log_error(struct ccp_device *, unsigned int); struct ccp_device *ccp_alloc_struct(struct sp_device *sp); bool ccp_queues_suspended(struct ccp_device *ccp); diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c index 67155cb21636..7f22a45bbc11 100644 --- a/drivers/crypto/ccp/ccp-dmaengine.c +++ b/drivers/crypto/ccp/ccp-dmaengine.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Cryptographic Coprocessor (CCP) driver * * Copyright (C) 2016,2017 Advanced Micro Devices, Inc. * * Author: Gary R Hook <gary.hook@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index 267a367bd076..866b2e05ca77 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -1,14 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Cryptographic Coprocessor (CCP) driver * - * Copyright (C) 2013,2018 Advanced Micro Devices, Inc. + * Copyright (C) 2013-2019 Advanced Micro Devices, Inc. * * Author: Tom Lendacky <thomas.lendacky@amd.com> * Author: Gary R Hook <gary.hook@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> @@ -893,8 +890,7 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return -EINVAL; if (((aes->mode == CCP_AES_MODE_ECB) || - (aes->mode == CCP_AES_MODE_CBC) || - (aes->mode == CCP_AES_MODE_CFB)) && + (aes->mode == CCP_AES_MODE_CBC)) && (aes->src_len & (AES_BLOCK_SIZE - 1))) return -EINVAL; @@ -1267,6 +1263,9 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) int ret; /* Error checks */ + if (cmd_q->ccp->vdata->version < CCP_VERSION(5, 0)) + return -EINVAL; + if (!cmd_q->ccp->vdata->perform->des3) return -EINVAL; @@ -1349,8 +1348,6 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) * passthru option to convert from big endian to little endian. */ if (des3->mode != CCP_DES3_MODE_ECB) { - u32 load_mode; - op.sb_ctx = cmd_q->sb_ctx; ret = ccp_init_dm_workarea(&ctx, cmd_q, @@ -1366,12 +1363,8 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) if (ret) goto e_ctx; - if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) - load_mode = CCP_PASSTHRU_BYTESWAP_NOOP; - else - load_mode = CCP_PASSTHRU_BYTESWAP_256BIT; ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx, - load_mode); + CCP_PASSTHRU_BYTESWAP_256BIT); if (ret) { cmd->engine_error = cmd_q->cmd_error; goto e_ctx; @@ -1433,10 +1426,6 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) } /* ...but we only need the last DES3_EDE_BLOCK_SIZE bytes */ - if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) - dm_offset = CCP_SB_BYTES - des3->iv_len; - else - dm_offset = 0; ccp_get_dm_area(&ctx, dm_offset, des3->iv, 0, DES3_EDE_BLOCK_SIZE); } diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index 656838433f2f..de5a8ca70d3d 100644 --- a/drivers/crypto/ccp/psp-dev.c +++ b/drivers/crypto/ccp/psp-dev.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Platform Security Processor (PSP) interface * * Copyright (C) 2016,2018 Advanced Micro Devices, Inc. * * Author: Brijesh Singh <brijesh.singh@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h index f5afeccf42a1..c5e06c92d40e 100644 --- a/drivers/crypto/ccp/psp-dev.h +++ b/drivers/crypto/ccp/psp-dev.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AMD Platform Security Processor (PSP) interface driver * * Copyright (C) 2017-2018 Advanced Micro Devices, Inc. * * Author: Brijesh Singh <brijesh.singh@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __PSP_DEV_H__ diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c index b2879767fc98..ce42675d3274 100644 --- a/drivers/crypto/ccp/sp-dev.c +++ b/drivers/crypto/ccp/sp-dev.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Secure Processor driver * @@ -6,10 +7,6 @@ * Author: Tom Lendacky <thomas.lendacky@amd.com> * Author: Gary R Hook <gary.hook@amd.com> * Author: Brijesh Singh <brijesh.singh@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h index 5b0790025db3..8abe9ea7e76f 100644 --- a/drivers/crypto/ccp/sp-dev.h +++ b/drivers/crypto/ccp/sp-dev.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AMD Secure Processor driver * @@ -6,10 +7,6 @@ * Author: Tom Lendacky <thomas.lendacky@amd.com> * Author: Gary R Hook <gary.hook@amd.com> * Author: Brijesh Singh <brijesh.singh@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __SP_DEV_H__ diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index 41bce0a3f4bb..b29d2e663e10 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Secure Processor device driver * @@ -5,10 +6,6 @@ * * Author: Tom Lendacky <thomas.lendacky@amd.com> * Author: Gary R Hook <gary.hook@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/ccp/sp-platform.c b/drivers/crypto/ccp/sp-platform.c index d24228efbaaa..1b45236e3716 100644 --- a/drivers/crypto/ccp/sp-platform.c +++ b/drivers/crypto/ccp/sp-platform.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Secure Processor device driver * * Copyright (C) 2014,2018 Advanced Micro Devices, Inc. * * Author: Tom Lendacky <thomas.lendacky@amd.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/ccree/cc_driver.c b/drivers/crypto/ccree/cc_driver.c index 86ac7b443355..980aa04b655b 100644 --- a/drivers/crypto/ccree/cc_driver.c +++ b/drivers/crypto/ccree/cc_driver.c @@ -48,6 +48,7 @@ struct cc_hw_data { }; #define CC_NUM_IDRS 4 +#define CC_HW_RESET_LOOP_COUNT 10 /* Note: PIDR3 holds CMOD/Rev so ignored for HW identification purposes */ static const u32 pidr_0124_offsets[CC_NUM_IDRS] = { @@ -133,6 +134,9 @@ static irqreturn_t cc_isr(int irq, void *dev_id) u32 imr; /* STAT_OP_TYPE_GENERIC STAT_PHASE_0: Interrupt */ + /* if driver suspended return, probebly shared interrupt */ + if (cc_pm_is_dev_suspended(dev)) + return IRQ_NONE; /* read the interrupt status */ irr = cc_ioread(drvdata, CC_REG(HOST_IRR)); @@ -188,6 +192,31 @@ static irqreturn_t cc_isr(int irq, void *dev_id) return IRQ_HANDLED; } +bool cc_wait_for_reset_completion(struct cc_drvdata *drvdata) +{ + unsigned int val; + unsigned int i; + + /* 712/710/63 has no reset completion indication, always return true */ + if (drvdata->hw_rev <= CC_HW_REV_712) + return true; + + for (i = 0; i < CC_HW_RESET_LOOP_COUNT; i++) { + /* in cc7x3 NVM_IS_IDLE indicates that CC reset is + * completed and device is fully functional + */ + val = cc_ioread(drvdata, CC_REG(NVM_IS_IDLE)); + if (val & CC_NVM_IS_IDLE_MASK) { + /* hw indicate reset completed */ + return true; + } + /* allow scheduling other process on the processor */ + schedule(); + } + /* reset not completed */ + return false; +} + int init_cc_regs(struct cc_drvdata *drvdata, bool is_probe) { unsigned int val, cache_params; @@ -315,15 +344,6 @@ static int init_cc_resources(struct platform_device *plat_dev) return new_drvdata->irq; } - rc = devm_request_irq(dev, new_drvdata->irq, cc_isr, - IRQF_SHARED, "ccree", new_drvdata); - if (rc) { - dev_err(dev, "Could not register to interrupt %d\n", - new_drvdata->irq); - return rc; - } - dev_dbg(dev, "Registered to IRQ: %d\n", new_drvdata->irq); - init_completion(&new_drvdata->hw_queue_avail); if (!plat_dev->dev.dma_mask) @@ -352,6 +372,11 @@ static int init_cc_resources(struct platform_device *plat_dev) new_drvdata->sec_disabled = cc_sec_disable; + /* wait for Crytpcell reset completion */ + if (!cc_wait_for_reset_completion(new_drvdata)) { + dev_err(dev, "Cryptocell reset not completed"); + } + if (hw_rev->rev <= CC_HW_REV_712) { /* Verify correct mapping */ val = cc_ioread(new_drvdata, new_drvdata->sig_offset); @@ -383,6 +408,24 @@ static int init_cc_resources(struct platform_device *plat_dev) } sig_cidr = val; + /* Check HW engine configuration */ + val = cc_ioread(new_drvdata, CC_REG(HOST_REMOVE_INPUT_PINS)); + switch (val) { + case CC_PINS_FULL: + /* This is fine */ + break; + case CC_PINS_SLIM: + if (new_drvdata->std_bodies & CC_STD_NIST) { + dev_warn(dev, "703 mode forced due to HW configuration.\n"); + new_drvdata->std_bodies = CC_STD_OSCCA; + } + break; + default: + dev_err(dev, "Unsupported engines configration.\n"); + rc = -EINVAL; + goto post_clk_err; + } + /* Check security disable state */ val = cc_ioread(new_drvdata, CC_REG(SECURITY_DISABLED)); val &= CC_SECURITY_DISABLED_MASK; @@ -401,6 +444,15 @@ static int init_cc_resources(struct platform_device *plat_dev) /* Display HW versions */ dev_info(dev, "ARM CryptoCell %s Driver: HW version 0x%08X/0x%8X, Driver version %s\n", hw_rev->name, hw_rev_pidr, sig_cidr, DRV_MODULE_VERSION); + /* register the driver isr function */ + rc = devm_request_irq(dev, new_drvdata->irq, cc_isr, + IRQF_SHARED, "ccree", new_drvdata); + if (rc) { + dev_err(dev, "Could not register to interrupt %d\n", + new_drvdata->irq); + goto post_clk_err; + } + dev_dbg(dev, "Registered to IRQ: %d\n", new_drvdata->irq); rc = init_cc_regs(new_drvdata, true); if (rc) { diff --git a/drivers/crypto/ccree/cc_driver.h b/drivers/crypto/ccree/cc_driver.h index b76181335c08..7cd99380bf1f 100644 --- a/drivers/crypto/ccree/cc_driver.h +++ b/drivers/crypto/ccree/cc_driver.h @@ -53,6 +53,9 @@ enum cc_std_body { #define CC_COHERENT_CACHE_PARAMS 0xEEE +#define CC_PINS_FULL 0x0 +#define CC_PINS_SLIM 0x9F + /* Maximum DMA mask supported by IP */ #define DMA_BIT_MASK_LEN 48 @@ -67,6 +70,8 @@ enum cc_std_body { #define CC_SECURITY_DISABLED_MASK BIT(CC_SECURITY_DISABLED_VALUE_BIT_SHIFT) +#define CC_NVM_IS_IDLE_MASK BIT(CC_NVM_IS_IDLE_VALUE_BIT_SHIFT) + #define AXIM_MON_COMP_VALUE GENMASK(CC_AXIM_MON_COMP_VALUE_BIT_SIZE + \ CC_AXIM_MON_COMP_VALUE_BIT_SHIFT, \ CC_AXIM_MON_COMP_VALUE_BIT_SHIFT) @@ -216,6 +221,7 @@ static inline void dump_byte_array(const char *name, const u8 *the_array, __dump_byte_array(name, the_array, size); } +bool cc_wait_for_reset_completion(struct cc_drvdata *drvdata); int init_cc_regs(struct cc_drvdata *drvdata, bool is_probe); void fini_cc_regs(struct cc_drvdata *drvdata); int cc_clk_on(struct cc_drvdata *drvdata); diff --git a/drivers/crypto/ccree/cc_host_regs.h b/drivers/crypto/ccree/cc_host_regs.h index d0764147573f..efe3e1d8b87b 100644 --- a/drivers/crypto/ccree/cc_host_regs.h +++ b/drivers/crypto/ccree/cc_host_regs.h @@ -114,6 +114,9 @@ #define CC_HOST_ICR_DSCRPTR_WATERMARK_QUEUE0_CLEAR_BIT_SIZE 0x1UL #define CC_HOST_ICR_AXIM_COMP_INT_CLEAR_BIT_SHIFT 0x17UL #define CC_HOST_ICR_AXIM_COMP_INT_CLEAR_BIT_SIZE 0x1UL +#define CC_NVM_IS_IDLE_REG_OFFSET 0x0A10UL +#define CC_NVM_IS_IDLE_VALUE_BIT_SHIFT 0x0UL +#define CC_NVM_IS_IDLE_VALUE_BIT_SIZE 0x1UL #define CC_SECURITY_DISABLED_REG_OFFSET 0x0A1CUL #define CC_SECURITY_DISABLED_VALUE_BIT_SHIFT 0x0UL #define CC_SECURITY_DISABLED_VALUE_BIT_SIZE 0x1UL @@ -203,6 +206,23 @@ #define CC_HOST_POWER_DOWN_EN_REG_OFFSET 0xA78UL #define CC_HOST_POWER_DOWN_EN_VALUE_BIT_SHIFT 0x0UL #define CC_HOST_POWER_DOWN_EN_VALUE_BIT_SIZE 0x1UL +#define CC_HOST_REMOVE_INPUT_PINS_REG_OFFSET 0x0A7CUL +#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_AES_ENGINE_BIT_SHIFT 0x0UL +#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_AES_ENGINE_BIT_SIZE 0x1UL +#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_AES_MAC_ENGINE_BIT_SHIFT 0x1UL +#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_AES_MAC_ENGINE_BIT_SIZE 0x1UL +#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_GHASH_ENGINE_BIT_SHIFT 0x2UL +#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_GHASH_ENGINE_BIT_SIZE 0x1UL +#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_DES_ENGINE_BIT_SHIFT 0x3UL +#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_DES_ENGINE_BIT_SIZE 0x1UL +#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_HASH_ENGINE_BIT_SHIFT 0x4UL +#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_HASH_ENGINE_BIT_SIZE 0x1UL +#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_SM3_ENGINE_BIT_SHIFT 0x5UL +#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_SM3_ENGINE_BIT_SIZE 0x1UL +#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_SM4_ENGINE_BIT_SHIFT 0x6UL +#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_SM4_ENGINE_BIT_SIZE 0x1UL +#define CC_HOST_REMOVE_INPUT_PINS_OTP_DISCONNECTED_BIT_SHIFT 0x7UL +#define CC_HOST_REMOVE_INPUT_PINS_OTP_DISCONNECTED_BIT_SIZE 0x1UL // -------------------------------------- // BLOCK: ID_REGISTERS // -------------------------------------- diff --git a/drivers/crypto/ccree/cc_pm.c b/drivers/crypto/ccree/cc_pm.c index 2dad9c9543c6..899a52f05b7a 100644 --- a/drivers/crypto/ccree/cc_pm.c +++ b/drivers/crypto/ccree/cc_pm.c @@ -49,6 +49,11 @@ int cc_pm_resume(struct device *dev) dev_err(dev, "failed getting clock back on. We're toast.\n"); return rc; } + /* wait for Crytpcell reset completion */ + if (!cc_wait_for_reset_completion(drvdata)) { + dev_err(dev, "Cryptocell reset not completed"); + return -EBUSY; + } cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE); rc = init_cc_regs(drvdata, false); @@ -101,6 +106,12 @@ int cc_pm_put_suspend(struct device *dev) return rc; } +bool cc_pm_is_dev_suspended(struct device *dev) +{ + /* check device state using runtime api */ + return pm_runtime_suspended(dev); +} + int cc_pm_init(struct cc_drvdata *drvdata) { struct device *dev = drvdata_to_dev(drvdata); diff --git a/drivers/crypto/ccree/cc_pm.h b/drivers/crypto/ccree/cc_pm.h index 6190cdba5dad..a7d98a5da2e1 100644 --- a/drivers/crypto/ccree/cc_pm.h +++ b/drivers/crypto/ccree/cc_pm.h @@ -22,6 +22,7 @@ int cc_pm_suspend(struct device *dev); int cc_pm_resume(struct device *dev); int cc_pm_get(struct device *dev); int cc_pm_put_suspend(struct device *dev); +bool cc_pm_is_dev_suspended(struct device *dev); #else @@ -54,6 +55,12 @@ static inline int cc_pm_put_suspend(struct device *dev) return 0; } +static inline bool cc_pm_is_dev_suspended(struct device *dev) +{ + /* if PM not supported device is never suspend */ + return false; +} + #endif #endif /*__POWER_MGR_H__*/ diff --git a/drivers/crypto/chelsio/chtls/chtls.h b/drivers/crypto/chelsio/chtls/chtls.h index 59bb67d5a7ce..025c831d0899 100644 --- a/drivers/crypto/chelsio/chtls/chtls.h +++ b/drivers/crypto/chelsio/chtls/chtls.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2018 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __CHTLS_H__ diff --git a/drivers/crypto/chelsio/chtls/chtls_cm.c b/drivers/crypto/chelsio/chtls/chtls_cm.c index 4e22332496c5..774d991d7cca 100644 --- a/drivers/crypto/chelsio/chtls/chtls_cm.c +++ b/drivers/crypto/chelsio/chtls/chtls_cm.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018 Chelsio Communications, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Written by: Atul Gupta (atul.gupta@chelsio.com) */ diff --git a/drivers/crypto/chelsio/chtls/chtls_cm.h b/drivers/crypto/chelsio/chtls/chtls_cm.h index 78eb3afa3a80..129d7ac649a9 100644 --- a/drivers/crypto/chelsio/chtls/chtls_cm.h +++ b/drivers/crypto/chelsio/chtls/chtls_cm.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2018 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __CHTLS_CM_H__ diff --git a/drivers/crypto/chelsio/chtls/chtls_hw.c b/drivers/crypto/chelsio/chtls/chtls_hw.c index 490960755864..f2424f4c5f78 100644 --- a/drivers/crypto/chelsio/chtls/chtls_hw.c +++ b/drivers/crypto/chelsio/chtls/chtls_hw.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018 Chelsio Communications, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Written by: Atul Gupta (atul.gupta@chelsio.com) */ diff --git a/drivers/crypto/chelsio/chtls/chtls_io.c b/drivers/crypto/chelsio/chtls/chtls_io.c index 1285a1bceda7..551bca6fef24 100644 --- a/drivers/crypto/chelsio/chtls/chtls_io.c +++ b/drivers/crypto/chelsio/chtls/chtls_io.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018 Chelsio Communications, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Written by: Atul Gupta (atul.gupta@chelsio.com) */ diff --git a/drivers/crypto/chelsio/chtls/chtls_main.c b/drivers/crypto/chelsio/chtls/chtls_main.c index dd2daf2a54e0..635bb4b447fb 100644 --- a/drivers/crypto/chelsio/chtls/chtls_main.c +++ b/drivers/crypto/chelsio/chtls/chtls_main.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018 Chelsio Communications, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Written by: Atul Gupta (atul.gupta@chelsio.com) */ #include <linux/kernel.h> diff --git a/drivers/crypto/hisilicon/sec/sec_drv.h b/drivers/crypto/hisilicon/sec/sec_drv.h index 2d2f186674ba..4d9063a8b10b 100644 --- a/drivers/crypto/hisilicon/sec/sec_drv.h +++ b/drivers/crypto/hisilicon/sec/sec_drv.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (c) 2016-2017 Hisilicon Limited. */ #ifndef _SEC_DRV_H_ diff --git a/drivers/crypto/img-hash.c b/drivers/crypto/img-hash.c index b87000a0a01c..d27c812c3d8d 100644 --- a/drivers/crypto/img-hash.c +++ b/drivers/crypto/img-hash.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 Imagination Technologies * Authors: Will Thomas, James Hartley * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Interface structure taken from omap-sham driver */ diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c index 86c699c14f84..df43a2c6933b 100644 --- a/drivers/crypto/inside-secure/safexcel.c +++ b/drivers/crypto/inside-secure/safexcel.c @@ -398,6 +398,12 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) /* Processing Engine configuration */ + /* Token & context configuration */ + val = EIP197_PE_EIP96_TOKEN_CTRL_CTX_UPDATES | + EIP197_PE_EIP96_TOKEN_CTRL_REUSE_CTX | + EIP197_PE_EIP96_TOKEN_CTRL_POST_REUSE_CTX; + writel(val, EIP197_PE(priv) + EIP197_PE_EIP96_TOKEN_CTRL(pe)); + /* H/W capabilities selection */ val = EIP197_FUNCTION_RSVD; val |= EIP197_PROTOCOL_ENCRYPT_ONLY | EIP197_PROTOCOL_HASH_ONLY; @@ -589,9 +595,9 @@ inline int safexcel_rdesc_check_errors(struct safexcel_crypto_priv *priv, if (rdesc->result_data.error_code & 0x407f) { /* Fatal error (bits 0-7, 14) */ dev_err(priv->dev, - "cipher: result: result descriptor error (%d)\n", + "cipher: result: result descriptor error (0x%x)\n", rdesc->result_data.error_code); - return -EIO; + return -EINVAL; } else if (rdesc->result_data.error_code == BIT(9)) { /* Authentication failed */ return -EBADMSG; @@ -720,11 +726,10 @@ handle_results: } acknowledge: - if (i) { + if (i) writel(EIP197_xDR_PROC_xD_PKT(i) | EIP197_xDR_PROC_xD_COUNT(tot_descs * priv->config.rd_offset), EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PROC_COUNT); - } /* If the number of requests overflowed the counter, try to proceed more * requests. diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h index 65624a81f0fd..e0c202f33674 100644 --- a/drivers/crypto/inside-secure/safexcel.h +++ b/drivers/crypto/inside-secure/safexcel.h @@ -118,6 +118,7 @@ #define EIP197_PE_ICE_SCRATCH_CTRL(n) (0x0d04 + (0x2000 * (n))) #define EIP197_PE_ICE_FPP_CTRL(n) (0x0d80 + (0x2000 * (n))) #define EIP197_PE_ICE_RAM_CTRL(n) (0x0ff0 + (0x2000 * (n))) +#define EIP197_PE_EIP96_TOKEN_CTRL(n) (0x1000 + (0x2000 * (n))) #define EIP197_PE_EIP96_FUNCTION_EN(n) (0x1004 + (0x2000 * (n))) #define EIP197_PE_EIP96_CONTEXT_CTRL(n) (0x1008 + (0x2000 * (n))) #define EIP197_PE_EIP96_CONTEXT_STAT(n) (0x100c + (0x2000 * (n))) @@ -249,6 +250,11 @@ #define EIP197_PE_ICE_RAM_CTRL_PUE_PROG_EN BIT(0) #define EIP197_PE_ICE_RAM_CTRL_FPP_PROG_EN BIT(1) +/* EIP197_PE_EIP96_TOKEN_CTRL */ +#define EIP197_PE_EIP96_TOKEN_CTRL_CTX_UPDATES BIT(16) +#define EIP197_PE_EIP96_TOKEN_CTRL_REUSE_CTX BIT(19) +#define EIP197_PE_EIP96_TOKEN_CTRL_POST_REUSE_CTX BIT(20) + /* EIP197_PE_EIP96_FUNCTION_EN */ #define EIP197_FUNCTION_RSVD (BIT(6) | BIT(15) | BIT(20) | BIT(23)) #define EIP197_PROTOCOL_HASH_ONLY BIT(0) @@ -333,6 +339,7 @@ struct safexcel_context_record { #define CONTEXT_CONTROL_IV3 BIT(8) #define CONTEXT_CONTROL_DIGEST_CNT BIT(9) #define CONTEXT_CONTROL_COUNTER_MODE BIT(10) +#define CONTEXT_CONTROL_CRYPTO_STORE BIT(12) #define CONTEXT_CONTROL_HASH_STORE BIT(19) /* The hash counter given to the engine in the context has a granularity of @@ -425,6 +432,10 @@ struct safexcel_token { #define EIP197_TOKEN_HASH_RESULT_VERIFY BIT(16) +#define EIP197_TOKEN_CTX_OFFSET(x) (x) +#define EIP197_TOKEN_DIRECTION_EXTERNAL BIT(11) +#define EIP197_TOKEN_EXEC_IF_SUCCESSFUL (0x1 << 12) + #define EIP197_TOKEN_STAT_LAST_HASH BIT(0) #define EIP197_TOKEN_STAT_LAST_PACKET BIT(1) #define EIP197_TOKEN_OPCODE_DIRECTION 0x0 @@ -432,6 +443,7 @@ struct safexcel_token { #define EIP197_TOKEN_OPCODE_NOOP EIP197_TOKEN_OPCODE_INSERT #define EIP197_TOKEN_OPCODE_RETRIEVE 0x4 #define EIP197_TOKEN_OPCODE_VERIFY 0xd +#define EIP197_TOKEN_OPCODE_CTX_ACCESS 0xe #define EIP197_TOKEN_OPCODE_BYPASS GENMASK(3, 0) static inline void eip197_noop_token(struct safexcel_token *token) @@ -442,6 +454,8 @@ static inline void eip197_noop_token(struct safexcel_token *token) /* Instructions */ #define EIP197_TOKEN_INS_INSERT_HASH_DIGEST 0x1c +#define EIP197_TOKEN_INS_ORIGIN_IV0 0x14 +#define EIP197_TOKEN_INS_ORIGIN_LEN(x) ((x) << 5) #define EIP197_TOKEN_INS_TYPE_OUTPUT BIT(5) #define EIP197_TOKEN_INS_TYPE_HASH BIT(6) #define EIP197_TOKEN_INS_TYPE_CRYTO BIT(7) @@ -468,6 +482,7 @@ struct safexcel_control_data_desc { #define EIP197_OPTION_MAGIC_VALUE BIT(0) #define EIP197_OPTION_64BIT_CTX BIT(1) +#define EIP197_OPTION_RC_AUTO (0x2 << 3) #define EIP197_OPTION_CTX_CTRL_IN_CMD BIT(8) #define EIP197_OPTION_2_TOKEN_IV_CMD GENMASK(11, 10) #define EIP197_OPTION_4_TOKEN_IV_CMD GENMASK(11, 9) @@ -629,7 +644,7 @@ struct safexcel_ahash_export_state { u32 digest; u32 state[SHA512_DIGEST_SIZE / sizeof(u32)]; - u8 cache[SHA512_BLOCK_SIZE]; + u8 cache[SHA512_BLOCK_SIZE << 1]; }; /* diff --git a/drivers/crypto/inside-secure/safexcel_cipher.c b/drivers/crypto/inside-secure/safexcel_cipher.c index de4be10b172f..8cdbdbe35681 100644 --- a/drivers/crypto/inside-secure/safexcel_cipher.c +++ b/drivers/crypto/inside-secure/safexcel_cipher.c @@ -51,6 +51,8 @@ struct safexcel_cipher_ctx { struct safexcel_cipher_req { enum safexcel_cipher_direction direction; + /* Number of result descriptors associated to the request */ + unsigned int rdescs; bool needs_inv; }; @@ -59,27 +61,26 @@ static void safexcel_skcipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv, u32 length) { struct safexcel_token *token; - unsigned offset = 0; + u32 offset = 0, block_sz = 0; if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) { switch (ctx->alg) { case SAFEXCEL_DES: - offset = DES_BLOCK_SIZE / sizeof(u32); - memcpy(cdesc->control_data.token, iv, DES_BLOCK_SIZE); + block_sz = DES_BLOCK_SIZE; cdesc->control_data.options |= EIP197_OPTION_2_TOKEN_IV_CMD; break; case SAFEXCEL_3DES: - offset = DES3_EDE_BLOCK_SIZE / sizeof(u32); - memcpy(cdesc->control_data.token, iv, DES3_EDE_BLOCK_SIZE); + block_sz = DES3_EDE_BLOCK_SIZE; cdesc->control_data.options |= EIP197_OPTION_2_TOKEN_IV_CMD; break; - case SAFEXCEL_AES: - offset = AES_BLOCK_SIZE / sizeof(u32); - memcpy(cdesc->control_data.token, iv, AES_BLOCK_SIZE); + block_sz = AES_BLOCK_SIZE; cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD; break; } + + offset = block_sz / sizeof(u32); + memcpy(cdesc->control_data.token, iv, block_sz); } token = (struct safexcel_token *)(cdesc->control_data.token + offset); @@ -91,6 +92,25 @@ static void safexcel_skcipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv, token[0].instructions = EIP197_TOKEN_INS_LAST | EIP197_TOKEN_INS_TYPE_CRYTO | EIP197_TOKEN_INS_TYPE_OUTPUT; + + if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) { + u32 last = (EIP197_MAX_TOKENS - 1) - offset; + + token[last].opcode = EIP197_TOKEN_OPCODE_CTX_ACCESS; + token[last].packet_length = EIP197_TOKEN_DIRECTION_EXTERNAL | + EIP197_TOKEN_EXEC_IF_SUCCESSFUL| + EIP197_TOKEN_CTX_OFFSET(0x2); + token[last].stat = EIP197_TOKEN_STAT_LAST_HASH | + EIP197_TOKEN_STAT_LAST_PACKET; + token[last].instructions = + EIP197_TOKEN_INS_ORIGIN_LEN(block_sz / sizeof(u32)) | + EIP197_TOKEN_INS_ORIGIN_IV0; + + /* Store the updated IV values back in the internal context + * registers. + */ + cdesc->control_data.control1 |= CONTEXT_CONTROL_CRYPTO_STORE; + } } static void safexcel_aead_token(struct safexcel_cipher_ctx *ctx, u8 *iv, @@ -333,7 +353,10 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin *ret = 0; - do { + if (unlikely(!sreq->rdescs)) + return 0; + + while (sreq->rdescs--) { rdesc = safexcel_ring_next_rptr(priv, &priv->ring[ring].rdr); if (IS_ERR(rdesc)) { dev_err(priv->dev, @@ -346,21 +369,15 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin *ret = safexcel_rdesc_check_errors(priv, rdesc); ndesc++; - } while (!rdesc->last_seg); + } safexcel_complete(priv, ring); if (src == dst) { - dma_unmap_sg(priv->dev, src, - sg_nents_for_len(src, cryptlen), - DMA_BIDIRECTIONAL); + dma_unmap_sg(priv->dev, src, sg_nents(src), DMA_BIDIRECTIONAL); } else { - dma_unmap_sg(priv->dev, src, - sg_nents_for_len(src, cryptlen), - DMA_TO_DEVICE); - dma_unmap_sg(priv->dev, dst, - sg_nents_for_len(dst, cryptlen), - DMA_FROM_DEVICE); + dma_unmap_sg(priv->dev, src, sg_nents(src), DMA_TO_DEVICE); + dma_unmap_sg(priv->dev, dst, sg_nents(dst), DMA_FROM_DEVICE); } *should_complete = true; @@ -385,26 +402,21 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, int i, ret = 0; if (src == dst) { - nr_src = dma_map_sg(priv->dev, src, - sg_nents_for_len(src, totlen), + nr_src = dma_map_sg(priv->dev, src, sg_nents(src), DMA_BIDIRECTIONAL); nr_dst = nr_src; if (!nr_src) return -EINVAL; } else { - nr_src = dma_map_sg(priv->dev, src, - sg_nents_for_len(src, totlen), + nr_src = dma_map_sg(priv->dev, src, sg_nents(src), DMA_TO_DEVICE); if (!nr_src) return -EINVAL; - nr_dst = dma_map_sg(priv->dev, dst, - sg_nents_for_len(dst, totlen), + nr_dst = dma_map_sg(priv->dev, dst, sg_nents(dst), DMA_FROM_DEVICE); if (!nr_dst) { - dma_unmap_sg(priv->dev, src, - sg_nents_for_len(src, totlen), - DMA_TO_DEVICE); + dma_unmap_sg(priv->dev, src, nr_src, DMA_TO_DEVICE); return -EINVAL; } } @@ -454,7 +466,7 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, /* result descriptors */ for_each_sg(dst, sg, nr_dst, i) { - bool first = !i, last = (i == nr_dst - 1); + bool first = !i, last = sg_is_last(sg); u32 len = sg_dma_len(sg); rdesc = safexcel_add_rdesc(priv, ring, first, last, @@ -483,16 +495,10 @@ cdesc_rollback: safexcel_ring_rollback_wptr(priv, &priv->ring[ring].cdr); if (src == dst) { - dma_unmap_sg(priv->dev, src, - sg_nents_for_len(src, totlen), - DMA_BIDIRECTIONAL); + dma_unmap_sg(priv->dev, src, nr_src, DMA_BIDIRECTIONAL); } else { - dma_unmap_sg(priv->dev, src, - sg_nents_for_len(src, totlen), - DMA_TO_DEVICE); - dma_unmap_sg(priv->dev, dst, - sg_nents_for_len(dst, totlen), - DMA_FROM_DEVICE); + dma_unmap_sg(priv->dev, src, nr_src, DMA_TO_DEVICE); + dma_unmap_sg(priv->dev, dst, nr_dst, DMA_FROM_DEVICE); } return ret; @@ -501,6 +507,7 @@ cdesc_rollback: static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv, int ring, struct crypto_async_request *base, + struct safexcel_cipher_req *sreq, bool *should_complete, int *ret) { struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(base->tfm); @@ -509,7 +516,10 @@ static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv, *ret = 0; - do { + if (unlikely(!sreq->rdescs)) + return 0; + + while (sreq->rdescs--) { rdesc = safexcel_ring_next_rptr(priv, &priv->ring[ring].rdr); if (IS_ERR(rdesc)) { dev_err(priv->dev, @@ -522,7 +532,7 @@ static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv, *ret = safexcel_rdesc_check_errors(priv, rdesc); ndesc++; - } while (!rdesc->last_seg); + } safexcel_complete(priv, ring); @@ -560,16 +570,35 @@ static int safexcel_skcipher_handle_result(struct safexcel_crypto_priv *priv, { struct skcipher_request *req = skcipher_request_cast(async); struct safexcel_cipher_req *sreq = skcipher_request_ctx(req); + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(async->tfm); int err; if (sreq->needs_inv) { sreq->needs_inv = false; - err = safexcel_handle_inv_result(priv, ring, async, + err = safexcel_handle_inv_result(priv, ring, async, sreq, should_complete, ret); } else { err = safexcel_handle_req_result(priv, ring, async, req->src, req->dst, req->cryptlen, sreq, should_complete, ret); + + if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) { + u32 block_sz = 0; + + switch (ctx->alg) { + case SAFEXCEL_DES: + block_sz = DES_BLOCK_SIZE; + break; + case SAFEXCEL_3DES: + block_sz = DES3_EDE_BLOCK_SIZE; + break; + case SAFEXCEL_AES: + block_sz = AES_BLOCK_SIZE; + break; + } + + memcpy(req->iv, ctx->base.ctxr->data, block_sz); + } } return err; @@ -587,7 +616,7 @@ static int safexcel_aead_handle_result(struct safexcel_crypto_priv *priv, if (sreq->needs_inv) { sreq->needs_inv = false; - err = safexcel_handle_inv_result(priv, ring, async, + err = safexcel_handle_inv_result(priv, ring, async, sreq, should_complete, ret); } else { err = safexcel_handle_req_result(priv, ring, async, req->src, @@ -633,6 +662,8 @@ static int safexcel_skcipher_send(struct crypto_async_request *async, int ring, ret = safexcel_send_req(async, ring, sreq, req->src, req->dst, req->cryptlen, 0, 0, req->iv, commands, results); + + sreq->rdescs = *results; return ret; } @@ -655,6 +686,7 @@ static int safexcel_aead_send(struct crypto_async_request *async, int ring, req->cryptlen, req->assoclen, crypto_aead_authsize(tfm), req->iv, commands, results); + sreq->rdescs = *results; return ret; } diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c index ac9282c1a5ec..a80a5e757b1f 100644 --- a/drivers/crypto/inside-secure/safexcel_hash.c +++ b/drivers/crypto/inside-secure/safexcel_hash.c @@ -41,19 +41,21 @@ struct safexcel_ahash_req { u64 len[2]; u64 processed[2]; - u8 cache[SHA512_BLOCK_SIZE] __aligned(sizeof(u32)); + u8 cache[SHA512_BLOCK_SIZE << 1] __aligned(sizeof(u32)); dma_addr_t cache_dma; unsigned int cache_sz; - u8 cache_next[SHA512_BLOCK_SIZE] __aligned(sizeof(u32)); + u8 cache_next[SHA512_BLOCK_SIZE << 1] __aligned(sizeof(u32)); }; static inline u64 safexcel_queued_len(struct safexcel_ahash_req *req) { - if (req->len[1] > req->processed[1]) - return 0xffffffff - (req->len[0] - req->processed[0]); + u64 len, processed; - return req->len[0] - req->processed[0]; + len = (0xffffffff * req->len[1]) + req->len[0]; + processed = (0xffffffff * req->processed[1]) + req->processed[0]; + + return len - processed; } static void safexcel_hash_token(struct safexcel_command_desc *cdesc, @@ -87,6 +89,9 @@ static void safexcel_context_control(struct safexcel_ahash_ctx *ctx, cdesc->control_data.control0 |= ctx->alg; cdesc->control_data.control0 |= req->digest; + if (!req->finish) + cdesc->control_data.control0 |= CONTEXT_CONTROL_NO_FINISH_HASH; + if (req->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED) { if (req->processed[0] || req->processed[1]) { if (ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_MD5) @@ -105,9 +110,6 @@ static void safexcel_context_control(struct safexcel_ahash_ctx *ctx, cdesc->control_data.control0 |= CONTEXT_CONTROL_RESTART_HASH; } - if (!req->finish) - cdesc->control_data.control0 |= CONTEXT_CONTROL_NO_FINISH_HASH; - /* * Copy the input digest if needed, and setup the context * fields. Do this now as we need it to setup the first command @@ -183,6 +185,7 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin dma_unmap_single(priv->dev, sreq->cache_dma, sreq->cache_sz, DMA_TO_DEVICE); sreq->cache_dma = 0; + sreq->cache_sz = 0; } if (sreq->finish) @@ -209,11 +212,15 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, struct safexcel_command_desc *cdesc, *first_cdesc = NULL; struct safexcel_result_desc *rdesc; struct scatterlist *sg; - int i, extra, n_cdesc = 0, ret = 0; - u64 queued, len, cache_len; + int i, extra = 0, n_cdesc = 0, ret = 0; + u64 queued, len, cache_len, cache_max; + + cache_max = crypto_ahash_blocksize(ahash); + if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC) + cache_max <<= 1; queued = len = safexcel_queued_len(req); - if (queued <= crypto_ahash_blocksize(ahash)) + if (queued <= cache_max) cache_len = queued; else cache_len = queued - areq->nbytes; @@ -223,26 +230,23 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, * fit into full blocks, cache it for the next send() call. */ extra = queued & (crypto_ahash_blocksize(ahash) - 1); + + if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC && + extra < crypto_ahash_blocksize(ahash)) + extra += crypto_ahash_blocksize(ahash); + + /* If this is not the last request and the queued data + * is a multiple of a block, cache the last one for now. + */ if (!extra) - /* If this is not the last request and the queued data - * is a multiple of a block, cache the last one for now. - */ extra = crypto_ahash_blocksize(ahash); - if (extra) { - sg_pcopy_to_buffer(areq->src, sg_nents(areq->src), - req->cache_next, extra, - areq->nbytes - extra); - - queued -= extra; - len -= extra; + sg_pcopy_to_buffer(areq->src, sg_nents(areq->src), + req->cache_next, extra, + areq->nbytes - extra); - if (!queued) { - *commands = 0; - *results = 0; - return 0; - } - } + queued -= extra; + len -= extra; } /* Add a command descriptor for the cached data, if any */ @@ -269,8 +273,7 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, } /* Now handle the current ahash request buffer(s) */ - req->nents = dma_map_sg(priv->dev, areq->src, - sg_nents_for_len(areq->src, areq->nbytes), + req->nents = dma_map_sg(priv->dev, areq->src, sg_nents(areq->src), DMA_TO_DEVICE); if (!req->nents) { ret = -ENOMEM; @@ -345,6 +348,7 @@ unmap_cache: if (req->cache_dma) { dma_unmap_single(priv->dev, req->cache_dma, req->cache_sz, DMA_TO_DEVICE); + req->cache_dma = 0; req->cache_sz = 0; } @@ -486,7 +490,7 @@ static int safexcel_ahash_exit_inv(struct crypto_tfm *tfm) struct safexcel_inv_result result = {}; int ring = ctx->base.ring; - memset(req, 0, sizeof(struct ahash_request)); + memset(req, 0, EIP197_AHASH_REQ_SIZE); /* create invalidation request */ init_completion(&result.completion); @@ -519,10 +523,9 @@ static int safexcel_ahash_exit_inv(struct crypto_tfm *tfm) /* safexcel_ahash_cache: cache data until at least one request can be sent to * the engine, aka. when there is at least 1 block size in the pipe. */ -static int safexcel_ahash_cache(struct ahash_request *areq) +static int safexcel_ahash_cache(struct ahash_request *areq, u32 cache_max) { struct safexcel_ahash_req *req = ahash_request_ctx(areq); - struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq); u64 queued, cache_len; /* queued: everything accepted by the driver which will be handled by @@ -539,7 +542,7 @@ static int safexcel_ahash_cache(struct ahash_request *areq) * In case there isn't enough bytes to proceed (less than a * block size), cache the data until we have enough. */ - if (cache_len + areq->nbytes <= crypto_ahash_blocksize(ahash)) { + if (cache_len + areq->nbytes <= cache_max) { sg_pcopy_to_buffer(areq->src, sg_nents(areq->src), req->cache + cache_len, areq->nbytes, 0); @@ -599,6 +602,7 @@ static int safexcel_ahash_update(struct ahash_request *areq) { struct safexcel_ahash_req *req = ahash_request_ctx(areq); struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq); + u32 cache_max; /* If the request is 0 length, do nothing */ if (!areq->nbytes) @@ -608,7 +612,11 @@ static int safexcel_ahash_update(struct ahash_request *areq) if (req->len[0] < areq->nbytes) req->len[1]++; - safexcel_ahash_cache(areq); + cache_max = crypto_ahash_blocksize(ahash); + if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC) + cache_max <<= 1; + + safexcel_ahash_cache(areq, cache_max); /* * We're not doing partial updates when performing an hmac request. @@ -621,7 +629,7 @@ static int safexcel_ahash_update(struct ahash_request *areq) return safexcel_ahash_enqueue(areq); if (!req->last_req && - safexcel_queued_len(req) > crypto_ahash_blocksize(ahash)) + safexcel_queued_len(req) > cache_max) return safexcel_ahash_enqueue(areq); return 0; @@ -678,6 +686,11 @@ static int safexcel_ahash_export(struct ahash_request *areq, void *out) struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq); struct safexcel_ahash_req *req = ahash_request_ctx(areq); struct safexcel_ahash_export_state *export = out; + u32 cache_sz; + + cache_sz = crypto_ahash_blocksize(ahash); + if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC) + cache_sz <<= 1; export->len[0] = req->len[0]; export->len[1] = req->len[1]; @@ -687,7 +700,7 @@ static int safexcel_ahash_export(struct ahash_request *areq, void *out) export->digest = req->digest; memcpy(export->state, req->state, req->state_sz); - memcpy(export->cache, req->cache, crypto_ahash_blocksize(ahash)); + memcpy(export->cache, req->cache, cache_sz); return 0; } @@ -697,12 +710,17 @@ static int safexcel_ahash_import(struct ahash_request *areq, const void *in) struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq); struct safexcel_ahash_req *req = ahash_request_ctx(areq); const struct safexcel_ahash_export_state *export = in; + u32 cache_sz; int ret; ret = crypto_ahash_init(areq); if (ret) return ret; + cache_sz = crypto_ahash_blocksize(ahash); + if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC) + cache_sz <<= 1; + req->len[0] = export->len[0]; req->len[1] = export->len[1]; req->processed[0] = export->processed[0]; @@ -710,7 +728,7 @@ static int safexcel_ahash_import(struct ahash_request *areq, const void *in) req->digest = export->digest; - memcpy(req->cache, export->cache, crypto_ahash_blocksize(ahash)); + memcpy(req->cache, export->cache, cache_sz); memcpy(req->state, export->state, req->state_sz); return 0; diff --git a/drivers/crypto/inside-secure/safexcel_ring.c b/drivers/crypto/inside-secure/safexcel_ring.c index eb75fa684876..142bc3f5c45c 100644 --- a/drivers/crypto/inside-secure/safexcel_ring.c +++ b/drivers/crypto/inside-secure/safexcel_ring.c @@ -145,6 +145,9 @@ struct safexcel_command_desc *safexcel_add_cdesc(struct safexcel_crypto_priv *pr (lower_32_bits(context) & GENMASK(31, 2)) >> 2; cdesc->control_data.context_hi = upper_32_bits(context); + if (priv->version == EIP197B || priv->version == EIP197D) + cdesc->control_data.options |= EIP197_OPTION_RC_AUTO; + /* TODO: large xform HMAC with SHA-384/512 uses refresh = 3 */ cdesc->control_data.refresh = 2; diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index e5cf3a59c420..acedafe3fa98 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -100,7 +100,7 @@ struct buffer_desc { u16 pkt_len; u16 buf_len; #endif - u32 phys_addr; + dma_addr_t phys_addr; u32 __reserved[4]; struct buffer_desc *next; enum dma_data_direction dir; @@ -117,9 +117,9 @@ struct crypt_ctl { u8 mode; /* NPE_OP_* operation mode */ #endif u8 iv[MAX_IVLEN]; /* IV for CBC mode or CTR IV for CTR mode */ - u32 icv_rev_aes; /* icv or rev aes */ - u32 src_buf; - u32 dst_buf; + dma_addr_t icv_rev_aes; /* icv or rev aes */ + dma_addr_t src_buf; + dma_addr_t dst_buf; #ifdef __ARMEB__ u16 auth_offs; /* Authentication start offset */ u16 auth_len; /* Authentication data length */ @@ -320,7 +320,8 @@ static struct crypt_ctl *get_crypt_desc_emerg(void) } } -static void free_buf_chain(struct device *dev, struct buffer_desc *buf,u32 phys) +static void free_buf_chain(struct device *dev, struct buffer_desc *buf, + dma_addr_t phys) { while (buf) { struct buffer_desc *buf1; @@ -602,7 +603,7 @@ static int register_chain_var(struct crypto_tfm *tfm, u8 xpad, u32 target, struct buffer_desc *buf; int i; u8 *pad; - u32 pad_phys, buf_phys; + dma_addr_t pad_phys, buf_phys; BUILD_BUG_ON(NPE_CTX_LEN < HMAC_PAD_BLOCKLEN); pad = dma_pool_alloc(ctx_pool, GFP_KERNEL, &pad_phys); @@ -787,7 +788,7 @@ static struct buffer_desc *chainup_buffers(struct device *dev, for (; nbytes > 0; sg = sg_next(sg)) { unsigned len = min(nbytes, sg->length); struct buffer_desc *next_buf; - u32 next_buf_phys; + dma_addr_t next_buf_phys; void *ptr; nbytes -= len; diff --git a/drivers/crypto/marvell/cesa.c b/drivers/crypto/marvell/cesa.c index a4aa6813de4b..8a5f0b0bdf77 100644 --- a/drivers/crypto/marvell/cesa.c +++ b/drivers/crypto/marvell/cesa.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Support for Marvell's Cryptographic Engine and Security Accelerator (CESA) * that can be found on the following platform: Orion, Kirkwood, Armada. This @@ -8,10 +9,6 @@ * * This work is based on an initial version written by * Sebastian Andrzej Siewior < sebastian at breakpoint dot cc > - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/crypto/marvell/cipher.c b/drivers/crypto/marvell/cipher.c index 2fd936b19c6d..f4321f3c0777 100644 --- a/drivers/crypto/marvell/cipher.c +++ b/drivers/crypto/marvell/cipher.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Cipher algorithms supported by the CESA: DES, 3DES and AES. * @@ -6,10 +7,6 @@ * * This work is based on an initial version written by * Sebastian Andrzej Siewior < sebastian at breakpoint dot cc > - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include <crypto/aes.h> diff --git a/drivers/crypto/marvell/hash.c b/drivers/crypto/marvell/hash.c index fd456dd703bf..0f0ac851f4eb 100644 --- a/drivers/crypto/marvell/hash.c +++ b/drivers/crypto/marvell/hash.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Hash algorithms supported by the CESA: MD5, SHA1 and SHA256. * @@ -6,10 +7,6 @@ * * This work is based on an initial version written by * Sebastian Andrzej Siewior < sebastian at breakpoint dot cc > - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include <crypto/hmac.h> diff --git a/drivers/crypto/marvell/tdma.c b/drivers/crypto/marvell/tdma.c index d0ef171c18df..45939d53e8d6 100644 --- a/drivers/crypto/marvell/tdma.c +++ b/drivers/crypto/marvell/tdma.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Provide TDMA helper functions used by cipher and hash algorithm * implementations. @@ -7,10 +8,6 @@ * * This work is based on an initial version written by * Sebastian Andrzej Siewior < sebastian at breakpoint dot cc > - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include "cesa.h" diff --git a/drivers/crypto/mediatek/mtk-aes.c b/drivers/crypto/mediatek/mtk-aes.c index c2058cf59f57..b7477ee32ca0 100644 --- a/drivers/crypto/mediatek/mtk-aes.c +++ b/drivers/crypto/mediatek/mtk-aes.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Cryptographic API. * @@ -5,10 +6,6 @@ * * Copyright (c) 2016 Ryder Lee <ryder.lee@mediatek.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Some ideas are from atmel-aes.c drivers. */ diff --git a/drivers/crypto/mediatek/mtk-platform.c b/drivers/crypto/mediatek/mtk-platform.c index 5660e5e5e022..125318a88cd4 100644 --- a/drivers/crypto/mediatek/mtk-platform.c +++ b/drivers/crypto/mediatek/mtk-platform.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for EIP97 cryptographic accelerator. * * Copyright (c) 2016 Ryder Lee <ryder.lee@mediatek.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/clk.h> diff --git a/drivers/crypto/mediatek/mtk-platform.h b/drivers/crypto/mediatek/mtk-platform.h index f0831f1742ab..47920c51abac 100644 --- a/drivers/crypto/mediatek/mtk-platform.h +++ b/drivers/crypto/mediatek/mtk-platform.h @@ -1,12 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Driver for EIP97 cryptographic accelerator. * * Copyright (c) 2016 Ryder Lee <ryder.lee@mediatek.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef __MTK_PLATFORM_H_ diff --git a/drivers/crypto/mediatek/mtk-sha.c b/drivers/crypto/mediatek/mtk-sha.c index a0806ba40c68..f03b0f06fb2f 100644 --- a/drivers/crypto/mediatek/mtk-sha.c +++ b/drivers/crypto/mediatek/mtk-sha.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Cryptographic API. * @@ -5,10 +6,6 @@ * * Copyright (c) 2016 Ryder Lee <ryder.lee@mediatek.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Some ideas are from atmel-sha.c and omap-sham.c drivers. */ diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index bdc4c42d3ac8..f1fa637cb029 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -986,8 +986,6 @@ static int mxs_dcp_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct dcp *sdcp = NULL; int i, ret; - - struct resource *iores; int dcp_vmi_irq, dcp_irq; if (global_sdcp) { @@ -995,7 +993,6 @@ static int mxs_dcp_probe(struct platform_device *pdev) return -ENODEV; } - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); dcp_vmi_irq = platform_get_irq(pdev, 0); if (dcp_vmi_irq < 0) { dev_err(dev, "Failed to get IRQ: (%d)!\n", dcp_vmi_irq); @@ -1013,7 +1010,7 @@ static int mxs_dcp_probe(struct platform_device *pdev) return -ENOMEM; sdcp->dev = dev; - sdcp->base = devm_ioremap_resource(dev, iores); + sdcp->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(sdcp->base)) return PTR_ERR(sdcp->base); diff --git a/drivers/crypto/nx/nx-842-powernv.c b/drivers/crypto/nx/nx-842-powernv.c index 4acbc47973e9..e78ff5c65ed6 100644 --- a/drivers/crypto/nx/nx-842-powernv.c +++ b/drivers/crypto/nx/nx-842-powernv.c @@ -27,8 +27,6 @@ MODULE_ALIAS_CRYPTO("842-nx"); #define WORKMEM_ALIGN (CRB_ALIGN) #define CSB_WAIT_MAX (5000) /* ms */ #define VAS_RETRIES (10) -/* # of requests allowed per RxFIFO at a time. 0 for unlimited */ -#define MAX_CREDITS_PER_RXFIFO (1024) struct nx842_workmem { /* Below fields must be properly aligned */ @@ -812,7 +810,11 @@ static int __init vas_cfg_coproc_info(struct device_node *dn, int chip_id, rxattr.lnotify_lpid = lpid; rxattr.lnotify_pid = pid; rxattr.lnotify_tid = tid; - rxattr.wcreds_max = MAX_CREDITS_PER_RXFIFO; + /* + * Maximum RX window credits can not be more than #CRBs in + * RxFIFO. Otherwise, can get checkstop if RxFIFO overruns. + */ + rxattr.wcreds_max = fifo_size / CRB_SIZE; /* * Open a VAS receice window which is used to configure RxFIFO diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c index 5c4aa606208c..2de5e3672e42 100644 --- a/drivers/crypto/nx/nx-842-pseries.c +++ b/drivers/crypto/nx/nx-842-pseries.c @@ -856,7 +856,7 @@ static ssize_t nx842_##_name##_show(struct device *dev, \ rcu_read_lock(); \ local_devdata = rcu_dereference(devdata); \ if (local_devdata) \ - p = snprintf(buf, PAGE_SIZE, "%ld\n", \ + p = snprintf(buf, PAGE_SIZE, "%lld\n", \ atomic64_read(&local_devdata->counters->_name)); \ rcu_read_unlock(); \ return p; \ @@ -909,7 +909,7 @@ static ssize_t nx842_timehist_show(struct device *dev, } for (i = 0; i < (NX842_HIST_SLOTS - 2); i++) { - bytes = snprintf(p, bytes_remain, "%u-%uus:\t%ld\n", + bytes = snprintf(p, bytes_remain, "%u-%uus:\t%lld\n", i ? (2<<(i-1)) : 0, (2<<i)-1, atomic64_read(×[i])); bytes_remain -= bytes; @@ -917,7 +917,7 @@ static ssize_t nx842_timehist_show(struct device *dev, } /* The last bucket holds everything over * 2<<(NX842_HIST_SLOTS - 2) us */ - bytes = snprintf(p, bytes_remain, "%uus - :\t%ld\n", + bytes = snprintf(p, bytes_remain, "%uus - :\t%lld\n", 2<<(NX842_HIST_SLOTS - 2), atomic64_read(×[(NX842_HIST_SLOTS - 1)])); p += bytes; diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c index 428c273a1ab6..28817880c76d 100644 --- a/drivers/crypto/nx/nx.c +++ b/drivers/crypto/nx/nx.c @@ -569,9 +569,7 @@ static int nx_register_algs(void) memset(&nx_driver.stats, 0, sizeof(struct nx_stats)); - rc = NX_DEBUGFS_INIT(&nx_driver); - if (rc) - goto out; + NX_DEBUGFS_INIT(&nx_driver); nx_driver.of.status = NX_OKAY; diff --git a/drivers/crypto/nx/nx.h b/drivers/crypto/nx/nx.h index c3e54af18645..c6b5a3be02be 100644 --- a/drivers/crypto/nx/nx.h +++ b/drivers/crypto/nx/nx.h @@ -76,20 +76,12 @@ struct nx_stats { atomic_t last_error_pid; }; -struct nx_debugfs { - struct dentry *dfs_root; - struct dentry *dfs_aes_ops, *dfs_aes_bytes; - struct dentry *dfs_sha256_ops, *dfs_sha256_bytes; - struct dentry *dfs_sha512_ops, *dfs_sha512_bytes; - struct dentry *dfs_errors, *dfs_last_error, *dfs_last_error_pid; -}; - struct nx_crypto_driver { struct nx_stats stats; struct nx_of of; struct vio_dev *viodev; struct vio_driver viodriver; - struct nx_debugfs dfs; + struct dentry *dfs_root; }; #define NX_GCM4106_NONCE_LEN (4) @@ -177,7 +169,7 @@ struct nx_sg *nx_walk_and_build(struct nx_sg *, unsigned int, #define NX_DEBUGFS_INIT(drv) nx_debugfs_init(drv) #define NX_DEBUGFS_FINI(drv) nx_debugfs_fini(drv) -int nx_debugfs_init(struct nx_crypto_driver *); +void nx_debugfs_init(struct nx_crypto_driver *); void nx_debugfs_fini(struct nx_crypto_driver *); #else #define NX_DEBUGFS_INIT(drv) (0) diff --git a/drivers/crypto/nx/nx_debugfs.c b/drivers/crypto/nx/nx_debugfs.c index 03e4f0363c6a..e0d44a5512ab 100644 --- a/drivers/crypto/nx/nx_debugfs.c +++ b/drivers/crypto/nx/nx_debugfs.c @@ -30,62 +30,37 @@ * Documentation/ABI/testing/debugfs-pfo-nx-crypto */ -int nx_debugfs_init(struct nx_crypto_driver *drv) +void nx_debugfs_init(struct nx_crypto_driver *drv) { - struct nx_debugfs *dfs = &drv->dfs; + struct dentry *root; - dfs->dfs_root = debugfs_create_dir(NX_NAME, NULL); + root = debugfs_create_dir(NX_NAME, NULL); + drv->dfs_root = root; - dfs->dfs_aes_ops = - debugfs_create_u32("aes_ops", - S_IRUSR | S_IRGRP | S_IROTH, - dfs->dfs_root, (u32 *)&drv->stats.aes_ops); - dfs->dfs_sha256_ops = - debugfs_create_u32("sha256_ops", - S_IRUSR | S_IRGRP | S_IROTH, - dfs->dfs_root, - (u32 *)&drv->stats.sha256_ops); - dfs->dfs_sha512_ops = - debugfs_create_u32("sha512_ops", - S_IRUSR | S_IRGRP | S_IROTH, - dfs->dfs_root, - (u32 *)&drv->stats.sha512_ops); - dfs->dfs_aes_bytes = - debugfs_create_u64("aes_bytes", - S_IRUSR | S_IRGRP | S_IROTH, - dfs->dfs_root, - (u64 *)&drv->stats.aes_bytes); - dfs->dfs_sha256_bytes = - debugfs_create_u64("sha256_bytes", - S_IRUSR | S_IRGRP | S_IROTH, - dfs->dfs_root, - (u64 *)&drv->stats.sha256_bytes); - dfs->dfs_sha512_bytes = - debugfs_create_u64("sha512_bytes", - S_IRUSR | S_IRGRP | S_IROTH, - dfs->dfs_root, - (u64 *)&drv->stats.sha512_bytes); - dfs->dfs_errors = - debugfs_create_u32("errors", - S_IRUSR | S_IRGRP | S_IROTH, - dfs->dfs_root, (u32 *)&drv->stats.errors); - dfs->dfs_last_error = - debugfs_create_u32("last_error", - S_IRUSR | S_IRGRP | S_IROTH, - dfs->dfs_root, - (u32 *)&drv->stats.last_error); - dfs->dfs_last_error_pid = - debugfs_create_u32("last_error_pid", - S_IRUSR | S_IRGRP | S_IROTH, - dfs->dfs_root, - (u32 *)&drv->stats.last_error_pid); - return 0; + debugfs_create_u32("aes_ops", S_IRUSR | S_IRGRP | S_IROTH, + root, (u32 *)&drv->stats.aes_ops); + debugfs_create_u32("sha256_ops", S_IRUSR | S_IRGRP | S_IROTH, + root, (u32 *)&drv->stats.sha256_ops); + debugfs_create_u32("sha512_ops", S_IRUSR | S_IRGRP | S_IROTH, + root, (u32 *)&drv->stats.sha512_ops); + debugfs_create_u64("aes_bytes", S_IRUSR | S_IRGRP | S_IROTH, + root, (u64 *)&drv->stats.aes_bytes); + debugfs_create_u64("sha256_bytes", S_IRUSR | S_IRGRP | S_IROTH, + root, (u64 *)&drv->stats.sha256_bytes); + debugfs_create_u64("sha512_bytes", S_IRUSR | S_IRGRP | S_IROTH, + root, (u64 *)&drv->stats.sha512_bytes); + debugfs_create_u32("errors", S_IRUSR | S_IRGRP | S_IROTH, + root, (u32 *)&drv->stats.errors); + debugfs_create_u32("last_error", S_IRUSR | S_IRGRP | S_IROTH, + root, (u32 *)&drv->stats.last_error); + debugfs_create_u32("last_error_pid", S_IRUSR | S_IRGRP | S_IROTH, + root, (u32 *)&drv->stats.last_error_pid); } void nx_debugfs_fini(struct nx_crypto_driver *drv) { - debugfs_remove_recursive(drv->dfs.dfs_root); + debugfs_remove_recursive(drv->dfs_root); } #endif diff --git a/drivers/crypto/omap-aes-gcm.c b/drivers/crypto/omap-aes-gcm.c index 0cc3b65d7162..9bbedbccfadf 100644 --- a/drivers/crypto/omap-aes-gcm.c +++ b/drivers/crypto/omap-aes-gcm.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Cryptographic API. * * Support for OMAP AES GCM HW acceleration. * * Copyright (c) 2016 Texas Instruments Incorporated - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * */ #include <linux/errno.h> diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 0120feb2d746..45a4647f7030 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Cryptographic API. * @@ -6,11 +7,6 @@ * Copyright (c) 2010 Nokia Corporation * Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com> * Copyright (c) 2011 Texas Instruments Incorporated - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * */ #define pr_fmt(fmt) "%20s: " fmt, __func__ diff --git a/drivers/crypto/omap-aes.h b/drivers/crypto/omap-aes.h index 7e02920ef6f8..2d4b1f87a1c9 100644 --- a/drivers/crypto/omap-aes.h +++ b/drivers/crypto/omap-aes.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Cryptographic API. * * Support for OMAP AES HW ACCELERATOR defines * * Copyright (c) 2015 Texas Instruments Incorporated - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * */ #ifndef __OMAP_AES_H__ #define __OMAP_AES_H__ diff --git a/drivers/crypto/omap-crypto.c b/drivers/crypto/omap-crypto.c index 2c42e4b4a6e9..7d592d93bb1c 100644 --- a/drivers/crypto/omap-crypto.c +++ b/drivers/crypto/omap-crypto.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP Crypto driver common support routines. * * Copyright (c) 2017 Texas Instruments Incorporated * Tero Kristo <t-kristo@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/crypto/omap-crypto.h b/drivers/crypto/omap-crypto.h index 36a230eb87af..506ccde6f380 100644 --- a/drivers/crypto/omap-crypto.h +++ b/drivers/crypto/omap-crypto.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * OMAP Crypto driver common support routines. * * Copyright (c) 2017 Texas Instruments Incorporated * Tero Kristo <t-kristo@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #ifndef __CRYPTO_OMAP_CRYPTO_H diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index 3d82d18ff810..1ee69a979677 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Support for OMAP DES and Triple DES HW acceleration. * * Copyright (c) 2013 Texas Instruments Incorporated * Author: Joel Fernandes <joelf@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * */ #define pr_fmt(fmt) "%s: " fmt, __func__ diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 51b20abac464..e8e2907bd9f4 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Cryptographic API. * @@ -7,10 +8,6 @@ * Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com> * Copyright (c) 2011 Texas Instruments Incorporated * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Some ideas are from old omap-sha1-md5.c driver. */ diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c index c8d401646902..b50eb55f8f57 100644 --- a/drivers/crypto/qat/qat_common/qat_algs.c +++ b/drivers/crypto/qat/qat_common/qat_algs.c @@ -131,7 +131,6 @@ struct qat_alg_ablkcipher_ctx { struct icp_qat_fw_la_bulk_req dec_fw_req; struct qat_crypto_instance *inst; struct crypto_tfm *tfm; - spinlock_t lock; /* protects qat_alg_ablkcipher_ctx struct */ }; static int qat_get_inter_state_size(enum icp_qat_hw_auth_algo qat_hash_alg) @@ -223,6 +222,9 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash, return -EFAULT; offset = round_up(qat_get_inter_state_size(ctx->qat_hash_alg), 8); + if (offset < 0) + return -EFAULT; + hash_state_out = (__be32 *)(hash->sha.state1 + offset); hash512_state_out = (__be64 *)hash_state_out; @@ -253,7 +255,24 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash, return 0; } -static void qat_alg_init_common_hdr(struct icp_qat_fw_comn_req_hdr *header) +static void qat_alg_init_hdr_iv_updt(struct icp_qat_fw_comn_req_hdr *header) +{ + ICP_QAT_FW_LA_CIPH_IV_FLD_FLAG_SET(header->serv_specif_flags, + ICP_QAT_FW_CIPH_IV_64BIT_PTR); + ICP_QAT_FW_LA_UPDATE_STATE_SET(header->serv_specif_flags, + ICP_QAT_FW_LA_UPDATE_STATE); +} + +static void qat_alg_init_hdr_no_iv_updt(struct icp_qat_fw_comn_req_hdr *header) +{ + ICP_QAT_FW_LA_CIPH_IV_FLD_FLAG_SET(header->serv_specif_flags, + ICP_QAT_FW_CIPH_IV_16BYTE_DATA); + ICP_QAT_FW_LA_UPDATE_STATE_SET(header->serv_specif_flags, + ICP_QAT_FW_LA_NO_UPDATE_STATE); +} + +static void qat_alg_init_common_hdr(struct icp_qat_fw_comn_req_hdr *header, + int aead) { header->hdr_flags = ICP_QAT_FW_COMN_HDR_FLAGS_BUILD(ICP_QAT_FW_COMN_REQ_FLAG_SET); @@ -263,12 +282,12 @@ static void qat_alg_init_common_hdr(struct icp_qat_fw_comn_req_hdr *header) QAT_COMN_PTR_TYPE_SGL); ICP_QAT_FW_LA_PARTIAL_SET(header->serv_specif_flags, ICP_QAT_FW_LA_PARTIAL_NONE); - ICP_QAT_FW_LA_CIPH_IV_FLD_FLAG_SET(header->serv_specif_flags, - ICP_QAT_FW_CIPH_IV_16BYTE_DATA); + if (aead) + qat_alg_init_hdr_no_iv_updt(header); + else + qat_alg_init_hdr_iv_updt(header); ICP_QAT_FW_LA_PROTO_SET(header->serv_specif_flags, ICP_QAT_FW_LA_NO_PROTO); - ICP_QAT_FW_LA_UPDATE_STATE_SET(header->serv_specif_flags, - ICP_QAT_FW_LA_NO_UPDATE_STATE); } static int qat_alg_aead_init_enc_session(struct crypto_aead *aead_tfm, @@ -303,7 +322,7 @@ static int qat_alg_aead_init_enc_session(struct crypto_aead *aead_tfm, return -EFAULT; /* Request setup */ - qat_alg_init_common_hdr(header); + qat_alg_init_common_hdr(header, 1); header->service_cmd_id = ICP_QAT_FW_LA_CMD_CIPHER_HASH; ICP_QAT_FW_LA_DIGEST_IN_BUFFER_SET(header->serv_specif_flags, ICP_QAT_FW_LA_DIGEST_IN_BUFFER); @@ -390,7 +409,7 @@ static int qat_alg_aead_init_dec_session(struct crypto_aead *aead_tfm, return -EFAULT; /* Request setup */ - qat_alg_init_common_hdr(header); + qat_alg_init_common_hdr(header, 1); header->service_cmd_id = ICP_QAT_FW_LA_CMD_HASH_CIPHER; ICP_QAT_FW_LA_DIGEST_IN_BUFFER_SET(header->serv_specif_flags, ICP_QAT_FW_LA_DIGEST_IN_BUFFER); @@ -454,7 +473,7 @@ static void qat_alg_ablkcipher_init_com(struct qat_alg_ablkcipher_ctx *ctx, struct icp_qat_fw_cipher_cd_ctrl_hdr *cd_ctrl = (void *)&req->cd_ctrl; memcpy(cd->aes.key, key, keylen); - qat_alg_init_common_hdr(header); + qat_alg_init_common_hdr(header, 0); header->service_cmd_id = ICP_QAT_FW_LA_CMD_CIPHER; cd_pars->u.s.content_desc_params_sz = sizeof(struct icp_qat_hw_cipher_algo_blk) >> 3; @@ -576,45 +595,52 @@ bad_key: return -EINVAL; } -static int qat_alg_aead_setkey(struct crypto_aead *tfm, const uint8_t *key, +static int qat_alg_aead_rekey(struct crypto_aead *tfm, const uint8_t *key, + unsigned int keylen) +{ + struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(tfm); + + memset(ctx->enc_cd, 0, sizeof(*ctx->enc_cd)); + memset(ctx->dec_cd, 0, sizeof(*ctx->dec_cd)); + memset(&ctx->enc_fw_req, 0, sizeof(ctx->enc_fw_req)); + memset(&ctx->dec_fw_req, 0, sizeof(ctx->dec_fw_req)); + + return qat_alg_aead_init_sessions(tfm, key, keylen, + ICP_QAT_HW_CIPHER_CBC_MODE); +} + +static int qat_alg_aead_newkey(struct crypto_aead *tfm, const uint8_t *key, unsigned int keylen) { struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(tfm); + struct qat_crypto_instance *inst = NULL; + int node = get_current_node(); struct device *dev; + int ret; - if (ctx->enc_cd) { - /* rekeying */ - dev = &GET_DEV(ctx->inst->accel_dev); - memset(ctx->enc_cd, 0, sizeof(*ctx->enc_cd)); - memset(ctx->dec_cd, 0, sizeof(*ctx->dec_cd)); - memset(&ctx->enc_fw_req, 0, sizeof(ctx->enc_fw_req)); - memset(&ctx->dec_fw_req, 0, sizeof(ctx->dec_fw_req)); - } else { - /* new key */ - int node = get_current_node(); - struct qat_crypto_instance *inst = - qat_crypto_get_instance_node(node); - if (!inst) { - return -EINVAL; - } - - dev = &GET_DEV(inst->accel_dev); - ctx->inst = inst; - ctx->enc_cd = dma_alloc_coherent(dev, sizeof(*ctx->enc_cd), - &ctx->enc_cd_paddr, - GFP_ATOMIC); - if (!ctx->enc_cd) { - return -ENOMEM; - } - ctx->dec_cd = dma_alloc_coherent(dev, sizeof(*ctx->dec_cd), - &ctx->dec_cd_paddr, - GFP_ATOMIC); - if (!ctx->dec_cd) { - goto out_free_enc; - } + inst = qat_crypto_get_instance_node(node); + if (!inst) + return -EINVAL; + dev = &GET_DEV(inst->accel_dev); + ctx->inst = inst; + ctx->enc_cd = dma_alloc_coherent(dev, sizeof(*ctx->enc_cd), + &ctx->enc_cd_paddr, + GFP_ATOMIC); + if (!ctx->enc_cd) { + ret = -ENOMEM; + goto out_free_inst; + } + ctx->dec_cd = dma_alloc_coherent(dev, sizeof(*ctx->dec_cd), + &ctx->dec_cd_paddr, + GFP_ATOMIC); + if (!ctx->dec_cd) { + ret = -ENOMEM; + goto out_free_enc; } - if (qat_alg_aead_init_sessions(tfm, key, keylen, - ICP_QAT_HW_CIPHER_CBC_MODE)) + + ret = qat_alg_aead_init_sessions(tfm, key, keylen, + ICP_QAT_HW_CIPHER_CBC_MODE); + if (ret) goto out_free_all; return 0; @@ -629,7 +655,21 @@ out_free_enc: dma_free_coherent(dev, sizeof(struct qat_alg_cd), ctx->enc_cd, ctx->enc_cd_paddr); ctx->enc_cd = NULL; - return -ENOMEM; +out_free_inst: + ctx->inst = NULL; + qat_crypto_put_instance(inst); + return ret; +} + +static int qat_alg_aead_setkey(struct crypto_aead *tfm, const uint8_t *key, + unsigned int keylen) +{ + struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(tfm); + + if (ctx->enc_cd) + return qat_alg_aead_rekey(tfm, key, keylen); + else + return qat_alg_aead_newkey(tfm, key, keylen); } static void qat_alg_free_bufl(struct qat_crypto_instance *inst, @@ -677,8 +717,7 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, dma_addr_t blp; dma_addr_t bloutp = 0; struct scatterlist *sg; - size_t sz_out, sz = sizeof(struct qat_alg_buf_list) + - ((1 + n) * sizeof(struct qat_alg_buf)); + size_t sz_out, sz = struct_size(bufl, bufers, n + 1); if (unlikely(!n)) return -EINVAL; @@ -715,8 +754,7 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, struct qat_alg_buf *bufers; n = sg_nents(sglout); - sz_out = sizeof(struct qat_alg_buf_list) + - ((1 + n) * sizeof(struct qat_alg_buf)); + sz_out = struct_size(buflout, bufers, n + 1); sg_nctr = 0; buflout = kzalloc_node(sz_out, GFP_ATOMIC, dev_to_node(&GET_DEV(inst->accel_dev))); @@ -801,11 +839,17 @@ static void qat_ablkcipher_alg_callback(struct icp_qat_fw_la_resp *qat_resp, struct qat_crypto_instance *inst = ctx->inst; struct ablkcipher_request *areq = qat_req->ablkcipher_req; uint8_t stat_filed = qat_resp->comn_resp.comn_status; + struct device *dev = &GET_DEV(ctx->inst->accel_dev); int res = 0, qat_res = ICP_QAT_FW_COMN_RESP_CRYPTO_STAT_GET(stat_filed); qat_alg_free_bufl(inst, qat_req); if (unlikely(qat_res != ICP_QAT_FW_COMN_STATUS_FLAG_OK)) res = -EINVAL; + + memcpy(areq->info, qat_req->iv, AES_BLOCK_SIZE); + dma_free_coherent(dev, AES_BLOCK_SIZE, qat_req->iv, + qat_req->iv_paddr); + areq->base.complete(&areq->base, res); } @@ -905,50 +949,49 @@ static int qat_alg_aead_enc(struct aead_request *areq) return -EINPROGRESS; } -static int qat_alg_ablkcipher_setkey(struct crypto_ablkcipher *tfm, +static int qat_alg_ablkcipher_rekey(struct qat_alg_ablkcipher_ctx *ctx, + const u8 *key, unsigned int keylen, + int mode) +{ + memset(ctx->enc_cd, 0, sizeof(*ctx->enc_cd)); + memset(ctx->dec_cd, 0, sizeof(*ctx->dec_cd)); + memset(&ctx->enc_fw_req, 0, sizeof(ctx->enc_fw_req)); + memset(&ctx->dec_fw_req, 0, sizeof(ctx->dec_fw_req)); + + return qat_alg_ablkcipher_init_sessions(ctx, key, keylen, mode); +} + +static int qat_alg_ablkcipher_newkey(struct qat_alg_ablkcipher_ctx *ctx, const u8 *key, unsigned int keylen, int mode) { - struct qat_alg_ablkcipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); + struct qat_crypto_instance *inst = NULL; struct device *dev; + int node = get_current_node(); + int ret; - spin_lock(&ctx->lock); - if (ctx->enc_cd) { - /* rekeying */ - dev = &GET_DEV(ctx->inst->accel_dev); - memset(ctx->enc_cd, 0, sizeof(*ctx->enc_cd)); - memset(ctx->dec_cd, 0, sizeof(*ctx->dec_cd)); - memset(&ctx->enc_fw_req, 0, sizeof(ctx->enc_fw_req)); - memset(&ctx->dec_fw_req, 0, sizeof(ctx->dec_fw_req)); - } else { - /* new key */ - int node = get_current_node(); - struct qat_crypto_instance *inst = - qat_crypto_get_instance_node(node); - if (!inst) { - spin_unlock(&ctx->lock); - return -EINVAL; - } - - dev = &GET_DEV(inst->accel_dev); - ctx->inst = inst; - ctx->enc_cd = dma_alloc_coherent(dev, sizeof(*ctx->enc_cd), - &ctx->enc_cd_paddr, - GFP_ATOMIC); - if (!ctx->enc_cd) { - spin_unlock(&ctx->lock); - return -ENOMEM; - } - ctx->dec_cd = dma_alloc_coherent(dev, sizeof(*ctx->dec_cd), - &ctx->dec_cd_paddr, - GFP_ATOMIC); - if (!ctx->dec_cd) { - spin_unlock(&ctx->lock); - goto out_free_enc; - } + inst = qat_crypto_get_instance_node(node); + if (!inst) + return -EINVAL; + dev = &GET_DEV(inst->accel_dev); + ctx->inst = inst; + ctx->enc_cd = dma_alloc_coherent(dev, sizeof(*ctx->enc_cd), + &ctx->enc_cd_paddr, + GFP_ATOMIC); + if (!ctx->enc_cd) { + ret = -ENOMEM; + goto out_free_instance; + } + ctx->dec_cd = dma_alloc_coherent(dev, sizeof(*ctx->dec_cd), + &ctx->dec_cd_paddr, + GFP_ATOMIC); + if (!ctx->dec_cd) { + ret = -ENOMEM; + goto out_free_enc; } - spin_unlock(&ctx->lock); - if (qat_alg_ablkcipher_init_sessions(ctx, key, keylen, mode)) + + ret = qat_alg_ablkcipher_init_sessions(ctx, key, keylen, mode); + if (ret) goto out_free_all; return 0; @@ -963,7 +1006,22 @@ out_free_enc: dma_free_coherent(dev, sizeof(*ctx->enc_cd), ctx->enc_cd, ctx->enc_cd_paddr); ctx->enc_cd = NULL; - return -ENOMEM; +out_free_instance: + ctx->inst = NULL; + qat_crypto_put_instance(inst); + return ret; +} + +static int qat_alg_ablkcipher_setkey(struct crypto_ablkcipher *tfm, + const u8 *key, unsigned int keylen, + int mode) +{ + struct qat_alg_ablkcipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); + + if (ctx->enc_cd) + return qat_alg_ablkcipher_rekey(ctx, key, keylen, mode); + else + return qat_alg_ablkcipher_newkey(ctx, key, keylen, mode); } static int qat_alg_ablkcipher_cbc_setkey(struct crypto_ablkcipher *tfm, @@ -995,11 +1053,23 @@ static int qat_alg_ablkcipher_encrypt(struct ablkcipher_request *req) struct qat_crypto_request *qat_req = ablkcipher_request_ctx(req); struct icp_qat_fw_la_cipher_req_params *cipher_param; struct icp_qat_fw_la_bulk_req *msg; + struct device *dev = &GET_DEV(ctx->inst->accel_dev); int ret, ctr = 0; + if (req->nbytes == 0) + return 0; + + qat_req->iv = dma_alloc_coherent(dev, AES_BLOCK_SIZE, + &qat_req->iv_paddr, GFP_ATOMIC); + if (!qat_req->iv) + return -ENOMEM; + ret = qat_alg_sgl_to_bufl(ctx->inst, req->src, req->dst, qat_req); - if (unlikely(ret)) + if (unlikely(ret)) { + dma_free_coherent(dev, AES_BLOCK_SIZE, qat_req->iv, + qat_req->iv_paddr); return ret; + } msg = &qat_req->req; *msg = ctx->enc_fw_req; @@ -1012,18 +1082,29 @@ static int qat_alg_ablkcipher_encrypt(struct ablkcipher_request *req) cipher_param = (void *)&qat_req->req.serv_specif_rqpars; cipher_param->cipher_length = req->nbytes; cipher_param->cipher_offset = 0; - memcpy(cipher_param->u.cipher_IV_array, req->info, AES_BLOCK_SIZE); + cipher_param->u.s.cipher_IV_ptr = qat_req->iv_paddr; + memcpy(qat_req->iv, req->info, AES_BLOCK_SIZE); do { ret = adf_send_message(ctx->inst->sym_tx, (uint32_t *)msg); } while (ret == -EAGAIN && ctr++ < 10); if (ret == -EAGAIN) { qat_alg_free_bufl(ctx->inst, qat_req); + dma_free_coherent(dev, AES_BLOCK_SIZE, qat_req->iv, + qat_req->iv_paddr); return -EBUSY; } return -EINPROGRESS; } +static int qat_alg_ablkcipher_blk_encrypt(struct ablkcipher_request *req) +{ + if (req->nbytes % AES_BLOCK_SIZE != 0) + return -EINVAL; + + return qat_alg_ablkcipher_encrypt(req); +} + static int qat_alg_ablkcipher_decrypt(struct ablkcipher_request *req) { struct crypto_ablkcipher *atfm = crypto_ablkcipher_reqtfm(req); @@ -1032,11 +1113,23 @@ static int qat_alg_ablkcipher_decrypt(struct ablkcipher_request *req) struct qat_crypto_request *qat_req = ablkcipher_request_ctx(req); struct icp_qat_fw_la_cipher_req_params *cipher_param; struct icp_qat_fw_la_bulk_req *msg; + struct device *dev = &GET_DEV(ctx->inst->accel_dev); int ret, ctr = 0; + if (req->nbytes == 0) + return 0; + + qat_req->iv = dma_alloc_coherent(dev, AES_BLOCK_SIZE, + &qat_req->iv_paddr, GFP_ATOMIC); + if (!qat_req->iv) + return -ENOMEM; + ret = qat_alg_sgl_to_bufl(ctx->inst, req->src, req->dst, qat_req); - if (unlikely(ret)) + if (unlikely(ret)) { + dma_free_coherent(dev, AES_BLOCK_SIZE, qat_req->iv, + qat_req->iv_paddr); return ret; + } msg = &qat_req->req; *msg = ctx->dec_fw_req; @@ -1049,18 +1142,28 @@ static int qat_alg_ablkcipher_decrypt(struct ablkcipher_request *req) cipher_param = (void *)&qat_req->req.serv_specif_rqpars; cipher_param->cipher_length = req->nbytes; cipher_param->cipher_offset = 0; - memcpy(cipher_param->u.cipher_IV_array, req->info, AES_BLOCK_SIZE); + cipher_param->u.s.cipher_IV_ptr = qat_req->iv_paddr; + memcpy(qat_req->iv, req->info, AES_BLOCK_SIZE); do { ret = adf_send_message(ctx->inst->sym_tx, (uint32_t *)msg); } while (ret == -EAGAIN && ctr++ < 10); if (ret == -EAGAIN) { qat_alg_free_bufl(ctx->inst, qat_req); + dma_free_coherent(dev, AES_BLOCK_SIZE, qat_req->iv, + qat_req->iv_paddr); return -EBUSY; } return -EINPROGRESS; } +static int qat_alg_ablkcipher_blk_decrypt(struct ablkcipher_request *req) +{ + if (req->nbytes % AES_BLOCK_SIZE != 0) + return -EINVAL; + + return qat_alg_ablkcipher_decrypt(req); +} static int qat_alg_aead_init(struct crypto_aead *tfm, enum icp_qat_hw_auth_algo hash, const char *hash_name) @@ -1119,7 +1222,6 @@ static int qat_alg_ablkcipher_init(struct crypto_tfm *tfm) { struct qat_alg_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm); - spin_lock_init(&ctx->lock); tfm->crt_ablkcipher.reqsize = sizeof(struct qat_crypto_request); ctx->tfm = tfm; return 0; @@ -1221,8 +1323,8 @@ static struct crypto_alg qat_algs[] = { { .cra_u = { .ablkcipher = { .setkey = qat_alg_ablkcipher_cbc_setkey, - .decrypt = qat_alg_ablkcipher_decrypt, - .encrypt = qat_alg_ablkcipher_encrypt, + .decrypt = qat_alg_ablkcipher_blk_decrypt, + .encrypt = qat_alg_ablkcipher_blk_encrypt, .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, @@ -1233,7 +1335,7 @@ static struct crypto_alg qat_algs[] = { { .cra_driver_name = "qat_aes_ctr", .cra_priority = 4001, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_blocksize = AES_BLOCK_SIZE, + .cra_blocksize = 1, .cra_ctxsize = sizeof(struct qat_alg_ablkcipher_ctx), .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, @@ -1265,8 +1367,8 @@ static struct crypto_alg qat_algs[] = { { .cra_u = { .ablkcipher = { .setkey = qat_alg_ablkcipher_xts_setkey, - .decrypt = qat_alg_ablkcipher_decrypt, - .encrypt = qat_alg_ablkcipher_encrypt, + .decrypt = qat_alg_ablkcipher_blk_decrypt, + .encrypt = qat_alg_ablkcipher_blk_encrypt, .min_keysize = 2 * AES_MIN_KEY_SIZE, .max_keysize = 2 * AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, diff --git a/drivers/crypto/qat/qat_common/qat_crypto.h b/drivers/crypto/qat/qat_common/qat_crypto.h index dc0273fe3620..c77a80020cde 100644 --- a/drivers/crypto/qat/qat_common/qat_crypto.h +++ b/drivers/crypto/qat/qat_common/qat_crypto.h @@ -88,6 +88,8 @@ struct qat_crypto_request { struct qat_crypto_request_buffs buf; void (*cb)(struct icp_qat_fw_la_resp *resp, struct qat_crypto_request *req); + void *iv; + dma_addr_t iv_paddr; }; #endif diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index fd11162a915e..b0b8e3d48aef 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Cryptographic API. * @@ -7,10 +8,6 @@ * Copyright (c) 2013 Vista Silicon S.L. * Author: Javier Martin <javier.martin@vista-silicon.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Based on omap-aes.c and tegra-aes.c */ @@ -1387,7 +1384,6 @@ MODULE_DEVICE_TABLE(of, sahara_dt_ids); static int sahara_probe(struct platform_device *pdev) { struct sahara_dev *dev; - struct resource *res; u32 version; int irq; int err; @@ -1401,8 +1397,7 @@ static int sahara_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); /* Get the base address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->regs_base = devm_ioremap_resource(&pdev->dev, res); + dev->regs_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dev->regs_base)) return PTR_ERR(dev->regs_base); diff --git a/drivers/crypto/stm32/Makefile b/drivers/crypto/stm32/Makefile index ce77e38c77e0..518e0e0b11a9 100644 --- a/drivers/crypto/stm32/Makefile +++ b/drivers/crypto/stm32/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_CRYPTO_DEV_STM32_CRC) += stm32_crc32.o +obj-$(CONFIG_CRYPTO_DEV_STM32_CRC) += stm32-crc32.o obj-$(CONFIG_CRYPTO_DEV_STM32_HASH) += stm32-hash.o obj-$(CONFIG_CRYPTO_DEV_STM32_CRYP) += stm32-cryp.o diff --git a/drivers/crypto/stm32/stm32_crc32.c b/drivers/crypto/stm32/stm32-crc32.c index 440c9f1bd006..440c9f1bd006 100644 --- a/drivers/crypto/stm32/stm32_crc32.c +++ b/drivers/crypto/stm32/stm32-crc32.c diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c index bfc49e67124b..23061f2bc74b 100644 --- a/drivers/crypto/stm32/stm32-hash.c +++ b/drivers/crypto/stm32/stm32-hash.c @@ -1,23 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * This file is part of STM32 Crypto driver for Linux. * * Copyright (C) 2017, STMicroelectronics - All Rights Reserved * Author(s): Lionel DEBIEVE <lionel.debieve@st.com> for STMicroelectronics. - * - * License terms: GPL V2.0. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - * */ #include <linux/clk.h> @@ -363,7 +349,7 @@ static int stm32_hash_xmit_cpu(struct stm32_hash_dev *hdev, return -ETIMEDOUT; if ((hdev->flags & HASH_FLAGS_HMAC) && - (hdev->flags & ~HASH_FLAGS_HMAC_KEY)) { + (!(hdev->flags & HASH_FLAGS_HMAC_KEY))) { hdev->flags |= HASH_FLAGS_HMAC_KEY; stm32_hash_write_key(hdev); if (stm32_hash_wait_busy(hdev)) @@ -461,8 +447,8 @@ static int stm32_hash_xmit_dma(struct stm32_hash_dev *hdev, dma_async_issue_pending(hdev->dma_lch); - if (!wait_for_completion_interruptible_timeout(&hdev->dma_completion, - msecs_to_jiffies(100))) + if (!wait_for_completion_timeout(&hdev->dma_completion, + msecs_to_jiffies(100))) err = -ETIMEDOUT; if (dma_async_is_tx_complete(hdev->dma_lch, cookie, diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c index 7b0c42882830..4ab14d58e85b 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c +++ b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c @@ -12,7 +12,7 @@ */ #include "sun4i-ss.h" -static int sun4i_ss_opti_poll(struct skcipher_request *areq) +static int noinline_for_stack sun4i_ss_opti_poll(struct skcipher_request *areq) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); @@ -114,6 +114,29 @@ release_ss: return err; } + +static int noinline_for_stack sun4i_ss_cipher_poll_fallback(struct skcipher_request *areq) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); + struct sun4i_cipher_req_ctx *ctx = skcipher_request_ctx(areq); + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, op->fallback_tfm); + int err; + + skcipher_request_set_sync_tfm(subreq, op->fallback_tfm); + skcipher_request_set_callback(subreq, areq->base.flags, NULL, + NULL); + skcipher_request_set_crypt(subreq, areq->src, areq->dst, + areq->cryptlen, areq->iv); + if (ctx->mode & SS_DECRYPTION) + err = crypto_skcipher_decrypt(subreq); + else + err = crypto_skcipher_encrypt(subreq); + skcipher_request_zero(subreq); + + return err; +} + /* Generic function that support SG with size not multiple of 4 */ static int sun4i_ss_cipher_poll(struct skcipher_request *areq) { @@ -140,8 +163,6 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq) unsigned int todo; struct sg_mapping_iter mi, mo; unsigned int oi, oo; /* offset for in and out */ - char buf[4 * SS_RX_MAX];/* buffer for linearize SG src */ - char bufo[4 * SS_TX_MAX]; /* buffer for linearize SG dst */ unsigned int ob = 0; /* offset in buf */ unsigned int obo = 0; /* offset in bufo*/ unsigned int obl = 0; /* length of data in bufo */ @@ -178,20 +199,8 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq) if (no_chunk == 1 && !need_fallback) return sun4i_ss_opti_poll(areq); - if (need_fallback) { - SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, op->fallback_tfm); - skcipher_request_set_sync_tfm(subreq, op->fallback_tfm); - skcipher_request_set_callback(subreq, areq->base.flags, NULL, - NULL); - skcipher_request_set_crypt(subreq, areq->src, areq->dst, - areq->cryptlen, areq->iv); - if (ctx->mode & SS_DECRYPTION) - err = crypto_skcipher_decrypt(subreq); - else - err = crypto_skcipher_encrypt(subreq); - skcipher_request_zero(subreq); - return err; - } + if (need_fallback) + return sun4i_ss_cipher_poll_fallback(areq); spin_lock_irqsave(&ss->slock, flags); @@ -224,6 +233,8 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq) while (oleft) { if (ileft) { + char buf[4 * SS_RX_MAX];/* buffer for linearize SG src */ + /* * todo is the number of consecutive 4byte word that we * can read from current SG @@ -281,6 +292,8 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq) oo = 0; } } else { + char bufo[4 * SS_TX_MAX]; /* buffer for linearize SG dst */ + /* * read obl bytes in bufo, we read at maximum for * emptying the device diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index fbc7bf9d7380..c9d686a0e805 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -265,11 +265,11 @@ static int init_device(struct device *dev) * callback must check err and feedback in descriptor header * for device processing status. */ -int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc, - void (*callback)(struct device *dev, - struct talitos_desc *desc, - void *context, int error), - void *context) +static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc, + void (*callback)(struct device *dev, + struct talitos_desc *desc, + void *context, int error), + void *context) { struct talitos_private *priv = dev_get_drvdata(dev); struct talitos_request *request; @@ -319,7 +319,21 @@ int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc, return -EINPROGRESS; } -EXPORT_SYMBOL(talitos_submit); + +static __be32 get_request_hdr(struct talitos_request *request, bool is_sec1) +{ + struct talitos_edesc *edesc; + + if (!is_sec1) + return request->desc->hdr; + + if (!request->desc->next_desc) + return request->desc->hdr1; + + edesc = container_of(request->desc, struct talitos_edesc, desc); + + return ((struct talitos_desc *)(edesc->buf + edesc->dma_len))->hdr1; +} /* * process what was done, notify callback of error if not @@ -342,12 +356,7 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) /* descriptors with their done bits set don't get the error */ rmb(); - if (!is_sec1) - hdr = request->desc->hdr; - else if (request->desc->next_desc) - hdr = (request->desc + 1)->hdr1; - else - hdr = request->desc->hdr1; + hdr = get_request_hdr(request, is_sec1); if ((hdr & DESC_HDR_DONE) == DESC_HDR_DONE) status = 0; @@ -477,8 +486,14 @@ static u32 current_desc_hdr(struct device *dev, int ch) } } - if (priv->chan[ch].fifo[iter].desc->next_desc == cur_desc) - return (priv->chan[ch].fifo[iter].desc + 1)->hdr; + if (priv->chan[ch].fifo[iter].desc->next_desc == cur_desc) { + struct talitos_edesc *edesc; + + edesc = container_of(priv->chan[ch].fifo[iter].desc, + struct talitos_edesc, desc); + return ((struct talitos_desc *) + (edesc->buf + edesc->dma_len))->hdr; + } return priv->chan[ch].fifo[iter].desc->hdr; } @@ -824,7 +839,11 @@ static void talitos_unregister_rng(struct device *dev) * HMAC_SNOOP_NO_AFEA (HSNA) instead of type IPSEC_ESP */ #define TALITOS_CRA_PRIORITY_AEAD_HSNA (TALITOS_CRA_PRIORITY - 1) +#ifdef CONFIG_CRYPTO_DEV_TALITOS2 #define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA512_BLOCK_SIZE) +#else +#define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA256_BLOCK_SIZE) +#endif #define TALITOS_MAX_IV_LENGTH 16 /* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */ struct talitos_ctx { @@ -948,36 +967,6 @@ badkey: goto out; } -/* - * talitos_edesc - s/w-extended descriptor - * @src_nents: number of segments in input scatterlist - * @dst_nents: number of segments in output scatterlist - * @icv_ool: whether ICV is out-of-line - * @iv_dma: dma address of iv for checking continuity and link table - * @dma_len: length of dma mapped link_tbl space - * @dma_link_tbl: bus physical address of link_tbl/buf - * @desc: h/w descriptor - * @link_tbl: input and output h/w link tables (if {src,dst}_nents > 1) (SEC2) - * @buf: input and output buffeur (if {src,dst}_nents > 1) (SEC1) - * - * if decrypting (with authcheck), or either one of src_nents or dst_nents - * is greater than 1, an integrity check value is concatenated to the end - * of link_tbl data - */ -struct talitos_edesc { - int src_nents; - int dst_nents; - bool icv_ool; - dma_addr_t iv_dma; - int dma_len; - dma_addr_t dma_link_tbl; - struct talitos_desc desc; - union { - struct talitos_ptr link_tbl[0]; - u8 buf[0]; - }; -}; - static void talitos_sg_unmap(struct device *dev, struct talitos_edesc *edesc, struct scatterlist *src, @@ -1008,11 +997,13 @@ static void talitos_sg_unmap(struct device *dev, static void ipsec_esp_unmap(struct device *dev, struct talitos_edesc *edesc, - struct aead_request *areq) + struct aead_request *areq, bool encrypt) { struct crypto_aead *aead = crypto_aead_reqtfm(areq); struct talitos_ctx *ctx = crypto_aead_ctx(aead); unsigned int ivsize = crypto_aead_ivsize(aead); + unsigned int authsize = crypto_aead_authsize(aead); + unsigned int cryptlen = areq->cryptlen - (encrypt ? 0 : authsize); bool is_ipsec_esp = edesc->desc.hdr & DESC_HDR_TYPE_IPSEC_ESP; struct talitos_ptr *civ_ptr = &edesc->desc.ptr[is_ipsec_esp ? 2 : 3]; @@ -1021,8 +1012,8 @@ static void ipsec_esp_unmap(struct device *dev, DMA_FROM_DEVICE); unmap_single_talitos_ptr(dev, civ_ptr, DMA_TO_DEVICE); - talitos_sg_unmap(dev, edesc, areq->src, areq->dst, areq->cryptlen, - areq->assoclen); + talitos_sg_unmap(dev, edesc, areq->src, areq->dst, + cryptlen + authsize, areq->assoclen); if (edesc->dma_len) dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len, @@ -1032,7 +1023,7 @@ static void ipsec_esp_unmap(struct device *dev, unsigned int dst_nents = edesc->dst_nents ? : 1; sg_pcopy_to_buffer(areq->dst, dst_nents, ctx->iv, ivsize, - areq->assoclen + areq->cryptlen - ivsize); + areq->assoclen + cryptlen - ivsize); } } @@ -1043,31 +1034,14 @@ static void ipsec_esp_encrypt_done(struct device *dev, struct talitos_desc *desc, void *context, int err) { - struct talitos_private *priv = dev_get_drvdata(dev); - bool is_sec1 = has_ftr_sec1(priv); struct aead_request *areq = context; struct crypto_aead *authenc = crypto_aead_reqtfm(areq); - unsigned int authsize = crypto_aead_authsize(authenc); unsigned int ivsize = crypto_aead_ivsize(authenc); struct talitos_edesc *edesc; - struct scatterlist *sg; - void *icvdata; edesc = container_of(desc, struct talitos_edesc, desc); - ipsec_esp_unmap(dev, edesc, areq); - - /* copy the generated ICV to dst */ - if (edesc->icv_ool) { - if (is_sec1) - icvdata = edesc->buf + areq->assoclen + areq->cryptlen; - else - icvdata = &edesc->link_tbl[edesc->src_nents + - edesc->dst_nents + 2]; - sg = sg_last(areq->dst, edesc->dst_nents); - memcpy((char *)sg_virt(sg) + sg->length - authsize, - icvdata, authsize); - } + ipsec_esp_unmap(dev, edesc, areq, true); dma_unmap_single(dev, edesc->iv_dma, ivsize, DMA_TO_DEVICE); @@ -1084,32 +1058,16 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev, struct crypto_aead *authenc = crypto_aead_reqtfm(req); unsigned int authsize = crypto_aead_authsize(authenc); struct talitos_edesc *edesc; - struct scatterlist *sg; char *oicv, *icv; - struct talitos_private *priv = dev_get_drvdata(dev); - bool is_sec1 = has_ftr_sec1(priv); edesc = container_of(desc, struct talitos_edesc, desc); - ipsec_esp_unmap(dev, edesc, req); + ipsec_esp_unmap(dev, edesc, req, false); if (!err) { /* auth check */ - sg = sg_last(req->dst, edesc->dst_nents ? : 1); - icv = (char *)sg_virt(sg) + sg->length - authsize; - - if (edesc->dma_len) { - if (is_sec1) - oicv = (char *)&edesc->dma_link_tbl + - req->assoclen + req->cryptlen; - else - oicv = (char *) - &edesc->link_tbl[edesc->src_nents + - edesc->dst_nents + 2]; - if (edesc->icv_ool) - icv = oicv + authsize; - } else - oicv = (char *)&edesc->link_tbl[0]; + oicv = edesc->buf + edesc->dma_len; + icv = oicv - authsize; err = crypto_memneq(oicv, icv, authsize) ? -EBADMSG : 0; } @@ -1128,7 +1086,7 @@ static void ipsec_esp_decrypt_hwauth_done(struct device *dev, edesc = container_of(desc, struct talitos_edesc, desc); - ipsec_esp_unmap(dev, edesc, req); + ipsec_esp_unmap(dev, edesc, req, false); /* check ICV auth status */ if (!err && ((desc->hdr_lo & DESC_HDR_LO_ICCR1_MASK) != @@ -1145,11 +1103,12 @@ static void ipsec_esp_decrypt_hwauth_done(struct device *dev, * stop at cryptlen bytes */ static int sg_to_link_tbl_offset(struct scatterlist *sg, int sg_count, - unsigned int offset, int cryptlen, + unsigned int offset, int datalen, int elen, struct talitos_ptr *link_tbl_ptr) { - int n_sg = sg_count; + int n_sg = elen ? sg_count + 1 : sg_count; int count = 0; + int cryptlen = datalen + elen; while (cryptlen && sg && n_sg--) { unsigned int len = sg_dma_len(sg); @@ -1164,11 +1123,20 @@ static int sg_to_link_tbl_offset(struct scatterlist *sg, int sg_count, if (len > cryptlen) len = cryptlen; + if (datalen > 0 && len > datalen) { + to_talitos_ptr(link_tbl_ptr + count, + sg_dma_address(sg) + offset, datalen, 0); + to_talitos_ptr_ext_set(link_tbl_ptr + count, 0, 0); + count++; + len -= datalen; + offset += datalen; + } to_talitos_ptr(link_tbl_ptr + count, sg_dma_address(sg) + offset, len, 0); to_talitos_ptr_ext_set(link_tbl_ptr + count, 0, 0); count++; cryptlen -= len; + datalen -= len; offset = 0; next: @@ -1178,7 +1146,7 @@ next: /* tag end of link table */ if (count > 0) to_talitos_ptr_ext_set(link_tbl_ptr + count - 1, - DESC_PTR_LNKTBL_RETURN, 0); + DESC_PTR_LNKTBL_RET, 0); return count; } @@ -1186,7 +1154,8 @@ next: static int talitos_sg_map_ext(struct device *dev, struct scatterlist *src, unsigned int len, struct talitos_edesc *edesc, struct talitos_ptr *ptr, int sg_count, - unsigned int offset, int tbl_off, int elen) + unsigned int offset, int tbl_off, int elen, + bool force) { struct talitos_private *priv = dev_get_drvdata(dev); bool is_sec1 = has_ftr_sec1(priv); @@ -1196,7 +1165,7 @@ static int talitos_sg_map_ext(struct device *dev, struct scatterlist *src, return 1; } to_talitos_ptr_ext_set(ptr, elen, is_sec1); - if (sg_count == 1) { + if (sg_count == 1 && !force) { to_talitos_ptr(ptr, sg_dma_address(src) + offset, len, is_sec1); return sg_count; } @@ -1204,9 +1173,9 @@ static int talitos_sg_map_ext(struct device *dev, struct scatterlist *src, to_talitos_ptr(ptr, edesc->dma_link_tbl + offset, len, is_sec1); return sg_count; } - sg_count = sg_to_link_tbl_offset(src, sg_count, offset, len + elen, + sg_count = sg_to_link_tbl_offset(src, sg_count, offset, len, elen, &edesc->link_tbl[tbl_off]); - if (sg_count == 1) { + if (sg_count == 1 && !force) { /* Only one segment now, so no link tbl needed*/ copy_talitos_ptr(ptr, &edesc->link_tbl[tbl_off], is_sec1); return sg_count; @@ -1224,13 +1193,14 @@ static int talitos_sg_map(struct device *dev, struct scatterlist *src, unsigned int offset, int tbl_off) { return talitos_sg_map_ext(dev, src, len, edesc, ptr, sg_count, offset, - tbl_off, 0); + tbl_off, 0, false); } /* * fill in and submit ipsec_esp descriptor */ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, + bool encrypt, void (*callback)(struct device *dev, struct talitos_desc *desc, void *context, int error)) @@ -1240,7 +1210,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, struct talitos_ctx *ctx = crypto_aead_ctx(aead); struct device *dev = ctx->dev; struct talitos_desc *desc = &edesc->desc; - unsigned int cryptlen = areq->cryptlen; + unsigned int cryptlen = areq->cryptlen - (encrypt ? 0 : authsize); unsigned int ivsize = crypto_aead_ivsize(aead); int tbl_off = 0; int sg_count, ret; @@ -1251,6 +1221,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, bool is_ipsec_esp = desc->hdr & DESC_HDR_TYPE_IPSEC_ESP; struct talitos_ptr *civ_ptr = &desc->ptr[is_ipsec_esp ? 2 : 3]; struct talitos_ptr *ckey_ptr = &desc->ptr[is_ipsec_esp ? 3 : 2]; + dma_addr_t dma_icv = edesc->dma_link_tbl + edesc->dma_len - authsize; /* hmac key */ to_talitos_ptr(&desc->ptr[0], ctx->dma_key, ctx->authkeylen, is_sec1); @@ -1290,7 +1261,8 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, elen = authsize; ret = talitos_sg_map_ext(dev, areq->src, cryptlen, edesc, &desc->ptr[4], - sg_count, areq->assoclen, tbl_off, elen); + sg_count, areq->assoclen, tbl_off, elen, + false); if (ret > 1) { tbl_off += ret; @@ -1304,55 +1276,32 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, dma_map_sg(dev, areq->dst, sg_count, DMA_FROM_DEVICE); } - ret = talitos_sg_map(dev, areq->dst, cryptlen, edesc, &desc->ptr[5], - sg_count, areq->assoclen, tbl_off); - - if (is_ipsec_esp) - to_talitos_ptr_ext_or(&desc->ptr[5], authsize, is_sec1); - - /* ICV data */ - if (ret > 1) { - tbl_off += ret; - edesc->icv_ool = true; - sync_needed = true; - - if (is_ipsec_esp) { - struct talitos_ptr *tbl_ptr = &edesc->link_tbl[tbl_off]; - int offset = (edesc->src_nents + edesc->dst_nents + 2) * - sizeof(struct talitos_ptr) + authsize; - - /* Add an entry to the link table for ICV data */ - to_talitos_ptr_ext_set(tbl_ptr - 1, 0, is_sec1); - to_talitos_ptr_ext_set(tbl_ptr, DESC_PTR_LNKTBL_RETURN, - is_sec1); + if (is_ipsec_esp && encrypt) + elen = authsize; + else + elen = 0; + ret = talitos_sg_map_ext(dev, areq->dst, cryptlen, edesc, &desc->ptr[5], + sg_count, areq->assoclen, tbl_off, elen, + is_ipsec_esp && !encrypt); + tbl_off += ret; - /* icv data follows link tables */ - to_talitos_ptr(tbl_ptr, edesc->dma_link_tbl + offset, - authsize, is_sec1); - } else { - dma_addr_t addr = edesc->dma_link_tbl; + if (!encrypt && is_ipsec_esp) { + struct talitos_ptr *tbl_ptr = &edesc->link_tbl[tbl_off]; - if (is_sec1) - addr += areq->assoclen + cryptlen; - else - addr += sizeof(struct talitos_ptr) * tbl_off; + /* Add an entry to the link table for ICV data */ + to_talitos_ptr_ext_set(tbl_ptr - 1, 0, is_sec1); + to_talitos_ptr_ext_set(tbl_ptr, DESC_PTR_LNKTBL_RET, is_sec1); - to_talitos_ptr(&desc->ptr[6], addr, authsize, is_sec1); - } + /* icv data follows link tables */ + to_talitos_ptr(tbl_ptr, dma_icv, authsize, is_sec1); + to_talitos_ptr_ext_or(&desc->ptr[5], authsize, is_sec1); + sync_needed = true; + } else if (!encrypt) { + to_talitos_ptr(&desc->ptr[6], dma_icv, authsize, is_sec1); + sync_needed = true; } else if (!is_ipsec_esp) { - ret = talitos_sg_map(dev, areq->dst, authsize, edesc, - &desc->ptr[6], sg_count, areq->assoclen + - cryptlen, - tbl_off); - if (ret > 1) { - tbl_off += ret; - edesc->icv_ool = true; - sync_needed = true; - } else { - edesc->icv_ool = false; - } - } else { - edesc->icv_ool = false; + talitos_sg_map(dev, areq->dst, authsize, edesc, &desc->ptr[6], + sg_count, areq->assoclen + cryptlen, tbl_off); } /* iv out */ @@ -1367,7 +1316,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, ret = talitos_submit(dev, ctx->ch, desc, callback, areq); if (ret != -EINPROGRESS) { - ipsec_esp_unmap(dev, edesc, areq); + ipsec_esp_unmap(dev, edesc, areq, encrypt); kfree(edesc); } return ret; @@ -1435,18 +1384,18 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, * and space for two sets of ICVs (stashed and generated) */ alloc_len = sizeof(struct talitos_edesc); - if (src_nents || dst_nents) { + if (src_nents || dst_nents || !encrypt) { if (is_sec1) dma_len = (src_nents ? src_len : 0) + - (dst_nents ? dst_len : 0); + (dst_nents ? dst_len : 0) + authsize; else dma_len = (src_nents + dst_nents + 2) * - sizeof(struct talitos_ptr) + authsize * 2; + sizeof(struct talitos_ptr) + authsize; alloc_len += dma_len; } else { dma_len = 0; - alloc_len += icv_stashing ? authsize : 0; } + alloc_len += icv_stashing ? authsize : 0; /* if its a ahash, add space for a second desc next to the first one */ if (is_sec1 && !dst) @@ -1466,15 +1415,11 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, edesc->dst_nents = dst_nents; edesc->iv_dma = iv_dma; edesc->dma_len = dma_len; - if (dma_len) { - void *addr = &edesc->link_tbl[0]; - - if (is_sec1 && !dst) - addr += sizeof(struct talitos_desc); - edesc->dma_link_tbl = dma_map_single(dev, addr, + if (dma_len) + edesc->dma_link_tbl = dma_map_single(dev, &edesc->link_tbl[0], edesc->dma_len, DMA_BIDIRECTIONAL); - } + return edesc; } @@ -1485,9 +1430,10 @@ static struct talitos_edesc *aead_edesc_alloc(struct aead_request *areq, u8 *iv, unsigned int authsize = crypto_aead_authsize(authenc); struct talitos_ctx *ctx = crypto_aead_ctx(authenc); unsigned int ivsize = crypto_aead_ivsize(authenc); + unsigned int cryptlen = areq->cryptlen - (encrypt ? 0 : authsize); return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst, - iv, areq->assoclen, areq->cryptlen, + iv, areq->assoclen, cryptlen, authsize, ivsize, icv_stashing, areq->base.flags, encrypt); } @@ -1506,7 +1452,7 @@ static int aead_encrypt(struct aead_request *req) /* set encrypt */ edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_MODE0_ENCRYPT; - return ipsec_esp(edesc, req, ipsec_esp_encrypt_done); + return ipsec_esp(edesc, req, true, ipsec_esp_encrypt_done); } static int aead_decrypt(struct aead_request *req) @@ -1516,17 +1462,15 @@ static int aead_decrypt(struct aead_request *req) struct talitos_ctx *ctx = crypto_aead_ctx(authenc); struct talitos_private *priv = dev_get_drvdata(ctx->dev); struct talitos_edesc *edesc; - struct scatterlist *sg; void *icvdata; - req->cryptlen -= authsize; - /* allocate extended descriptor */ edesc = aead_edesc_alloc(req, req->iv, 1, false); if (IS_ERR(edesc)) return PTR_ERR(edesc); - if ((priv->features & TALITOS_FTR_HW_AUTH_CHECK) && + if ((edesc->desc.hdr & DESC_HDR_TYPE_IPSEC_ESP) && + (priv->features & TALITOS_FTR_HW_AUTH_CHECK) && ((!edesc->src_nents && !edesc->dst_nents) || priv->features & TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT)) { @@ -1537,24 +1481,20 @@ static int aead_decrypt(struct aead_request *req) /* reset integrity check result bits */ - return ipsec_esp(edesc, req, ipsec_esp_decrypt_hwauth_done); + return ipsec_esp(edesc, req, false, + ipsec_esp_decrypt_hwauth_done); } /* Have to check the ICV with software */ edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND; /* stash incoming ICV for later cmp with ICV generated by the h/w */ - if (edesc->dma_len) - icvdata = (char *)&edesc->link_tbl[edesc->src_nents + - edesc->dst_nents + 2]; - else - icvdata = &edesc->link_tbl[0]; + icvdata = edesc->buf + edesc->dma_len; - sg = sg_last(req->src, edesc->src_nents ? : 1); + sg_pcopy_to_buffer(req->src, edesc->src_nents ? : 1, icvdata, authsize, + req->assoclen + req->cryptlen - authsize); - memcpy(icvdata, (char *)sg_virt(sg) + sg->length - authsize, authsize); - - return ipsec_esp(edesc, req, ipsec_esp_decrypt_swauth_done); + return ipsec_esp(edesc, req, false, ipsec_esp_decrypt_swauth_done); } static int ablkcipher_setkey(struct crypto_ablkcipher *cipher, @@ -1605,6 +1545,18 @@ static int ablkcipher_des3_setkey(struct crypto_ablkcipher *cipher, return ablkcipher_setkey(cipher, key, keylen); } +static int ablkcipher_aes_setkey(struct crypto_ablkcipher *cipher, + const u8 *key, unsigned int keylen) +{ + if (keylen == AES_KEYSIZE_128 || keylen == AES_KEYSIZE_192 || + keylen == AES_KEYSIZE_256) + return ablkcipher_setkey(cipher, key, keylen); + + crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); + + return -EINVAL; +} + static void common_nonsnoop_unmap(struct device *dev, struct talitos_edesc *edesc, struct ablkcipher_request *areq) @@ -1624,11 +1576,15 @@ static void ablkcipher_done(struct device *dev, int err) { struct ablkcipher_request *areq = context; + struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq); + struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); + unsigned int ivsize = crypto_ablkcipher_ivsize(cipher); struct talitos_edesc *edesc; edesc = container_of(desc, struct talitos_edesc, desc); common_nonsnoop_unmap(dev, edesc, areq); + memcpy(areq->info, ctx->iv, ivsize); kfree(edesc); @@ -1723,6 +1679,14 @@ static int ablkcipher_encrypt(struct ablkcipher_request *areq) struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq); struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); struct talitos_edesc *edesc; + unsigned int blocksize = + crypto_tfm_alg_blocksize(crypto_ablkcipher_tfm(cipher)); + + if (!areq->nbytes) + return 0; + + if (areq->nbytes % blocksize) + return -EINVAL; /* allocate extended descriptor */ edesc = ablkcipher_edesc_alloc(areq, true); @@ -1740,6 +1704,14 @@ static int ablkcipher_decrypt(struct ablkcipher_request *areq) struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq); struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); struct talitos_edesc *edesc; + unsigned int blocksize = + crypto_tfm_alg_blocksize(crypto_ablkcipher_tfm(cipher)); + + if (!areq->nbytes) + return 0; + + if (areq->nbytes % blocksize) + return -EINVAL; /* allocate extended descriptor */ edesc = ablkcipher_edesc_alloc(areq, false); @@ -1759,14 +1731,16 @@ static void common_nonsnoop_hash_unmap(struct device *dev, struct talitos_private *priv = dev_get_drvdata(dev); bool is_sec1 = has_ftr_sec1(priv); struct talitos_desc *desc = &edesc->desc; - struct talitos_desc *desc2 = desc + 1; + struct talitos_desc *desc2 = (struct talitos_desc *) + (edesc->buf + edesc->dma_len); unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE); if (desc->next_desc && desc->ptr[5].ptr != desc2->ptr[5].ptr) unmap_single_talitos_ptr(dev, &desc2->ptr[5], DMA_FROM_DEVICE); - talitos_sg_unmap(dev, edesc, req_ctx->psrc, NULL, 0, 0); + if (req_ctx->psrc) + talitos_sg_unmap(dev, edesc, req_ctx->psrc, NULL, 0, 0); /* When using hashctx-in, must unmap it. */ if (from_talitos_ptr_len(&edesc->desc.ptr[1], is_sec1)) @@ -1833,7 +1807,6 @@ static void talitos_handle_buggy_hash(struct talitos_ctx *ctx, static int common_nonsnoop_hash(struct talitos_edesc *edesc, struct ahash_request *areq, unsigned int length, - unsigned int offset, void (*callback) (struct device *dev, struct talitos_desc *desc, void *context, int error)) @@ -1872,9 +1845,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, sg_count = edesc->src_nents ?: 1; if (is_sec1 && sg_count > 1) - sg_pcopy_to_buffer(req_ctx->psrc, sg_count, - edesc->buf + sizeof(struct talitos_desc), - length, req_ctx->nbuf); + sg_copy_to_buffer(req_ctx->psrc, sg_count, edesc->buf, length); else if (length) sg_count = dma_map_sg(dev, req_ctx->psrc, sg_count, DMA_TO_DEVICE); @@ -1887,7 +1858,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, DMA_TO_DEVICE); } else { sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc, - &desc->ptr[3], sg_count, offset, 0); + &desc->ptr[3], sg_count, 0, 0); if (sg_count > 1) sync_needed = true; } @@ -1911,7 +1882,8 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, talitos_handle_buggy_hash(ctx, edesc, &desc->ptr[3]); if (is_sec1 && req_ctx->nbuf && length) { - struct talitos_desc *desc2 = desc + 1; + struct talitos_desc *desc2 = (struct talitos_desc *) + (edesc->buf + edesc->dma_len); dma_addr_t next_desc; memset(desc2, 0, sizeof(*desc2)); @@ -1932,7 +1904,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, DMA_TO_DEVICE); copy_talitos_ptr(&desc2->ptr[2], &desc->ptr[2], is_sec1); sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc, - &desc2->ptr[3], sg_count, offset, 0); + &desc2->ptr[3], sg_count, 0, 0); if (sg_count > 1) sync_needed = true; copy_talitos_ptr(&desc2->ptr[5], &desc->ptr[5], is_sec1); @@ -2043,7 +2015,6 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes) struct device *dev = ctx->dev; struct talitos_private *priv = dev_get_drvdata(dev); bool is_sec1 = has_ftr_sec1(priv); - int offset = 0; u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx]; if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) { @@ -2083,6 +2054,8 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes) sg_chain(req_ctx->bufsl, 2, areq->src); req_ctx->psrc = req_ctx->bufsl; } else if (is_sec1 && req_ctx->nbuf && req_ctx->nbuf < blocksize) { + int offset; + if (nbytes_to_hash > blocksize) offset = blocksize - req_ctx->nbuf; else @@ -2095,7 +2068,8 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes) sg_copy_to_buffer(areq->src, nents, ctx_buf + req_ctx->nbuf, offset); req_ctx->nbuf += offset; - req_ctx->psrc = areq->src; + req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, areq->src, + offset); } else req_ctx->psrc = areq->src; @@ -2135,8 +2109,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes) if (ctx->keylen && (req_ctx->first || req_ctx->last)) edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC; - return common_nonsnoop_hash(edesc, areq, nbytes_to_hash, offset, - ahash_done); + return common_nonsnoop_hash(edesc, areq, nbytes_to_hash, ahash_done); } static int ahash_update(struct ahash_request *areq) @@ -2339,7 +2312,7 @@ static struct talitos_alg_template driver_algs[] = { .base = { .cra_name = "authenc(hmac(sha1),cbc(aes))", .cra_driver_name = "authenc-hmac-sha1-" - "cbc-aes-talitos", + "cbc-aes-talitos-hsna", .cra_blocksize = AES_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_ASYNC, }, @@ -2384,7 +2357,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_name = "authenc(hmac(sha1)," "cbc(des3_ede))", .cra_driver_name = "authenc-hmac-sha1-" - "cbc-3des-talitos", + "cbc-3des-talitos-hsna", .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_ASYNC, }, @@ -2427,7 +2400,7 @@ static struct talitos_alg_template driver_algs[] = { .base = { .cra_name = "authenc(hmac(sha224),cbc(aes))", .cra_driver_name = "authenc-hmac-sha224-" - "cbc-aes-talitos", + "cbc-aes-talitos-hsna", .cra_blocksize = AES_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_ASYNC, }, @@ -2472,7 +2445,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_name = "authenc(hmac(sha224)," "cbc(des3_ede))", .cra_driver_name = "authenc-hmac-sha224-" - "cbc-3des-talitos", + "cbc-3des-talitos-hsna", .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_ASYNC, }, @@ -2515,7 +2488,7 @@ static struct talitos_alg_template driver_algs[] = { .base = { .cra_name = "authenc(hmac(sha256),cbc(aes))", .cra_driver_name = "authenc-hmac-sha256-" - "cbc-aes-talitos", + "cbc-aes-talitos-hsna", .cra_blocksize = AES_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_ASYNC, }, @@ -2560,7 +2533,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_name = "authenc(hmac(sha256)," "cbc(des3_ede))", .cra_driver_name = "authenc-hmac-sha256-" - "cbc-3des-talitos", + "cbc-3des-talitos-hsna", .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_ASYNC, }, @@ -2689,7 +2662,7 @@ static struct talitos_alg_template driver_algs[] = { .base = { .cra_name = "authenc(hmac(md5),cbc(aes))", .cra_driver_name = "authenc-hmac-md5-" - "cbc-aes-talitos", + "cbc-aes-talitos-hsna", .cra_blocksize = AES_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_ASYNC, }, @@ -2732,7 +2705,7 @@ static struct talitos_alg_template driver_algs[] = { .base = { .cra_name = "authenc(hmac(md5),cbc(des3_ede))", .cra_driver_name = "authenc-hmac-md5-" - "cbc-3des-talitos", + "cbc-3des-talitos-hsna", .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_ASYNC, }, @@ -2760,7 +2733,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_ablkcipher = { .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, + .setkey = ablkcipher_aes_setkey, } }, .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2777,6 +2750,7 @@ static struct talitos_alg_template driver_algs[] = { .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, + .setkey = ablkcipher_aes_setkey, } }, .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2787,13 +2761,14 @@ static struct talitos_alg_template driver_algs[] = { .alg.crypto = { .cra_name = "ctr(aes)", .cra_driver_name = "ctr-aes-talitos", - .cra_blocksize = AES_BLOCK_SIZE, + .cra_blocksize = 1, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_ablkcipher = { .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, + .setkey = ablkcipher_aes_setkey, } }, .desc_hdr_template = DESC_HDR_TYPE_AESU_CTR_NONSNOOP | @@ -2810,7 +2785,6 @@ static struct talitos_alg_template driver_algs[] = { .cra_ablkcipher = { .min_keysize = DES_KEY_SIZE, .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, .setkey = ablkcipher_des_setkey, } }, @@ -2845,7 +2819,6 @@ static struct talitos_alg_template driver_algs[] = { .cra_ablkcipher = { .min_keysize = DES3_EDE_KEY_SIZE, .max_keysize = DES3_EDE_KEY_SIZE, - .ivsize = DES3_EDE_BLOCK_SIZE, .setkey = ablkcipher_des3_setkey, } }, @@ -3270,7 +3243,10 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, alg->cra_priority = t_alg->algt.priority; else alg->cra_priority = TALITOS_CRA_PRIORITY; - alg->cra_alignmask = 0; + if (has_ftr_sec1(priv)) + alg->cra_alignmask = 3; + else + alg->cra_alignmask = 0; alg->cra_ctxsize = sizeof(struct talitos_ctx); alg->cra_flags |= CRYPTO_ALG_KERN_DRIVER_ONLY; @@ -3418,7 +3394,7 @@ static int talitos_probe(struct platform_device *ofdev) if (err) goto err_out; - if (of_device_is_compatible(np, "fsl,sec1.0")) { + if (has_ftr_sec1(priv)) { if (priv->num_channels == 1) tasklet_init(&priv->done_task[0], talitos1_done_ch0, (unsigned long)dev); diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h index a65a63e0d6c1..1469b956948a 100644 --- a/drivers/crypto/talitos.h +++ b/drivers/crypto/talitos.h @@ -1,31 +1,8 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Freescale SEC (talitos) device register and descriptor header defines * * Copyright (c) 2006-2011 Freescale Semiconductor, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * */ #define TALITOS_TIMEOUT 100000 @@ -65,6 +42,34 @@ struct talitos_desc { #define TALITOS_DESC_SIZE (sizeof(struct talitos_desc) - sizeof(__be32)) +/* + * talitos_edesc - s/w-extended descriptor + * @src_nents: number of segments in input scatterlist + * @dst_nents: number of segments in output scatterlist + * @iv_dma: dma address of iv for checking continuity and link table + * @dma_len: length of dma mapped link_tbl space + * @dma_link_tbl: bus physical address of link_tbl/buf + * @desc: h/w descriptor + * @link_tbl: input and output h/w link tables (if {src,dst}_nents > 1) (SEC2) + * @buf: input and output buffeur (if {src,dst}_nents > 1) (SEC1) + * + * if decrypting (with authcheck), or either one of src_nents or dst_nents + * is greater than 1, an integrity check value is concatenated to the end + * of link_tbl data + */ +struct talitos_edesc { + int src_nents; + int dst_nents; + dma_addr_t iv_dma; + int dma_len; + dma_addr_t dma_link_tbl; + struct talitos_desc desc; + union { + struct talitos_ptr link_tbl[0]; + u8 buf[0]; + }; +}; + /** * talitos_request - descriptor submission request * @desc: descriptor pointer (kernel virtual) @@ -150,12 +155,6 @@ struct talitos_private { bool rng_registered; }; -extern int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc, - void (*callback)(struct device *dev, - struct talitos_desc *desc, - void *context, int error), - void *context); - /* .features flag */ #define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001 #define TALITOS_FTR_HW_AUTH_CHECK 0x00000002 @@ -170,13 +169,11 @@ extern int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc, */ static inline bool has_ftr_sec1(struct talitos_private *priv) { -#if defined(CONFIG_CRYPTO_DEV_TALITOS1) && defined(CONFIG_CRYPTO_DEV_TALITOS2) - return priv->features & TALITOS_FTR_SEC1 ? true : false; -#elif defined(CONFIG_CRYPTO_DEV_TALITOS1) - return true; -#else - return false; -#endif + if (IS_ENABLED(CONFIG_CRYPTO_DEV_TALITOS1) && + IS_ENABLED(CONFIG_CRYPTO_DEV_TALITOS2)) + return priv->features & TALITOS_FTR_SEC1; + + return IS_ENABLED(CONFIG_CRYPTO_DEV_TALITOS1); } /* @@ -412,5 +409,5 @@ static inline bool has_ftr_sec1(struct talitos_private *priv) /* link table extent field bits */ #define DESC_PTR_LNKTBL_JUMP 0x80 -#define DESC_PTR_LNKTBL_RETURN 0x02 +#define DESC_PTR_LNKTBL_RET 0x02 #define DESC_PTR_LNKTBL_NEXT 0x01 diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c index c7e515a1bc97..d88084447f1c 100644 --- a/drivers/crypto/vmx/aes_cbc.c +++ b/drivers/crypto/vmx/aes_cbc.c @@ -7,64 +7,52 @@ * Author: Marcelo Henrique Cerri <mhcerri@br.ibm.com> */ -#include <linux/types.h> -#include <linux/err.h> -#include <linux/crypto.h> -#include <linux/delay.h> #include <asm/simd.h> #include <asm/switch_to.h> #include <crypto/aes.h> #include <crypto/internal/simd.h> -#include <crypto/scatterwalk.h> -#include <crypto/skcipher.h> +#include <crypto/internal/skcipher.h> #include "aesp8-ppc.h" struct p8_aes_cbc_ctx { - struct crypto_sync_skcipher *fallback; + struct crypto_skcipher *fallback; struct aes_key enc_key; struct aes_key dec_key; }; -static int p8_aes_cbc_init(struct crypto_tfm *tfm) +static int p8_aes_cbc_init(struct crypto_skcipher *tfm) { - const char *alg = crypto_tfm_alg_name(tfm); - struct crypto_sync_skcipher *fallback; - struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm); - - fallback = crypto_alloc_sync_skcipher(alg, 0, - CRYPTO_ALG_NEED_FALLBACK); + struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm); + struct crypto_skcipher *fallback; + fallback = crypto_alloc_skcipher("cbc(aes)", 0, + CRYPTO_ALG_NEED_FALLBACK | + CRYPTO_ALG_ASYNC); if (IS_ERR(fallback)) { - printk(KERN_ERR - "Failed to allocate transformation for '%s': %ld\n", - alg, PTR_ERR(fallback)); + pr_err("Failed to allocate cbc(aes) fallback: %ld\n", + PTR_ERR(fallback)); return PTR_ERR(fallback); } - crypto_sync_skcipher_set_flags( - fallback, - crypto_skcipher_get_flags((struct crypto_skcipher *)tfm)); + crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) + + crypto_skcipher_reqsize(fallback)); ctx->fallback = fallback; - return 0; } -static void p8_aes_cbc_exit(struct crypto_tfm *tfm) +static void p8_aes_cbc_exit(struct crypto_skcipher *tfm) { - struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm); + struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm); - if (ctx->fallback) { - crypto_free_sync_skcipher(ctx->fallback); - ctx->fallback = NULL; - } + crypto_free_skcipher(ctx->fallback); } -static int p8_aes_cbc_setkey(struct crypto_tfm *tfm, const u8 *key, +static int p8_aes_cbc_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) { + struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm); int ret; - struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm); preempt_disable(); pagefault_disable(); @@ -75,108 +63,71 @@ static int p8_aes_cbc_setkey(struct crypto_tfm *tfm, const u8 *key, pagefault_enable(); preempt_enable(); - ret |= crypto_sync_skcipher_setkey(ctx->fallback, key, keylen); + ret |= crypto_skcipher_setkey(ctx->fallback, key, keylen); return ret ? -EINVAL : 0; } -static int p8_aes_cbc_encrypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) +static int p8_aes_cbc_crypt(struct skcipher_request *req, int enc) { + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + const struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm); + struct skcipher_walk walk; + unsigned int nbytes; int ret; - struct blkcipher_walk walk; - struct p8_aes_cbc_ctx *ctx = - crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm)); if (!crypto_simd_usable()) { - SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback); - skcipher_request_set_sync_tfm(req, ctx->fallback); - skcipher_request_set_callback(req, desc->flags, NULL, NULL); - skcipher_request_set_crypt(req, src, dst, nbytes, desc->info); - ret = crypto_skcipher_encrypt(req); - skcipher_request_zero(req); - } else { - blkcipher_walk_init(&walk, dst, src, nbytes); - ret = blkcipher_walk_virt(desc, &walk); - while ((nbytes = walk.nbytes)) { - preempt_disable(); - pagefault_disable(); - enable_kernel_vsx(); - aes_p8_cbc_encrypt(walk.src.virt.addr, - walk.dst.virt.addr, - nbytes & AES_BLOCK_MASK, - &ctx->enc_key, walk.iv, 1); - disable_kernel_vsx(); - pagefault_enable(); - preempt_enable(); - - nbytes &= AES_BLOCK_SIZE - 1; - ret = blkcipher_walk_done(desc, &walk, nbytes); - } + struct skcipher_request *subreq = skcipher_request_ctx(req); + + *subreq = *req; + skcipher_request_set_tfm(subreq, ctx->fallback); + return enc ? crypto_skcipher_encrypt(subreq) : + crypto_skcipher_decrypt(subreq); } + ret = skcipher_walk_virt(&walk, req, false); + while ((nbytes = walk.nbytes) != 0) { + preempt_disable(); + pagefault_disable(); + enable_kernel_vsx(); + aes_p8_cbc_encrypt(walk.src.virt.addr, + walk.dst.virt.addr, + round_down(nbytes, AES_BLOCK_SIZE), + enc ? &ctx->enc_key : &ctx->dec_key, + walk.iv, enc); + disable_kernel_vsx(); + pagefault_enable(); + preempt_enable(); + + ret = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE); + } return ret; } -static int p8_aes_cbc_decrypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) +static int p8_aes_cbc_encrypt(struct skcipher_request *req) { - int ret; - struct blkcipher_walk walk; - struct p8_aes_cbc_ctx *ctx = - crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm)); - - if (!crypto_simd_usable()) { - SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback); - skcipher_request_set_sync_tfm(req, ctx->fallback); - skcipher_request_set_callback(req, desc->flags, NULL, NULL); - skcipher_request_set_crypt(req, src, dst, nbytes, desc->info); - ret = crypto_skcipher_decrypt(req); - skcipher_request_zero(req); - } else { - blkcipher_walk_init(&walk, dst, src, nbytes); - ret = blkcipher_walk_virt(desc, &walk); - while ((nbytes = walk.nbytes)) { - preempt_disable(); - pagefault_disable(); - enable_kernel_vsx(); - aes_p8_cbc_encrypt(walk.src.virt.addr, - walk.dst.virt.addr, - nbytes & AES_BLOCK_MASK, - &ctx->dec_key, walk.iv, 0); - disable_kernel_vsx(); - pagefault_enable(); - preempt_enable(); - - nbytes &= AES_BLOCK_SIZE - 1; - ret = blkcipher_walk_done(desc, &walk, nbytes); - } - } - - return ret; + return p8_aes_cbc_crypt(req, 1); } +static int p8_aes_cbc_decrypt(struct skcipher_request *req) +{ + return p8_aes_cbc_crypt(req, 0); +} -struct crypto_alg p8_aes_cbc_alg = { - .cra_name = "cbc(aes)", - .cra_driver_name = "p8_aes_cbc", - .cra_module = THIS_MODULE, - .cra_priority = 2000, - .cra_type = &crypto_blkcipher_type, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK, - .cra_alignmask = 0, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct p8_aes_cbc_ctx), - .cra_init = p8_aes_cbc_init, - .cra_exit = p8_aes_cbc_exit, - .cra_blkcipher = { - .ivsize = AES_BLOCK_SIZE, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = p8_aes_cbc_setkey, - .encrypt = p8_aes_cbc_encrypt, - .decrypt = p8_aes_cbc_decrypt, - }, +struct skcipher_alg p8_aes_cbc_alg = { + .base.cra_name = "cbc(aes)", + .base.cra_driver_name = "p8_aes_cbc", + .base.cra_module = THIS_MODULE, + .base.cra_priority = 2000, + .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK, + .base.cra_blocksize = AES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct p8_aes_cbc_ctx), + .setkey = p8_aes_cbc_setkey, + .encrypt = p8_aes_cbc_encrypt, + .decrypt = p8_aes_cbc_decrypt, + .init = p8_aes_cbc_init, + .exit = p8_aes_cbc_exit, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, }; diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c index dd017ef42fa9..79ba062ee1c1 100644 --- a/drivers/crypto/vmx/aes_ctr.c +++ b/drivers/crypto/vmx/aes_ctr.c @@ -7,62 +7,51 @@ * Author: Marcelo Henrique Cerri <mhcerri@br.ibm.com> */ -#include <linux/types.h> -#include <linux/err.h> -#include <linux/crypto.h> -#include <linux/delay.h> #include <asm/simd.h> #include <asm/switch_to.h> #include <crypto/aes.h> #include <crypto/internal/simd.h> -#include <crypto/scatterwalk.h> -#include <crypto/skcipher.h> +#include <crypto/internal/skcipher.h> #include "aesp8-ppc.h" struct p8_aes_ctr_ctx { - struct crypto_sync_skcipher *fallback; + struct crypto_skcipher *fallback; struct aes_key enc_key; }; -static int p8_aes_ctr_init(struct crypto_tfm *tfm) +static int p8_aes_ctr_init(struct crypto_skcipher *tfm) { - const char *alg = crypto_tfm_alg_name(tfm); - struct crypto_sync_skcipher *fallback; - struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm); + struct p8_aes_ctr_ctx *ctx = crypto_skcipher_ctx(tfm); + struct crypto_skcipher *fallback; - fallback = crypto_alloc_sync_skcipher(alg, 0, - CRYPTO_ALG_NEED_FALLBACK); + fallback = crypto_alloc_skcipher("ctr(aes)", 0, + CRYPTO_ALG_NEED_FALLBACK | + CRYPTO_ALG_ASYNC); if (IS_ERR(fallback)) { - printk(KERN_ERR - "Failed to allocate transformation for '%s': %ld\n", - alg, PTR_ERR(fallback)); + pr_err("Failed to allocate ctr(aes) fallback: %ld\n", + PTR_ERR(fallback)); return PTR_ERR(fallback); } - crypto_sync_skcipher_set_flags( - fallback, - crypto_skcipher_get_flags((struct crypto_skcipher *)tfm)); + crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) + + crypto_skcipher_reqsize(fallback)); ctx->fallback = fallback; - return 0; } -static void p8_aes_ctr_exit(struct crypto_tfm *tfm) +static void p8_aes_ctr_exit(struct crypto_skcipher *tfm) { - struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm); + struct p8_aes_ctr_ctx *ctx = crypto_skcipher_ctx(tfm); - if (ctx->fallback) { - crypto_free_sync_skcipher(ctx->fallback); - ctx->fallback = NULL; - } + crypto_free_skcipher(ctx->fallback); } -static int p8_aes_ctr_setkey(struct crypto_tfm *tfm, const u8 *key, +static int p8_aes_ctr_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) { + struct p8_aes_ctr_ctx *ctx = crypto_skcipher_ctx(tfm); int ret; - struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm); preempt_disable(); pagefault_disable(); @@ -72,13 +61,13 @@ static int p8_aes_ctr_setkey(struct crypto_tfm *tfm, const u8 *key, pagefault_enable(); preempt_enable(); - ret |= crypto_sync_skcipher_setkey(ctx->fallback, key, keylen); + ret |= crypto_skcipher_setkey(ctx->fallback, key, keylen); return ret ? -EINVAL : 0; } -static void p8_aes_ctr_final(struct p8_aes_ctr_ctx *ctx, - struct blkcipher_walk *walk) +static void p8_aes_ctr_final(const struct p8_aes_ctr_ctx *ctx, + struct skcipher_walk *walk) { u8 *ctrblk = walk->iv; u8 keystream[AES_BLOCK_SIZE]; @@ -98,77 +87,63 @@ static void p8_aes_ctr_final(struct p8_aes_ctr_ctx *ctx, crypto_inc(ctrblk, AES_BLOCK_SIZE); } -static int p8_aes_ctr_crypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) +static int p8_aes_ctr_crypt(struct skcipher_request *req) { + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + const struct p8_aes_ctr_ctx *ctx = crypto_skcipher_ctx(tfm); + struct skcipher_walk walk; + unsigned int nbytes; int ret; - u64 inc; - struct blkcipher_walk walk; - struct p8_aes_ctr_ctx *ctx = - crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm)); if (!crypto_simd_usable()) { - SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback); - skcipher_request_set_sync_tfm(req, ctx->fallback); - skcipher_request_set_callback(req, desc->flags, NULL, NULL); - skcipher_request_set_crypt(req, src, dst, nbytes, desc->info); - ret = crypto_skcipher_encrypt(req); - skcipher_request_zero(req); - } else { - blkcipher_walk_init(&walk, dst, src, nbytes); - ret = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE); - while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) { - preempt_disable(); - pagefault_disable(); - enable_kernel_vsx(); - aes_p8_ctr32_encrypt_blocks(walk.src.virt.addr, - walk.dst.virt.addr, - (nbytes & - AES_BLOCK_MASK) / - AES_BLOCK_SIZE, - &ctx->enc_key, - walk.iv); - disable_kernel_vsx(); - pagefault_enable(); - preempt_enable(); - - /* We need to update IV mostly for last bytes/round */ - inc = (nbytes & AES_BLOCK_MASK) / AES_BLOCK_SIZE; - if (inc > 0) - while (inc--) - crypto_inc(walk.iv, AES_BLOCK_SIZE); - - nbytes &= AES_BLOCK_SIZE - 1; - ret = blkcipher_walk_done(desc, &walk, nbytes); - } - if (walk.nbytes) { - p8_aes_ctr_final(ctx, &walk); - ret = blkcipher_walk_done(desc, &walk, 0); - } + struct skcipher_request *subreq = skcipher_request_ctx(req); + + *subreq = *req; + skcipher_request_set_tfm(subreq, ctx->fallback); + return crypto_skcipher_encrypt(subreq); } + ret = skcipher_walk_virt(&walk, req, false); + while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) { + preempt_disable(); + pagefault_disable(); + enable_kernel_vsx(); + aes_p8_ctr32_encrypt_blocks(walk.src.virt.addr, + walk.dst.virt.addr, + nbytes / AES_BLOCK_SIZE, + &ctx->enc_key, walk.iv); + disable_kernel_vsx(); + pagefault_enable(); + preempt_enable(); + + do { + crypto_inc(walk.iv, AES_BLOCK_SIZE); + } while ((nbytes -= AES_BLOCK_SIZE) >= AES_BLOCK_SIZE); + + ret = skcipher_walk_done(&walk, nbytes); + } + if (nbytes) { + p8_aes_ctr_final(ctx, &walk); + ret = skcipher_walk_done(&walk, 0); + } return ret; } -struct crypto_alg p8_aes_ctr_alg = { - .cra_name = "ctr(aes)", - .cra_driver_name = "p8_aes_ctr", - .cra_module = THIS_MODULE, - .cra_priority = 2000, - .cra_type = &crypto_blkcipher_type, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK, - .cra_alignmask = 0, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct p8_aes_ctr_ctx), - .cra_init = p8_aes_ctr_init, - .cra_exit = p8_aes_ctr_exit, - .cra_blkcipher = { - .ivsize = AES_BLOCK_SIZE, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = p8_aes_ctr_setkey, - .encrypt = p8_aes_ctr_crypt, - .decrypt = p8_aes_ctr_crypt, - }, +struct skcipher_alg p8_aes_ctr_alg = { + .base.cra_name = "ctr(aes)", + .base.cra_driver_name = "p8_aes_ctr", + .base.cra_module = THIS_MODULE, + .base.cra_priority = 2000, + .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK, + .base.cra_blocksize = 1, + .base.cra_ctxsize = sizeof(struct p8_aes_ctr_ctx), + .setkey = p8_aes_ctr_setkey, + .encrypt = p8_aes_ctr_crypt, + .decrypt = p8_aes_ctr_crypt, + .init = p8_aes_ctr_init, + .exit = p8_aes_ctr_exit, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .chunksize = AES_BLOCK_SIZE, }; diff --git a/drivers/crypto/vmx/aes_xts.c b/drivers/crypto/vmx/aes_xts.c index 536167e737a0..49f7258045fa 100644 --- a/drivers/crypto/vmx/aes_xts.c +++ b/drivers/crypto/vmx/aes_xts.c @@ -7,67 +7,56 @@ * Author: Leonidas S. Barbosa <leosilva@linux.vnet.ibm.com> */ -#include <linux/types.h> -#include <linux/err.h> -#include <linux/crypto.h> -#include <linux/delay.h> #include <asm/simd.h> #include <asm/switch_to.h> #include <crypto/aes.h> #include <crypto/internal/simd.h> -#include <crypto/scatterwalk.h> +#include <crypto/internal/skcipher.h> #include <crypto/xts.h> -#include <crypto/skcipher.h> #include "aesp8-ppc.h" struct p8_aes_xts_ctx { - struct crypto_sync_skcipher *fallback; + struct crypto_skcipher *fallback; struct aes_key enc_key; struct aes_key dec_key; struct aes_key tweak_key; }; -static int p8_aes_xts_init(struct crypto_tfm *tfm) +static int p8_aes_xts_init(struct crypto_skcipher *tfm) { - const char *alg = crypto_tfm_alg_name(tfm); - struct crypto_sync_skcipher *fallback; - struct p8_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm); + struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); + struct crypto_skcipher *fallback; - fallback = crypto_alloc_sync_skcipher(alg, 0, - CRYPTO_ALG_NEED_FALLBACK); + fallback = crypto_alloc_skcipher("xts(aes)", 0, + CRYPTO_ALG_NEED_FALLBACK | + CRYPTO_ALG_ASYNC); if (IS_ERR(fallback)) { - printk(KERN_ERR - "Failed to allocate transformation for '%s': %ld\n", - alg, PTR_ERR(fallback)); + pr_err("Failed to allocate xts(aes) fallback: %ld\n", + PTR_ERR(fallback)); return PTR_ERR(fallback); } - crypto_sync_skcipher_set_flags( - fallback, - crypto_skcipher_get_flags((struct crypto_skcipher *)tfm)); + crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) + + crypto_skcipher_reqsize(fallback)); ctx->fallback = fallback; - return 0; } -static void p8_aes_xts_exit(struct crypto_tfm *tfm) +static void p8_aes_xts_exit(struct crypto_skcipher *tfm) { - struct p8_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm); + struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); - if (ctx->fallback) { - crypto_free_sync_skcipher(ctx->fallback); - ctx->fallback = NULL; - } + crypto_free_skcipher(ctx->fallback); } -static int p8_aes_xts_setkey(struct crypto_tfm *tfm, const u8 *key, +static int p8_aes_xts_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) { + struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); int ret; - struct p8_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm); - ret = xts_check_key(tfm, key, keylen); + ret = xts_verify_key(tfm, key, keylen); if (ret) return ret; @@ -81,100 +70,90 @@ static int p8_aes_xts_setkey(struct crypto_tfm *tfm, const u8 *key, pagefault_enable(); preempt_enable(); - ret |= crypto_sync_skcipher_setkey(ctx->fallback, key, keylen); + ret |= crypto_skcipher_setkey(ctx->fallback, key, keylen); return ret ? -EINVAL : 0; } -static int p8_aes_xts_crypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes, int enc) +static int p8_aes_xts_crypt(struct skcipher_request *req, int enc) { - int ret; + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + const struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); + struct skcipher_walk walk; + unsigned int nbytes; u8 tweak[AES_BLOCK_SIZE]; - u8 *iv; - struct blkcipher_walk walk; - struct p8_aes_xts_ctx *ctx = - crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm)); + int ret; if (!crypto_simd_usable()) { - SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback); - skcipher_request_set_sync_tfm(req, ctx->fallback); - skcipher_request_set_callback(req, desc->flags, NULL, NULL); - skcipher_request_set_crypt(req, src, dst, nbytes, desc->info); - ret = enc? crypto_skcipher_encrypt(req) : crypto_skcipher_decrypt(req); - skcipher_request_zero(req); - } else { - blkcipher_walk_init(&walk, dst, src, nbytes); + struct skcipher_request *subreq = skcipher_request_ctx(req); + + *subreq = *req; + skcipher_request_set_tfm(subreq, ctx->fallback); + return enc ? crypto_skcipher_encrypt(subreq) : + crypto_skcipher_decrypt(subreq); + } + + ret = skcipher_walk_virt(&walk, req, false); + if (ret) + return ret; + + preempt_disable(); + pagefault_disable(); + enable_kernel_vsx(); - ret = blkcipher_walk_virt(desc, &walk); + aes_p8_encrypt(walk.iv, tweak, &ctx->tweak_key); + + disable_kernel_vsx(); + pagefault_enable(); + preempt_enable(); + while ((nbytes = walk.nbytes) != 0) { preempt_disable(); pagefault_disable(); enable_kernel_vsx(); - - iv = walk.iv; - memset(tweak, 0, AES_BLOCK_SIZE); - aes_p8_encrypt(iv, tweak, &ctx->tweak_key); - + if (enc) + aes_p8_xts_encrypt(walk.src.virt.addr, + walk.dst.virt.addr, + round_down(nbytes, AES_BLOCK_SIZE), + &ctx->enc_key, NULL, tweak); + else + aes_p8_xts_decrypt(walk.src.virt.addr, + walk.dst.virt.addr, + round_down(nbytes, AES_BLOCK_SIZE), + &ctx->dec_key, NULL, tweak); disable_kernel_vsx(); pagefault_enable(); preempt_enable(); - while ((nbytes = walk.nbytes)) { - preempt_disable(); - pagefault_disable(); - enable_kernel_vsx(); - if (enc) - aes_p8_xts_encrypt(walk.src.virt.addr, walk.dst.virt.addr, - nbytes & AES_BLOCK_MASK, &ctx->enc_key, NULL, tweak); - else - aes_p8_xts_decrypt(walk.src.virt.addr, walk.dst.virt.addr, - nbytes & AES_BLOCK_MASK, &ctx->dec_key, NULL, tweak); - disable_kernel_vsx(); - pagefault_enable(); - preempt_enable(); - - nbytes &= AES_BLOCK_SIZE - 1; - ret = blkcipher_walk_done(desc, &walk, nbytes); - } + ret = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE); } return ret; } -static int p8_aes_xts_encrypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) +static int p8_aes_xts_encrypt(struct skcipher_request *req) { - return p8_aes_xts_crypt(desc, dst, src, nbytes, 1); + return p8_aes_xts_crypt(req, 1); } -static int p8_aes_xts_decrypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) +static int p8_aes_xts_decrypt(struct skcipher_request *req) { - return p8_aes_xts_crypt(desc, dst, src, nbytes, 0); + return p8_aes_xts_crypt(req, 0); } -struct crypto_alg p8_aes_xts_alg = { - .cra_name = "xts(aes)", - .cra_driver_name = "p8_aes_xts", - .cra_module = THIS_MODULE, - .cra_priority = 2000, - .cra_type = &crypto_blkcipher_type, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK, - .cra_alignmask = 0, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct p8_aes_xts_ctx), - .cra_init = p8_aes_xts_init, - .cra_exit = p8_aes_xts_exit, - .cra_blkcipher = { - .ivsize = AES_BLOCK_SIZE, - .min_keysize = 2 * AES_MIN_KEY_SIZE, - .max_keysize = 2 * AES_MAX_KEY_SIZE, - .setkey = p8_aes_xts_setkey, - .encrypt = p8_aes_xts_encrypt, - .decrypt = p8_aes_xts_decrypt, - } +struct skcipher_alg p8_aes_xts_alg = { + .base.cra_name = "xts(aes)", + .base.cra_driver_name = "p8_aes_xts", + .base.cra_module = THIS_MODULE, + .base.cra_priority = 2000, + .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK, + .base.cra_blocksize = AES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct p8_aes_xts_ctx), + .setkey = p8_aes_xts_setkey, + .encrypt = p8_aes_xts_encrypt, + .decrypt = p8_aes_xts_decrypt, + .init = p8_aes_xts_init, + .exit = p8_aes_xts_exit, + .min_keysize = 2 * AES_MIN_KEY_SIZE, + .max_keysize = 2 * AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, }; diff --git a/drivers/crypto/vmx/aesp8-ppc.h b/drivers/crypto/vmx/aesp8-ppc.h index 349646b73754..01774a4d26a2 100644 --- a/drivers/crypto/vmx/aesp8-ppc.h +++ b/drivers/crypto/vmx/aesp8-ppc.h @@ -2,8 +2,6 @@ #include <linux/types.h> #include <crypto/aes.h> -#define AES_BLOCK_MASK (~(AES_BLOCK_SIZE-1)) - struct aes_key { u8 key[AES_MAX_KEYLENGTH]; int rounds; diff --git a/drivers/crypto/vmx/aesp8-ppc.pl b/drivers/crypto/vmx/aesp8-ppc.pl index 9c6b5c1d6a1a..db874367b602 100644 --- a/drivers/crypto/vmx/aesp8-ppc.pl +++ b/drivers/crypto/vmx/aesp8-ppc.pl @@ -1286,6 +1286,24 @@ ___ ######################################################################### {{{ # CTR procedure[s] # + +####################### WARNING: Here be dragons! ####################### +# +# This code is written as 'ctr32', based on a 32-bit counter used +# upstream. The kernel does *not* use a 32-bit counter. The kernel uses +# a 128-bit counter. +# +# This leads to subtle changes from the upstream code: the counter +# is incremented with vaddu_q_m rather than vaddu_w_m. This occurs in +# both the bulk (8 blocks at a time) path, and in the individual block +# path. Be aware of this when doing updates. +# +# See: +# 1d4aa0b4c181 ("crypto: vmx - Fixing AES-CTR counter bug") +# 009b30ac7444 ("crypto: vmx - CTR: always increment IV as quadword") +# https://github.com/openssl/openssl/pull/8942 +# +######################################################################### my ($inp,$out,$len,$key,$ivp,$x10,$rounds,$idx)=map("r$_",(3..10)); my ($rndkey0,$rndkey1,$inout,$tmp)= map("v$_",(0..3)); my ($ivec,$inptail,$inpperm,$outhead,$outperm,$outmask,$keyperm,$one)= @@ -1357,7 +1375,7 @@ Loop_ctr32_enc: addi $idx,$idx,16 bdnz Loop_ctr32_enc - vadduqm $ivec,$ivec,$one + vadduqm $ivec,$ivec,$one # Kernel change for 128-bit vmr $dat,$inptail lvx $inptail,0,$inp addi $inp,$inp,16 @@ -1501,7 +1519,7 @@ Load_ctr32_enc_key: $SHL $len,$len,4 vadduqm $out1,$ivec,$one # counter values ... - vadduqm $out2,$ivec,$two + vadduqm $out2,$ivec,$two # (do all ctr adds as 128-bit) vxor $out0,$ivec,$rndkey0 # ... xored with rndkey[0] le?li $idx,8 vadduqm $out3,$out1,$two diff --git a/drivers/crypto/vmx/vmx.c b/drivers/crypto/vmx/vmx.c index 6c4c77f4e159..3e0335fb406c 100644 --- a/drivers/crypto/vmx/vmx.c +++ b/drivers/crypto/vmx/vmx.c @@ -15,54 +15,58 @@ #include <linux/crypto.h> #include <asm/cputable.h> #include <crypto/internal/hash.h> +#include <crypto/internal/skcipher.h> extern struct shash_alg p8_ghash_alg; extern struct crypto_alg p8_aes_alg; -extern struct crypto_alg p8_aes_cbc_alg; -extern struct crypto_alg p8_aes_ctr_alg; -extern struct crypto_alg p8_aes_xts_alg; -static struct crypto_alg *algs[] = { - &p8_aes_alg, - &p8_aes_cbc_alg, - &p8_aes_ctr_alg, - &p8_aes_xts_alg, - NULL, -}; +extern struct skcipher_alg p8_aes_cbc_alg; +extern struct skcipher_alg p8_aes_ctr_alg; +extern struct skcipher_alg p8_aes_xts_alg; static int __init p8_init(void) { - int ret = 0; - struct crypto_alg **alg_it; + int ret; - for (alg_it = algs; *alg_it; alg_it++) { - ret = crypto_register_alg(*alg_it); - printk(KERN_INFO "crypto_register_alg '%s' = %d\n", - (*alg_it)->cra_name, ret); - if (ret) { - for (alg_it--; alg_it >= algs; alg_it--) - crypto_unregister_alg(*alg_it); - break; - } - } + ret = crypto_register_shash(&p8_ghash_alg); if (ret) - return ret; + goto err; - ret = crypto_register_shash(&p8_ghash_alg); - if (ret) { - for (alg_it = algs; *alg_it; alg_it++) - crypto_unregister_alg(*alg_it); - } + ret = crypto_register_alg(&p8_aes_alg); + if (ret) + goto err_unregister_ghash; + + ret = crypto_register_skcipher(&p8_aes_cbc_alg); + if (ret) + goto err_unregister_aes; + + ret = crypto_register_skcipher(&p8_aes_ctr_alg); + if (ret) + goto err_unregister_aes_cbc; + + ret = crypto_register_skcipher(&p8_aes_xts_alg); + if (ret) + goto err_unregister_aes_ctr; + + return 0; + +err_unregister_aes_ctr: + crypto_unregister_skcipher(&p8_aes_ctr_alg); +err_unregister_aes_cbc: + crypto_unregister_skcipher(&p8_aes_cbc_alg); +err_unregister_aes: + crypto_unregister_alg(&p8_aes_alg); +err_unregister_ghash: + crypto_unregister_shash(&p8_ghash_alg); +err: return ret; } static void __exit p8_exit(void) { - struct crypto_alg **alg_it; - - for (alg_it = algs; *alg_it; alg_it++) { - printk(KERN_INFO "Removing '%s'\n", (*alg_it)->cra_name); - crypto_unregister_alg(*alg_it); - } + crypto_unregister_skcipher(&p8_aes_xts_alg); + crypto_unregister_skcipher(&p8_aes_ctr_alg); + crypto_unregister_skcipher(&p8_aes_cbc_alg); + crypto_unregister_alg(&p8_aes_alg); crypto_unregister_shash(&p8_ghash_alg); } diff --git a/drivers/devfreq/devfreq-event.c b/drivers/devfreq/devfreq-event.c index 87e93406d7cd..3dc5fd6065a3 100644 --- a/drivers/devfreq/devfreq-event.c +++ b/drivers/devfreq/devfreq-event.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * devfreq-event: a framework to provide raw data and events of devfreq devices * * Copyright (C) 2015 Samsung Electronics * Author: Chanwoo Choi <cw00.choi@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This driver is based on drivers/devfreq/devfreq.c. */ diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 6b6991f0e873..ab22bf8a12d6 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * devfreq: Generic Dynamic Voltage and Frequency Scaling (DVFS) Framework * for Non-CPU Devices. * * Copyright (C) 2011 Samsung Electronics * MyungJoo Ham <myungjoo.ham@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/devfreq/event/exynos-nocp.c b/drivers/devfreq/event/exynos-nocp.c index f6e7956fc91a..1c565926db9f 100644 --- a/drivers/devfreq/event/exynos-nocp.c +++ b/drivers/devfreq/event/exynos-nocp.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * exynos-nocp.c - EXYNOS NoC (Network On Chip) Probe support * * Copyright (c) 2016 Samsung Electronics Co., Ltd. * Author : Chanwoo Choi <cw00.choi@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/devfreq/event/exynos-nocp.h b/drivers/devfreq/event/exynos-nocp.h index 28564db0edb8..55cc96284a36 100644 --- a/drivers/devfreq/event/exynos-nocp.h +++ b/drivers/devfreq/event/exynos-nocp.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * exynos-nocp.h - EXYNOS NoC (Network on Chip) Probe header file * * Copyright (c) 2016 Samsung Electronics Co., Ltd. * Author : Chanwoo Choi <cw00.choi@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __EXYNOS_NOCP_H__ diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c index c2ea94957501..3ee3dd5653aa 100644 --- a/drivers/devfreq/event/exynos-ppmu.c +++ b/drivers/devfreq/event/exynos-ppmu.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support * * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd. * Author : Chanwoo Choi <cw00.choi@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This driver is based on drivers/devfreq/exynos/exynos_ppmu.c */ diff --git a/drivers/devfreq/event/exynos-ppmu.h b/drivers/devfreq/event/exynos-ppmu.h index 05774c449137..284420047455 100644 --- a/drivers/devfreq/event/exynos-ppmu.h +++ b/drivers/devfreq/event/exynos-ppmu.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * exynos_ppmu.h - EXYNOS PPMU header file * * Copyright (c) 2015 Samsung Electronics Co., Ltd. * Author : Chanwoo Choi <cw00.choi@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __EXYNOS_PPMU_H__ diff --git a/drivers/devfreq/exynos-bus.c b/drivers/devfreq/exynos-bus.c index 486cc5b422f1..d9f377912c10 100644 --- a/drivers/devfreq/exynos-bus.c +++ b/drivers/devfreq/exynos-bus.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic Exynos Bus frequency driver with DEVFREQ Framework * @@ -6,10 +7,6 @@ * * This driver support Exynos Bus frequency feature by using * DEVFREQ framework and is based on drivers/devfreq/exynos/exynos4_bus.c. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h index f53339ca610f..bbe5ff9fcecf 100644 --- a/drivers/devfreq/governor.h +++ b/drivers/devfreq/governor.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * governor.h - internal header for devfreq governors. * * Copyright (C) 2011 Samsung Electronics * MyungJoo Ham <myungjoo.ham@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This header is for devfreq governors in drivers/devfreq/ */ diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c index 3bc29acbd54e..58308948b863 100644 --- a/drivers/devfreq/governor_passive.c +++ b/drivers/devfreq/governor_passive.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/devfreq/governor_passive.c * * Copyright (C) 2016 Samsung Electronics * Author: Chanwoo Choi <cw00.choi@samsung.com> * Author: MyungJoo Ham <myungjoo.ham@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c index ded429fd51be..5dbc1e56ec08 100644 --- a/drivers/devfreq/governor_performance.c +++ b/drivers/devfreq/governor_performance.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/devfreq/governor_performance.c * * Copyright (C) 2011 Samsung Electronics * MyungJoo Ham <myungjoo.ham@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/devfreq.h> diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c index 9e8897f5ac42..4746af2435b0 100644 --- a/drivers/devfreq/governor_powersave.c +++ b/drivers/devfreq/governor_powersave.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/devfreq/governor_powersave.c * * Copyright (C) 2011 Samsung Electronics * MyungJoo Ham <myungjoo.ham@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/devfreq.h> diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index c0417f0e081e..3d809f228619 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/devfreq/governor_simpleondemand.c * * Copyright (C) 2011 Samsung Electronics * MyungJoo Ham <myungjoo.ham@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/errno.h> diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c index 378d84c011df..af94942fcf95 100644 --- a/drivers/devfreq/governor_userspace.c +++ b/drivers/devfreq/governor_userspace.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/devfreq/governor_userspace.c * * Copyright (C) 2011 Samsung Electronics * MyungJoo Ham <myungjoo.ham@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/slab.h> diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 7c858020d14b..bf4d4c80fbc6 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Framework for buffer objects that can be shared across devices/subsystems. * @@ -8,18 +9,6 @@ * Arnd Bergmann <arnd@arndb.de>, Rob Clark <rob@ti.com> and * Daniel Vetter <daniel@ffwll.ch> for their support in creation and * refining of this idea. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/fs.h> diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c index 4a748c3435d7..30243f5c0710 100644 --- a/drivers/dma/acpi-dma.c +++ b/drivers/dma/acpi-dma.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ACPI helpers for DMA request / controller * @@ -6,10 +7,6 @@ * Copyright (C) 2013, Intel Corporation * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> * Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index e4ae2ee46d3f..627ef3e5b312 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for the Atmel Extensible DMA Controller (aka XDMAC on AT91 systems) * * Copyright (C) 2014 Atmel Corporation * * Author: Ludovic Desroches <ludovic.desroches@atmel.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <asm/barrier.h> diff --git a/drivers/dma/bestcomm/bcom_ata_task.c b/drivers/dma/bestcomm/bcom_ata_task.c index cc6049a4e469..9a1c349e932f 100644 --- a/drivers/dma/bestcomm/bcom_ata_task.c +++ b/drivers/dma/bestcomm/bcom_ata_task.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Bestcomm ATA task microcode * * Copyright (c) 2004 Freescale Semiconductor, Inc. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Created based on bestcom/code_dma/image_rtos1/dma_image.hex */ diff --git a/drivers/dma/bestcomm/bcom_fec_rx_task.c b/drivers/dma/bestcomm/bcom_fec_rx_task.c index a1ad6a02fcef..c610dc76a82e 100644 --- a/drivers/dma/bestcomm/bcom_fec_rx_task.c +++ b/drivers/dma/bestcomm/bcom_fec_rx_task.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Bestcomm FEC RX task microcode * * Copyright (c) 2004 Freescale Semiconductor, Inc. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex * on Tue Mar 22 11:19:38 2005 GMT */ diff --git a/drivers/dma/bestcomm/bcom_fec_tx_task.c b/drivers/dma/bestcomm/bcom_fec_tx_task.c index b1c495c3a65a..410b42695668 100644 --- a/drivers/dma/bestcomm/bcom_fec_tx_task.c +++ b/drivers/dma/bestcomm/bcom_fec_tx_task.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Bestcomm FEC TX task microcode * * Copyright (c) 2004 Freescale Semiconductor, Inc. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex * on Tue Mar 22 11:19:29 2005 GMT */ diff --git a/drivers/dma/bestcomm/bcom_gen_bd_rx_task.c b/drivers/dma/bestcomm/bcom_gen_bd_rx_task.c index efee022b0256..8dd38ede26d2 100644 --- a/drivers/dma/bestcomm/bcom_gen_bd_rx_task.c +++ b/drivers/dma/bestcomm/bcom_gen_bd_rx_task.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Bestcomm GenBD RX task microcode * @@ -5,13 +6,8 @@ * Jeff Gibbons <jeff.gibbons@appspec.com> * Copyright (c) 2004 Freescale Semiconductor, Inc. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex * on Tue Mar 4 10:14:12 2006 GMT - * */ #include <asm/types.h> diff --git a/drivers/dma/bestcomm/bcom_gen_bd_tx_task.c b/drivers/dma/bestcomm/bcom_gen_bd_tx_task.c index c605aa42ecbb..844dfe258639 100644 --- a/drivers/dma/bestcomm/bcom_gen_bd_tx_task.c +++ b/drivers/dma/bestcomm/bcom_gen_bd_tx_task.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Bestcomm GenBD TX task microcode * @@ -5,13 +6,8 @@ * Jeff Gibbons <jeff.gibbons@appspec.com> * Copyright (c) 2004 Freescale Semiconductor, Inc. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex * on Tue Mar 4 10:14:12 2006 GMT - * */ #include <asm/types.h> diff --git a/drivers/dma/bestcomm/gen_bd.c b/drivers/dma/bestcomm/gen_bd.c index 1a5b22d88127..906ddba6a6f5 100644 --- a/drivers/dma/bestcomm/gen_bd.c +++ b/drivers/dma/bestcomm/gen_bd.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for MPC52xx processor BestComm General Buffer Descriptor * * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com> * Copyright (C) 2006 AppSpec Computer Technologies Corp. * Jeff Gibbons <jeff.gibbons@appspec.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 263bee76ef0d..6b8c4c458e8a 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -718,12 +718,13 @@ static irqreturn_t jz4780_dma_irq_handler(int irq, void *data) { struct jz4780_dma_dev *jzdma = data; unsigned int nb_channels = jzdma->soc_data->nb_channels; - uint32_t pending, dmac; + unsigned long pending; + uint32_t dmac; int i; pending = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DIRQP); - for_each_set_bit(i, (unsigned long *)&pending, nb_channels) { + for_each_set_bit(i, &pending, nb_channels) { if (jz4780_dma_chan_irq(jzdma, &jzdma->chan[i])) pending &= ~BIT(i); } diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index b96814a7dceb..d0ad46e916a6 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * DMA Engine test module * * Copyright (C) 2007 Atmel Corporation * Copyright (C) 2013 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c index e06f20272fd7..0c2610066ba9 100644 --- a/drivers/dma/hsu/hsu.c +++ b/drivers/dma/hsu/hsu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Core driver for the High Speed UART DMA * @@ -5,10 +6,6 @@ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> * * Partially based on the bits found in drivers/tty/serial/mfd.c. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /* diff --git a/drivers/dma/hsu/hsu.h b/drivers/dma/hsu/hsu.h index 486b023b3af0..9e5956345748 100644 --- a/drivers/dma/hsu/hsu.h +++ b/drivers/dma/hsu/hsu.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Driver for the High Speed UART DMA * * Copyright (C) 2015 Intel Corporation * * Partially based on the bits found in drivers/tty/serial/mfd.c. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __DMA_HSU_H__ diff --git a/drivers/dma/hsu/pci.c b/drivers/dma/hsu/pci.c index ad45cd344bba..07cc7320a614 100644 --- a/drivers/dma/hsu/pci.c +++ b/drivers/dma/hsu/pci.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PCI driver for the High Speed UART DMA * @@ -5,10 +6,6 @@ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> * * Partially based on the bits found in drivers/tty/serial/mfd.c. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c index 07fd4f25cdd8..f5a84c846394 100644 --- a/drivers/dma/idma64.c +++ b/drivers/dma/idma64.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Core driver for the Intel integrated DMA 64-bit * * Copyright (C) 2015 Intel Corporation * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> diff --git a/drivers/dma/idma64.h b/drivers/dma/idma64.h index baa32e1425de..d013b54356aa 100644 --- a/drivers/dma/idma64.h +++ b/drivers/dma/idma64.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Driver for the Intel integrated DMA 64-bit * * Copyright (C) 2015 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __DMA_IDMA64_H__ diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 99d9f431ae2c..4ec84a633bd3 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -703,7 +703,7 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, spin_lock_irqsave(&sdma->channel_0_lock, flags); bd0->mode.command = C0_SETPM; - bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; + bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD; bd0->mode.count = size / 2; bd0->buffer_addr = buf_phys; bd0->ext_buffer_addr = address; @@ -1025,7 +1025,7 @@ static int sdma_load_context(struct sdma_channel *sdmac) context->gReg[7] = sdmac->watermark_level; bd0->mode.command = C0_SETDM; - bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; + bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD; bd0->mode.count = sizeof(*context) / 4; bd0->buffer_addr = sdma->context_phys; bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * channel; @@ -2096,27 +2096,6 @@ static int sdma_probe(struct platform_device *pdev) if (pdata && pdata->script_addrs) sdma_add_scripts(sdma, pdata->script_addrs); - if (pdata) { - ret = sdma_get_firmware(sdma, pdata->fw_name); - if (ret) - dev_warn(&pdev->dev, "failed to get firmware from platform data\n"); - } else { - /* - * Because that device tree does not encode ROM script address, - * the RAM script in firmware is mandatory for device tree - * probe, otherwise it fails. - */ - ret = of_property_read_string(np, "fsl,sdma-ram-script-name", - &fw_name); - if (ret) - dev_warn(&pdev->dev, "failed to get firmware name\n"); - else { - ret = sdma_get_firmware(sdma, fw_name); - if (ret) - dev_warn(&pdev->dev, "failed to get firmware from device tree\n"); - } - } - sdma->dma_device.dev = &pdev->dev; sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources; @@ -2161,6 +2140,33 @@ static int sdma_probe(struct platform_device *pdev) of_node_put(spba_bus); } + /* + * Kick off firmware loading as the very last step: + * attempt to load firmware only if we're not on the error path, because + * the firmware callback requires a fully functional and allocated sdma + * instance. + */ + if (pdata) { + ret = sdma_get_firmware(sdma, pdata->fw_name); + if (ret) + dev_warn(&pdev->dev, "failed to get firmware from platform data\n"); + } else { + /* + * Because that device tree does not encode ROM script address, + * the RAM script in firmware is mandatory for device tree + * probe, otherwise it fails. + */ + ret = of_property_read_string(np, "fsl,sdma-ram-script-name", + &fw_name); + if (ret) { + dev_warn(&pdev->dev, "failed to get firmware name\n"); + } else { + ret = sdma_get_firmware(sdma, fw_name); + if (ret) + dev_warn(&pdev->dev, "failed to get firmware from device tree\n"); + } + } + return 0; err_register: diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c index bbff52be4f0f..0457b1f26540 100644 --- a/drivers/dma/ipu/ipu_idmac.c +++ b/drivers/dma/ipu/ipu_idmac.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2008 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de> * * Copyright (C) 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/dma-mapping.h> diff --git a/drivers/dma/ipu/ipu_intern.h b/drivers/dma/ipu/ipu_intern.h index 545cf11a94ab..e7ec1dec3edf 100644 --- a/drivers/dma/ipu/ipu_intern.h +++ b/drivers/dma/ipu/ipu_intern.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2008 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de> * * Copyright (C) 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _IPU_INTERN_H_ diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c index 284627806b88..0d5c42f7bfa4 100644 --- a/drivers/dma/ipu/ipu_irq.c +++ b/drivers/dma/ipu/ipu_irq.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2008 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index 5737d92eaeeb..4b36c8810517 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 - 2015 Linaro Ltd. * Copyright (c) 2013 Hisilicon Limited. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/sched.h> #include <linux/device.h> diff --git a/drivers/dma/lpc18xx-dmamux.c b/drivers/dma/lpc18xx-dmamux.c index 761f32687055..df98cae8792b 100644 --- a/drivers/dma/lpc18xx-dmamux.c +++ b/drivers/dma/lpc18xx-dmamux.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * DMA Router driver for LPC18xx/43xx DMA MUX * @@ -6,11 +7,6 @@ * Based on TI DMA Crossbar driver by: * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/err.h> diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index 334bab92d26d..7fe494fc50d4 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2012 Marvell International Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c index 91fd395c90c4..1e4d9ef2aea1 100644 --- a/drivers/dma/of-dma.c +++ b/drivers/dma/of-dma.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device tree helpers for DMA request / controller * * Based on of_gpio.c * * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c index b429642f3e7a..468c234cb3be 100644 --- a/drivers/dma/pxa_dma.c +++ b/drivers/dma/pxa_dma.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2015 Robert Jarzmik <robert.jarzmik@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c index 4b43844f6af5..8e90a405939d 100644 --- a/drivers/dma/qcom/bam_dma.c +++ b/drivers/dma/qcom/bam_dma.c @@ -799,6 +799,9 @@ static u32 process_channel_irqs(struct bam_device *bdev) /* Number of bytes available to read */ avail = CIRC_CNT(offset, bchan->head, MAX_DESCRIPTORS + 1); + if (offset < bchan->head) + avail--; + list_for_each_entry_safe(async_desc, tmp, &bchan->desc_list, desc_node) { /* Not enough data to read */ diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c index 3fae23768b47..afb68055ed1b 100644 --- a/drivers/dma/sa11x0-dma.c +++ b/drivers/dma/sa11x0-dma.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SA11x0 DMAengine support * * Copyright (C) 2012 Russell King * Derived in part from arch/arm/mach-sa1100/dma.c, * Copyright (C) 2000, 2001 by Nicolas Pitre - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/sched.h> #include <linux/device.h> diff --git a/drivers/dma/ti/dma-crossbar.c b/drivers/dma/ti/dma-crossbar.c index 9272b173c746..ad2f0a4cd6a4 100644 --- a/drivers/dma/ti/dma-crossbar.c +++ b/drivers/dma/ti/dma-crossbar.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/slab.h> #include <linux/err.h> diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c index a4a931ddf6f6..ba2489d4ea24 100644 --- a/drivers/dma/ti/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP DMAengine support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> #include <linux/dmaengine.h> diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c index e8d0881b64d8..628bdf4430c7 100644 --- a/drivers/dma/txx9dmac.c +++ b/drivers/dma/txx9dmac.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for the TXx9 SoC DMA Controller * * Copyright (C) 2009 Atsushi Nemoto - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/dma-mapping.h> #include <linux/init.h> diff --git a/drivers/dma/txx9dmac.h b/drivers/dma/txx9dmac.h index f6517b928bab..aa53eafb1519 100644 --- a/drivers/dma/txx9dmac.h +++ b/drivers/dma/txx9dmac.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Driver for the TXx9 SoC DMA Controller * * Copyright (C) 2009 Atsushi Nemoto - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef TXX9DMAC_H #define TXX9DMAC_H diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c index 88ad8ed2a8d6..bb5390847257 100644 --- a/drivers/dma/virt-dma.c +++ b/drivers/dma/virt-dma.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Virtual DMA channel support for DMAengine * * Copyright (C) 2012 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> #include <linux/dmaengine.h> diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h index b09b75ab0751..23342ca23d4a 100644 --- a/drivers/dma/virt-dma.h +++ b/drivers/dma/virt-dma.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Virtual DMA channel support for DMAengine * * Copyright (C) 2012 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef VIRT_DMA_H #define VIRT_DMA_H diff --git a/drivers/dma/zx_dma.c b/drivers/dma/zx_dma.c index 2571bc7693df..9f4436f7c914 100644 --- a/drivers/dma/zx_dma.c +++ b/drivers/dma/zx_dma.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2015 Linaro. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/sched.h> #include <linux/device.h> diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 5e2e0348d460..200c04ce5b0e 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -460,6 +460,12 @@ config EDAC_ALTERA_SDMMC Support for error detection and correction on the Altera SDMMC FIFO Memory for Altera SoCs. +config EDAC_SIFIVE + bool "Sifive platform EDAC driver" + depends on EDAC=y && RISCV + help + Support for error detection and correction on the SiFive SoCs. + config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" depends on ARCH_ZYNQ || ARCH_ZYNQMP diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 89ad4a84a0f6..165ca65e1a3a 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o obj-$(CONFIG_EDAC_THUNDERX) += thunderx_edac.o obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o +obj-$(CONFIG_EDAC_SIFIVE) += sifive_edac.o obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o obj-$(CONFIG_EDAC_TI) += ti_edac.o diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 8816f74a22b4..c2e693e34d43 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1223,8 +1223,31 @@ static const struct edac_device_prv_data ocramecc_data = { .inject_fops = &altr_edac_device_inject_fops, }; +static int __maybe_unused +altr_check_ocram_deps_init(struct altr_edac_device_dev *device) +{ + void __iomem *base = device->base; + int ret; + + ret = altr_check_ecc_deps(device); + if (ret) + return ret; + + /* Verify OCRAM has been initialized */ + if (!ecc_test_bits(ALTR_A10_ECC_INITCOMPLETEA, + (base + ALTR_A10_ECC_INITSTAT_OFST))) + return -ENODEV; + + /* Enable IRQ on Single Bit Error */ + writel(ALTR_A10_ECC_SERRINTEN, (base + ALTR_A10_ECC_ERRINTENS_OFST)); + /* Ensure all writes complete */ + wmb(); + + return 0; +} + static const struct edac_device_prv_data a10_ocramecc_data = { - .setup = altr_check_ecc_deps, + .setup = altr_check_ocram_deps_init, .ce_clear_mask = ALTR_A10_ECC_SERRPENA, .ue_clear_mask = ALTR_A10_ECC_DERRPENA, .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_OCRAM, @@ -1234,7 +1257,7 @@ static const struct edac_device_prv_data a10_ocramecc_data = { .ue_set_mask = ALTR_A10_ECC_TDERRA, .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, .ecc_irq_handler = altr_edac_a10_ecc_irq, - .inject_fops = &altr_edac_a10_device_inject_fops, + .inject_fops = &altr_edac_a10_device_inject2_fops, /* * OCRAM panic on uncorrectable error because sleep/resume * functions and FPGA contents are stored in OCRAM. Prefer @@ -1560,8 +1583,12 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) dci->mod_name = ecc_name; dci->dev_name = ecc_name; - /* Update the IRQs for PortB */ + /* Update the PortB IRQs - A10 has 4, S10 has 2, Index accordingly */ +#ifdef CONFIG_ARCH_STRATIX10 + altdev->sb_irq = irq_of_parse_and_map(np, 1); +#else altdev->sb_irq = irq_of_parse_and_map(np, 2); +#endif if (!altdev->sb_irq) { edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB SBIRQ alloc\n"); rc = -ENODEV; @@ -1576,6 +1603,15 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) goto err_release_group_1; } +#ifdef CONFIG_ARCH_STRATIX10 + /* Use IRQ to determine SError origin instead of assigning IRQ */ + rc = of_property_read_u32_index(np, "interrupts", 1, &altdev->db_irq); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, + "Error PortB DBIRQ alloc\n"); + goto err_release_group_1; + } +#else altdev->db_irq = irq_of_parse_and_map(np, 3); if (!altdev->db_irq) { edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB DBIRQ alloc\n"); @@ -1590,6 +1626,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n"); goto err_release_group_1; } +#endif rc = edac_device_add_device(dci); if (rc) { diff --git a/drivers/edac/aspeed_edac.c b/drivers/edac/aspeed_edac.c index 11833c0a5d07..5634437bb39d 100644 --- a/drivers/edac/aspeed_edac.c +++ b/drivers/edac/aspeed_edac.c @@ -281,15 +281,11 @@ static int aspeed_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct edac_mc_layer layers[2]; struct mem_ctl_info *mci; - struct device_node *np; struct resource *res; void __iomem *regs; u32 reg04; int rc; - /* setup regmap */ - np = dev->of_node; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENOENT; diff --git a/drivers/edac/debugfs.c b/drivers/edac/debugfs.c index 6b8e484db851..1f943599a8ac 100644 --- a/drivers/edac/debugfs.c +++ b/drivers/edac/debugfs.c @@ -118,23 +118,23 @@ edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent, EXPORT_SYMBOL_GPL(edac_debugfs_create_file); /* Wrapper for debugfs_create_x8() */ -struct dentry *edac_debugfs_create_x8(const char *name, umode_t mode, - struct dentry *parent, u8 *value) +void edac_debugfs_create_x8(const char *name, umode_t mode, + struct dentry *parent, u8 *value) { if (!parent) parent = edac_debugfs; - return debugfs_create_x8(name, mode, parent, value); + debugfs_create_x8(name, mode, parent, value); } EXPORT_SYMBOL_GPL(edac_debugfs_create_x8); /* Wrapper for debugfs_create_x16() */ -struct dentry *edac_debugfs_create_x16(const char *name, umode_t mode, - struct dentry *parent, u16 *value) +void edac_debugfs_create_x16(const char *name, umode_t mode, + struct dentry *parent, u16 *value) { if (!parent) parent = edac_debugfs; - return debugfs_create_x16(name, mode, parent, value); + debugfs_create_x16(name, mode, parent, value); } EXPORT_SYMBOL_GPL(edac_debugfs_create_x16); diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 464174685589..4386ea4b9b5a 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -26,7 +26,7 @@ static int edac_mc_log_ue = 1; static int edac_mc_log_ce = 1; static int edac_mc_panic_on_ue; -static int edac_mc_poll_msec = 1000; +static unsigned int edac_mc_poll_msec = 1000; /* Getter functions for above */ int edac_mc_get_log_ue(void) @@ -45,30 +45,30 @@ int edac_mc_get_panic_on_ue(void) } /* this is temporary */ -int edac_mc_get_poll_msec(void) +unsigned int edac_mc_get_poll_msec(void) { return edac_mc_poll_msec; } static int edac_set_poll_msec(const char *val, const struct kernel_param *kp) { - unsigned long l; + unsigned int i; int ret; if (!val) return -EINVAL; - ret = kstrtoul(val, 0, &l); + ret = kstrtouint(val, 0, &i); if (ret) return ret; - if (l < 1000) + if (i < 1000) return -EINVAL; - *((unsigned long *)kp->arg) = l; + *((unsigned int *)kp->arg) = i; /* notify edac_mc engine to reset the poll period */ - edac_mc_reset_delay_period(l); + edac_mc_reset_delay_period(i); return 0; } @@ -82,7 +82,7 @@ MODULE_PARM_DESC(edac_mc_log_ue, module_param(edac_mc_log_ce, int, 0644); MODULE_PARM_DESC(edac_mc_log_ce, "Log correctable error to console: 0=off 1=on"); -module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_int, +module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_uint, &edac_mc_poll_msec, 0644); MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds"); @@ -404,6 +404,8 @@ static inline int nr_pages_per_csrow(struct csrow_info *csrow) static int edac_create_csrow_object(struct mem_ctl_info *mci, struct csrow_info *csrow, int index) { + int err; + csrow->dev.type = &csrow_attr_type; csrow->dev.groups = csrow_dev_groups; device_initialize(&csrow->dev); @@ -415,7 +417,11 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci, edac_dbg(0, "creating (virtual) csrow node %s\n", dev_name(&csrow->dev)); - return device_add(&csrow->dev); + err = device_add(&csrow->dev); + if (err) + put_device(&csrow->dev); + + return err; } /* Create a CSROW object under specifed edac_mc_device */ @@ -443,7 +449,8 @@ error: csrow = mci->csrows[i]; if (!nr_pages_per_csrow(csrow)) continue; - put_device(&mci->csrows[i]->dev); + + device_del(&mci->csrows[i]->dev); } return err; @@ -645,9 +652,11 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci, dev_set_drvdata(&dimm->dev, dimm); pm_runtime_forbid(&mci->dev); - err = device_add(&dimm->dev); + err = device_add(&dimm->dev); + if (err) + put_device(&dimm->dev); - edac_dbg(0, "creating rank/dimm device %s\n", dev_name(&dimm->dev)); + edac_dbg(0, "created rank/dimm device %s\n", dev_name(&dimm->dev)); return err; } @@ -928,6 +937,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, err = device_add(&mci->dev); if (err < 0) { edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev)); + put_device(&mci->dev); goto out; } diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index dd7d0b509aa3..b2f59ee76c22 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h @@ -36,7 +36,7 @@ extern int edac_mc_get_log_ue(void); extern int edac_mc_get_log_ce(void); extern int edac_mc_get_panic_on_ue(void); extern int edac_get_poll_msec(void); -extern int edac_mc_get_poll_msec(void); +extern unsigned int edac_mc_get_poll_msec(void); unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf, unsigned len); @@ -78,10 +78,10 @@ edac_debugfs_create_dir_at(const char *dirname, struct dentry *parent); struct dentry * edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops); -struct dentry * -edac_debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, u8 *value); -struct dentry * -edac_debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, u16 *value); +void edac_debugfs_create_x8(const char *name, umode_t mode, + struct dentry *parent, u8 *value); +void edac_debugfs_create_x16(const char *name, umode_t mode, + struct dentry *parent, u16 *value); #else static inline void edac_debugfs_init(void) { } static inline void edac_debugfs_exit(void) { } @@ -92,12 +92,10 @@ edac_debugfs_create_dir_at(const char *dirname, struct dentry *parent) { return static inline struct dentry * edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops) { return NULL; } -static inline struct dentry * -edac_debugfs_create_x8(const char *name, umode_t mode, - struct dentry *parent, u8 *value) { return NULL; } -static inline struct dentry * -edac_debugfs_create_x16(const char *name, umode_t mode, - struct dentry *parent, u16 *value) { return NULL; } +static inline void edac_debugfs_create_x8(const char *name, umode_t mode, + struct dentry *parent, u8 *value) { } +static inline void edac_debugfs_create_x16(const char *name, umode_t mode, + struct dentry *parent, u16 *value) { } #endif /* diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index 6f06aec4877c..83392f2841de 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -124,6 +124,8 @@ static int i10nm_get_all_munits(void) static const struct x86_cpu_id i10nm_cpuids[] = { { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_TREMONT_X, 0, 0 }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ICELAKE_X, 0, 0 }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ICELAKE_XEON_D, 0, 0 }, { } }; MODULE_DEVICE_TABLE(x86cpu, i10nm_cpuids); @@ -166,9 +168,9 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci) ndimms += skx_get_nvdimm_info(dimm, imc, i, j, EDAC_MOD_STR); } - if (ndimms && !i10nm_check_ecc(imc, 0)) { - i10nm_printk(KERN_ERR, "ECC is disabled on imc %d\n", - imc->mc); + if (ndimms && !i10nm_check_ecc(imc, i)) { + i10nm_printk(KERN_ERR, "ECC is disabled on imc %d channel %d\n", + imc->mc, i); return -ENODEV; } } @@ -265,7 +267,7 @@ static int __init i10nm_init(void) goto fail; list_for_each_entry(d, i10nm_edac_list, list) { - rc = skx_get_src_id(d, &src_id); + rc = skx_get_src_id(d, 0xf8, &src_id); if (rc < 0) goto fail; diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c index adf60eb45bd4..d26300f9cb07 100644 --- a/drivers/edac/ie31200_edac.c +++ b/drivers/edac/ie31200_edac.c @@ -20,11 +20,13 @@ * 0c08: Xeon E3-1200 v3 Processor DRAM Controller * 1918: Xeon E3-1200 v5 Skylake Host Bridge/DRAM Registers * 5918: Xeon E3-1200 Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers + * 3e..: 8th/9th Gen Core Processor Host Bridge/DRAM Registers * * Based on Intel specification: * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e3-1200v3-vol-2-datasheet.pdf * http://www.intel.com/content/www/us/en/processors/xeon/xeon-e3-1200-family-vol-2-datasheet.html * http://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-h-processor-lines-datasheet-vol-2.html + * https://www.intel.com/content/www/us/en/products/docs/processors/core/8th-gen-core-family-datasheet-vol-2.html * * According to the above datasheet (p.16): * " @@ -61,6 +63,26 @@ #define PCI_DEVICE_ID_INTEL_IE31200_HB_8 0x1918 #define PCI_DEVICE_ID_INTEL_IE31200_HB_9 0x5918 +/* Coffee Lake-S */ +#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK 0x3e00 +#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_1 0x3e0f +#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_2 0x3e18 +#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_3 0x3e1f +#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_4 0x3e30 +#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_5 0x3e31 +#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_6 0x3e32 +#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_7 0x3e33 +#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_8 0x3ec2 +#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_9 0x3ec6 +#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_10 0x3eca + +/* Test if HB is for Skylake or later. */ +#define DEVICE_ID_SKYLAKE_OR_LATER(did) \ + (((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_8) || \ + ((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_9) || \ + (((did) & PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK) == \ + PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK)) + #define IE31200_DIMMS 4 #define IE31200_RANKS 8 #define IE31200_RANKS_PER_CHANNEL 4 @@ -381,10 +403,10 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx) u32 addr_decode, mad_offset; /* - * Kaby Lake seems to work like Skylake. Please re-visit this logic - * when adding new CPU support. + * Kaby Lake, Coffee Lake seem to work like Skylake. Please re-visit + * this logic when adding new CPU support. */ - bool skl = (pdev->device >= PCI_DEVICE_ID_INTEL_IE31200_HB_8); + bool skl = DEVICE_ID_SKYLAKE_OR_LATER(pdev->device); edac_dbg(0, "MC:\n"); @@ -542,36 +564,26 @@ static void ie31200_remove_one(struct pci_dev *pdev) } static const struct pci_device_id ie31200_pci_tbl[] = { - { - PCI_VEND_DEV(INTEL, IE31200_HB_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - IE31200}, - { - PCI_VEND_DEV(INTEL, IE31200_HB_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - IE31200}, - { - PCI_VEND_DEV(INTEL, IE31200_HB_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - IE31200}, - { - PCI_VEND_DEV(INTEL, IE31200_HB_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - IE31200}, - { - PCI_VEND_DEV(INTEL, IE31200_HB_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - IE31200}, - { - PCI_VEND_DEV(INTEL, IE31200_HB_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - IE31200}, - { - PCI_VEND_DEV(INTEL, IE31200_HB_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - IE31200}, - { - PCI_VEND_DEV(INTEL, IE31200_HB_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - IE31200}, - { - PCI_VEND_DEV(INTEL, IE31200_HB_9), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - IE31200}, - { - 0, - } /* 0 terminated list. */ + { PCI_VEND_DEV(INTEL, IE31200_HB_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_9), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_9), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_10), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { 0, } /* 0 terminated list. */ }; MODULE_DEVICE_TABLE(pci, ie31200_pci_tbl); diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index fa700a170380..37746b045e18 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -1511,7 +1511,6 @@ static int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes) sad_actual_size[mc] += tad_size; } } - tad_base = tad_limit+1; } } diff --git a/drivers/edac/sifive_edac.c b/drivers/edac/sifive_edac.c new file mode 100644 index 000000000000..413cdb4a591d --- /dev/null +++ b/drivers/edac/sifive_edac.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SiFive Platform EDAC Driver + * + * Copyright (C) 2018-2019 SiFive, Inc. + * + * This driver is partially based on octeon_edac-pc.c + * + */ +#include <linux/edac.h> +#include <linux/platform_device.h> +#include "edac_module.h" +#include <asm/sifive_l2_cache.h> + +#define DRVNAME "sifive_edac" + +struct sifive_edac_priv { + struct notifier_block notifier; + struct edac_device_ctl_info *dci; +}; + +/** + * EDAC error callback + * + * @event: non-zero if unrecoverable. + */ +static +int ecc_err_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + const char *msg = (char *)ptr; + struct sifive_edac_priv *p; + + p = container_of(this, struct sifive_edac_priv, notifier); + + if (event == SIFIVE_L2_ERR_TYPE_UE) + edac_device_handle_ue(p->dci, 0, 0, msg); + else if (event == SIFIVE_L2_ERR_TYPE_CE) + edac_device_handle_ce(p->dci, 0, 0, msg); + + return NOTIFY_OK; +} + +static int ecc_register(struct platform_device *pdev) +{ + struct sifive_edac_priv *p; + + p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + p->notifier.notifier_call = ecc_err_event; + platform_set_drvdata(pdev, p); + + p->dci = edac_device_alloc_ctl_info(0, "sifive_ecc", 1, "sifive_ecc", + 1, 1, NULL, 0, + edac_device_alloc_index()); + if (IS_ERR(p->dci)) + return PTR_ERR(p->dci); + + p->dci->dev = &pdev->dev; + p->dci->mod_name = "Sifive ECC Manager"; + p->dci->ctl_name = dev_name(&pdev->dev); + p->dci->dev_name = dev_name(&pdev->dev); + + if (edac_device_add_device(p->dci)) { + dev_err(p->dci->dev, "failed to register with EDAC core\n"); + goto err; + } + + register_sifive_l2_error_notifier(&p->notifier); + + return 0; + +err: + edac_device_free_ctl_info(p->dci); + + return -ENXIO; +} + +static int ecc_unregister(struct platform_device *pdev) +{ + struct sifive_edac_priv *p = platform_get_drvdata(pdev); + + unregister_sifive_l2_error_notifier(&p->notifier); + edac_device_del_device(&pdev->dev); + edac_device_free_ctl_info(p->dci); + + return 0; +} + +static struct platform_device *sifive_pdev; + +static int __init sifive_edac_init(void) +{ + int ret; + + sifive_pdev = platform_device_register_simple(DRVNAME, 0, NULL, 0); + if (IS_ERR(sifive_pdev)) + return PTR_ERR(sifive_pdev); + + ret = ecc_register(sifive_pdev); + if (ret) + platform_device_unregister(sifive_pdev); + + return ret; +} + +static void __exit sifive_edac_exit(void) +{ + ecc_unregister(sifive_pdev); + platform_device_unregister(sifive_pdev); +} + +module_init(sifive_edac_init); +module_exit(sifive_edac_exit); + +MODULE_AUTHOR("SiFive Inc."); +MODULE_DESCRIPTION("SiFive platform EDAC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/edac/skx_base.c b/drivers/edac/skx_base.c index a5c8fa3a249a..0fcf3785e8f3 100644 --- a/drivers/edac/skx_base.c +++ b/drivers/edac/skx_base.c @@ -639,7 +639,7 @@ static int __init skx_init(void) } list_for_each_entry(d, skx_edac_list, list) { - rc = skx_get_src_id(d, &src_id); + rc = skx_get_src_id(d, 0xf0, &src_id); if (rc < 0) goto fail; rc = skx_get_node_id(d, &node_id); diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index b0dddcfa9baa..d8ff63d91b86 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -136,11 +136,11 @@ void skx_set_decode(skx_decode_f decode) skx_decode = decode; } -int skx_get_src_id(struct skx_dev *d, u8 *id) +int skx_get_src_id(struct skx_dev *d, int off, u8 *id) { u32 reg; - if (pci_read_config_dword(d->util_all, 0xf0, ®)) { + if (pci_read_config_dword(d->util_all, off, ®)) { skx_printk(KERN_ERR, "Failed to read src id\n"); return -ENODEV; } diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index d18fa98669af..08cc971a50ea 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -118,7 +118,7 @@ int __init skx_adxl_get(void); void __exit skx_adxl_put(void); void skx_set_decode(skx_decode_f decode); -int skx_get_src_id(struct skx_dev *d, u8 *id); +int skx_get_src_id(struct skx_dev *d, int off, u8 *id); int skx_get_node_id(struct skx_dev *d, u8 *id); int skx_get_all_bus_mappings(unsigned int did, int off, enum type, diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 18026354c332..ee9b5f70bfa4 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/extcon/extcon-adc-jack.c * @@ -10,11 +11,6 @@ * MyungJoo Ham <myungjoo.ham@samsung.com> * * Modified for calling to IIO to get adc by <anish.singh@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/extcon/extcon-max3355.c b/drivers/extcon/extcon-max3355.c index 1335a476bfec..fa01926c09f1 100644 --- a/drivers/extcon/extcon-max3355.c +++ b/drivers/extcon/extcon-max3355.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Maxim Integrated MAX3355 USB OTG chip extcon driver * * Copyright (C) 2014-2015 Cogent Embedded, Inc. * Author: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. */ #include <linux/extcon-provider.h> diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 9026df923542..d40ccc3af9e2 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -256,7 +256,7 @@ config TI_SCI_PROTOCOL config TRUSTED_FOUNDATIONS bool "Trusted Foundations secure monitor support" - depends on ARM + depends on ARM && CPU_V7 help Some devices (including most early Tegra-based consumer devices on the market) are booted with the Trusted Foundations secure monitor diff --git a/drivers/firmware/efi/efi-bgrt.c b/drivers/firmware/efi/efi-bgrt.c index a2384184a7de..b07c17643210 100644 --- a/drivers/firmware/efi/efi-bgrt.c +++ b/drivers/firmware/efi/efi-bgrt.c @@ -47,11 +47,6 @@ void __init efi_bgrt_init(struct acpi_table_header *table) bgrt->version); goto out; } - if (bgrt->status & 0xfe) { - pr_notice("Ignoring BGRT: reserved status bits are non-zero %u\n", - bgrt->status); - goto out; - } if (bgrt->image_type != 0) { pr_notice("Ignoring BGRT: invalid image type %u (expected 0)\n", bgrt->image_type); diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 16b2137d117c..ad3b1f4866b3 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -52,6 +52,7 @@ struct efi __read_mostly efi = { .mem_attr_table = EFI_INVALID_TABLE_ADDR, .rng_seed = EFI_INVALID_TABLE_ADDR, .tpm_log = EFI_INVALID_TABLE_ADDR, + .tpm_final_log = EFI_INVALID_TABLE_ADDR, .mem_reserve = EFI_INVALID_TABLE_ADDR, }; EXPORT_SYMBOL(efi); @@ -484,6 +485,7 @@ static __initdata efi_config_table_type_t common_tables[] = { {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table}, {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed}, {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log}, + {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log}, {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve}, {NULL_GUID, NULL, NULL}, }; @@ -1009,14 +1011,16 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size) /* first try to find a slot in an existing linked list entry */ for (prsv = efi_memreserve_root->next; prsv; prsv = rsv->next) { - rsv = __va(prsv); + rsv = memremap(prsv, sizeof(*rsv), MEMREMAP_WB); index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size); if (index < rsv->size) { rsv->entry[index].base = addr; rsv->entry[index].size = size; + memunmap(rsv); return 0; } + memunmap(rsv); } /* no slot found - allocate a new linked list entry */ @@ -1024,7 +1028,13 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size) if (!rsv) return -ENOMEM; - rsv->size = EFI_MEMRESERVE_COUNT(PAGE_SIZE); + /* + * The memremap() call above assumes that a linux_efi_memreserve entry + * never crosses a page boundary, so let's ensure that this remains true + * even when kexec'ing a 4k pages kernel from a >4k pages kernel, by + * using SZ_4K explicitly in the size calculation below. + */ + rsv->size = EFI_MEMRESERVE_COUNT(SZ_4K); atomic_set(&rsv->count, 1); rsv->entry[0].base = addr; rsv->entry[0].size = size; diff --git a/drivers/firmware/efi/efibc.c b/drivers/firmware/efi/efibc.c index 61e099826cbb..35dccc88ac0a 100644 --- a/drivers/firmware/efi/efibc.c +++ b/drivers/firmware/efi/efibc.c @@ -43,11 +43,13 @@ static int efibc_set_variable(const char *name, const char *value) efibc_str_to_str16(value, (efi_char16_t *)entry->var.Data); memcpy(&entry->var.VendorGuid, &guid, sizeof(guid)); - ret = efivar_entry_set(entry, - EFI_VARIABLE_NON_VOLATILE - | EFI_VARIABLE_BOOTSERVICE_ACCESS - | EFI_VARIABLE_RUNTIME_ACCESS, - size, entry->var.Data, NULL); + ret = efivar_entry_set_safe(entry->var.VariableName, + entry->var.VendorGuid, + EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_RUNTIME_ACCESS, + false, size, entry->var.Data); + if (ret) pr_err("failed to set %s EFI variable: 0x%x\n", name, ret); diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 04e6ecd72cd9..c382a48c6678 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * EFI stub implementation that is shared by arm and arm64 architectures. * This should be #included by the EFI stub implementation files. @@ -6,10 +7,6 @@ * Roy Franz <roy.franz@linaro.org * Copyright (C) 2013 Red Hat, Inc. * Mark Salter <msalter@redhat.com> - * - * This file is part of the Linux kernel, and is made available under the - * terms of the GNU General Public License version 2. - * */ #include <linux/efi.h> diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index e4610e72b78f..1db780c0f07b 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -926,3 +926,18 @@ free_map: fail: return status; } + +void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid) +{ + efi_config_table_t *tables = (efi_config_table_t *)sys_table->tables; + int i; + + for (i = 0; i < sys_table->nr_tables; i++) { + if (efi_guidcmp(tables[i].guid, guid) != 0) + continue; + + return (void *)tables[i].table; + } + + return NULL; +} diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 1b1dfcaa6fb9..7f1556fd867d 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -65,6 +65,8 @@ efi_status_t check_platform_features(efi_system_table_t *sys_table_arg); efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg); +void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid); + /* Helper macros for the usual case of using simple C variables: */ #ifndef fdt_setprop_inplace_var #define fdt_setprop_inplace_var(fdt, node_offset, name, var) \ diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index 5440ba17a1c5..0bf0190917e0 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -363,26 +363,17 @@ fail: void *get_fdt(efi_system_table_t *sys_table, unsigned long *fdt_size) { - efi_guid_t fdt_guid = DEVICE_TREE_GUID; - efi_config_table_t *tables; - int i; + void *fdt; - tables = (efi_config_table_t *)sys_table->tables; + fdt = get_efi_config_table(sys_table, DEVICE_TREE_GUID); - for (i = 0; i < sys_table->nr_tables; i++) { - void *fdt; + if (!fdt) + return NULL; - if (efi_guidcmp(tables[i].guid, fdt_guid) != 0) - continue; - - fdt = (void *)tables[i].table; - if (fdt_check_header(fdt) != 0) { - pr_efi_err(sys_table, "Invalid header detected on UEFI supplied FDT, ignoring ...\n"); - return NULL; - } - *fdt_size = fdt_totalsize(fdt); - return fdt; + if (fdt_check_header(fdt) != 0) { + pr_efi_err(sys_table, "Invalid header detected on UEFI supplied FDT, ignoring ...\n"); + return NULL; } - - return NULL; + *fdt_size = fdt_totalsize(fdt); + return fdt; } diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index 5bd04f75d8d6..eb9af83e4d59 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -57,31 +57,40 @@ void efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg) #endif -static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) +void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg) { efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID; efi_status_t status; efi_physical_addr_t log_location = 0, log_last_entry = 0; struct linux_efi_tpm_eventlog *log_tbl = NULL; + struct efi_tcg2_final_events_table *final_events_table; unsigned long first_entry_addr, last_entry_addr; size_t log_size, last_entry_size; efi_bool_t truncated; + int version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; void *tcg2_protocol = NULL; + int final_events_size = 0; status = efi_call_early(locate_protocol, &tcg2_guid, NULL, &tcg2_protocol); if (status != EFI_SUCCESS) return; - status = efi_call_proto(efi_tcg2_protocol, get_event_log, tcg2_protocol, - EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2, - &log_location, &log_last_entry, &truncated); - if (status != EFI_SUCCESS) - return; + status = efi_call_proto(efi_tcg2_protocol, get_event_log, + tcg2_protocol, version, &log_location, + &log_last_entry, &truncated); + + if (status != EFI_SUCCESS || !log_location) { + version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; + status = efi_call_proto(efi_tcg2_protocol, get_event_log, + tcg2_protocol, version, &log_location, + &log_last_entry, &truncated); + if (status != EFI_SUCCESS || !log_location) + return; + + } - if (!log_location) - return; first_entry_addr = (unsigned long) log_location; /* @@ -96,8 +105,23 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) * We need to calculate its size to deduce the full size of * the logs. */ - last_entry_size = sizeof(struct tcpa_event) + - ((struct tcpa_event *) last_entry_addr)->event_size; + if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) { + /* + * The TCG2 log format has variable length entries, + * and the information to decode the hash algorithms + * back into a size is contained in the first entry - + * pass a pointer to the final entry (to calculate its + * size) and the first entry (so we know how long each + * digest is) + */ + last_entry_size = + __calc_tpm2_event_size((void *)last_entry_addr, + (void *)(long)log_location, + false); + } else { + last_entry_size = sizeof(struct tcpa_event) + + ((struct tcpa_event *) last_entry_addr)->event_size; + } log_size = log_last_entry - log_location + last_entry_size; } @@ -112,9 +136,37 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) return; } + /* + * Figure out whether any events have already been logged to the + * final events structure, and if so how much space they take up + */ + final_events_table = get_efi_config_table(sys_table_arg, + LINUX_EFI_TPM_FINAL_LOG_GUID); + if (final_events_table && final_events_table->nr_events) { + struct tcg_pcr_event2_head *header; + int offset; + void *data; + int event_size; + int i = final_events_table->nr_events; + + data = (void *)final_events_table; + offset = sizeof(final_events_table->version) + + sizeof(final_events_table->nr_events); + + while (i > 0) { + header = data + offset + final_events_size; + event_size = __calc_tpm2_event_size(header, + (void *)(long)log_location, + false); + final_events_size += event_size; + i--; + } + } + memset(log_tbl, 0, sizeof(*log_tbl) + log_size); log_tbl->size = log_size; - log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; + log_tbl->final_events_preboot_size = final_events_size; + log_tbl->version = version; memcpy(log_tbl->log, (void *) first_entry_addr, log_size); status = efi_call_early(install_configuration_table, @@ -126,9 +178,3 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) err_free: efi_call_early(free_pool, log_tbl); } - -void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg) -{ - /* Only try to retrieve the logs in 1.2 format. */ - efi_retrieve_tpm2_eventlog_1_2(sys_table_arg); -} diff --git a/drivers/firmware/efi/tpm.c b/drivers/firmware/efi/tpm.c index 3a689b40ccc0..1d3f5ca3eaaf 100644 --- a/drivers/firmware/efi/tpm.c +++ b/drivers/firmware/efi/tpm.c @@ -4,11 +4,34 @@ * Thiebaud Weksteen <tweek@google.com> */ +#define TPM_MEMREMAP(start, size) early_memremap(start, size) +#define TPM_MEMUNMAP(start, size) early_memunmap(start, size) + +#include <asm/early_ioremap.h> #include <linux/efi.h> #include <linux/init.h> #include <linux/memblock.h> +#include <linux/tpm_eventlog.h> -#include <asm/early_ioremap.h> +int efi_tpm_final_log_size; +EXPORT_SYMBOL(efi_tpm_final_log_size); + +static int tpm2_calc_event_log_size(void *data, int count, void *size_info) +{ + struct tcg_pcr_event2_head *header; + int event_size, size = 0; + + while (count > 0) { + header = data + size; + event_size = __calc_tpm2_event_size(header, size_info, true); + if (event_size == 0) + return -1; + size += event_size; + count--; + } + + return size; +} /* * Reserve the memory associated with the TPM Event Log configuration table. @@ -16,22 +39,54 @@ int __init efi_tpm_eventlog_init(void) { struct linux_efi_tpm_eventlog *log_tbl; + struct efi_tcg2_final_events_table *final_tbl; unsigned int tbl_size; + int ret = 0; - if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) + if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) { + /* + * We can't calculate the size of the final events without the + * first entry in the TPM log, so bail here. + */ return 0; + } log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl)); if (!log_tbl) { pr_err("Failed to map TPM Event Log table @ 0x%lx\n", - efi.tpm_log); + efi.tpm_log); efi.tpm_log = EFI_INVALID_TABLE_ADDR; return -ENOMEM; } tbl_size = sizeof(*log_tbl) + log_tbl->size; memblock_reserve(efi.tpm_log, tbl_size); + + if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR) + goto out; + + final_tbl = early_memremap(efi.tpm_final_log, sizeof(*final_tbl)); + + if (!final_tbl) { + pr_err("Failed to map TPM Final Event Log table @ 0x%lx\n", + efi.tpm_final_log); + efi.tpm_final_log = EFI_INVALID_TABLE_ADDR; + ret = -ENOMEM; + goto out; + } + + tbl_size = tpm2_calc_event_log_size((void *)efi.tpm_final_log + + sizeof(final_tbl->version) + + sizeof(final_tbl->nr_events), + final_tbl->nr_events, + log_tbl->log); + memblock_reserve((unsigned long)final_tbl, + tbl_size + sizeof(*final_tbl)); + early_memunmap(final_tbl, sizeof(*final_tbl)); + efi_tpm_final_log_size = tbl_size; + +out: early_memunmap(log_tbl, sizeof(*log_tbl)); - return 0; + return ret; } diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c index 043833ad3c1a..687121f8c4d5 100644 --- a/drivers/firmware/imx/imx-scu-irq.c +++ b/drivers/firmware/imx/imx-scu-irq.c @@ -100,6 +100,9 @@ int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable) struct imx_sc_rpc_msg *hdr = &msg.hdr; int ret; + if (!imx_sc_irq_ipc_handle) + return -EPROBE_DEFER; + hdr->ver = IMX_SC_RPC_VERSION; hdr->svc = IMX_SC_RPC_SVC_IRQ; hdr->func = IMX_SC_IRQ_FUNC_ENABLE; diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c index e83d6aec0c13..4adeb7a2bdf5 100644 --- a/drivers/firmware/pcdp.c +++ b/drivers/firmware/pcdp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Parse the EFI PCDP table to locate the console device. * @@ -5,10 +6,6 @@ * Khalid Aziz <khalid.aziz@hp.com> * Alex Williamson <alex.williamson@hp.com> * Bjorn Helgaas <bjorn.helgaas@hp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/firmware/pcdp.h b/drivers/firmware/pcdp.h index e5530608e00d..ce75d1da9e84 100644 --- a/drivers/firmware/pcdp.h +++ b/drivers/firmware/pcdp.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Definitions for PCDP-defined console devices * @@ -7,10 +8,6 @@ * (c) Copyright 2002, 2004 Hewlett-Packard Development Company, L.P. * Khalid Aziz <khalid.aziz@hp.com> * Bjorn Helgaas <bjorn.helgaas@hp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define PCDP_CONSOLE 0 diff --git a/drivers/fmc/Kconfig b/drivers/fmc/Kconfig deleted file mode 100644 index ae3d7f634932..000000000000 --- a/drivers/fmc/Kconfig +++ /dev/null @@ -1,52 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# FMC (ANSI-VITA 57.1) bus support -# - -menuconfig FMC - tristate "FMC support" - help - - FMC (FPGA Mezzanine Carrier) is a mechanical and electrical - standard for mezzanine cards that plug into a carrier board. - This kernel subsystem supports the matching between carrier - and mezzanine based on identifiers stored in the internal I2C - EEPROM, as well as having carrier-independent drivers. - - The framework was born outside of the kernel and at this time - the off-tree code base is more complete. Code and documentation - is at git://ohwr.org/fmc-projects/fmc-bus.git . - -if FMC - -config FMC_FAKEDEV - tristate "FMC fake device (software testing)" - help - This is a fake carrier, bringing a default EEPROM content - that can be rewritten at run time and usef for matching - mezzanines. - -config FMC_TRIVIAL - tristate "FMC trivial mezzanine driver (software testing)" - help - This is a fake mezzanine driver, to show how FMC works and test it. - The driver also handles interrupts (we used it with a real carrier - before the mezzanines were produced) - -config FMC_WRITE_EEPROM - tristate "FMC mezzanine driver to write I2C EEPROM" - help - This driver matches every mezzanine device and can write the - internal EEPROM of the PCB, using the firmware loader to get - its binary and the function carrier->reprogram to actually do it. - It is useful when the mezzanines are produced. - -config FMC_CHARDEV - tristate "FMC mezzanine driver that registers a char device" - help - This driver matches every mezzanine device and allows user - space to read and write registers using a char device. It - can be used to write user-space drivers, or just get - acquainted with a mezzanine before writing its specific driver. - -endif # FMC diff --git a/drivers/fmc/Makefile b/drivers/fmc/Makefile deleted file mode 100644 index e3da6192cf39..000000000000 --- a/drivers/fmc/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -obj-$(CONFIG_FMC) += fmc.o - -fmc-y = fmc-core.o -fmc-y += fmc-match.o -fmc-y += fmc-sdb.o -fmc-y += fru-parse.o -fmc-y += fmc-dump.o -fmc-y += fmc-debug.o - -obj-$(CONFIG_FMC_FAKEDEV) += fmc-fakedev.o -obj-$(CONFIG_FMC_TRIVIAL) += fmc-trivial.o -obj-$(CONFIG_FMC_WRITE_EEPROM) += fmc-write-eeprom.o -obj-$(CONFIG_FMC_CHARDEV) += fmc-chardev.o diff --git a/drivers/fmc/fmc-chardev.c b/drivers/fmc/fmc-chardev.c deleted file mode 100644 index 7d2091b5e978..000000000000 --- a/drivers/fmc/fmc-chardev.c +++ /dev/null @@ -1,199 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * This work is part of the White Rabbit project, a research effort led - * by CERN, the European Institute for Nuclear Research. - */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/slab.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/spinlock.h> -#include <linux/fmc.h> -#include <linux/uaccess.h> - -static LIST_HEAD(fc_devices); -static DEFINE_SPINLOCK(fc_lock); - -struct fc_instance { - struct list_head list; - struct fmc_device *fmc; - struct miscdevice misc; -}; - -/* at open time, we must identify our device */ -static int fc_open(struct inode *ino, struct file *f) -{ - struct fmc_device *fmc; - struct fc_instance *fc; - int minor = iminor(ino); - - list_for_each_entry(fc, &fc_devices, list) - if (fc->misc.minor == minor) - break; - if (fc->misc.minor != minor) - return -ENODEV; - fmc = fc->fmc; - if (try_module_get(fmc->owner) == 0) - return -ENODEV; - - f->private_data = fmc; - return 0; -} - -static int fc_release(struct inode *ino, struct file *f) -{ - struct fmc_device *fmc = f->private_data; - module_put(fmc->owner); - return 0; -} - -/* read and write are simple after the default llseek has been used */ -static ssize_t fc_read(struct file *f, char __user *buf, size_t count, - loff_t *offp) -{ - struct fmc_device *fmc = f->private_data; - unsigned long addr; - uint32_t val; - - if (count < sizeof(val)) - return -EINVAL; - count = sizeof(val); - - addr = *offp; - if (addr > fmc->memlen) - return -ESPIPE; /* Illegal seek */ - val = fmc_readl(fmc, addr); - if (copy_to_user(buf, &val, count)) - return -EFAULT; - *offp += count; - return count; -} - -static ssize_t fc_write(struct file *f, const char __user *buf, size_t count, - loff_t *offp) -{ - struct fmc_device *fmc = f->private_data; - unsigned long addr; - uint32_t val; - - if (count < sizeof(val)) - return -EINVAL; - count = sizeof(val); - - addr = *offp; - if (addr > fmc->memlen) - return -ESPIPE; /* Illegal seek */ - if (copy_from_user(&val, buf, count)) - return -EFAULT; - fmc_writel(fmc, val, addr); - *offp += count; - return count; -} - -static const struct file_operations fc_fops = { - .owner = THIS_MODULE, - .open = fc_open, - .release = fc_release, - .llseek = generic_file_llseek, - .read = fc_read, - .write = fc_write, -}; - - -/* Device part .. */ -static int fc_probe(struct fmc_device *fmc); -static int fc_remove(struct fmc_device *fmc); - -static struct fmc_driver fc_drv = { - .version = FMC_VERSION, - .driver.name = KBUILD_MODNAME, - .probe = fc_probe, - .remove = fc_remove, - /* no table: we want to match everything */ -}; - -/* We accept the generic busid parameter */ -FMC_PARAM_BUSID(fc_drv); - -/* probe and remove must allocate and release a misc device */ -static int fc_probe(struct fmc_device *fmc) -{ - int ret; - int index = 0; - - struct fc_instance *fc; - - index = fmc_validate(fmc, &fc_drv); - if (index < 0) - return -EINVAL; /* not our device: invalid */ - - /* Create a char device: we want to create it anew */ - fc = kzalloc(sizeof(*fc), GFP_KERNEL); - if (!fc) - return -ENOMEM; - fc->fmc = fmc; - fc->misc.minor = MISC_DYNAMIC_MINOR; - fc->misc.fops = &fc_fops; - fc->misc.name = kstrdup(dev_name(&fmc->dev), GFP_KERNEL); - - ret = misc_register(&fc->misc); - if (ret < 0) - goto out; - spin_lock(&fc_lock); - list_add(&fc->list, &fc_devices); - spin_unlock(&fc_lock); - dev_info(&fc->fmc->dev, "Created misc device \"%s\"\n", - fc->misc.name); - return 0; - -out: - kfree(fc->misc.name); - kfree(fc); - return ret; -} - -static int fc_remove(struct fmc_device *fmc) -{ - struct fc_instance *fc; - - list_for_each_entry(fc, &fc_devices, list) - if (fc->fmc == fmc) - break; - if (fc->fmc != fmc) { - dev_err(&fmc->dev, "remove called but not found\n"); - return -ENODEV; - } - - spin_lock(&fc_lock); - list_del(&fc->list); - spin_unlock(&fc_lock); - misc_deregister(&fc->misc); - kfree(fc->misc.name); - kfree(fc); - - return 0; -} - - -static int fc_init(void) -{ - int ret; - - ret = fmc_driver_register(&fc_drv); - return ret; -} - -static void fc_exit(void) -{ - fmc_driver_unregister(&fc_drv); -} - -module_init(fc_init); -module_exit(fc_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/fmc/fmc-core.c b/drivers/fmc/fmc-core.c deleted file mode 100644 index 573f5471f680..000000000000 --- a/drivers/fmc/fmc-core.c +++ /dev/null @@ -1,388 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * This work is part of the White Rabbit project, a research effort led - * by CERN, the European Institute for Nuclear Research. - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/device.h> -#include <linux/fmc.h> -#include <linux/fmc-sdb.h> - -#include "fmc-private.h" - -static int fmc_check_version(unsigned long version, const char *name) -{ - if (__FMC_MAJOR(version) != FMC_MAJOR) { - pr_err("%s: \"%s\" has wrong major (has %li, expected %i)\n", - __func__, name, __FMC_MAJOR(version), FMC_MAJOR); - return -EINVAL; - } - - if (__FMC_MINOR(version) != FMC_MINOR) - pr_info("%s: \"%s\" has wrong minor (has %li, expected %i)\n", - __func__, name, __FMC_MINOR(version), FMC_MINOR); - return 0; -} - -static int fmc_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - /* struct fmc_device *fdev = to_fmc_device(dev); */ - - /* FIXME: The MODALIAS */ - add_uevent_var(env, "MODALIAS=%s", "fmc"); - return 0; -} - -static int fmc_probe(struct device *dev) -{ - struct fmc_driver *fdrv = to_fmc_driver(dev->driver); - struct fmc_device *fdev = to_fmc_device(dev); - - return fdrv->probe(fdev); -} - -static int fmc_remove(struct device *dev) -{ - struct fmc_driver *fdrv = to_fmc_driver(dev->driver); - struct fmc_device *fdev = to_fmc_device(dev); - - return fdrv->remove(fdev); -} - -static void fmc_shutdown(struct device *dev) -{ - /* not implemented but mandatory */ -} - -static struct bus_type fmc_bus_type = { - .name = "fmc", - .match = fmc_match, - .uevent = fmc_uevent, - .probe = fmc_probe, - .remove = fmc_remove, - .shutdown = fmc_shutdown, -}; - -static void fmc_release(struct device *dev) -{ - struct fmc_device *fmc = container_of(dev, struct fmc_device, dev); - - kfree(fmc); -} - -/* - * The eeprom is exported in sysfs, through a binary attribute - */ - -static ssize_t fmc_read_eeprom(struct file *file, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct device *dev; - struct fmc_device *fmc; - int eelen; - - dev = container_of(kobj, struct device, kobj); - fmc = container_of(dev, struct fmc_device, dev); - eelen = fmc->eeprom_len; - if (off > eelen) - return -ESPIPE; - if (off == eelen) - return 0; /* EOF */ - if (off + count > eelen) - count = eelen - off; - memcpy(buf, fmc->eeprom + off, count); - return count; -} - -static ssize_t fmc_write_eeprom(struct file *file, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct device *dev; - struct fmc_device *fmc; - - dev = container_of(kobj, struct device, kobj); - fmc = container_of(dev, struct fmc_device, dev); - return fmc->op->write_ee(fmc, off, buf, count); -} - -static struct bin_attribute fmc_eeprom_attr = { - .attr = { .name = "eeprom", .mode = S_IRUGO | S_IWUSR, }, - .size = 8192, /* more or less standard */ - .read = fmc_read_eeprom, - .write = fmc_write_eeprom, -}; - -int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h, - char *name, int flags) -{ - if (fmc->op->irq_request) - return fmc->op->irq_request(fmc, h, name, flags); - return -EPERM; -} -EXPORT_SYMBOL(fmc_irq_request); - -void fmc_irq_free(struct fmc_device *fmc) -{ - if (fmc->op->irq_free) - fmc->op->irq_free(fmc); -} -EXPORT_SYMBOL(fmc_irq_free); - -void fmc_irq_ack(struct fmc_device *fmc) -{ - if (likely(fmc->op->irq_ack)) - fmc->op->irq_ack(fmc); -} -EXPORT_SYMBOL(fmc_irq_ack); - -int fmc_validate(struct fmc_device *fmc, struct fmc_driver *drv) -{ - if (fmc->op->validate) - return fmc->op->validate(fmc, drv); - return -EPERM; -} -EXPORT_SYMBOL(fmc_validate); - -int fmc_gpio_config(struct fmc_device *fmc, struct fmc_gpio *gpio, int ngpio) -{ - if (fmc->op->gpio_config) - return fmc->op->gpio_config(fmc, gpio, ngpio); - return -EPERM; -} -EXPORT_SYMBOL(fmc_gpio_config); - -int fmc_read_ee(struct fmc_device *fmc, int pos, void *d, int l) -{ - if (fmc->op->read_ee) - return fmc->op->read_ee(fmc, pos, d, l); - return -EPERM; -} -EXPORT_SYMBOL(fmc_read_ee); - -int fmc_write_ee(struct fmc_device *fmc, int pos, const void *d, int l) -{ - if (fmc->op->write_ee) - return fmc->op->write_ee(fmc, pos, d, l); - return -EPERM; -} -EXPORT_SYMBOL(fmc_write_ee); - -/* - * Functions for client modules follow - */ - -int fmc_driver_register(struct fmc_driver *drv) -{ - if (fmc_check_version(drv->version, drv->driver.name)) - return -EINVAL; - drv->driver.bus = &fmc_bus_type; - return driver_register(&drv->driver); -} -EXPORT_SYMBOL(fmc_driver_register); - -void fmc_driver_unregister(struct fmc_driver *drv) -{ - driver_unregister(&drv->driver); -} -EXPORT_SYMBOL(fmc_driver_unregister); - -/* - * When a device set is registered, all eeproms must be read - * and all FRUs must be parsed - */ -int fmc_device_register_n_gw(struct fmc_device **devs, int n, - struct fmc_gateware *gw) -{ - struct fmc_device *fmc, **devarray; - uint32_t device_id; - int i, ret = 0; - - if (n < 1) - return 0; - - /* Check the version of the first data structure (function prints) */ - if (fmc_check_version(devs[0]->version, devs[0]->carrier_name)) - return -EINVAL; - - devarray = kmemdup(devs, n * sizeof(*devs), GFP_KERNEL); - if (!devarray) - return -ENOMEM; - - /* Make all other checks before continuing, for all devices */ - for (i = 0; i < n; i++) { - fmc = devarray[i]; - if (!fmc->hwdev) { - pr_err("%s: device nr. %i has no hwdev pointer\n", - __func__, i); - ret = -EINVAL; - break; - } - if (fmc->flags & FMC_DEVICE_NO_MEZZANINE) { - dev_info(fmc->hwdev, "absent mezzanine in slot %d\n", - fmc->slot_id); - continue; - } - if (!fmc->eeprom) { - dev_err(fmc->hwdev, "no eeprom provided for slot %i\n", - fmc->slot_id); - ret = -EINVAL; - } - if (!fmc->eeprom_addr) { - dev_err(fmc->hwdev, "no eeprom_addr for slot %i\n", - fmc->slot_id); - ret = -EINVAL; - } - if (!fmc->carrier_name || !fmc->carrier_data || - !fmc->device_id) { - dev_err(fmc->hwdev, - "device nr %i: carrier name, " - "data or dev_id not set\n", i); - ret = -EINVAL; - } - if (ret) - break; - - } - if (ret) { - kfree(devarray); - return ret; - } - - /* Validation is ok. Now init and register the devices */ - for (i = 0; i < n; i++) { - fmc = devarray[i]; - - fmc->nr_slots = n; /* each slot must know how many are there */ - fmc->devarray = devarray; - - device_initialize(&fmc->dev); - fmc->dev.release = fmc_release; - fmc->dev.parent = fmc->hwdev; - - /* Fill the identification stuff (may fail) */ - fmc_fill_id_info(fmc); - - fmc->dev.bus = &fmc_bus_type; - - /* Name from mezzanine info or carrier info. Or 0,1,2.. */ - device_id = fmc->device_id; - if (!fmc->mezzanine_name) - dev_set_name(&fmc->dev, "fmc-%04x", device_id); - else - dev_set_name(&fmc->dev, "%s-%04x", fmc->mezzanine_name, - device_id); - - if (gw) { - /* - * The carrier already know the bitstream to load - * for this set of FMC mezzanines. - */ - ret = fmc->op->reprogram_raw(fmc, NULL, - gw->bitstream, gw->len); - if (ret) { - dev_warn(fmc->hwdev, - "Invalid gateware for FMC mezzanine\n"); - goto out; - } - } - - ret = device_add(&fmc->dev); - if (ret < 0) { - dev_err(fmc->hwdev, "Slot %i: Failed in registering " - "\"%s\"\n", fmc->slot_id, fmc->dev.kobj.name); - goto out; - } - ret = sysfs_create_bin_file(&fmc->dev.kobj, &fmc_eeprom_attr); - if (ret < 0) { - dev_err(&fmc->dev, "Failed in registering eeprom\n"); - goto out1; - } - /* This device went well, give information to the user */ - fmc_dump_eeprom(fmc); - fmc_debug_init(fmc); - } - return 0; - -out1: - device_del(&fmc->dev); -out: - kfree(devarray); - for (i--; i >= 0; i--) { - fmc_debug_exit(devs[i]); - sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr); - device_del(&devs[i]->dev); - fmc_free_id_info(devs[i]); - put_device(&devs[i]->dev); - } - return ret; - -} -EXPORT_SYMBOL(fmc_device_register_n_gw); - -int fmc_device_register_n(struct fmc_device **devs, int n) -{ - return fmc_device_register_n_gw(devs, n, NULL); -} -EXPORT_SYMBOL(fmc_device_register_n); - -int fmc_device_register_gw(struct fmc_device *fmc, struct fmc_gateware *gw) -{ - return fmc_device_register_n_gw(&fmc, 1, gw); -} -EXPORT_SYMBOL(fmc_device_register_gw); - -int fmc_device_register(struct fmc_device *fmc) -{ - return fmc_device_register_n(&fmc, 1); -} -EXPORT_SYMBOL(fmc_device_register); - -void fmc_device_unregister_n(struct fmc_device **devs, int n) -{ - int i; - - if (n < 1) - return; - - /* Free devarray first, not used by the later loop */ - kfree(devs[0]->devarray); - - for (i = 0; i < n; i++) { - fmc_debug_exit(devs[i]); - sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr); - device_del(&devs[i]->dev); - fmc_free_id_info(devs[i]); - put_device(&devs[i]->dev); - } -} -EXPORT_SYMBOL(fmc_device_unregister_n); - -void fmc_device_unregister(struct fmc_device *fmc) -{ - fmc_device_unregister_n(&fmc, 1); -} -EXPORT_SYMBOL(fmc_device_unregister); - -/* Init and exit are trivial */ -static int fmc_init(void) -{ - return bus_register(&fmc_bus_type); -} - -static void fmc_exit(void) -{ - bus_unregister(&fmc_bus_type); -} - -module_init(fmc_init); -module_exit(fmc_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/fmc/fmc-debug.c b/drivers/fmc/fmc-debug.c deleted file mode 100644 index 1734c7cf0e76..000000000000 --- a/drivers/fmc/fmc-debug.c +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2015 CERN (www.cern.ch) - * Author: Federico Vaga <federico.vaga@cern.ch> - */ - -#include <linux/module.h> -#include <linux/device.h> -#include <linux/init.h> -#include <linux/fs.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <asm/byteorder.h> - -#include <linux/fmc.h> -#include <linux/sdb.h> -#include <linux/fmc-sdb.h> - -#define FMC_DBG_SDB_DUMP "dump_sdb" - -static char *__strip_trailing_space(char *buf, char *str, int len) -{ - int i = len - 1; - - memcpy(buf, str, len); - buf[len] = '\0'; - while (i >= 0 && buf[i] == ' ') - buf[i--] = '\0'; - return buf; -} - -#define __sdb_string(buf, field) ({ \ - BUILD_BUG_ON(sizeof(buf) < sizeof(field)); \ - __strip_trailing_space(buf, (void *)(field), sizeof(field)); \ - }) - -/** - * We do not check seq_printf() errors because we want to see things in any case - */ -static void fmc_sdb_dump_recursive(struct fmc_device *fmc, struct seq_file *s, - const struct sdb_array *arr) -{ - unsigned long base = arr->baseaddr; - int i, j, n = arr->len, level = arr->level; - char tmp[64]; - - for (i = 0; i < n; i++) { - union sdb_record *r; - struct sdb_product *p; - struct sdb_component *c; - - r = &arr->record[i]; - c = &r->dev.sdb_component; - p = &c->product; - - for (j = 0; j < level; j++) - seq_printf(s, " "); - switch (r->empty.record_type) { - case sdb_type_interconnect: - seq_printf(s, "%08llx:%08x %.19s\n", - __be64_to_cpu(p->vendor_id), - __be32_to_cpu(p->device_id), - p->name); - break; - case sdb_type_device: - seq_printf(s, "%08llx:%08x %.19s (%08llx-%08llx)\n", - __be64_to_cpu(p->vendor_id), - __be32_to_cpu(p->device_id), - p->name, - __be64_to_cpu(c->addr_first) + base, - __be64_to_cpu(c->addr_last) + base); - break; - case sdb_type_bridge: - seq_printf(s, "%08llx:%08x %.19s (bridge: %08llx)\n", - __be64_to_cpu(p->vendor_id), - __be32_to_cpu(p->device_id), - p->name, - __be64_to_cpu(c->addr_first) + base); - if (IS_ERR(arr->subtree[i])) { - seq_printf(s, "SDB: (bridge error %li)\n", - PTR_ERR(arr->subtree[i])); - break; - } - fmc_sdb_dump_recursive(fmc, s, arr->subtree[i]); - break; - case sdb_type_integration: - seq_printf(s, "integration\n"); - break; - case sdb_type_repo_url: - seq_printf(s, "Synthesis repository: %s\n", - __sdb_string(tmp, r->repo_url.repo_url)); - break; - case sdb_type_synthesis: - seq_printf(s, "Bitstream '%s' ", - __sdb_string(tmp, r->synthesis.syn_name)); - seq_printf(s, "synthesized %08x by %s ", - __be32_to_cpu(r->synthesis.date), - __sdb_string(tmp, r->synthesis.user_name)); - seq_printf(s, "(%s version %x), ", - __sdb_string(tmp, r->synthesis.tool_name), - __be32_to_cpu(r->synthesis.tool_version)); - seq_printf(s, "commit %pm\n", - r->synthesis.commit_id); - break; - case sdb_type_empty: - seq_printf(s, "empty\n"); - break; - default: - seq_printf(s, "UNKNOWN TYPE 0x%02x\n", - r->empty.record_type); - break; - } - } -} - -static int fmc_sdb_dump(struct seq_file *s, void *offset) -{ - struct fmc_device *fmc = s->private; - - if (!fmc->sdb) { - seq_printf(s, "no SDB information\n"); - return 0; - } - - seq_printf(s, "FMC: %s (%s), slot %i, device %s\n", dev_name(fmc->hwdev), - fmc->carrier_name, fmc->slot_id, dev_name(&fmc->dev)); - /* Dump SDB information */ - fmc_sdb_dump_recursive(fmc, s, fmc->sdb); - - return 0; -} - - -static int fmc_sdb_dump_open(struct inode *inode, struct file *file) -{ - struct fmc_device *fmc = inode->i_private; - - return single_open(file, fmc_sdb_dump, fmc); -} - - -const struct file_operations fmc_dbgfs_sdb_dump = { - .owner = THIS_MODULE, - .open = fmc_sdb_dump_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -int fmc_debug_init(struct fmc_device *fmc) -{ - fmc->dbg_dir = debugfs_create_dir(dev_name(&fmc->dev), NULL); - if (IS_ERR_OR_NULL(fmc->dbg_dir)) { - pr_err("FMC: Cannot create debugfs\n"); - return PTR_ERR(fmc->dbg_dir); - } - - fmc->dbg_sdb_dump = debugfs_create_file(FMC_DBG_SDB_DUMP, 0444, - fmc->dbg_dir, fmc, - &fmc_dbgfs_sdb_dump); - if (IS_ERR_OR_NULL(fmc->dbg_sdb_dump)) - pr_err("FMC: Cannot create debugfs file %s\n", - FMC_DBG_SDB_DUMP); - - return 0; -} - -void fmc_debug_exit(struct fmc_device *fmc) -{ - if (fmc->dbg_dir) - debugfs_remove_recursive(fmc->dbg_dir); -} diff --git a/drivers/fmc/fmc-dump.c b/drivers/fmc/fmc-dump.c deleted file mode 100644 index 6c81dbde1d16..000000000000 --- a/drivers/fmc/fmc-dump.c +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2013 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * This work is part of the White Rabbit project, a research effort led - * by CERN, the European Institute for Nuclear Research. - */ -#include <linux/kernel.h> -#include <linux/moduleparam.h> -#include <linux/device.h> -#include <linux/fmc.h> -#include <linux/fmc-sdb.h> - -static int fmc_must_dump_eeprom; -module_param_named(dump_eeprom, fmc_must_dump_eeprom, int, 0644); - -#define LINELEN 16 - -/* Dumping 8k takes oh so much: avoid duplicate lines */ -static const uint8_t *dump_line(int addr, const uint8_t *line, - const uint8_t *prev) -{ - int i; - - if (!prev || memcmp(line, prev, LINELEN)) { - pr_info("%04x: ", addr); - for (i = 0; i < LINELEN; ) { - printk(KERN_CONT "%02x", line[i]); - i++; - printk(i & 3 ? " " : i & (LINELEN - 1) ? " " : "\n"); - } - return line; - } - /* repeated line */ - if (line == prev + LINELEN) - pr_info("[...]\n"); - return prev; -} - -void fmc_dump_eeprom(const struct fmc_device *fmc) -{ - const uint8_t *line, *prev; - int i; - - if (!fmc_must_dump_eeprom) - return; - - pr_info("FMC: %s (%s), slot %i, device %s\n", dev_name(fmc->hwdev), - fmc->carrier_name, fmc->slot_id, dev_name(&fmc->dev)); - pr_info("FMC: dumping eeprom 0x%x (%i) bytes\n", fmc->eeprom_len, - fmc->eeprom_len); - - line = fmc->eeprom; - prev = NULL; - for (i = 0; i < fmc->eeprom_len; i += LINELEN, line += LINELEN) - prev = dump_line(i, line, prev); -} diff --git a/drivers/fmc/fmc-fakedev.c b/drivers/fmc/fmc-fakedev.c deleted file mode 100644 index 941d0930969a..000000000000 --- a/drivers/fmc/fmc-fakedev.c +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * The software is provided "as is"; the copyright holders disclaim - * all warranties and liabilities, to the extent permitted by - * applicable law. - */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/device.h> -#include <linux/slab.h> -#include <linux/firmware.h> -#include <linux/workqueue.h> -#include <linux/err.h> -#include <linux/fmc.h> - -#define FF_EEPROM_SIZE 8192 /* The standard eeprom size */ -#define FF_MAX_MEZZANINES 4 /* Fakes a multi-mezzanine carrier */ - -/* The user can pass up to 4 names of eeprom images to load */ -static char *ff_eeprom[FF_MAX_MEZZANINES]; -static int ff_nr_eeprom; -module_param_array_named(eeprom, ff_eeprom, charp, &ff_nr_eeprom, 0444); - -/* The user can ask for a multi-mezzanine carrier, with the default eeprom */ -static int ff_nr_dev = 1; -module_param_named(ndev, ff_nr_dev, int, 0444); - - -/* Lazily, don't support the "standard" module parameters */ - -/* - * Eeprom built from these commands: - - ../fru-generator -v fake-vendor -n fake-design-for-testing \ - -s 01234 -p none > IPMI-FRU - - gensdbfs . ../fake-eeprom.bin -*/ -static char ff_eeimg[FF_MAX_MEZZANINES][FF_EEPROM_SIZE] = { - { - 0x01, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x00, 0xf2, 0x01, 0x0b, 0x00, 0xb2, - 0x86, 0x87, 0xcb, 0x66, 0x61, 0x6b, 0x65, 0x2d, 0x76, 0x65, 0x6e, 0x64, - 0x6f, 0x72, 0xd7, 0x66, 0x61, 0x6b, 0x65, 0x2d, 0x64, 0x65, 0x73, 0x69, - 0x67, 0x6e, 0x2d, 0x66, 0x6f, 0x72, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x69, - 0x6e, 0x67, 0xc5, 0x30, 0x31, 0x32, 0x33, 0x34, 0xc4, 0x6e, 0x6f, 0x6e, - 0x65, 0xda, 0x32, 0x30, 0x31, 0x32, 0x2d, 0x31, 0x31, 0x2d, 0x31, 0x39, - 0x20, 0x32, 0x32, 0x3a, 0x34, 0x32, 0x3a, 0x33, 0x30, 0x2e, 0x30, 0x37, - 0x34, 0x30, 0x35, 0x35, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, - 0x02, 0x02, 0x0d, 0xf7, 0xf8, 0x02, 0xb0, 0x04, 0x74, 0x04, 0xec, 0x04, - 0x00, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x02, 0x02, 0x0d, 0x5c, 0x93, 0x01, - 0x4a, 0x01, 0x39, 0x01, 0x5a, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x0b, - 0x02, 0x02, 0x0d, 0x63, 0x8c, 0x00, 0xfa, 0x00, 0xed, 0x00, 0x06, 0x01, - 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x01, 0x02, 0x0d, 0xfb, 0xf5, 0x05, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x0d, 0xfc, 0xf4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x0d, 0xfd, 0xf3, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x82, 0x0b, 0xea, 0x8f, 0xa2, 0x12, 0x00, 0x00, 0x1e, 0x44, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x53, 0x44, 0x42, 0x2d, 0x00, 0x03, 0x01, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xc4, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, - 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x2e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x46, 0x69, 0x6c, 0x65, - 0x44, 0x61, 0x74, 0x61, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, - 0x46, 0x69, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0x49, 0x50, 0x4d, 0x49, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, 0x50, 0x4d, 0x49, - 0x2d, 0x46, 0x52, 0x55, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x01, 0x66, 0x61, 0x6b, 0x65, 0x0a, - }, -}; - -struct ff_dev { - struct fmc_device *fmc[FF_MAX_MEZZANINES]; - struct device dev; -}; - -static struct ff_dev *ff_current_dev; /* We have 1 carrier, 1 slot */ - -static int ff_reprogram(struct fmc_device *fmc, struct fmc_driver *drv, - char *gw) -{ - const struct firmware *fw; - int ret; - - if (!gw) { - /* program golden: success */ - fmc->flags &= ~FMC_DEVICE_HAS_CUSTOM; - fmc->flags |= FMC_DEVICE_HAS_GOLDEN; - return 0; - } - - dev_info(&fmc->dev, "reprogramming with %s\n", gw); - ret = request_firmware(&fw, gw, &fmc->dev); - if (ret < 0) { - dev_warn(&fmc->dev, "request firmware \"%s\": error %i\n", - gw, ret); - goto out; - } - fmc->flags &= ~FMC_DEVICE_HAS_GOLDEN; - fmc->flags |= FMC_DEVICE_HAS_CUSTOM; - -out: - release_firmware(fw); - return ret; -} - -static int ff_irq_request(struct fmc_device *fmc, irq_handler_t handler, - char *name, int flags) -{ - return -EOPNOTSUPP; -} - -/* FIXME: should also have some fake FMC GPIO mapping */ - - -/* - * This work function is called when we changed the eeprom. It removes the - * current fmc device and registers a new one, with different identifiers. - */ -static struct ff_dev *ff_dev_create(void); /* defined later */ - -static void ff_work_fn(struct work_struct *work) -{ - struct ff_dev *ff = ff_current_dev; - int ret; - - fmc_device_unregister_n(ff->fmc, ff_nr_dev); - device_unregister(&ff->dev); - ff_current_dev = NULL; - - ff = ff_dev_create(); - if (IS_ERR(ff)) { - pr_warning("%s: can't re-create FMC devices\n", __func__); - return; - } - ret = fmc_device_register_n(ff->fmc, ff_nr_dev); - if (ret < 0) { - dev_warn(&ff->dev, "can't re-register FMC devices\n"); - device_unregister(&ff->dev); - return; - } - - ff_current_dev = ff; -} - -static DECLARE_DELAYED_WORK(ff_work, ff_work_fn); - - -/* low-level i2c */ -static int ff_eeprom_read(struct fmc_device *fmc, uint32_t offset, - void *buf, size_t size) -{ - if (offset > FF_EEPROM_SIZE) - return -EINVAL; - if (offset + size > FF_EEPROM_SIZE) - size = FF_EEPROM_SIZE - offset; - memcpy(buf, fmc->eeprom + offset, size); - return size; -} - -static int ff_eeprom_write(struct fmc_device *fmc, uint32_t offset, - const void *buf, size_t size) -{ - if (offset > FF_EEPROM_SIZE) - return -EINVAL; - if (offset + size > FF_EEPROM_SIZE) - size = FF_EEPROM_SIZE - offset; - dev_info(&fmc->dev, "write_eeprom: offset %i, size %zi\n", - (int)offset, size); - memcpy(fmc->eeprom + offset, buf, size); - schedule_delayed_work(&ff_work, HZ * 2); /* remove, replug, in 2s */ - return size; -} - -/* i2c operations for fmc */ -static int ff_read_ee(struct fmc_device *fmc, int pos, void *data, int len) -{ - if (!(fmc->flags & FMC_DEVICE_HAS_GOLDEN)) - return -EOPNOTSUPP; - return ff_eeprom_read(fmc, pos, data, len); -} - -static int ff_write_ee(struct fmc_device *fmc, int pos, - const void *data, int len) -{ - if (!(fmc->flags & FMC_DEVICE_HAS_GOLDEN)) - return -EOPNOTSUPP; - return ff_eeprom_write(fmc, pos, data, len); -} - -/* readl and writel do not do anything. Don't waste RAM with "base" */ -static uint32_t ff_readl(struct fmc_device *fmc, int offset) -{ - return 0; -} - -static void ff_writel(struct fmc_device *fmc, uint32_t value, int offset) -{ - return; -} - -/* validate is useful so fmc-write-eeprom will not reprogram every 2 seconds */ -static int ff_validate(struct fmc_device *fmc, struct fmc_driver *drv) -{ - int i; - - if (!drv->busid_n) - return 0; /* everyhing is valid */ - for (i = 0; i < drv->busid_n; i++) - if (drv->busid_val[i] == fmc->device_id) - return i; - return -ENOENT; -} - - - -static struct fmc_operations ff_fmc_operations = { - .read32 = ff_readl, - .write32 = ff_writel, - .reprogram = ff_reprogram, - .irq_request = ff_irq_request, - .read_ee = ff_read_ee, - .write_ee = ff_write_ee, - .validate = ff_validate, -}; - -/* This device is kmalloced: release it */ -static void ff_dev_release(struct device *dev) -{ - struct ff_dev *ff = container_of(dev, struct ff_dev, dev); - kfree(ff); -} - -static struct fmc_device ff_template_fmc = { - .version = FMC_VERSION, - .owner = THIS_MODULE, - .carrier_name = "fake-fmc-carrier", - .device_id = 0xf001, /* fool */ - .eeprom_len = sizeof(ff_eeimg[0]), - .memlen = 0x1000, /* 4k, to show something */ - .op = &ff_fmc_operations, - .hwdev = NULL, /* filled at creation time */ - .flags = FMC_DEVICE_HAS_GOLDEN, -}; - -static struct ff_dev *ff_dev_create(void) -{ - struct ff_dev *ff; - struct fmc_device *fmc; - int i, ret; - - ff = kzalloc(sizeof(*ff), GFP_KERNEL); - if (!ff) - return ERR_PTR(-ENOMEM); - dev_set_name(&ff->dev, "fake-fmc-carrier"); - ff->dev.release = ff_dev_release; - - ret = device_register(&ff->dev); - if (ret < 0) { - put_device(&ff->dev); - return ERR_PTR(ret); - } - - /* Create fmc structures that refer to this new "hw" device */ - for (i = 0; i < ff_nr_dev; i++) { - fmc = kmemdup(&ff_template_fmc, sizeof(ff_template_fmc), - GFP_KERNEL); - fmc->hwdev = &ff->dev; - fmc->carrier_data = ff; - fmc->nr_slots = ff_nr_dev; - /* the following fields are different for each slot */ - fmc->eeprom = ff_eeimg[i]; - fmc->eeprom_addr = 0x50 + 2 * i; - fmc->slot_id = i; - ff->fmc[i] = fmc; - /* increment the identifier, each must be different */ - ff_template_fmc.device_id++; - } - return ff; -} - -/* init and exit */ -static int ff_init(void) -{ - struct ff_dev *ff; - const struct firmware *fw; - int i, len, ret = 0; - - /* Replicate the default eeprom for the max number of mezzanines */ - for (i = 1; i < FF_MAX_MEZZANINES; i++) - memcpy(ff_eeimg[i], ff_eeimg[0], sizeof(ff_eeimg[0])); - - if (ff_nr_eeprom > ff_nr_dev) - ff_nr_dev = ff_nr_eeprom; - - ff = ff_dev_create(); - if (IS_ERR(ff)) - return PTR_ERR(ff); - - /* If the user passed "eeprom=" as a parameter, fetch them */ - for (i = 0; i < ff_nr_eeprom; i++) { - if (!strlen(ff_eeprom[i])) - continue; - ret = request_firmware(&fw, ff_eeprom[i], &ff->dev); - if (ret < 0) { - dev_err(&ff->dev, "Mezzanine %i: can't load \"%s\" " - "(error %i)\n", i, ff_eeprom[i], -ret); - } else { - len = min_t(size_t, fw->size, (size_t)FF_EEPROM_SIZE); - memcpy(ff_eeimg[i], fw->data, len); - release_firmware(fw); - dev_info(&ff->dev, "Mezzanine %i: eeprom \"%s\"\n", i, - ff_eeprom[i]); - } - } - - ret = fmc_device_register_n(ff->fmc, ff_nr_dev); - if (ret) { - device_unregister(&ff->dev); - return ret; - } - ff_current_dev = ff; - return ret; -} - -static void ff_exit(void) -{ - if (ff_current_dev) { - fmc_device_unregister_n(ff_current_dev->fmc, ff_nr_dev); - device_unregister(&ff_current_dev->dev); - } - cancel_delayed_work_sync(&ff_work); -} - -module_init(ff_init); -module_exit(ff_exit); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/fmc/fmc-match.c b/drivers/fmc/fmc-match.c deleted file mode 100644 index 995bd6041a67..000000000000 --- a/drivers/fmc/fmc-match.c +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * This work is part of the White Rabbit project, a research effort led - * by CERN, the European Institute for Nuclear Research. - */ -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/fmc.h> -#include <linux/ipmi-fru.h> - -/* The fru parser is both user and kernel capable: it needs alloc */ -void *fru_alloc(size_t size) -{ - return kzalloc(size, GFP_KERNEL); -} - -/* The actual match function */ -int fmc_match(struct device *dev, struct device_driver *drv) -{ - struct fmc_driver *fdrv = to_fmc_driver(drv); - struct fmc_device *fdev = to_fmc_device(dev); - struct fmc_fru_id *fid; - int i, matched = 0; - - /* This currently only matches the EEPROM (FRU id) */ - fid = fdrv->id_table.fru_id; - if (!fid) { - dev_warn(&fdev->dev, "Driver has no ID: matches all\n"); - matched = 1; - } else { - if (!fdev->id.manufacturer || !fdev->id.product_name) - return 0; /* the device has no FRU information */ - for (i = 0; i < fdrv->id_table.fru_id_nr; i++, fid++) { - if (fid->manufacturer && - strcmp(fid->manufacturer, fdev->id.manufacturer)) - continue; - if (fid->product_name && - strcmp(fid->product_name, fdev->id.product_name)) - continue; - matched = 1; - break; - } - } - - /* FIXME: match SDB contents */ - return matched; -} - -/* This function creates ID info for a newly registered device */ -int fmc_fill_id_info(struct fmc_device *fmc) -{ - struct fru_common_header *h; - struct fru_board_info_area *bia; - int ret, allocated = 0; - - /* If we know the eeprom length, try to read it off the device */ - if (fmc->eeprom_len && !fmc->eeprom) { - fmc->eeprom = kzalloc(fmc->eeprom_len, GFP_KERNEL); - if (!fmc->eeprom) - return -ENOMEM; - allocated = 1; - ret = fmc_read_ee(fmc, 0, fmc->eeprom, fmc->eeprom_len); - if (ret < 0) - goto out; - } - - /* If no eeprom, continue with other matches */ - if (!fmc->eeprom) - return 0; - - dev_info(fmc->hwdev, "mezzanine %i\n", fmc->slot_id); /* header */ - - /* So we have the eeprom: parse the FRU part (if any) */ - h = (void *)fmc->eeprom; - if (h->format != 1) { - pr_info(" EEPROM has no FRU information\n"); - goto out; - } - if (!fru_header_cksum_ok(h)) { - pr_info(" FRU: wrong header checksum\n"); - goto out; - } - bia = fru_get_board_area(h); - if (!fru_bia_cksum_ok(bia)) { - pr_info(" FRU: wrong board area checksum\n"); - goto out; - } - fmc->id.manufacturer = fru_get_board_manufacturer(h); - fmc->id.product_name = fru_get_product_name(h); - pr_info(" Manufacturer: %s\n", fmc->id.manufacturer); - pr_info(" Product name: %s\n", fmc->id.product_name); - - /* Create the short name (FIXME: look in sdb as well) */ - fmc->mezzanine_name = kstrdup(fmc->id.product_name, GFP_KERNEL); - -out: - if (allocated) { - kfree(fmc->eeprom); - fmc->eeprom = NULL; - } - return 0; /* no error: let other identification work */ -} - -/* Some ID data is allocated using fru_alloc() above, so release it */ -void fmc_free_id_info(struct fmc_device *fmc) -{ - kfree(fmc->mezzanine_name); - kfree(fmc->id.manufacturer); - kfree(fmc->id.product_name); -} diff --git a/drivers/fmc/fmc-private.h b/drivers/fmc/fmc-private.h deleted file mode 100644 index 93cb8030f764..000000000000 --- a/drivers/fmc/fmc-private.h +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2015 CERN (www.cern.ch) - * Author: Federico Vaga <federico.vaga@cern.ch> - */ - -extern int fmc_debug_init(struct fmc_device *fmc); -extern void fmc_debug_exit(struct fmc_device *fmc); diff --git a/drivers/fmc/fmc-sdb.c b/drivers/fmc/fmc-sdb.c deleted file mode 100644 index 14758db1a5fb..000000000000 --- a/drivers/fmc/fmc-sdb.c +++ /dev/null @@ -1,219 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * This work is part of the White Rabbit project, a research effort led - * by CERN, the European Institute for Nuclear Research. - */ -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/fmc.h> -#include <linux/sdb.h> -#include <linux/err.h> -#include <linux/fmc-sdb.h> -#include <asm/byteorder.h> - -static uint32_t __sdb_rd(struct fmc_device *fmc, unsigned long address, - int convert) -{ - uint32_t res = fmc_readl(fmc, address); - if (convert) - return __be32_to_cpu(res); - return res; -} - -static struct sdb_array *__fmc_scan_sdb_tree(struct fmc_device *fmc, - unsigned long sdb_addr, - unsigned long reg_base, int level) -{ - uint32_t onew; - int i, j, n, convert = 0; - struct sdb_array *arr, *sub; - - onew = fmc_readl(fmc, sdb_addr); - if (onew == SDB_MAGIC) { - /* Uh! If we are little-endian, we must convert */ - if (SDB_MAGIC != __be32_to_cpu(SDB_MAGIC)) - convert = 1; - } else if (onew == __be32_to_cpu(SDB_MAGIC)) { - /* ok, don't convert */ - } else { - return ERR_PTR(-ENOENT); - } - /* So, the magic was there: get the count from offset 4*/ - onew = __sdb_rd(fmc, sdb_addr + 4, convert); - n = __be16_to_cpu(*(uint16_t *)&onew); - arr = kzalloc(sizeof(*arr), GFP_KERNEL); - if (!arr) - return ERR_PTR(-ENOMEM); - arr->record = kcalloc(n, sizeof(arr->record[0]), GFP_KERNEL); - arr->subtree = kcalloc(n, sizeof(arr->subtree[0]), GFP_KERNEL); - if (!arr->record || !arr->subtree) { - kfree(arr->record); - kfree(arr->subtree); - kfree(arr); - return ERR_PTR(-ENOMEM); - } - - arr->len = n; - arr->level = level; - arr->fmc = fmc; - for (i = 0; i < n; i++) { - union sdb_record *r; - - for (j = 0; j < sizeof(arr->record[0]); j += 4) { - *(uint32_t *)((void *)(arr->record + i) + j) = - __sdb_rd(fmc, sdb_addr + (i * 64) + j, convert); - } - r = &arr->record[i]; - arr->subtree[i] = ERR_PTR(-ENODEV); - if (r->empty.record_type == sdb_type_bridge) { - struct sdb_component *c = &r->bridge.sdb_component; - uint64_t subaddr = __be64_to_cpu(r->bridge.sdb_child); - uint64_t newbase = __be64_to_cpu(c->addr_first); - - subaddr += reg_base; - newbase += reg_base; - sub = __fmc_scan_sdb_tree(fmc, subaddr, newbase, - level + 1); - arr->subtree[i] = sub; /* may be error */ - if (IS_ERR(sub)) - continue; - sub->parent = arr; - sub->baseaddr = newbase; - } - } - return arr; -} - -int fmc_scan_sdb_tree(struct fmc_device *fmc, unsigned long address) -{ - struct sdb_array *ret; - if (fmc->sdb) - return -EBUSY; - ret = __fmc_scan_sdb_tree(fmc, address, 0 /* regs */, 0); - if (IS_ERR(ret)) - return PTR_ERR(ret); - fmc->sdb = ret; - return 0; -} -EXPORT_SYMBOL(fmc_scan_sdb_tree); - -static void __fmc_sdb_free(struct sdb_array *arr) -{ - int i, n; - - if (!arr) - return; - n = arr->len; - for (i = 0; i < n; i++) { - if (IS_ERR(arr->subtree[i])) - continue; - __fmc_sdb_free(arr->subtree[i]); - } - kfree(arr->record); - kfree(arr->subtree); - kfree(arr); -} - -int fmc_free_sdb_tree(struct fmc_device *fmc) -{ - __fmc_sdb_free(fmc->sdb); - fmc->sdb = NULL; - return 0; -} -EXPORT_SYMBOL(fmc_free_sdb_tree); - -/* This helper calls reprogram and inizialized sdb as well */ -int fmc_reprogram_raw(struct fmc_device *fmc, struct fmc_driver *d, - void *gw, unsigned long len, int sdb_entry) -{ - int ret; - - ret = fmc->op->reprogram_raw(fmc, d, gw, len); - if (ret < 0) - return ret; - if (sdb_entry < 0) - return ret; - - /* We are required to find SDB at a given offset */ - ret = fmc_scan_sdb_tree(fmc, sdb_entry); - if (ret < 0) { - dev_err(&fmc->dev, "Can't find SDB at address 0x%x\n", - sdb_entry); - return -ENODEV; - } - - return 0; -} -EXPORT_SYMBOL(fmc_reprogram_raw); - -/* This helper calls reprogram and inizialized sdb as well */ -int fmc_reprogram(struct fmc_device *fmc, struct fmc_driver *d, char *gw, - int sdb_entry) -{ - int ret; - - ret = fmc->op->reprogram(fmc, d, gw); - if (ret < 0) - return ret; - if (sdb_entry < 0) - return ret; - - /* We are required to find SDB at a given offset */ - ret = fmc_scan_sdb_tree(fmc, sdb_entry); - if (ret < 0) { - dev_err(&fmc->dev, "Can't find SDB at address 0x%x\n", - sdb_entry); - return -ENODEV; - } - - return 0; -} -EXPORT_SYMBOL(fmc_reprogram); - -void fmc_show_sdb_tree(const struct fmc_device *fmc) -{ - pr_err("%s: not supported anymore, use debugfs to dump SDB\n", - __func__); -} -EXPORT_SYMBOL(fmc_show_sdb_tree); - -signed long fmc_find_sdb_device(struct sdb_array *tree, - uint64_t vid, uint32_t did, unsigned long *sz) -{ - signed long res = -ENODEV; - union sdb_record *r; - struct sdb_product *p; - struct sdb_component *c; - int i, n = tree->len; - uint64_t last, first; - - /* FIXME: what if the first interconnect is not at zero? */ - for (i = 0; i < n; i++) { - r = &tree->record[i]; - c = &r->dev.sdb_component; - p = &c->product; - - if (!IS_ERR(tree->subtree[i])) - res = fmc_find_sdb_device(tree->subtree[i], - vid, did, sz); - if (res >= 0) - return res + tree->baseaddr; - if (r->empty.record_type != sdb_type_device) - continue; - if (__be64_to_cpu(p->vendor_id) != vid) - continue; - if (__be32_to_cpu(p->device_id) != did) - continue; - /* found */ - last = __be64_to_cpu(c->addr_last); - first = __be64_to_cpu(c->addr_first); - if (sz) - *sz = (typeof(*sz))(last + 1 - first); - return first + tree->baseaddr; - } - return res; -} -EXPORT_SYMBOL(fmc_find_sdb_device); diff --git a/drivers/fmc/fmc-trivial.c b/drivers/fmc/fmc-trivial.c deleted file mode 100644 index 8defdee3e3a3..000000000000 --- a/drivers/fmc/fmc-trivial.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * The software is provided "as is"; the copyright holders disclaim - * all warranties and liabilities, to the extent permitted by - * applicable law. - */ - -/* A trivial fmc driver that can load a gateware file and reports interrupts */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/gpio.h> -#include <linux/fmc.h> - -static struct fmc_driver t_drv; /* initialized later */ - -static irqreturn_t t_handler(int irq, void *dev_id) -{ - struct fmc_device *fmc = dev_id; - - fmc_irq_ack(fmc); - dev_info(&fmc->dev, "received irq %i\n", irq); - return IRQ_HANDLED; -} - -static struct fmc_gpio t_gpio[] = { - { - .gpio = FMC_GPIO_IRQ(0), - .mode = GPIOF_DIR_IN, - .irqmode = IRQF_TRIGGER_RISING, - }, { - .gpio = FMC_GPIO_IRQ(1), - .mode = GPIOF_DIR_IN, - .irqmode = IRQF_TRIGGER_RISING, - } -}; - -static int t_probe(struct fmc_device *fmc) -{ - int ret; - int index = 0; - - index = fmc_validate(fmc, &t_drv); - if (index < 0) - return -EINVAL; /* not our device: invalid */ - - ret = fmc_irq_request(fmc, t_handler, "fmc-trivial", IRQF_SHARED); - if (ret < 0) - return ret; - /* ignore error code of call below, we really don't care */ - fmc_gpio_config(fmc, t_gpio, ARRAY_SIZE(t_gpio)); - - ret = fmc_reprogram(fmc, &t_drv, "", 0); - if (ret == -EPERM) /* programming not supported */ - ret = 0; - if (ret < 0) - fmc_irq_free(fmc); - - /* FIXME: reprogram LM32 too */ - return ret; -} - -static int t_remove(struct fmc_device *fmc) -{ - fmc_irq_free(fmc); - return 0; -} - -static struct fmc_driver t_drv = { - .version = FMC_VERSION, - .driver.name = KBUILD_MODNAME, - .probe = t_probe, - .remove = t_remove, - /* no table, as the current match just matches everything */ -}; - - /* We accept the generic parameters */ -FMC_PARAM_BUSID(t_drv); -FMC_PARAM_GATEWARE(t_drv); - -static int t_init(void) -{ - int ret; - - ret = fmc_driver_register(&t_drv); - return ret; -} - -static void t_exit(void) -{ - fmc_driver_unregister(&t_drv); -} - -module_init(t_init); -module_exit(t_exit); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/fmc/fmc-write-eeprom.c b/drivers/fmc/fmc-write-eeprom.c deleted file mode 100644 index 1c7826e3f526..000000000000 --- a/drivers/fmc/fmc-write-eeprom.c +++ /dev/null @@ -1,175 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * This work is part of the White Rabbit project, a research effort led - * by CERN, the European Institute for Nuclear Research. - */ -#include <linux/module.h> -#include <linux/string.h> -#include <linux/firmware.h> -#include <linux/init.h> -#include <linux/fmc.h> -#include <asm/unaligned.h> - -/* - * This module uses the firmware loader to program the whole or part - * of the FMC eeprom. The meat is in the _run functions. However, no - * default file name is provided, to avoid accidental mishaps. Also, - * you must pass the busid argument - */ -static struct fmc_driver fwe_drv; - -FMC_PARAM_BUSID(fwe_drv); - -/* The "file=" is like the generic "gateware=" used elsewhere */ -static char *fwe_file[FMC_MAX_CARDS]; -static int fwe_file_n; -module_param_array_named(file, fwe_file, charp, &fwe_file_n, 0444); - -static int fwe_run_tlv(struct fmc_device *fmc, const struct firmware *fw, - int write) -{ - const uint8_t *p = fw->data; - int len = fw->size; - uint16_t thislen, thisaddr; - int err; - - /* format is: 'w' addr16 len16 data... */ - while (len > 5) { - thisaddr = get_unaligned_le16(p+1); - thislen = get_unaligned_le16(p+3); - if (p[0] != 'w' || thislen + 5 > len) { - dev_err(&fmc->dev, "invalid tlv at offset %ti\n", - p - fw->data); - return -EINVAL; - } - err = 0; - if (write) { - dev_info(&fmc->dev, "write %i bytes at 0x%04x\n", - thislen, thisaddr); - err = fmc_write_ee(fmc, thisaddr, p + 5, thislen); - } - if (err < 0) { - dev_err(&fmc->dev, "write failure @0x%04x\n", - thisaddr); - return err; - } - p += 5 + thislen; - len -= 5 + thislen; - } - if (write) - dev_info(&fmc->dev, "write_eeprom: success\n"); - return 0; -} - -static int fwe_run_bin(struct fmc_device *fmc, const struct firmware *fw) -{ - int ret; - - dev_info(&fmc->dev, "programming %zi bytes\n", fw->size); - ret = fmc_write_ee(fmc, 0, (void *)fw->data, fw->size); - if (ret < 0) { - dev_info(&fmc->dev, "write_eeprom: error %i\n", ret); - return ret; - } - dev_info(&fmc->dev, "write_eeprom: success\n"); - return 0; -} - -static int fwe_run(struct fmc_device *fmc, const struct firmware *fw, char *s) -{ - char *last4 = s + strlen(s) - 4; - int err; - - if (!strcmp(last4, ".bin")) - return fwe_run_bin(fmc, fw); - if (!strcmp(last4, ".tlv")) { - err = fwe_run_tlv(fmc, fw, 0); - if (!err) - err = fwe_run_tlv(fmc, fw, 1); - return err; - } - dev_err(&fmc->dev, "invalid file name \"%s\"\n", s); - return -EINVAL; -} - -/* - * Programming is done at probe time. Morever, only those listed with - * busid= are programmed. - * card is probed for, only one is programmed. Unfortunately, it's - * difficult to know in advance when probing the first card if others - * are there. - */ -static int fwe_probe(struct fmc_device *fmc) -{ - int err, index = 0; - const struct firmware *fw; - struct device *dev = &fmc->dev; - char *s; - - if (!fwe_drv.busid_n) { - dev_err(dev, "%s: no busid passed, refusing all cards\n", - KBUILD_MODNAME); - return -ENODEV; - } - - index = fmc_validate(fmc, &fwe_drv); - if (index < 0) { - pr_err("%s: refusing device \"%s\"\n", KBUILD_MODNAME, - dev_name(dev)); - return -ENODEV; - } - if (index >= fwe_file_n) { - pr_err("%s: no filename for device index %i\n", - KBUILD_MODNAME, index); - return -ENODEV; - } - s = fwe_file[index]; - if (!s) { - pr_err("%s: no filename for \"%s\" not programming\n", - KBUILD_MODNAME, dev_name(dev)); - return -ENOENT; - } - err = request_firmware(&fw, s, dev); - if (err < 0) { - dev_err(&fmc->dev, "request firmware \"%s\": error %i\n", - s, err); - return err; - } - fwe_run(fmc, fw, s); - release_firmware(fw); - return 0; -} - -static int fwe_remove(struct fmc_device *fmc) -{ - return 0; -} - -static struct fmc_driver fwe_drv = { - .version = FMC_VERSION, - .driver.name = KBUILD_MODNAME, - .probe = fwe_probe, - .remove = fwe_remove, - /* no table, as the current match just matches everything */ -}; - -static int fwe_init(void) -{ - int ret; - - ret = fmc_driver_register(&fwe_drv); - return ret; -} - -static void fwe_exit(void) -{ - fmc_driver_unregister(&fwe_drv); -} - -module_init(fwe_init); -module_exit(fwe_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/fmc/fru-parse.c b/drivers/fmc/fru-parse.c deleted file mode 100644 index f551b81f4fd9..000000000000 --- a/drivers/fmc/fru-parse.c +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * This work is part of the White Rabbit project, a research effort led - * by CERN, the European Institute for Nuclear Research. - */ -#include <linux/ipmi-fru.h> - -/* Some internal helpers */ -static struct fru_type_length * -__fru_get_board_tl(struct fru_common_header *header, int nr) -{ - struct fru_board_info_area *bia; - struct fru_type_length *tl; - - bia = fru_get_board_area(header); - tl = bia->tl; - while (nr > 0 && !fru_is_eof(tl)) { - tl = fru_next_tl(tl); - nr--; - } - if (fru_is_eof(tl)) - return NULL; - return tl; -} - -static char *__fru_alloc_get_tl(struct fru_common_header *header, int nr) -{ - struct fru_type_length *tl; - char *res; - - tl = __fru_get_board_tl(header, nr); - if (!tl) - return NULL; - - res = fru_alloc(fru_strlen(tl) + 1); - if (!res) - return NULL; - return fru_strcpy(res, tl); -} - -/* Public checksum verifiers */ -int fru_header_cksum_ok(struct fru_common_header *header) -{ - uint8_t *ptr = (void *)header; - int i, sum; - - for (i = sum = 0; i < sizeof(*header); i++) - sum += ptr[i]; - return (sum & 0xff) == 0; -} -int fru_bia_cksum_ok(struct fru_board_info_area *bia) -{ - uint8_t *ptr = (void *)bia; - int i, sum; - - for (i = sum = 0; i < 8 * bia->area_len; i++) - sum += ptr[i]; - return (sum & 0xff) == 0; -} - -/* Get various stuff, trivial */ -char *fru_get_board_manufacturer(struct fru_common_header *header) -{ - return __fru_alloc_get_tl(header, 0); -} -char *fru_get_product_name(struct fru_common_header *header) -{ - return __fru_alloc_get_tl(header, 1); -} -char *fru_get_serial_number(struct fru_common_header *header) -{ - return __fru_alloc_get_tl(header, 2); -} -char *fru_get_part_number(struct fru_common_header *header) -{ - return __fru_alloc_get_tl(header, 3); -} diff --git a/drivers/fsi/fsi-scom.c b/drivers/fsi/fsi-scom.c index 81dc01ac2351..343153d47e5b 100644 --- a/drivers/fsi/fsi-scom.c +++ b/drivers/fsi/fsi-scom.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SCOM FSI Client device driver * * Copyright (C) IBM Corporation 2016 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERGCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/fsi.h> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index acd40eb51c46..e4fee216d5a4 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -62,16 +62,12 @@ config GPIO_SYSFS bool "/sys/class/gpio/... (sysfs interface)" depends on SYSFS help - Say Y here to add a sysfs interface for GPIOs. + Say Y here to add the legacy sysfs interface for GPIOs. - This is mostly useful to work around omissions in a system's - kernel support. Those are common in custom and semicustom - hardware assembled using standard kernels with a minimum of - custom patches. In those cases, userspace code may import - a given GPIO from the kernel, if no kernel driver requested it. - - Kernel drivers may also request that a particular GPIO be - exported to userspace; this can be useful when debugging. + This ABI is deprecated. If you want to use GPIO from userspace, + use the character device /dev/gpiochipN with the appropriate + ioctl() operations instead. The character device is always + available. config GPIO_GENERIC depends on HAS_IOMEM # Only for IOMEM drivers @@ -178,7 +174,7 @@ config GPIO_CLPS711X config GPIO_DAVINCI bool "TI Davinci/Keystone GPIO support" default y if ARCH_DAVINCI - depends on ARM && (ARCH_DAVINCI || ARCH_KEYSTONE) + depends on (ARM || ARM64) && (ARCH_DAVINCI || ARCH_KEYSTONE || ARCH_K3) help Say yes here to enable GPIO support for TI Davinci/Keystone SoCs. @@ -493,7 +489,8 @@ config GPIO_STA2X11 config GPIO_STP_XWAY bool "XWAY STP GPIOs" - depends on SOC_XWAY + depends on SOC_XWAY || COMPILE_TEST + depends on OF_GPIO help This enables support for the Serial To Parallel (STP) unit found on XWAY SoC. The STP allows the SoC to drive a shift registers cascade, @@ -602,7 +599,6 @@ config GPIO_XGENE_SB config GPIO_XILINX tristate "Xilinx GPIO support" - depends on OF_GPIO help Say yes here to support the Xilinx FPGA GPIO device diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 6700eee860b7..9e400e34e300 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -17,154 +17,154 @@ obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o # directly supported by gpio-generic gpio-generic-$(CONFIG_GPIO_GENERIC) += gpio-mmio.o -obj-$(CONFIG_GPIO_104_DIO_48E) += gpio-104-dio-48e.o -obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o -obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o -obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o -obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o -obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o -obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o -obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o -obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o -obj-$(CONFIG_GPIO_ALTERA_A10SR) += gpio-altera-a10sr.o -obj-$(CONFIG_GPIO_AMD_FCH) += gpio-amd-fch.o -obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o -obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o -obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o -obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o -obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o -obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o -obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o -obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o -obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o -obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o -obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o -obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o -obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o -obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o -obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o -obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o -obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o -obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o -obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o -obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o -obj-$(CONFIG_GPIO_EM) += gpio-em.o -obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o -obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o -obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o -obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o -obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o -obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o -obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o -obj-$(CONFIG_GPIO_GW_PLD) += gpio-gw-pld.o -obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o -obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o -obj-$(CONFIG_GPIO_ICH) += gpio-ich.o -obj-$(CONFIG_GPIO_IOP) += gpio-iop.o -obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o -obj-$(CONFIG_GPIO_IT87) += gpio-it87.o -obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o -obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o -obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o -obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o -obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o -obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o -obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o -obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o -obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o -obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o -obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o -obj-$(CONFIG_GPIO_MADERA) += gpio-madera.o -obj-$(CONFIG_GPIO_MAX3191X) += gpio-max3191x.o -obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o -obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o -obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o -obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o -obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o -obj-$(CONFIG_GPIO_MAX77650) += gpio-max77650.o -obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o -obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o -obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o -obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o -obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o -obj-$(CONFIG_GPIO_MLXBF) += gpio-mlxbf.o -obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o -obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o -obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o -obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o -obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o -obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o +obj-$(CONFIG_GPIO_104_DIO_48E) += gpio-104-dio-48e.o +obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o +obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o +obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o +obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o +obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o +obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o +obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o +obj-$(CONFIG_GPIO_ALTERA_A10SR) += gpio-altera-a10sr.o +obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o +obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o +obj-$(CONFIG_GPIO_AMD_FCH) += gpio-amd-fch.o +obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o +obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o +obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o +obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o +obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o +obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o +obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o +obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o +obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o +obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o +obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o +obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o +obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o +obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o +obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o +obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o +obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o +obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o +obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o +obj-$(CONFIG_GPIO_EM) += gpio-em.o +obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o +obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o +obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o +obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o +obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o +obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o +obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o +obj-$(CONFIG_GPIO_GW_PLD) += gpio-gw-pld.o +obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o +obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o +obj-$(CONFIG_GPIO_ICH) += gpio-ich.o +obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o +obj-$(CONFIG_GPIO_IOP) += gpio-iop.o +obj-$(CONFIG_GPIO_IT87) += gpio-it87.o +obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o +obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o +obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o +obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o +obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o +obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o +obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o +obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o +obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o +obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o +obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o +obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o +obj-$(CONFIG_GPIO_MADERA) += gpio-madera.o +obj-$(CONFIG_GPIO_MAX3191X) += gpio-max3191x.o +obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o +obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o +obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o +obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o +obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o +obj-$(CONFIG_GPIO_MAX77650) += gpio-max77650.o +obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o +obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o +obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o +obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o +obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o +obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o +obj-$(CONFIG_GPIO_MLXBF) += gpio-mlxbf.o +obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o +obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o +obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o +obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o +obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o -obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o -obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o -obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o -obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o -obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o -obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o -obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o -obj-$(CONFIG_GPIO_PCH) += gpio-pch.o -obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o -obj-$(CONFIG_GPIO_PCIE_IDIO_24) += gpio-pcie-idio-24.o -obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o -obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o +obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o +obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o +obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o +obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o +obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o +obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o +obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o +obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o +obj-$(CONFIG_GPIO_PCH) += gpio-pch.o +obj-$(CONFIG_GPIO_PCIE_IDIO_24) += gpio-pcie-idio-24.o +obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o +obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o +obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o -obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o -obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o -obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o -obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o -obj-$(CONFIG_GPIO_REG) += gpio-reg.o -obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o +obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o +obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o +obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o +obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o +obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o +obj-$(CONFIG_GPIO_REG) += gpio-reg.o +obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o -obj-$(CONFIG_GPIO_SCH) += gpio-sch.o -obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o -obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o -obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o -obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o -obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o -obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o -obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o -obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o -obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o -obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o -obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o -obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o -obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o -obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o -obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o -obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o -obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o -obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o -obj-$(CONFIG_GPIO_TPS65086) += gpio-tps65086.o -obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o -obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o -obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o -obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o -obj-$(CONFIG_GPIO_TPS68470) += gpio-tps68470.o -obj-$(CONFIG_GPIO_TQMX86) += gpio-tqmx86.o -obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o -obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o -obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o -obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o -obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o -obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o -obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o -obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o -obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o -obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o -obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o -obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o -obj-$(CONFIG_GPIO_WINBOND) += gpio-winbond.o -obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o -obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o -obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o -obj-$(CONFIG_GPIO_WS16C48) += gpio-ws16c48.o -obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o -obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o -obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o -obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o -obj-$(CONFIG_GPIO_XRA1403) += gpio-xra1403.o -obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o -obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o -obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o -obj-$(CONFIG_GPIO_ZX) += gpio-zx.o -obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o +obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o +obj-$(CONFIG_GPIO_SCH) += gpio-sch.o +obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o +obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o +obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o +obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o +obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o +obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o +obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o +obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o +obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o +obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o +obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o +obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o +obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o +obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o +obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o +obj-$(CONFIG_GPIO_TPS65086) += gpio-tps65086.o +obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o +obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o +obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o +obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o +obj-$(CONFIG_GPIO_TPS68470) += gpio-tps68470.o +obj-$(CONFIG_GPIO_TQMX86) += gpio-tqmx86.o +obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o +obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o +obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o +obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o +obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o +obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o +obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o +obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o +obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o +obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o +obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o +obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o +obj-$(CONFIG_GPIO_WINBOND) += gpio-winbond.o +obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o +obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o +obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o +obj-$(CONFIG_GPIO_WS16C48) += gpio-ws16c48.o +obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o +obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o +obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o +obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o +obj-$(CONFIG_GPIO_XRA1403) += gpio-xra1403.o +obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o +obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o +obj-$(CONFIG_GPIO_ZX) += gpio-zx.o +obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO index 19d27c904916..9c048f10c9ad 100644 --- a/drivers/gpio/TODO +++ b/drivers/gpio/TODO @@ -90,6 +90,46 @@ GPIOLIB irqchip The GPIOLIB irqchip is a helper irqchip for "simple cases" that should try to cover any generic kind of irqchip cascaded from a GPIO. +- Convert all the GPIOLIB_IRQCHIP users to pass an irqchip template, + parent and flags before calling [devm_]gpiochip_add[_data](). + Currently we set up the irqchip after setting up the gpiochip + using gpiochip_irqchip_add() and gpiochip_set_[chained|nested]_irqchip(). + This is too complex, so convert all users over to just set up + the irqchip before registering the gpio_chip, typical example: + + /* Typical state container with dynamic irqchip */ + struct my_gpio { + struct gpio_chip gc; + struct irq_chip irq; + }; + + int irq; /* from platform etc */ + struct my_gpio *g; + struct gpio_irq_chip *girq + + /* Set up the irqchip dynamically */ + g->irq.name = "my_gpio_irq"; + g->irq.irq_ack = my_gpio_ack_irq; + g->irq.irq_mask = my_gpio_mask_irq; + g->irq.irq_unmask = my_gpio_unmask_irq; + g->irq.irq_set_type = my_gpio_set_irq_type; + + /* Get a pointer to the gpio_irq_chip */ + girq = &g->gc.irq; + girq->chip = &g->irq; + girq->parent_handler = ftgpio_gpio_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + girq->parents[0] = irq; + + When this is done, we will delete the old APIs for instatiating + GPIOLIB_IRQCHIP and simplify the code. + - Look over and identify any remaining easily converted drivers and dry-code conversions to gpiolib irqchip for maintainers to test diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index 12acdac85820..b9fcaab2a931 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011-2012 Avionic Design GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/gpio/driver.h> diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index e088b908c2c1..9f2e6b04c361 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -30,6 +30,7 @@ struct altera_gpio_chip { raw_spinlock_t gpio_lock; int interrupt_trigger; int mapped_irq; + struct irq_chip irq_chip; }; static void altera_gpio_irq_unmask(struct irq_data *d) @@ -101,15 +102,6 @@ static unsigned int altera_gpio_irq_startup(struct irq_data *d) return 0; } -static struct irq_chip altera_irq_chip = { - .name = "altera-gpio", - .irq_mask = altera_gpio_irq_mask, - .irq_unmask = altera_gpio_irq_unmask, - .irq_set_type = altera_gpio_irq_set_type, - .irq_startup = altera_gpio_irq_startup, - .irq_shutdown = altera_gpio_irq_mask, -}; - static int altera_gpio_get(struct gpio_chip *gc, unsigned offset) { struct of_mm_gpio_chip *mm_gc; @@ -246,6 +238,7 @@ static int altera_gpio_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; int reg, ret; struct altera_gpio_chip *altera_gc; + struct gpio_irq_chip *girq; altera_gc = devm_kzalloc(&pdev->dev, sizeof(*altera_gc), GFP_KERNEL); if (!altera_gc) @@ -273,50 +266,50 @@ static int altera_gpio_probe(struct platform_device *pdev) altera_gc->mmchip.gc.owner = THIS_MODULE; altera_gc->mmchip.gc.parent = &pdev->dev; - ret = of_mm_gpiochip_add_data(node, &altera_gc->mmchip, altera_gc); - if (ret) { - dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n"); - return ret; - } - - platform_set_drvdata(pdev, altera_gc); - altera_gc->mapped_irq = platform_get_irq(pdev, 0); if (altera_gc->mapped_irq < 0) goto skip_irq; if (of_property_read_u32(node, "altr,interrupt-type", ®)) { - ret = -EINVAL; dev_err(&pdev->dev, "altr,interrupt-type value not set in device tree\n"); - goto teardown; + return -EINVAL; } altera_gc->interrupt_trigger = reg; - ret = gpiochip_irqchip_add(&altera_gc->mmchip.gc, &altera_irq_chip, 0, - handle_bad_irq, IRQ_TYPE_NONE); + altera_gc->irq_chip.name = "altera-gpio"; + altera_gc->irq_chip.irq_mask = altera_gpio_irq_mask; + altera_gc->irq_chip.irq_unmask = altera_gpio_irq_unmask; + altera_gc->irq_chip.irq_set_type = altera_gpio_irq_set_type; + altera_gc->irq_chip.irq_startup = altera_gpio_irq_startup; + altera_gc->irq_chip.irq_shutdown = altera_gpio_irq_mask; + + girq = &altera_gc->mmchip.gc.irq; + girq->chip = &altera_gc->irq_chip; + if (altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH) + girq->parent_handler = altera_gpio_irq_leveL_high_handler; + else + girq->parent_handler = altera_gpio_irq_edge_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, 1, sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + girq->parents[0] = altera_gc->mapped_irq; +skip_irq: + ret = of_mm_gpiochip_add_data(node, &altera_gc->mmchip, altera_gc); if (ret) { - dev_err(&pdev->dev, "could not add irqchip\n"); - goto teardown; + dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n"); + return ret; } - gpiochip_set_chained_irqchip(&altera_gc->mmchip.gc, - &altera_irq_chip, - altera_gc->mapped_irq, - altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH ? - altera_gpio_irq_leveL_high_handler : - altera_gpio_irq_edge_handler); + platform_set_drvdata(pdev, altera_gc); -skip_irq: return 0; -teardown: - of_mm_gpiochip_remove(&altera_gc->mmchip); - pr_err("%pOF: registration failed with status %d\n", - node, ret); - - return ret; } static int altera_gpio_remove(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-amd-fch.c b/drivers/gpio/gpio-amd-fch.c index 38c3f4a3d4aa..181df1581df5 100644 --- a/drivers/gpio/gpio-amd-fch.c +++ b/drivers/gpio/gpio-amd-fch.c @@ -25,14 +25,13 @@ #define AMD_FCH_GPIO_FLAG_WRITE BIT(22) #define AMD_FCH_GPIO_FLAG_READ BIT(16) -static struct resource amd_fch_gpio_iores = +static const struct resource amd_fch_gpio_iores = DEFINE_RES_MEM_NAMED( AMD_FCH_MMIO_BASE + AMD_FCH_GPIO_BANK0_BASE, AMD_FCH_GPIO_SIZE, "amd-fch-gpio-iomem"); struct amd_fch_gpio_priv { - struct platform_device *pdev; struct gpio_chip gc; void __iomem *base; struct amd_fch_gpio_pdata *pdata; @@ -153,7 +152,6 @@ static int amd_fch_gpio_probe(struct platform_device *pdev) return -ENOMEM; priv->pdata = pdata; - priv->pdev = pdev; priv->gc.owner = THIS_MODULE; priv->gc.parent = &pdev->dev; diff --git a/drivers/gpio/gpio-amdpt.c b/drivers/gpio/gpio-amdpt.c index 1ffd7c2d1285..44398992ae15 100644 --- a/drivers/gpio/gpio-amdpt.c +++ b/drivers/gpio/gpio-amdpt.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD Promontory GPIO driver * * Copyright (C) 2015 ASMedia Technology Inc. * Author: YD Tseng <yd_tseng@asmedia.com.tw> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> @@ -91,7 +88,7 @@ static int pt_gpio_probe(struct platform_device *pdev) pt_gpio->reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pt_gpio->reg_base)) { - dev_err(&pdev->dev, "Failed to map MMIO resource for PT GPIO.\n"); + dev_err(dev, "Failed to map MMIO resource for PT GPIO.\n"); return PTR_ERR(pt_gpio->reg_base); } @@ -101,7 +98,7 @@ static int pt_gpio_probe(struct platform_device *pdev) pt_gpio->reg_base + PT_DIRECTION_REG, NULL, BGPIOF_READ_OUTPUT_REG_SET); if (ret) { - dev_err(&pdev->dev, "bgpio_init failed\n"); + dev_err(dev, "bgpio_init failed\n"); return ret; } @@ -110,11 +107,11 @@ static int pt_gpio_probe(struct platform_device *pdev) pt_gpio->gc.free = pt_gpio_free; pt_gpio->gc.ngpio = PT_TOTAL_GPIO; #if defined(CONFIG_OF_GPIO) - pt_gpio->gc.of_node = pdev->dev.of_node; + pt_gpio->gc.of_node = dev->of_node; #endif ret = gpiochip_add_data(&pt_gpio->gc, pt_gpio); if (ret) { - dev_err(&pdev->dev, "Failed to register GPIO lib\n"); + dev_err(dev, "Failed to register GPIO lib\n"); return ret; } @@ -124,7 +121,7 @@ static int pt_gpio_probe(struct platform_device *pdev) writel(0, pt_gpio->reg_base + PT_SYNC_REG); writel(0, pt_gpio->reg_base + PT_CLOCKRATE_REG); - dev_dbg(&pdev->dev, "PT GPIO driver loaded\n"); + dev_dbg(dev, "PT GPIO driver loaded\n"); return ret; } diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c index 0a553d676042..f1a5ea9b3de2 100644 --- a/drivers/gpio/gpio-ath79.c +++ b/drivers/gpio/gpio-ath79.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Atheros AR71XX/AR724X/AR913X GPIO API support * @@ -5,10 +6,6 @@ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include <linux/gpio/driver.h> @@ -225,14 +222,16 @@ MODULE_DEVICE_TABLE(of, ath79_gpio_of_match); static int ath79_gpio_probe(struct platform_device *pdev) { struct ath79_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct ath79_gpio_ctrl *ctrl; + struct gpio_irq_chip *girq; struct resource *res; u32 ath79_gpio_count; bool oe_inverted; int err; - ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); + ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); if (!ctrl) return -ENOMEM; platform_set_drvdata(pdev, ctrl); @@ -240,7 +239,7 @@ static int ath79_gpio_probe(struct platform_device *pdev) if (np) { err = of_property_read_u32(np, "ngpios", &ath79_gpio_count); if (err) { - dev_err(&pdev->dev, "ngpios property is not valid\n"); + dev_err(dev, "ngpios property is not valid\n"); return err; } oe_inverted = of_device_is_compatible(np, "qca,ar9340-gpio"); @@ -248,25 +247,24 @@ static int ath79_gpio_probe(struct platform_device *pdev) ath79_gpio_count = pdata->ngpios; oe_inverted = pdata->oe_inverted; } else { - dev_err(&pdev->dev, "No DT node or platform data found\n"); + dev_err(dev, "No DT node or platform data found\n"); return -EINVAL; } if (ath79_gpio_count >= 32) { - dev_err(&pdev->dev, "ngpios must be less than 32\n"); + dev_err(dev, "ngpios must be less than 32\n"); return -EINVAL; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -EINVAL; - ctrl->base = devm_ioremap_nocache( - &pdev->dev, res->start, resource_size(res)); + ctrl->base = devm_ioremap_nocache(dev, res->start, resource_size(res)); if (!ctrl->base) return -ENOMEM; raw_spin_lock_init(&ctrl->lock); - err = bgpio_init(&ctrl->gc, &pdev->dev, 4, + err = bgpio_init(&ctrl->gc, dev, 4, ctrl->base + AR71XX_GPIO_REG_IN, ctrl->base + AR71XX_GPIO_REG_SET, ctrl->base + AR71XX_GPIO_REG_CLEAR, @@ -274,45 +272,33 @@ static int ath79_gpio_probe(struct platform_device *pdev) oe_inverted ? ctrl->base + AR71XX_GPIO_REG_OE : NULL, 0); if (err) { - dev_err(&pdev->dev, "bgpio_init failed\n"); + dev_err(dev, "bgpio_init failed\n"); return err; } /* Use base 0 to stay compatible with legacy platforms */ ctrl->gc.base = 0; - err = gpiochip_add_data(&ctrl->gc, ctrl); - if (err) { - dev_err(&pdev->dev, - "cannot add AR71xx GPIO chip, error=%d", err); - return err; + /* Optional interrupt setup */ + if (!np || of_property_read_bool(np, "interrupt-controller")) { + girq = &ctrl->gc.irq; + girq->chip = &ath79_gpio_irqchip; + girq->parent_handler = ath79_gpio_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = platform_get_irq(pdev, 0); + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; } - if (np && !of_property_read_bool(np, "interrupt-controller")) - return 0; - - err = gpiochip_irqchip_add(&ctrl->gc, &ath79_gpio_irqchip, 0, - handle_simple_irq, IRQ_TYPE_NONE); + err = devm_gpiochip_add_data(dev, &ctrl->gc, ctrl); if (err) { - dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n"); - goto gpiochip_remove; + dev_err(dev, + "cannot add AR71xx GPIO chip, error=%d", err); + return err; } - - gpiochip_set_chained_irqchip(&ctrl->gc, &ath79_gpio_irqchip, - platform_get_irq(pdev, 0), - ath79_gpio_irq_handler); - - return 0; - -gpiochip_remove: - gpiochip_remove(&ctrl->gc); - return err; -} - -static int ath79_gpio_remove(struct platform_device *pdev) -{ - struct ath79_gpio_ctrl *ctrl = platform_get_drvdata(pdev); - - gpiochip_remove(&ctrl->gc); return 0; } @@ -322,7 +308,6 @@ static struct platform_driver ath79_gpio_driver = { .of_match_table = ath79_gpio_of_match, }, .probe = ath79_gpio_probe, - .remove = ath79_gpio_remove, }; module_platform_driver(ath79_gpio_driver); diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 3bbf5804bd11..fc494a84a29d 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -297,7 +297,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) static void gpio_irq_disable(struct irq_data *d) { struct davinci_gpio_regs __iomem *g = irq2regs(d); - u32 mask = (u32) irq_data_get_irq_handler_data(d); + uintptr_t mask = (uintptr_t)irq_data_get_irq_handler_data(d); writel_relaxed(mask, &g->clr_falling); writel_relaxed(mask, &g->clr_rising); @@ -306,7 +306,7 @@ static void gpio_irq_disable(struct irq_data *d) static void gpio_irq_enable(struct irq_data *d) { struct davinci_gpio_regs __iomem *g = irq2regs(d); - u32 mask = (u32) irq_data_get_irq_handler_data(d); + uintptr_t mask = (uintptr_t)irq_data_get_irq_handler_data(d); unsigned status = irqd_get_trigger_type(d); status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING; @@ -447,7 +447,7 @@ davinci_gpio_irq_map(struct irq_domain *d, unsigned int irq, "davinci_gpio"); irq_set_irq_type(irq, IRQ_TYPE_NONE); irq_set_chip_data(irq, (__force void *)g); - irq_set_handler_data(irq, (void *)__gpio_mask(hw)); + irq_set_handler_data(irq, (void *)(uintptr_t)__gpio_mask(hw)); return 0; } @@ -632,6 +632,7 @@ done: static const struct of_device_id davinci_gpio_ids[] = { { .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip}, + { .compatible = "ti,am654-gpio", keystone_gpio_get_irq_chip}, { .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip}, { /* sentinel */ }, }; diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index d3eda65fd6d3..3108be5e208c 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011 Jamie Iles * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * All enquiries to support@picochip.com */ #include <linux/acpi.h> diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c index 77092268ee95..7b9ac4a12c20 100644 --- a/drivers/gpio/gpio-eic-sprd.c +++ b/drivers/gpio/gpio-eic-sprd.c @@ -568,7 +568,6 @@ static int sprd_eic_probe(struct platform_device *pdev) const struct sprd_eic_variant_data *pdata; struct gpio_irq_chip *irq; struct sprd_eic *sprd_eic; - struct resource *res; int ret, i; pdata = of_device_get_match_data(&pdev->dev); @@ -597,13 +596,9 @@ static int sprd_eic_probe(struct platform_device *pdev) * have one bank EIC, thus base[1] and base[2] can be * optional. */ - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (!res) - continue; - - sprd_eic->base[i] = devm_ioremap_resource(&pdev->dev, res); + sprd_eic->base[i] = devm_platform_ioremap_resource(pdev, i); if (IS_ERR(sprd_eic->base[i])) - return PTR_ERR(sprd_eic->base[i]); + continue; } sprd_eic->chip.label = sprd_eic_label_name[sprd_eic->type]; diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 84a7375cee0a..b6af705a4e5f 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -270,10 +270,8 @@ static int em_gio_probe(struct platform_device *pdev) int ret; p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); - if (!p) { - ret = -ENOMEM; - goto err0; - } + if (!p) + return -ENOMEM; p->pdev = pdev; platform_set_drvdata(pdev, p); @@ -286,30 +284,22 @@ static int em_gio_probe(struct platform_device *pdev) if (!io[0] || !io[1] || !irq[0] || !irq[1]) { dev_err(&pdev->dev, "missing IRQ or IOMEM\n"); - ret = -EINVAL; - goto err0; + return -EINVAL; } p->base0 = devm_ioremap_nocache(&pdev->dev, io[0]->start, resource_size(io[0])); - if (!p->base0) { - dev_err(&pdev->dev, "failed to remap low I/O memory\n"); - ret = -ENXIO; - goto err0; - } + if (!p->base0) + return -ENOMEM; p->base1 = devm_ioremap_nocache(&pdev->dev, io[1]->start, resource_size(io[1])); - if (!p->base1) { - dev_err(&pdev->dev, "failed to remap high I/O memory\n"); - ret = -ENXIO; - goto err0; - } + if (!p->base1) + return -ENOMEM; if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) { dev_err(&pdev->dev, "Missing ngpios OF property\n"); - ret = -EINVAL; - goto err0; + return -EINVAL; } gpio_chip = &p->gpio_chip; @@ -339,9 +329,8 @@ static int em_gio_probe(struct platform_device *pdev) p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, ngpios, 0, &em_gio_irq_domain_ops, p); if (!p->irq_domain) { - ret = -ENXIO; dev_err(&pdev->dev, "cannot initialize irq domain\n"); - goto err0; + return -ENXIO; } if (devm_request_irq(&pdev->dev, irq[0]->start, @@ -358,7 +347,7 @@ static int em_gio_probe(struct platform_device *pdev) goto err1; } - ret = gpiochip_add_data(gpio_chip, p); + ret = devm_gpiochip_add_data(&pdev->dev, gpio_chip, p); if (ret) { dev_err(&pdev->dev, "failed to add GPIO controller\n"); goto err1; @@ -368,7 +357,6 @@ static int em_gio_probe(struct platform_device *pdev) err1: irq_domain_remove(p->irq_domain); -err0: return ret; } @@ -376,8 +364,6 @@ static int em_gio_remove(struct platform_device *pdev) { struct em_gio_priv *p = platform_get_drvdata(pdev); - gpiochip_remove(&p->gpio_chip); - irq_domain_remove(p->irq_domain); return 0; } diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 71728d6e0bca..a90870a60c15 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -393,16 +393,13 @@ static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev, static int ep93xx_gpio_probe(struct platform_device *pdev) { struct ep93xx_gpio *epg; - struct resource *res; int i; - struct device *dev = &pdev->dev; - epg = devm_kzalloc(dev, sizeof(*epg), GFP_KERNEL); + epg = devm_kzalloc(&pdev->dev, sizeof(*epg), GFP_KERNEL); if (!epg) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - epg->base = devm_ioremap_resource(dev, res); + epg->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(epg->base)) return PTR_ERR(epg->base); diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c index a09d2f9ebacc..fae327d5b06e 100644 --- a/drivers/gpio/gpio-exar.c +++ b/drivers/gpio/gpio-exar.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * GPIO driver for Exar XR17V35X chip * * Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@codethink.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> #include <linux/device.h> diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c index 8ff8ce2970d9..250e71f3e688 100644 --- a/drivers/gpio/gpio-ftgpio010.c +++ b/drivers/gpio/gpio-ftgpio010.c @@ -226,6 +226,7 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ftgpio_gpio *g; + struct gpio_irq_chip *girq; int irq; int ret; @@ -277,6 +278,24 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) if (!IS_ERR(g->clk)) g->gc.set_config = ftgpio_gpio_set_config; + g->irq.name = "FTGPIO010"; + g->irq.irq_ack = ftgpio_gpio_ack_irq; + g->irq.irq_mask = ftgpio_gpio_mask_irq; + g->irq.irq_unmask = ftgpio_gpio_unmask_irq; + g->irq.irq_set_type = ftgpio_gpio_set_irq_type; + + girq = &g->gc.irq; + girq->chip = &g->irq; + girq->parent_handler = ftgpio_gpio_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + girq->parents[0] = irq; + ret = devm_gpiochip_add_data(dev, &g->gc, g); if (ret) goto dis_clk; @@ -289,22 +308,6 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) /* Clear any use of debounce */ writel(0x0, g->base + GPIO_DEBOUNCE_EN); - g->irq.name = "FTGPIO010"; - g->irq.irq_ack = ftgpio_gpio_ack_irq; - g->irq.irq_mask = ftgpio_gpio_mask_irq; - g->irq.irq_unmask = ftgpio_gpio_unmask_irq; - g->irq.irq_set_type = ftgpio_gpio_set_irq_type; - - ret = gpiochip_irqchip_add(&g->gc, &g->irq, - 0, handle_bad_irq, - IRQ_TYPE_NONE); - if (ret) { - dev_info(dev, "could not add irqchip\n"); - goto dis_clk; - } - gpiochip_set_chained_irqchip(&g->gc, &g->irq, - irq, ftgpio_gpio_irq_handler); - platform_set_drvdata(pdev, g); dev_info(dev, "FTGPIO010 @%p registered\n", g->base); diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 7df48e76baea..0937b605e134 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -329,7 +329,6 @@ static int grgpio_probe(struct platform_device *ofdev) void __iomem *regs; struct gpio_chip *gc; struct grgpio_priv *priv; - struct resource *res; int err; u32 prop; s32 *irqmap; @@ -340,8 +339,7 @@ static int grgpio_probe(struct platform_device *ofdev) if (!priv) return -ENOMEM; - res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&ofdev->dev, res); + regs = devm_platform_ioremap_resource(ofdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/drivers/gpio/gpio-ixp4xx.c b/drivers/gpio/gpio-ixp4xx.c index 4b1cf7ea858d..670c2a85a35b 100644 --- a/drivers/gpio/gpio-ixp4xx.c +++ b/drivers/gpio/gpio-ixp4xx.c @@ -205,20 +205,20 @@ static int ixp4xx_gpio_irq_domain_translate(struct irq_domain *domain, unsigned long *hwirq, unsigned int *type) { + int ret; /* We support standard DT translation */ if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) { - *hwirq = fwspec->param[0]; - *type = fwspec->param[1]; - return 0; + return irq_domain_translate_twocell(domain, fwspec, + hwirq, type); } /* This goes away when we transition to DT */ if (is_fwnode_irqchip(fwspec->fwnode)) { - if (fwspec->param_count != 2) - return -EINVAL; - *hwirq = fwspec->param[0]; - *type = fwspec->param[1]; + ret = irq_domain_translate_twocell(domain, fwspec, + hwirq, type); + if (ret) + return ret; WARN_ON(*type == IRQ_TYPE_NONE); return 0; } diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/gpio-janz-ttl.c index 6b5b5a8b9173..cdf50e4ea165 100644 --- a/drivers/gpio/gpio-janz-ttl.c +++ b/drivers/gpio/gpio-janz-ttl.c @@ -140,18 +140,17 @@ static void ttl_setup_device(struct ttl_module *mod) static int ttl_probe(struct platform_device *pdev) { struct janz_platform_data *pdata; - struct device *dev = &pdev->dev; struct ttl_module *mod; struct gpio_chip *gpio; int ret; pdata = dev_get_platdata(&pdev->dev); if (!pdata) { - dev_err(dev, "no platform data\n"); + dev_err(&pdev->dev, "no platform data\n"); return -ENXIO; } - mod = devm_kzalloc(dev, sizeof(*mod), GFP_KERNEL); + mod = devm_kzalloc(&pdev->dev, sizeof(*mod), GFP_KERNEL); if (!mod) return -ENOMEM; @@ -177,9 +176,9 @@ static int ttl_probe(struct platform_device *pdev) gpio->base = -1; gpio->ngpio = 20; - ret = devm_gpiochip_add_data(dev, gpio, NULL); + ret = devm_gpiochip_add_data(&pdev->dev, gpio, NULL); if (ret) { - dev_err(dev, "unable to add GPIO chip\n"); + dev_err(&pdev->dev, "unable to add GPIO chip\n"); return ret; } diff --git a/drivers/gpio/gpio-madera.c b/drivers/gpio/gpio-madera.c index c9dad0543672..4dbc837d1215 100644 --- a/drivers/gpio/gpio-madera.c +++ b/drivers/gpio/gpio-madera.c @@ -1,12 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GPIO support for Cirrus Logic Madera codecs * * Copyright (C) 2015-2018 Cirrus Logic - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2. */ #include <linux/gpio/driver.h> diff --git a/drivers/gpio/gpio-max3191x.c b/drivers/gpio/gpio-max3191x.c index 9a8876abeb57..4b4b2ceb82fc 100644 --- a/drivers/gpio/gpio-max3191x.c +++ b/drivers/gpio/gpio-max3191x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * gpio-max3191x.c - GPIO driver for Maxim MAX3191x industrial serializer * @@ -27,10 +28,6 @@ * https://datasheets.maximintegrated.com/en/ds/MAX31912.pdf * https://datasheets.maximintegrated.com/en/ds/MAX31913.pdf * https://datasheets.maximintegrated.com/en/ds/MAX31953-MAX31963.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (version 2) as - * published by the Free Software Foundation. */ #include <linux/bitmap.h> diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c index 1ae9ba851c9a..19cc2ed6a3f5 100644 --- a/drivers/gpio/gpio-max7300.c +++ b/drivers/gpio/gpio-max7300.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Wolfram Sang, Pengutronix * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Check max730x.c for further details. */ diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/gpio-max7301.c index 647dfbbc4e1c..1307c243b4e9 100644 --- a/drivers/gpio/gpio-max7301.c +++ b/drivers/gpio/gpio-max7301.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2006 Juergen Beisert, Pengutronix * Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix * Copyright (C) 2009 Wolfram Sang, Pengutronix * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Check max730x.c for further details. */ diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index 198a36b07773..1e1935c51096 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /** * Copyright (C) 2006 Juergen Beisert, Pengutronix * Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix * Copyright (C) 2009 Wolfram Sang, Pengutronix * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The Maxim MAX7300/1 device is an I2C/SPI driven GPIO expander. There are * 28 GPIOs. 8 of them can trigger an interrupt. See datasheet for more * details diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 5e4102e7b1f9..5fb0bcf31142 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -649,12 +649,12 @@ static int max732x_probe(struct i2c_client *client, case 0x60: chip->client_group_a = client; if (nr_port > 8) { - c = i2c_new_dummy(client->adapter, addr_b); - if (!c) { + c = devm_i2c_new_dummy_device(&client->dev, + client->adapter, addr_b); + if (IS_ERR(c)) { dev_err(&client->dev, "Failed to allocate I2C device\n"); - ret = -ENODEV; - goto out_failed; + return PTR_ERR(c); } chip->client_group_b = chip->client_dummy = c; } @@ -662,12 +662,12 @@ static int max732x_probe(struct i2c_client *client, case 0x50: chip->client_group_b = client; if (nr_port > 8) { - c = i2c_new_dummy(client->adapter, addr_a); - if (!c) { + c = devm_i2c_new_dummy_device(&client->dev, + client->adapter, addr_a); + if (IS_ERR(c)) { dev_err(&client->dev, "Failed to allocate I2C device\n"); - ret = -ENODEV; - goto out_failed; + return PTR_ERR(c); } chip->client_group_a = chip->client_dummy = c; } @@ -675,37 +675,33 @@ static int max732x_probe(struct i2c_client *client, default: dev_err(&client->dev, "invalid I2C address specified %02x\n", client->addr); - ret = -EINVAL; - goto out_failed; + return -EINVAL; } if (nr_port > 8 && !chip->client_dummy) { dev_err(&client->dev, "Failed to allocate second group I2C device\n"); - ret = -ENODEV; - goto out_failed; + return -ENODEV; } mutex_init(&chip->lock); ret = max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]); if (ret) - goto out_failed; + return ret; if (nr_port > 8) { ret = max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]); if (ret) - goto out_failed; + return ret; } - ret = gpiochip_add_data(&chip->gpio_chip, chip); + ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip); if (ret) - goto out_failed; + return ret; ret = max732x_irq_setup(chip, id); - if (ret) { - gpiochip_remove(&chip->gpio_chip); - goto out_failed; - } + if (ret) + return ret; if (pdata && pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, @@ -716,10 +712,6 @@ static int max732x_probe(struct i2c_client *client, i2c_set_clientdata(client, chip); return 0; - -out_failed: - i2c_unregister_device(chip->client_dummy); - return ret; } static int max732x_remove(struct i2c_client *client) @@ -739,11 +731,6 @@ static int max732x_remove(struct i2c_client *client) } } - gpiochip_remove(&chip->gpio_chip); - - /* unregister any dummy i2c_client */ - i2c_unregister_device(chip->client_dummy); - return 0; } diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c index 9bfff171f9fe..8f466993cd24 100644 --- a/drivers/gpio/gpio-mb86s7x.c +++ b/drivers/gpio/gpio-mb86s7x.c @@ -6,6 +6,7 @@ * Copyright (C) 2015 Linaro Ltd. */ +#include <linux/acpi.h> #include <linux/io.h> #include <linux/init.h> #include <linux/clk.h> @@ -19,6 +20,8 @@ #include <linux/spinlock.h> #include <linux/slab.h> +#include "gpiolib.h" + /* * Only first 8bits of a register correspond to each pin, * so there are 4 registers for 32 pins. @@ -135,6 +138,20 @@ static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value) spin_unlock_irqrestore(&gchip->lock, flags); } +static int mb86s70_gpio_to_irq(struct gpio_chip *gc, unsigned int offset) +{ + int irq, index; + + for (index = 0;; index++) { + irq = platform_get_irq(to_platform_device(gc->parent), index); + if (irq <= 0) + break; + if (irq_get_irq_data(irq)->hwirq == offset) + return irq; + } + return -EINVAL; +} + static int mb86s70_gpio_probe(struct platform_device *pdev) { struct mb86s70_gpio_chip *gchip; @@ -150,13 +167,15 @@ static int mb86s70_gpio_probe(struct platform_device *pdev) if (IS_ERR(gchip->base)) return PTR_ERR(gchip->base); - gchip->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(gchip->clk)) - return PTR_ERR(gchip->clk); + if (!has_acpi_companion(&pdev->dev)) { + gchip->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(gchip->clk)) + return PTR_ERR(gchip->clk); - ret = clk_prepare_enable(gchip->clk); - if (ret) - return ret; + ret = clk_prepare_enable(gchip->clk); + if (ret) + return ret; + } spin_lock_init(&gchip->lock); @@ -172,19 +191,28 @@ static int mb86s70_gpio_probe(struct platform_device *pdev) gchip->gc.parent = &pdev->dev; gchip->gc.base = -1; + if (has_acpi_companion(&pdev->dev)) + gchip->gc.to_irq = mb86s70_gpio_to_irq; + ret = gpiochip_add_data(&gchip->gc, gchip); if (ret) { dev_err(&pdev->dev, "couldn't register gpio driver\n"); clk_disable_unprepare(gchip->clk); + return ret; } - return ret; + if (has_acpi_companion(&pdev->dev)) + acpi_gpiochip_request_interrupts(&gchip->gc); + + return 0; } static int mb86s70_gpio_remove(struct platform_device *pdev) { struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev); + if (has_acpi_companion(&pdev->dev)) + acpi_gpiochip_free_interrupts(&gchip->gc); gpiochip_remove(&gchip->gc); clk_disable_unprepare(gchip->clk); @@ -197,10 +225,19 @@ static const struct of_device_id mb86s70_gpio_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids); +#ifdef CONFIG_ACPI +static const struct acpi_device_id mb86s70_gpio_acpi_ids[] = { + { "SCX0007" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(acpi, mb86s70_gpio_acpi_ids); +#endif + static struct platform_driver mb86s70_gpio_driver = { .driver = { .name = "mb86s70-gpio", .of_match_table = mb86s70_gpio_dt_ids, + .acpi_match_table = ACPI_PTR(mb86s70_gpio_acpi_ids), }, .probe = mb86s70_gpio_probe, .remove = mb86s70_gpio_remove, diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c index b0754fe69e77..f460d71b0c92 100644 --- a/drivers/gpio/gpio-mm-lantiq.c +++ b/drivers/gpio/gpio-mm-lantiq.c @@ -1,7 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. * * Copyright (C) 2012 John Crispin <john@phrozen.org> */ diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index b6a4efce7c92..f1a9c0544e3f 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -315,7 +315,6 @@ static void gpio_mockup_debugfs_setup(struct device *dev, struct gpio_mockup_chip *chip) { struct gpio_mockup_dbgfs_private *priv; - struct dentry *evfile; struct gpio_chip *gc; const char *devname; char *name; @@ -325,32 +324,25 @@ static void gpio_mockup_debugfs_setup(struct device *dev, devname = dev_name(&gc->gpiodev->dev); chip->dbg_dir = debugfs_create_dir(devname, gpio_mockup_dbg_dir); - if (IS_ERR_OR_NULL(chip->dbg_dir)) - goto err; for (i = 0; i < gc->ngpio; i++) { name = devm_kasprintf(dev, GFP_KERNEL, "%d", i); if (!name) - goto err; + return; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) - goto err; + return; priv->chip = chip; priv->offset = i; priv->desc = &gc->gpiodev->descs[i]; - evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv, - &gpio_mockup_debugfs_ops); - if (IS_ERR_OR_NULL(evfile)) - goto err; + debugfs_create_file(name, 0200, chip->dbg_dir, priv, + &gpio_mockup_debugfs_ops); } return; - -err: - dev_err(dev, "error creating debugfs files\n"); } static int gpio_mockup_name_lines(struct device *dev, @@ -447,8 +439,7 @@ static int gpio_mockup_probe(struct platform_device *pdev) if (rv) return rv; - if (!IS_ERR_OR_NULL(gpio_mockup_dbg_dir)) - gpio_mockup_debugfs_setup(dev, chip); + gpio_mockup_debugfs_setup(dev, chip); return 0; } @@ -501,8 +492,6 @@ static int __init gpio_mockup_init(void) } gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup", NULL); - if (IS_ERR_OR_NULL(gpio_mockup_dbg_dir)) - gpio_mockup_err("error creating debugfs directory\n"); err = platform_driver_register(&gpio_mockup_driver); if (err) { diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 059094ac44cb..869d47f89599 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -38,6 +38,7 @@ #include <linux/err.h> #include <linux/gpio/driver.h> #include <linux/gpio/consumer.h> +#include <linux/gpio/machine.h> #include <linux/init.h> #include <linux/io.h> #include <linux/irq.h> @@ -618,18 +619,14 @@ static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) ret = -EBUSY; } else { desc = gpiochip_request_own_desc(&mvchip->chip, - pwm->hwpwm, "mvebu-pwm", 0); + pwm->hwpwm, "mvebu-pwm", + GPIO_ACTIVE_HIGH, + GPIOD_OUT_LOW); if (IS_ERR(desc)) { ret = PTR_ERR(desc); goto out; } - ret = gpiod_direction_output(desc, 0); - if (ret) { - gpiochip_free_own_desc(desc); - goto out; - } - mvpwm->gpiod = desc; } out: diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 16289bafa001..d0f27084a942 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Support functions for OMAP GPIO * @@ -6,10 +7,6 @@ * * Copyright (C) 2009 Texas Instruments * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> @@ -47,8 +44,9 @@ struct gpio_regs { }; struct gpio_bank { - struct list_head node; void __iomem *base; + const struct omap_gpio_reg_offs *regs; + int irq; u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; @@ -75,11 +73,7 @@ struct gpio_bank { int context_loss_count; void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable); - void (*set_dataout_multiple)(struct gpio_bank *bank, - unsigned long *mask, unsigned long *bits); int (*get_context_loss_count)(struct device *dev); - - struct omap_gpio_reg_offs *regs; }; #define GPIO_MOD_CTRL_BIT BIT(0) @@ -95,20 +89,25 @@ static inline struct gpio_bank *omap_irq_data_get_bank(struct irq_data *d) return gpiochip_get_data(chip); } -static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio, - int is_input) +static inline u32 omap_gpio_rmw(void __iomem *reg, u32 mask, bool set) { - void __iomem *reg = bank->base; - u32 l; + u32 val = readl_relaxed(reg); - reg += bank->regs->direction; - l = readl_relaxed(reg); - if (is_input) - l |= BIT(gpio); + if (set) + val |= mask; else - l &= ~(BIT(gpio)); - writel_relaxed(l, reg); - bank->context.oe = l; + val &= ~mask; + + writel_relaxed(val, reg); + + return val; +} + +static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio, + int is_input) +{ + bank->context.oe = omap_gpio_rmw(bank->base + bank->regs->direction, + BIT(gpio), is_input); } @@ -134,88 +133,8 @@ static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, unsigned offset, static void omap_set_gpio_dataout_mask(struct gpio_bank *bank, unsigned offset, int enable) { - void __iomem *reg = bank->base + bank->regs->dataout; - u32 gpio_bit = BIT(offset); - u32 l; - - l = readl_relaxed(reg); - if (enable) - l |= gpio_bit; - else - l &= ~gpio_bit; - writel_relaxed(l, reg); - bank->context.dataout = l; -} - -static int omap_get_gpio_datain(struct gpio_bank *bank, int offset) -{ - void __iomem *reg = bank->base + bank->regs->datain; - - return (readl_relaxed(reg) & (BIT(offset))) != 0; -} - -static int omap_get_gpio_dataout(struct gpio_bank *bank, int offset) -{ - void __iomem *reg = bank->base + bank->regs->dataout; - - return (readl_relaxed(reg) & (BIT(offset))) != 0; -} - -/* set multiple data out values using dedicate set/clear register */ -static void omap_set_gpio_dataout_reg_multiple(struct gpio_bank *bank, - unsigned long *mask, - unsigned long *bits) -{ - void __iomem *reg = bank->base; - u32 l; - - l = *bits & *mask; - writel_relaxed(l, reg + bank->regs->set_dataout); - bank->context.dataout |= l; - - l = ~*bits & *mask; - writel_relaxed(l, reg + bank->regs->clr_dataout); - bank->context.dataout &= ~l; -} - -/* set multiple data out values using mask register */ -static void omap_set_gpio_dataout_mask_multiple(struct gpio_bank *bank, - unsigned long *mask, - unsigned long *bits) -{ - void __iomem *reg = bank->base + bank->regs->dataout; - u32 l = (readl_relaxed(reg) & ~*mask) | (*bits & *mask); - - writel_relaxed(l, reg); - bank->context.dataout = l; -} - -static unsigned long omap_get_gpio_datain_multiple(struct gpio_bank *bank, - unsigned long *mask) -{ - void __iomem *reg = bank->base + bank->regs->datain; - - return readl_relaxed(reg) & *mask; -} - -static unsigned long omap_get_gpio_dataout_multiple(struct gpio_bank *bank, - unsigned long *mask) -{ - void __iomem *reg = bank->base + bank->regs->dataout; - - return readl_relaxed(reg) & *mask; -} - -static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) -{ - int l = readl_relaxed(base + reg); - - if (set) - l |= mask; - else - l &= ~mask; - - writel_relaxed(l, base + reg); + bank->context.dataout = omap_gpio_rmw(bank->base + bank->regs->dataout, + BIT(offset), enable); } static inline void omap_gpio_dbck_enable(struct gpio_bank *bank) @@ -259,7 +178,6 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank) static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, unsigned debounce) { - void __iomem *reg; u32 val; u32 l; bool enable = !!debounce; @@ -276,19 +194,11 @@ static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, l = BIT(offset); clk_enable(bank->dbck); - reg = bank->base + bank->regs->debounce; - writel_relaxed(debounce, reg); + writel_relaxed(debounce, bank->base + bank->regs->debounce); - reg = bank->base + bank->regs->debounce_en; - val = readl_relaxed(reg); - - if (enable) - val |= l; - else - val &= ~l; + val = omap_gpio_rmw(bank->base + bank->regs->debounce_en, l, enable); bank->dbck_enable_mask = val; - writel_relaxed(val, reg); clk_disable(bank->dbck); /* * Enable debounce clock per module. @@ -363,9 +273,9 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio, void __iomem *base = bank->base; u32 gpio_bit = BIT(gpio); - omap_gpio_rmw(base, bank->regs->leveldetect0, gpio_bit, + omap_gpio_rmw(base + bank->regs->leveldetect0, gpio_bit, trigger & IRQ_TYPE_LEVEL_LOW); - omap_gpio_rmw(base, bank->regs->leveldetect1, gpio_bit, + omap_gpio_rmw(base + bank->regs->leveldetect1, gpio_bit, trigger & IRQ_TYPE_LEVEL_HIGH); /* @@ -373,9 +283,9 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio, * to be woken from idle state. Set the appropriate edge detection * in addition to the level detection. */ - omap_gpio_rmw(base, bank->regs->risingdetect, gpio_bit, + omap_gpio_rmw(base + bank->regs->risingdetect, gpio_bit, trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH)); - omap_gpio_rmw(base, bank->regs->fallingdetect, gpio_bit, + omap_gpio_rmw(base + bank->regs->fallingdetect, gpio_bit, trigger & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)); bank->context.leveldetect0 = @@ -387,11 +297,8 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio, bank->context.fallingdetect = readl_relaxed(bank->base + bank->regs->fallingdetect); - if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { - omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0); - bank->context.wake_en = - readl_relaxed(bank->base + bank->regs->wkup_en); - } + bank->level_mask = bank->context.leveldetect0 | + bank->context.leveldetect1; /* This part needs to be executed always for OMAP{34xx, 44xx} */ if (!bank->regs->irqctrl && !omap_gpio_is_off_wakeup_capable(bank, gpio)) { @@ -406,44 +313,25 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio, else bank->enabled_non_wakeup_gpios &= ~gpio_bit; } - - bank->level_mask = - readl_relaxed(bank->base + bank->regs->leveldetect0) | - readl_relaxed(bank->base + bank->regs->leveldetect1); } -#ifdef CONFIG_ARCH_OMAP1 /* * This only applies to chips that can't do both rising and falling edge * detection at once. For all other chips, this function is a noop. */ static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) { - void __iomem *reg = bank->base; - u32 l = 0; - - if (!bank->regs->irqctrl) - return; + if (IS_ENABLED(CONFIG_ARCH_OMAP1) && bank->regs->irqctrl) { + void __iomem *reg = bank->base + bank->regs->irqctrl; - reg += bank->regs->irqctrl; - - l = readl_relaxed(reg); - if ((l >> gpio) & 1) - l &= ~(BIT(gpio)); - else - l |= BIT(gpio); - - writel_relaxed(l, reg); + writel_relaxed(readl_relaxed(reg) ^ BIT(gpio), reg); + } } -#else -static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {} -#endif static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio, unsigned trigger) { void __iomem *reg = bank->base; - void __iomem *base = bank->base; u32 l = 0; if (bank->regs->leveldetect0 && bank->regs->wkup_en) { @@ -475,11 +363,6 @@ static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio, l |= 2 << (gpio << 1); if (trigger & IRQ_TYPE_EDGE_FALLING) l |= BIT(gpio << 1); - - /* Enable wake-up during idle for dynamic tick */ - omap_gpio_rmw(base, bank->regs->wkup_en, BIT(gpio), trigger); - bank->context.wake_en = - readl_relaxed(bank->base + bank->regs->wkup_en); writel_relaxed(l, reg); } return 0; @@ -508,17 +391,6 @@ static void omap_enable_gpio_module(struct gpio_bank *bank, unsigned offset) static void omap_disable_gpio_module(struct gpio_bank *bank, unsigned offset) { - void __iomem *base = bank->base; - - if (bank->regs->wkup_en && - !LINE_USED(bank->mod_usage, offset) && - !LINE_USED(bank->irq_usage, offset)) { - /* Disable wake-up during idle for dynamic tick */ - omap_gpio_rmw(base, bank->regs->wkup_en, BIT(offset), 0); - bank->context.wake_en = - readl_relaxed(bank->base + bank->regs->wkup_en); - } - if (bank->regs->ctrl && !BANK_USED(bank)) { void __iomem *reg = bank->base + bank->regs->ctrl; u32 ctrl; @@ -629,57 +501,39 @@ static u32 omap_get_gpio_irqbank_mask(struct gpio_bank *bank) return l; } -static void omap_enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) +static inline void omap_set_gpio_irqenable(struct gpio_bank *bank, + unsigned offset, int enable) { void __iomem *reg = bank->base; - u32 l; + u32 gpio_mask = BIT(offset); - if (bank->regs->set_irqenable) { - reg += bank->regs->set_irqenable; - l = gpio_mask; - bank->context.irqenable1 |= gpio_mask; + if (bank->regs->set_irqenable && bank->regs->clr_irqenable) { + if (enable) { + reg += bank->regs->set_irqenable; + bank->context.irqenable1 |= gpio_mask; + } else { + reg += bank->regs->clr_irqenable; + bank->context.irqenable1 &= ~gpio_mask; + } + writel_relaxed(gpio_mask, reg); } else { - reg += bank->regs->irqenable; - l = readl_relaxed(reg); - if (bank->regs->irqenable_inv) - l &= ~gpio_mask; - else - l |= gpio_mask; - bank->context.irqenable1 = l; + bank->context.irqenable1 = + omap_gpio_rmw(reg + bank->regs->irqenable, gpio_mask, + enable ^ bank->regs->irqenable_inv); } - writel_relaxed(l, reg); -} - -static void omap_disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) -{ - void __iomem *reg = bank->base; - u32 l; - - if (bank->regs->clr_irqenable) { - reg += bank->regs->clr_irqenable; - l = gpio_mask; - bank->context.irqenable1 &= ~gpio_mask; - } else { - reg += bank->regs->irqenable; - l = readl_relaxed(reg); - if (bank->regs->irqenable_inv) - l |= gpio_mask; - else - l &= ~gpio_mask; - bank->context.irqenable1 = l; + /* + * Program GPIO wakeup along with IRQ enable to satisfy OMAP4430 TRM + * note requiring correlation between the IRQ enable registers and + * the wakeup registers. In any case, we want wakeup from idle + * enabled for the GPIOs which support this feature. + */ + if (bank->regs->wkup_en && + (bank->regs->edgectrl1 || !(bank->non_wakeup_gpios & gpio_mask))) { + bank->context.wake_en = + omap_gpio_rmw(bank->base + bank->regs->wkup_en, + gpio_mask, enable); } - - writel_relaxed(l, reg); -} - -static inline void omap_set_gpio_irqenable(struct gpio_bank *bank, - unsigned offset, int enable) -{ - if (enable) - omap_enable_gpio_irqbank(bank, BIT(offset)); - else - omap_disable_gpio_irqbank(bank, BIT(offset)); } /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ @@ -690,38 +544,6 @@ static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable) return irq_set_irq_wake(bank->irq, enable); } -static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - struct gpio_bank *bank = gpiochip_get_data(chip); - unsigned long flags; - - pm_runtime_get_sync(chip->parent); - - raw_spin_lock_irqsave(&bank->lock, flags); - omap_enable_gpio_module(bank, offset); - bank->mod_usage |= BIT(offset); - raw_spin_unlock_irqrestore(&bank->lock, flags); - - return 0; -} - -static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) -{ - struct gpio_bank *bank = gpiochip_get_data(chip); - unsigned long flags; - - raw_spin_lock_irqsave(&bank->lock, flags); - bank->mod_usage &= ~(BIT(offset)); - if (!LINE_USED(bank->irq_usage, offset)) { - omap_set_gpio_direction(bank, offset, 1); - omap_clear_gpio_debounce(bank, offset); - } - omap_disable_gpio_module(bank, offset); - raw_spin_unlock_irqrestore(&bank->lock, flags); - - pm_runtime_put(chip->parent); -} - /* * We need to unmask the GPIO bank interrupt as soon as possible to * avoid missing GPIO interrupts for other lines in the bank. @@ -734,7 +556,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank) { void __iomem *isr_reg = NULL; - u32 enabled, isr, level_mask; + u32 enabled, isr, edge; unsigned int bit; struct gpio_bank *bank = gpiobank; unsigned long wa_lock_flags; @@ -754,16 +576,14 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank) enabled = omap_get_gpio_irqbank_mask(bank); isr = readl_relaxed(isr_reg) & enabled; - if (bank->level_mask) - level_mask = bank->level_mask & enabled; - else - level_mask = 0; - - /* clear edge sensitive interrupts before handler(s) are - called so that we don't miss any interrupt occurred while - executing them */ - if (isr & ~level_mask) - omap_clear_gpio_irqbank(bank, isr & ~level_mask); + /* + * Clear edge sensitive interrupts before calling handler(s) + * so subsequent edge transitions are not missed while the + * handlers are running. + */ + edge = isr & ~bank->level_mask; + if (edge) + omap_clear_gpio_irqbank(bank, edge); raw_spin_unlock_irqrestore(&bank->lock, lock_flags); @@ -810,8 +630,6 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d) if (!LINE_USED(bank->mod_usage, offset)) omap_set_gpio_direction(bank, offset, 1); - else if (!omap_gpio_is_input(bank, offset)) - goto err; omap_enable_gpio_module(bank, offset); bank->irq_usage |= BIT(offset); @@ -819,9 +637,6 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d) omap_gpio_unmask_irq(d); return 0; -err: - raw_spin_unlock_irqrestore(&bank->lock, flags); - return -EINVAL; } static void omap_gpio_irq_shutdown(struct irq_data *d) @@ -832,9 +647,9 @@ static void omap_gpio_irq_shutdown(struct irq_data *d) raw_spin_lock_irqsave(&bank->lock, flags); bank->irq_usage &= ~(BIT(offset)); - omap_set_gpio_irqenable(bank, offset, 0); - omap_clear_gpio_irqstatus(bank, offset); omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); + omap_clear_gpio_irqstatus(bank, offset); + omap_set_gpio_irqenable(bank, offset, 0); if (!LINE_USED(bank->mod_usage, offset)) omap_clear_gpio_debounce(bank, offset); omap_disable_gpio_module(bank, offset); @@ -855,14 +670,6 @@ static void gpio_irq_bus_sync_unlock(struct irq_data *data) pm_runtime_put(bank->chip.parent); } -static void omap_gpio_ack_irq(struct irq_data *d) -{ - struct gpio_bank *bank = omap_irq_data_get_bank(d); - unsigned offset = d->hwirq; - - omap_clear_gpio_irqstatus(bank, offset); -} - static void omap_gpio_mask_irq(struct irq_data *d) { struct gpio_bank *bank = omap_irq_data_get_bank(d); @@ -870,8 +677,8 @@ static void omap_gpio_mask_irq(struct irq_data *d) unsigned long flags; raw_spin_lock_irqsave(&bank->lock, flags); - omap_set_gpio_irqenable(bank, offset, 0); omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); + omap_set_gpio_irqenable(bank, offset, 0); raw_spin_unlock_irqrestore(&bank->lock, flags); } @@ -883,9 +690,6 @@ static void omap_gpio_unmask_irq(struct irq_data *d) unsigned long flags; raw_spin_lock_irqsave(&bank->lock, flags); - if (trigger) - omap_set_gpio_triggering(bank, offset, trigger); - omap_set_gpio_irqenable(bank, offset, 1); /* @@ -893,9 +697,13 @@ static void omap_gpio_unmask_irq(struct irq_data *d) * is cleared, thus after the handler has run. OMAP4 needs this done * after enabing the interrupt to clear the wakeup status. */ - if (bank->level_mask & BIT(offset)) + if (bank->regs->leveldetect0 && bank->regs->wkup_en && + trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) omap_clear_gpio_irqstatus(bank, offset); + if (trigger) + omap_set_gpio_triggering(bank, offset, trigger); + raw_spin_unlock_irqrestore(&bank->lock, flags); } @@ -961,19 +769,44 @@ static inline void omap_mpuio_init(struct gpio_bank *bank) /*---------------------------------------------------------------------*/ -static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) { - struct gpio_bank *bank; + struct gpio_bank *bank = gpiochip_get_data(chip); + unsigned long flags; + + pm_runtime_get_sync(chip->parent); + + raw_spin_lock_irqsave(&bank->lock, flags); + omap_enable_gpio_module(bank, offset); + bank->mod_usage |= BIT(offset); + raw_spin_unlock_irqrestore(&bank->lock, flags); + + return 0; +} + +static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_bank *bank = gpiochip_get_data(chip); unsigned long flags; - void __iomem *reg; - int dir; - bank = gpiochip_get_data(chip); - reg = bank->base + bank->regs->direction; raw_spin_lock_irqsave(&bank->lock, flags); - dir = !!(readl_relaxed(reg) & BIT(offset)); + bank->mod_usage &= ~(BIT(offset)); + if (!LINE_USED(bank->irq_usage, offset)) { + omap_set_gpio_direction(bank, offset, 1); + omap_clear_gpio_debounce(bank, offset); + } + omap_disable_gpio_module(bank, offset); raw_spin_unlock_irqrestore(&bank->lock, flags); - return dir; + + pm_runtime_put(chip->parent); +} + +static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_bank *bank = gpiochip_get_data(chip); + + return !!(readl_relaxed(bank->base + bank->regs->direction) & + BIT(offset)); } static int omap_gpio_input(struct gpio_chip *chip, unsigned offset) @@ -990,14 +823,15 @@ static int omap_gpio_input(struct gpio_chip *chip, unsigned offset) static int omap_gpio_get(struct gpio_chip *chip, unsigned offset) { - struct gpio_bank *bank; - - bank = gpiochip_get_data(chip); + struct gpio_bank *bank = gpiochip_get_data(chip); + void __iomem *reg; if (omap_gpio_is_input(bank, offset)) - return omap_get_gpio_datain(bank, offset); + reg = bank->base + bank->regs->datain; else - return omap_get_gpio_dataout(bank, offset); + reg = bank->base + bank->regs->dataout; + + return (readl_relaxed(reg) & BIT(offset)) != 0; } static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value) @@ -1017,18 +851,20 @@ static int omap_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits) { struct gpio_bank *bank = gpiochip_get_data(chip); - void __iomem *reg = bank->base + bank->regs->direction; - unsigned long in = readl_relaxed(reg), l; + void __iomem *base = bank->base; + u32 direction, m, val = 0; - *bits = 0; + direction = readl_relaxed(base + bank->regs->direction); - l = in & *mask; - if (l) - *bits |= omap_get_gpio_datain_multiple(bank, &l); + m = direction & *mask; + if (m) + val |= readl_relaxed(base + bank->regs->datain) & m; - l = ~in & *mask; - if (l) - *bits |= omap_get_gpio_dataout_multiple(bank, &l); + m = ~direction & *mask; + if (m) + val |= readl_relaxed(base + bank->regs->dataout) & m; + + *bits = val; return 0; } @@ -1081,10 +917,14 @@ static void omap_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits) { struct gpio_bank *bank = gpiochip_get_data(chip); + void __iomem *reg = bank->base + bank->regs->dataout; unsigned long flags; + u32 l; raw_spin_lock_irqsave(&bank->lock, flags); - bank->set_dataout_multiple(bank, mask, bits); + l = (readl_relaxed(reg) & ~*mask) | (*bits & *mask); + writel_relaxed(l, reg); + bank->context.dataout = l; raw_spin_unlock_irqrestore(&bank->lock, flags); } @@ -1118,9 +958,9 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) return; } - omap_gpio_rmw(base, bank->regs->irqenable, l, + omap_gpio_rmw(base + bank->regs->irqenable, l, bank->regs->irqenable_inv); - omap_gpio_rmw(base, bank->regs->irqstatus, l, + omap_gpio_rmw(base + bank->regs->irqstatus, l, !bank->regs->irqenable_inv); if (bank->regs->debounce_en) writel_relaxed(0, base + bank->regs->debounce_en); @@ -1183,11 +1023,8 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) #endif /* MPUIO is a bit different, reading IRQ status clears it */ - if (bank->is_mpuio) { - irqc->irq_ack = dummy_irq_chip.irq_ack; - if (!bank->regs->wkup_en) - irqc->irq_set_wake = NULL; - } + if (bank->is_mpuio && !bank->regs->wkup_en) + irqc->irq_set_wake = NULL; irq = &bank->chip.irq; irq->chip = irqc; @@ -1218,7 +1055,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) static void omap_gpio_init_context(struct gpio_bank *p) { - struct omap_gpio_reg_offs *regs = p->regs; + const struct omap_gpio_reg_offs *regs = p->regs; void __iomem *base = p->base; p->context.ctrl = readl_relaxed(base + regs->ctrl); @@ -1230,60 +1067,56 @@ static void omap_gpio_init_context(struct gpio_bank *p) p->context.fallingdetect = readl_relaxed(base + regs->fallingdetect); p->context.irqenable1 = readl_relaxed(base + regs->irqenable); p->context.irqenable2 = readl_relaxed(base + regs->irqenable2); - - if (regs->set_dataout && p->regs->clr_dataout) - p->context.dataout = readl_relaxed(base + regs->set_dataout); - else - p->context.dataout = readl_relaxed(base + regs->dataout); + p->context.dataout = readl_relaxed(base + regs->dataout); p->context_valid = true; } static void omap_gpio_restore_context(struct gpio_bank *bank) { - writel_relaxed(bank->context.wake_en, - bank->base + bank->regs->wkup_en); - writel_relaxed(bank->context.ctrl, bank->base + bank->regs->ctrl); - writel_relaxed(bank->context.leveldetect0, - bank->base + bank->regs->leveldetect0); - writel_relaxed(bank->context.leveldetect1, - bank->base + bank->regs->leveldetect1); - writel_relaxed(bank->context.risingdetect, - bank->base + bank->regs->risingdetect); - writel_relaxed(bank->context.fallingdetect, - bank->base + bank->regs->fallingdetect); - if (bank->regs->set_dataout && bank->regs->clr_dataout) - writel_relaxed(bank->context.dataout, - bank->base + bank->regs->set_dataout); - else - writel_relaxed(bank->context.dataout, - bank->base + bank->regs->dataout); - writel_relaxed(bank->context.oe, bank->base + bank->regs->direction); + const struct omap_gpio_reg_offs *regs = bank->regs; + void __iomem *base = bank->base; + + writel_relaxed(bank->context.wake_en, base + regs->wkup_en); + writel_relaxed(bank->context.ctrl, base + regs->ctrl); + writel_relaxed(bank->context.leveldetect0, base + regs->leveldetect0); + writel_relaxed(bank->context.leveldetect1, base + regs->leveldetect1); + writel_relaxed(bank->context.risingdetect, base + regs->risingdetect); + writel_relaxed(bank->context.fallingdetect, base + regs->fallingdetect); + writel_relaxed(bank->context.dataout, base + regs->dataout); + writel_relaxed(bank->context.oe, base + regs->direction); if (bank->dbck_enable_mask) { - writel_relaxed(bank->context.debounce, bank->base + - bank->regs->debounce); + writel_relaxed(bank->context.debounce, base + regs->debounce); writel_relaxed(bank->context.debounce_en, - bank->base + bank->regs->debounce_en); + base + regs->debounce_en); } - writel_relaxed(bank->context.irqenable1, - bank->base + bank->regs->irqenable); - writel_relaxed(bank->context.irqenable2, - bank->base + bank->regs->irqenable2); + writel_relaxed(bank->context.irqenable1, base + regs->irqenable); + writel_relaxed(bank->context.irqenable2, base + regs->irqenable2); } static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context) { struct device *dev = bank->chip.parent; void __iomem *base = bank->base; - u32 nowake; + u32 mask, nowake; bank->saved_datain = readl_relaxed(base + bank->regs->datain); if (!bank->enabled_non_wakeup_gpios) goto update_gpio_context_count; + /* Check for pending EDGE_FALLING, ignore EDGE_BOTH */ + mask = bank->enabled_non_wakeup_gpios & bank->context.fallingdetect; + mask &= ~bank->context.risingdetect; + bank->saved_datain |= mask; + + /* Check for pending EDGE_RISING, ignore EDGE_BOTH */ + mask = bank->enabled_non_wakeup_gpios & bank->context.risingdetect; + mask &= ~bank->context.fallingdetect; + bank->saved_datain &= ~mask; + if (!may_lose_context) goto update_gpio_context_count; @@ -1294,8 +1127,8 @@ static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context) */ if (!bank->loses_context && bank->enabled_non_wakeup_gpios) { nowake = bank->enabled_non_wakeup_gpios; - omap_gpio_rmw(base, bank->regs->fallingdetect, nowake, ~nowake); - omap_gpio_rmw(base, bank->regs->risingdetect, nowake, ~nowake); + omap_gpio_rmw(base + bank->regs->fallingdetect, nowake, ~nowake); + omap_gpio_rmw(base + bank->regs->risingdetect, nowake, ~nowake); } update_gpio_context_count: @@ -1424,7 +1257,7 @@ static int gpio_omap_cpu_notifier(struct notifier_block *nb, return NOTIFY_OK; } -static struct omap_gpio_reg_offs omap2_gpio_regs = { +static const struct omap_gpio_reg_offs omap2_gpio_regs = { .revision = OMAP24XX_GPIO_REVISION, .direction = OMAP24XX_GPIO_OE, .datain = OMAP24XX_GPIO_DATAIN, @@ -1447,7 +1280,7 @@ static struct omap_gpio_reg_offs omap2_gpio_regs = { .fallingdetect = OMAP24XX_GPIO_FALLINGDETECT, }; -static struct omap_gpio_reg_offs omap4_gpio_regs = { +static const struct omap_gpio_reg_offs omap4_gpio_regs = { .revision = OMAP4_GPIO_REVISION, .direction = OMAP4_GPIO_OE, .datain = OMAP4_GPIO_DATAIN, @@ -1456,6 +1289,8 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = { .clr_dataout = OMAP4_GPIO_CLEARDATAOUT, .irqstatus = OMAP4_GPIO_IRQSTATUS0, .irqstatus2 = OMAP4_GPIO_IRQSTATUS1, + .irqstatus_raw0 = OMAP4_GPIO_IRQSTATUSRAW0, + .irqstatus_raw1 = OMAP4_GPIO_IRQSTATUSRAW1, .irqenable = OMAP4_GPIO_IRQSTATUSSET0, .irqenable2 = OMAP4_GPIO_IRQSTATUSSET1, .set_irqenable = OMAP4_GPIO_IRQSTATUSSET0, @@ -1531,7 +1366,7 @@ static int omap_gpio_probe(struct platform_device *pdev) irqc->irq_startup = omap_gpio_irq_startup, irqc->irq_shutdown = omap_gpio_irq_shutdown, - irqc->irq_ack = omap_gpio_ack_irq, + irqc->irq_ack = dummy_irq_chip.irq_ack, irqc->irq_mask = omap_gpio_mask_irq, irqc->irq_unmask = omap_gpio_unmask_irq, irqc->irq_set_type = omap_gpio_irq_type, @@ -1575,14 +1410,10 @@ static int omap_gpio_probe(struct platform_device *pdev) pdata->get_context_loss_count; } - if (bank->regs->set_dataout && bank->regs->clr_dataout) { + if (bank->regs->set_dataout && bank->regs->clr_dataout) bank->set_dataout = omap_set_gpio_dataout_reg; - bank->set_dataout_multiple = omap_set_gpio_dataout_reg_multiple; - } else { + else bank->set_dataout = omap_set_gpio_dataout_mask; - bank->set_dataout_multiple = - omap_set_gpio_dataout_mask_multiple; - } raw_spin_lock_init(&bank->lock); raw_spin_lock_init(&bank->wa_lock); @@ -1638,7 +1469,6 @@ static int omap_gpio_remove(struct platform_device *pdev) struct gpio_bank *bank = platform_get_drvdata(pdev); cpu_pm_unregister_notifier(&bank->nb); - list_del(&bank->node); gpiochip_remove(&bank->chip); pm_runtime_disable(&pdev->dev); if (bank->dbck_flag) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index cfe827cefad8..378b206d2dc9 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -1178,6 +1178,7 @@ static const struct of_device_id pca953x_dt_ids[] = { { .compatible = "ti,tca6408", .data = OF_953X( 8, PCA_INT), }, { .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), }, { .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), }, + { .compatible = "ti,tca9539", .data = OF_953X(16, PCA_INT), }, { .compatible = "onnn,cat9554", .data = OF_953X( 8, PCA_INT), }, { .compatible = "onnn,pca9654", .data = OF_953X( 8, PCA_INT), }, diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index dc42571e6fdc..722ce5cf861e 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2008, 2009 Provigent Ltd. * * Author: Baruch Siach <baruch@tkos.co.il> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Driver for the ARM PrimeCell(tm) General Purpose Input/Output (PL061) * * Data sheet: ARM DDI 0190B, September 2000 @@ -286,6 +283,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; struct pl061 *pl061; + struct gpio_irq_chip *girq; int ret, irq; pl061 = devm_kzalloc(dev, sizeof(*pl061), GFP_KERNEL); @@ -313,10 +311,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) pl061->gc.parent = dev; pl061->gc.owner = THIS_MODULE; - ret = gpiochip_add_data(&pl061->gc, pl061); - if (ret) - return ret; - /* * irq_chip support */ @@ -335,19 +329,24 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) } pl061->parent_irq = irq; - ret = gpiochip_irqchip_add(&pl061->gc, &pl061->irq_chip, - 0, handle_bad_irq, - IRQ_TYPE_NONE); - if (ret) { - dev_info(&adev->dev, "could not add irqchip\n"); + girq = &pl061->gc.irq; + girq->chip = &pl061->irq_chip; + girq->parent_handler = pl061_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = irq; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + + ret = devm_gpiochip_add_data(dev, &pl061->gc, pl061); + if (ret) return ret; - } - gpiochip_set_chained_irqchip(&pl061->gc, &pl061->irq_chip, - irq, pl061_irq_handler); amba_set_drvdata(adev, pl061); - dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n", - &adev->res.start); + dev_info(dev, "PL061 GPIO chip registered\n"); return 0; } diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 26f77fdb217e..9888b62f37af 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/arch/arm/plat-pxa/gpio.c * @@ -6,10 +7,6 @@ * Author: Nicolas Pitre * Created: Jun 15, 2001 * Copyright: MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/clk.h> diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 70e95fc4779f..187984d26f47 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -489,7 +489,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) irq_chip->irq_unmask = gpio_rcar_irq_enable; irq_chip->irq_set_type = gpio_rcar_irq_set_type; irq_chip->irq_set_wake = gpio_rcar_irq_set_wake; - irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; + irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; ret = gpiochip_add_data(gpio_chip, p); if (ret) { diff --git a/drivers/gpio/gpio-reg.c b/drivers/gpio/gpio-reg.c index e85903eddc68..fdc7a9d5b382 100644 --- a/drivers/gpio/gpio-reg.c +++ b/drivers/gpio/gpio-reg.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * gpio-reg: single register individually fixed-direction GPIOs * * Copyright (C) 2016 Russell King - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. */ #include <linux/gpio/driver.h> #include <linux/gpio/gpio-reg.h> diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index 986eb3b231ac..46b7cf23fb0f 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/arch/arm/mach-sa1100/gpio.c * * Generic SA-1100 GPIO handling - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/gpio/driver.h> #include <linux/init.h> diff --git a/drivers/gpio/gpio-siox.c b/drivers/gpio/gpio-siox.c index 571b2a81c6de..006a7e6a75f2 100644 --- a/drivers/gpio/gpio-siox.c +++ b/drivers/gpio/gpio-siox.c @@ -211,20 +211,22 @@ static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset) static int gpio_siox_probe(struct siox_device *sdevice) { struct gpio_siox_ddata *ddata; + struct gpio_irq_chip *girq; + struct device *dev = &sdevice->dev; int ret; - ddata = devm_kzalloc(&sdevice->dev, sizeof(*ddata), GFP_KERNEL); + ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); if (!ddata) return -ENOMEM; - dev_set_drvdata(&sdevice->dev, ddata); + dev_set_drvdata(dev, ddata); mutex_init(&ddata->lock); spin_lock_init(&ddata->irqlock); ddata->gchip.base = -1; ddata->gchip.can_sleep = 1; - ddata->gchip.parent = &sdevice->dev; + ddata->gchip.parent = dev; ddata->gchip.owner = THIS_MODULE; ddata->gchip.get = gpio_siox_get; ddata->gchip.set = gpio_siox_set; @@ -239,54 +241,27 @@ static int gpio_siox_probe(struct siox_device *sdevice) ddata->ichip.irq_unmask = gpio_siox_irq_unmask; ddata->ichip.irq_set_type = gpio_siox_irq_set_type; - ret = gpiochip_add(&ddata->gchip); - if (ret) { - dev_err(&sdevice->dev, - "Failed to register gpio chip (%d)\n", ret); - goto err_gpiochip; - } + girq = &ddata->gchip.irq; + girq->chip = &ddata->ichip; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_level_irq; - ret = gpiochip_irqchip_add(&ddata->gchip, &ddata->ichip, - 0, handle_level_irq, IRQ_TYPE_EDGE_RISING); - if (ret) { - dev_err(&sdevice->dev, - "Failed to register irq chip (%d)\n", ret); -err_gpiochip: - gpiochip_remove(&ddata->gchip); - } + ret = devm_gpiochip_add_data(dev, &ddata->gchip, NULL); + if (ret) + dev_err(dev, "Failed to register gpio chip (%d)\n", ret); return ret; } -static int gpio_siox_remove(struct siox_device *sdevice) -{ - struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev); - - gpiochip_remove(&ddata->gchip); - return 0; -} - static struct siox_driver gpio_siox_driver = { .probe = gpio_siox_probe, - .remove = gpio_siox_remove, .set_data = gpio_siox_set_data, .get_data = gpio_siox_get_data, .driver = { .name = "gpio-siox", }, }; - -static int __init gpio_siox_init(void) -{ - return siox_driver_register(&gpio_siox_driver); -} -module_init(gpio_siox_init); - -static void __exit gpio_siox_exit(void) -{ - siox_driver_unregister(&gpio_siox_driver); -} -module_exit(gpio_siox_exit); +module_siox_driver(gpio_siox_driver); MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); MODULE_DESCRIPTION("SIOX gpio driver"); diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 65a2315f1673..dbf9cbe36b2b 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) ST-Ericsson SA 2010 * - * License Terms: GNU General Public License, version 2 * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson */ diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c index 8a319d56c5de..9e23a5ae8108 100644 --- a/drivers/gpio/gpio-stp-xway.c +++ b/drivers/gpio/gpio-stp-xway.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. * * Copyright (C) 2012 John Crispin <john@phrozen.org> - * */ #include <linux/slab.h> @@ -18,8 +15,6 @@ #include <linux/clk.h> #include <linux/err.h> -#include <lantiq_soc.h> - /* * The Serial To Parallel (STP) is found on MIPS based Lantiq socs. It is a * peripheral controller used to drive external shift register cascades. At most @@ -74,8 +69,7 @@ #define xway_stp_r32(m, reg) __raw_readl(m + reg) #define xway_stp_w32(m, val, reg) __raw_writel(val, m + reg) #define xway_stp_w32_mask(m, clear, set, reg) \ - ltq_w32((ltq_r32(m + reg) & ~(clear)) | (set), \ - m + reg) + xway_stp_w32(m, (xway_stp_r32(m, reg) & ~(clear)) | (set), reg) struct xway_stp { struct gpio_chip gc; @@ -159,9 +153,9 @@ static int xway_stp_request(struct gpio_chip *gc, unsigned gpio) /** * xway_stp_hw_init() - Configure the STP unit and enable the clock gate - * @virt: pointer to the remapped register range + * @chip: Pointer to the xway_stp chip structure */ -static int xway_stp_hw_init(struct xway_stp *chip) +static void xway_stp_hw_init(struct xway_stp *chip) { /* sane defaults */ xway_stp_w32(chip->virt, 0, XWAY_STP_AR); @@ -204,8 +198,6 @@ static int xway_stp_hw_init(struct xway_stp *chip) if (chip->reserved) xway_stp_w32_mask(chip->virt, XWAY_STP_UPD_MASK, XWAY_STP_UPD_FPI, XWAY_STP_CON1); - - return 0; } static int xway_stp_probe(struct platform_device *pdev) @@ -261,21 +253,27 @@ static int xway_stp_probe(struct platform_device *pdev) if (!of_find_property(pdev->dev.of_node, "lantiq,rising", NULL)) chip->edge = XWAY_STP_FALLING; - clk = clk_get(&pdev->dev, NULL); + clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Failed to get clock\n"); return PTR_ERR(clk); } - clk_enable(clk); - ret = xway_stp_hw_init(chip); - if (!ret) - ret = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip); + ret = clk_prepare_enable(clk); + if (ret) + return ret; - if (!ret) - dev_info(&pdev->dev, "Init done\n"); + xway_stp_hw_init(chip); - return ret; + ret = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip); + if (ret) { + clk_disable_unprepare(clk); + return ret; + } + + dev_info(&pdev->dev, "Init done\n"); + + return 0; } static const struct of_device_id xway_stp_match[] = { diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 91a8ef8e7f3f..75b1135b383a 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) ST-Ericsson SA 2010 * - * License Terms: GNU General Public License, version 2 * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson */ diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index f57bfc07ae22..0f59161a4701 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -541,8 +541,8 @@ DEFINE_SHOW_ATTRIBUTE(tegra_dbg_gpio); static void tegra_gpio_debuginit(struct tegra_gpio_info *tgi) { - (void) debugfs_create_file("tegra_gpio", 0444, - NULL, tgi, &tegra_dbg_gpio_fops); + debugfs_create_file("tegra_gpio", 0444, NULL, tgi, + &tegra_dbg_gpio_fops); } #else diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 7d42e3d7572c..a9058fda187e 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2017 NVIDIA Corporation * * Author: Thierry Reding <treding@nvidia.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. */ #include <linux/gpio/driver.h> diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c index 5dbe31bf6699..d2a8644864c3 100644 --- a/drivers/gpio/gpio-ucb1400.c +++ b/drivers/gpio/gpio-ucb1400.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Philips UCB1400 GPIO driver * * Author: Marek Vasut <marek.vasut@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 30aef41e3b7e..7ba668db171b 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -265,7 +265,8 @@ static int vf610_gpio_probe(struct platform_device *pdev) return port->irq; port->clk_port = devm_clk_get(dev, "port"); - if (!IS_ERR(port->clk_port)) { + ret = PTR_ERR_OR_ZERO(port->clk_port); + if (!ret) { ret = clk_prepare_enable(port->clk_port); if (ret) return ret; @@ -273,16 +274,17 @@ static int vf610_gpio_probe(struct platform_device *pdev) port->clk_port); if (ret) return ret; - } else if (port->clk_port == ERR_PTR(-EPROBE_DEFER)) { + } else if (ret == -EPROBE_DEFER) { /* * Percolate deferrals, for anything else, * just live without the clocking. */ - return PTR_ERR(port->clk_port); + return ret; } port->clk_gpio = devm_clk_get(dev, "gpio"); - if (!IS_ERR(port->clk_gpio)) { + ret = PTR_ERR_OR_ZERO(port->clk_gpio); + if (!ret) { ret = clk_prepare_enable(port->clk_gpio); if (ret) return ret; @@ -290,8 +292,8 @@ static int vf610_gpio_probe(struct platform_device *pdev) port->clk_gpio); if (ret) return ret; - } else if (port->clk_gpio == ERR_PTR(-EPROBE_DEFER)) { - return PTR_ERR(port->clk_gpio); + } else if (ret == -EPROBE_DEFER) { + return ret; } gc = &port->gc; diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c index b13a49c89cc1..98cd715ccc33 100644 --- a/drivers/gpio/gpio-vr41xx.c +++ b/drivers/gpio/gpio-vr41xx.c @@ -467,10 +467,9 @@ static struct gpio_chip vr41xx_gpio_chip = { static int giu_probe(struct platform_device *pdev) { - struct resource *res; unsigned int trigger, i, pin; struct irq_chip *chip; - int irq, ret; + int irq; switch (pdev->id) { case GPIO_50PINS_PULLUPDOWN: @@ -489,21 +488,14 @@ static int giu_probe(struct platform_device *pdev) return -ENODEV; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EBUSY; - - giu_base = ioremap(res->start, resource_size(res)); - if (!giu_base) - return -ENOMEM; + giu_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(giu_base)) + return PTR_ERR(giu_base); vr41xx_gpio_chip.parent = &pdev->dev; - ret = gpiochip_add_data(&vr41xx_gpio_chip, NULL); - if (!ret) { - iounmap(giu_base); + if (gpiochip_add_data(&vr41xx_gpio_chip, NULL)) return -ENODEV; - } giu_write(GIUINTENL, 0); giu_write(GIUINTENH, 0); @@ -534,7 +526,6 @@ static int giu_probe(struct platform_device *pdev) static int giu_remove(struct platform_device *pdev) { if (giu_base) { - iounmap(giu_base); giu_base = NULL; } diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c index f1c6ec17b90a..2918363884de 100644 --- a/drivers/gpio/gpio-xgene.c +++ b/drivers/gpio/gpio-xgene.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppliedMicro X-Gene SoC GPIO Driver * * Copyright (c) 2014, Applied Micro Circuits Corporation * Author: Feng Kan <fkan@apm.com>. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/acpi.h> diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 32944eb886c1..a9748b5198e6 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -11,7 +11,6 @@ #include <linux/module.h> #include <linux/of_device.h> #include <linux/of_platform.h> -#include <linux/of_gpio.h> #include <linux/io.h> #include <linux/gpio/driver.h> #include <linux/slab.h> @@ -33,14 +32,16 @@ /** * struct xgpio_instance - Stores information about GPIO device - * @mmchip: OF GPIO chip for memory mapped banks + * @gc: GPIO chip + * @regs: register block * @gpio_width: GPIO width for every channel * @gpio_state: GPIO state shadow register * @gpio_dir: GPIO direction shadow register * @gpio_lock: Lock used for synchronization */ struct xgpio_instance { - struct of_mm_gpio_chip mmchip; + struct gpio_chip gc; + void __iomem *regs; unsigned int gpio_width[2]; u32 gpio_state[2]; u32 gpio_dir[2]; @@ -84,11 +85,10 @@ static inline int xgpio_offset(struct xgpio_instance *chip, int gpio) */ static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) { - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = gpiochip_get_data(gc); u32 val; - val = xgpio_readreg(mm_gc->regs + XGPIO_DATA_OFFSET + + val = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET + xgpio_regoffset(chip, gpio)); return !!(val & BIT(xgpio_offset(chip, gpio))); @@ -106,7 +106,6 @@ static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { unsigned long flags; - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = gpiochip_get_data(gc); int index = xgpio_index(chip, gpio); int offset = xgpio_offset(chip, gpio); @@ -119,7 +118,7 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) else chip->gpio_state[index] &= ~BIT(offset); - xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + + xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + xgpio_regoffset(chip, gpio), chip->gpio_state[index]); spin_unlock_irqrestore(&chip->gpio_lock[index], flags); @@ -138,7 +137,6 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, unsigned long *bits) { unsigned long flags; - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = gpiochip_get_data(gc); int index = xgpio_index(chip, 0); int offset, i; @@ -150,7 +148,7 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, if (*mask == 0) break; if (index != xgpio_index(chip, i)) { - xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + + xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + xgpio_regoffset(chip, i), chip->gpio_state[index]); spin_unlock_irqrestore(&chip->gpio_lock[index], flags); @@ -166,7 +164,7 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, } } - xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + + xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + xgpio_regoffset(chip, i), chip->gpio_state[index]); spin_unlock_irqrestore(&chip->gpio_lock[index], flags); @@ -184,7 +182,6 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { unsigned long flags; - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = gpiochip_get_data(gc); int index = xgpio_index(chip, gpio); int offset = xgpio_offset(chip, gpio); @@ -193,7 +190,7 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) /* Set the GPIO bit in shadow register and set direction as input */ chip->gpio_dir[index] |= BIT(offset); - xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + + xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET + xgpio_regoffset(chip, gpio), chip->gpio_dir[index]); spin_unlock_irqrestore(&chip->gpio_lock[index], flags); @@ -216,7 +213,6 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { unsigned long flags; - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = gpiochip_get_data(gc); int index = xgpio_index(chip, gpio); int offset = xgpio_offset(chip, gpio); @@ -228,12 +224,12 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) chip->gpio_state[index] |= BIT(offset); else chip->gpio_state[index] &= ~BIT(offset); - xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + + xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + xgpio_regoffset(chip, gpio), chip->gpio_state[index]); /* Clear the GPIO bit in shadow register and set direction as output */ chip->gpio_dir[index] &= ~BIT(offset); - xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + + xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET + xgpio_regoffset(chip, gpio), chip->gpio_dir[index]); spin_unlock_irqrestore(&chip->gpio_lock[index], flags); @@ -243,43 +239,23 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) /** * xgpio_save_regs - Set initial values of GPIO pins - * @mm_gc: Pointer to memory mapped GPIO chip structure + * @chip: Pointer to GPIO instance */ -static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) +static void xgpio_save_regs(struct xgpio_instance *chip) { - struct xgpio_instance *chip = - container_of(mm_gc, struct xgpio_instance, mmchip); - - xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]); - xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]); + xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]); + xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]); if (!chip->gpio_width[1]) return; - xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET, + xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET, chip->gpio_state[1]); - xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET, + xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET, chip->gpio_dir[1]); } /** - * xgpio_remove - Remove method for the GPIO device. - * @pdev: pointer to the platform device - * - * This function remove gpiochips and frees all the allocated resources. - * - * Return: 0 always - */ -static int xgpio_remove(struct platform_device *pdev) -{ - struct xgpio_instance *chip = platform_get_drvdata(pdev); - - of_mm_gpiochip_remove(&chip->mmchip); - - return 0; -} - -/** * xgpio_of_probe - Probe method for the GPIO device. * @pdev: pointer to the platform device * @@ -340,21 +316,28 @@ static int xgpio_probe(struct platform_device *pdev) spin_lock_init(&chip->gpio_lock[1]); } - chip->mmchip.gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1]; - chip->mmchip.gc.parent = &pdev->dev; - chip->mmchip.gc.direction_input = xgpio_dir_in; - chip->mmchip.gc.direction_output = xgpio_dir_out; - chip->mmchip.gc.get = xgpio_get; - chip->mmchip.gc.set = xgpio_set; - chip->mmchip.gc.set_multiple = xgpio_set_multiple; + chip->gc.base = -1; + chip->gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1]; + chip->gc.parent = &pdev->dev; + chip->gc.direction_input = xgpio_dir_in; + chip->gc.direction_output = xgpio_dir_out; + chip->gc.get = xgpio_get; + chip->gc.set = xgpio_set; + chip->gc.set_multiple = xgpio_set_multiple; + + chip->gc.label = dev_name(&pdev->dev); + + chip->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(chip->regs)) { + dev_err(&pdev->dev, "failed to ioremap memory resource\n"); + return PTR_ERR(chip->regs); + } - chip->mmchip.save_regs = xgpio_save_regs; + xgpio_save_regs(chip); - /* Call the OF gpio helper to setup and register the GPIO device */ - status = of_mm_gpiochip_add_data(np, &chip->mmchip, chip); + status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip); if (status) { - pr_err("%pOF: error in probe function with status %d\n", - np, status); + dev_err(&pdev->dev, "failed to add GPIO chip\n"); return status; } @@ -370,7 +353,6 @@ MODULE_DEVICE_TABLE(of, xgpio_of_match); static struct platform_driver xgpio_plat_driver = { .probe = xgpio_probe, - .remove = xgpio_remove, .driver = { .name = "gpio-xilinx", .of_match_table = xgpio_of_match, diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c index 57432397e5e5..f6f8a541348f 100644 --- a/drivers/gpio/gpio-zevio.c +++ b/drivers/gpio/gpio-zevio.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * GPIO controller in LSI ZEVIO SoCs. * * Author: Fabian Vogt <fabian@ritter-vogt.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/spinlock.h> diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c index fb927559aefa..8637adb6bc20 100644 --- a/drivers/gpio/gpio-zx.c +++ b/drivers/gpio/gpio-zx.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ZTE ZX296702 GPIO driver * * Author: Jun Nie <jun.nie@linaro.org> * * Copyright (C) 2015 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> #include <linux/device.h> diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index c9fc9e232aaf..39f2f9035c11 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -217,14 +217,13 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares, if (!handler) return AE_OK; - desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event", 0); + desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event", + GPIO_ACTIVE_HIGH, GPIOD_IN); if (IS_ERR(desc)) { dev_err(chip->parent, "Failed to request GPIO\n"); return AE_ERROR; } - gpiod_direction_input(desc); - ret = gpiochip_lock_as_irq(chip, pin); if (ret) { dev_err(chip->parent, "Failed to lock GPIO as interrupt\n"); @@ -951,6 +950,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, const char *label = "ACPI:OpRegion"; desc = gpiochip_request_own_desc(chip, pin, label, + GPIO_ACTIVE_HIGH, flags); if (IS_ERR(desc)) { status = AE_ERROR; diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index aec7bd86ae7e..f974075ff00e 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -118,8 +118,15 @@ static void of_gpio_flags_quirks(struct device_node *np, * Legacy handling of SPI active high chip select. If we have a * property named "cs-gpios" we need to inspect the child node * to determine if the flags should have inverted semantics. + * + * This does not apply to an SPI device named "spi-gpio", because + * these have traditionally obtained their own GPIOs by parsing + * the device tree directly and did not respect any "spi-cs-high" + * property on the SPI bus children. */ - if (IS_ENABLED(CONFIG_SPI_MASTER) && !strcmp(propname, "cs-gpios") && + if (IS_ENABLED(CONFIG_SPI_MASTER) && + !strcmp(propname, "cs-gpios") && + !of_device_is_compatible(np, "spi-gpio") && of_property_read_bool(np, "cs-gpios")) { struct device_node *child; u32 cs; @@ -158,6 +165,12 @@ static void of_gpio_flags_quirks(struct device_node *np, } } } + + /* Legacy handling of stmmac's active-low PHY reset line */ + if (IS_ENABLED(CONFIG_STMMAC_ETH) && + !strcmp(propname, "snps,reset-gpio") && + of_property_read_bool(np, "snps,reset-active-low")) + *flags |= OF_GPIO_ACTIVE_LOW; } /** @@ -255,6 +268,37 @@ static struct gpio_desc *of_find_spi_gpio(struct device *dev, const char *con_id } /* + * The old Freescale bindings use simply "gpios" as name for the chip select + * lines rather than "cs-gpios" like all other SPI hardware. Account for this + * with a special quirk. + */ +static struct gpio_desc *of_find_spi_cs_gpio(struct device *dev, + const char *con_id, + unsigned int idx, + unsigned long *flags) +{ + struct device_node *np = dev->of_node; + + if (!IS_ENABLED(CONFIG_SPI_MASTER)) + return ERR_PTR(-ENOENT); + + /* Allow this specifically for Freescale devices */ + if (!of_device_is_compatible(np, "fsl,spi") && + !of_device_is_compatible(np, "aeroflexgaisler,spictrl")) + return ERR_PTR(-ENOENT); + /* Allow only if asking for "cs-gpios" */ + if (!con_id || strcmp(con_id, "cs")) + return ERR_PTR(-ENOENT); + + /* + * While all other SPI controllers use "cs-gpios" the Freescale + * uses just "gpios" so translate to that when "cs-gpios" is + * requested. + */ + return of_find_gpio(dev, NULL, idx, flags); +} + +/* * Some regulator bindings happened before we managed to establish that GPIO * properties should be named "foo-gpios" so we have this special kludge for * them. @@ -325,6 +369,12 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, /* Special handling for SPI GPIOs if used */ if (IS_ERR(desc)) desc = of_find_spi_gpio(dev, con_id, &of_flags); + if (IS_ERR(desc)) { + /* This quirk looks up flags and all */ + desc = of_find_spi_cs_gpio(dev, con_id, idx, flags); + if (!IS_ERR(desc)) + return desc; + } /* Special handling for regulator GPIOs if used */ if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e013d417a936..3ee99d070608 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1644,39 +1644,47 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid); /** * gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip - * @gpiochip: the gpiochip to set the irqchip chain to + * @gc: the gpiochip to set the irqchip chain to * @parent_irq: the irq number corresponding to the parent IRQ for this * chained irqchip * @parent_handler: the parent interrupt handler for the accumulated IRQ * coming out of the gpiochip. If the interrupt is nested rather than * cascaded, pass NULL in this handler argument */ -static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip, +static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gc, unsigned int parent_irq, irq_flow_handler_t parent_handler) { - if (!gpiochip->irq.domain) { - chip_err(gpiochip, "called %s before setting up irqchip\n", + struct gpio_irq_chip *girq = &gc->irq; + struct device *dev = &gc->gpiodev->dev; + + if (!girq->domain) { + chip_err(gc, "called %s before setting up irqchip\n", __func__); return; } if (parent_handler) { - if (gpiochip->can_sleep) { - chip_err(gpiochip, + if (gc->can_sleep) { + chip_err(gc, "you cannot have chained interrupts on a chip that may sleep\n"); return; } + girq->parents = devm_kcalloc(dev, 1, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) { + chip_err(gc, "out of memory allocating parent IRQ\n"); + return; + } + girq->parents[0] = parent_irq; + girq->num_parents = 1; /* * The parent irqchip is already using the chip_data for this * irqchip, so our callbacks simply use the handler_data. */ irq_set_chained_handler_and_data(parent_irq, parent_handler, - gpiochip); - - gpiochip->irq.parent_irq = parent_irq; - gpiochip->irq.parents = &gpiochip->irq.parent_irq; - gpiochip->irq.num_parents = 1; + gc); } } @@ -2503,7 +2511,11 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); * @chip: GPIO chip * @hwnum: hardware number of the GPIO for which to request the descriptor * @label: label for the GPIO - * @flags: flags for this GPIO or 0 if default + * @lflags: lookup flags for this GPIO or 0 if default, this can be used to + * specify things like line inversion semantics with the machine flags + * such as GPIO_OUT_LOW + * @dflags: descriptor request flags for this GPIO or 0 if default, this + * can be used to specify consumer semantics such as open drain * * Function allows GPIO chip drivers to request and use their own GPIO * descriptors via gpiolib API. Difference to gpiod_request() is that this @@ -2517,9 +2529,9 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); */ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum, const char *label, - enum gpiod_flags flags) + enum gpio_lookup_flags lflags, + enum gpiod_flags dflags) { - unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT; struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum); int err; @@ -2532,7 +2544,7 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum, if (err < 0) return ERR_PTR(err); - err = gpiod_configure_flags(desc, label, lflags, flags); + err = gpiod_configure_flags(desc, label, lflags, dflags); if (err) { chip_err(chip, "setup of own GPIO %s failed\n", label); gpiod_free_commit(desc); @@ -3019,13 +3031,13 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, * Return the GPIO's raw value, i.e. the value of the physical line disregarding * its ACTIVE_LOW status, or negative errno on failure. * - * This function should be called from contexts where we cannot sleep, and will + * This function can be called from contexts where we cannot sleep, and will * complain if the GPIO chip functions potentially sleep. */ int gpiod_get_raw_value(const struct gpio_desc *desc) { VALIDATE_DESC(desc); - /* Should be using gpio_get_value_cansleep() */ + /* Should be using gpiod_get_raw_value_cansleep() */ WARN_ON(desc->gdev->chip->can_sleep); return gpiod_get_raw_value_commit(desc); } @@ -3038,7 +3050,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_value); * Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into * account, or negative errno on failure. * - * This function should be called from contexts where we cannot sleep, and will + * This function can be called from contexts where we cannot sleep, and will * complain if the GPIO chip functions potentially sleep. */ int gpiod_get_value(const struct gpio_desc *desc) @@ -3046,7 +3058,7 @@ int gpiod_get_value(const struct gpio_desc *desc) int value; VALIDATE_DESC(desc); - /* Should be using gpio_get_value_cansleep() */ + /* Should be using gpiod_get_value_cansleep() */ WARN_ON(desc->gdev->chip->can_sleep); value = gpiod_get_raw_value_commit(desc); @@ -3071,7 +3083,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); * without regard for their ACTIVE_LOW status. Return 0 in case of success, * else an error code. * - * This function should be called from contexts where we cannot sleep, + * This function can be called from contexts where we cannot sleep, * and it will complain if the GPIO chip functions potentially sleep. */ int gpiod_get_raw_array_value(unsigned int array_size, @@ -3097,7 +3109,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value); * Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status * into account. Return 0 in case of success, else an error code. * - * This function should be called from contexts where we cannot sleep, + * This function can be called from contexts where we cannot sleep, * and it will complain if the GPIO chip functions potentially sleep. */ int gpiod_get_array_value(unsigned int array_size, @@ -3311,13 +3323,13 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, * Set the raw value of the GPIO, i.e. the value of its physical line without * regard for its ACTIVE_LOW status. * - * This function should be called from contexts where we cannot sleep, and will + * This function can be called from contexts where we cannot sleep, and will * complain if the GPIO chip functions potentially sleep. */ void gpiod_set_raw_value(struct gpio_desc *desc, int value) { VALIDATE_DESC_VOID(desc); - /* Should be using gpiod_set_value_cansleep() */ + /* Should be using gpiod_set_raw_value_cansleep() */ WARN_ON(desc->gdev->chip->can_sleep); gpiod_set_raw_value_commit(desc, value); } @@ -3352,12 +3364,13 @@ static void gpiod_set_value_nocheck(struct gpio_desc *desc, int value) * Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW, * OPEN_DRAIN and OPEN_SOURCE flags into account. * - * This function should be called from contexts where we cannot sleep, and will + * This function can be called from contexts where we cannot sleep, and will * complain if the GPIO chip functions potentially sleep. */ void gpiod_set_value(struct gpio_desc *desc, int value) { VALIDATE_DESC_VOID(desc); + /* Should be using gpiod_set_value_cansleep() */ WARN_ON(desc->gdev->chip->can_sleep); gpiod_set_value_nocheck(desc, value); } @@ -3373,7 +3386,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_value); * Set the raw values of the GPIOs, i.e. the values of the physical lines * without regard for their ACTIVE_LOW status. * - * This function should be called from contexts where we cannot sleep, and will + * This function can be called from contexts where we cannot sleep, and will * complain if the GPIO chip functions potentially sleep. */ int gpiod_set_raw_array_value(unsigned int array_size, @@ -3398,7 +3411,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value); * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status * into account. * - * This function should be called from contexts where we cannot sleep, and will + * This function can be called from contexts where we cannot sleep, and will * complain if the GPIO chip functions potentially sleep. */ int gpiod_set_array_value(unsigned int array_size, @@ -4244,8 +4257,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_index); * * Returns: * On successful request the GPIO pin is configured in accordance with - * provided @dflags. If the node does not have the requested GPIO - * property, NULL is returned. + * provided @dflags. * * In case of error an ERR_PTR() is returned. */ @@ -4267,9 +4279,6 @@ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, index, &flags); if (!desc || IS_ERR(desc)) { - /* If it is not there, just return NULL */ - if (PTR_ERR(desc) == -ENOENT) - return NULL; return desc; } @@ -4420,15 +4429,8 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, chip = gpiod_to_chip(desc); hwnum = gpio_chip_hwgpio(desc); - /* - * FIXME: not very elegant that we call gpiod_configure_flags() - * twice here (once inside gpiochip_request_own_desc() and - * again here), but the gpiochip_request_own_desc() is external - * and cannot really pass the lflags so this is the lesser evil - * at the moment. Pass zero as dflags on this first call so we - * don't screw anything up. - */ - local_desc = gpiochip_request_own_desc(chip, hwnum, name, 0); + local_desc = gpiochip_request_own_desc(chip, hwnum, name, + lflags, dflags); if (IS_ERR(local_desc)) { status = PTR_ERR(local_desc); pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %d\n", @@ -4436,14 +4438,6 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, return status; } - status = gpiod_configure_flags(desc, name, lflags, dflags); - if (status < 0) { - pr_err("setup of hog GPIO %s (chip %s, offset %d) failed, %d\n", - name, chip->label, hwnum, status); - gpiochip_free_own_desc(desc); - return status; - } - /* Mark GPIO as hogged so it can be identified and removed later */ set_bit(FLAG_IS_HOGGED, &desc->flags); @@ -4805,8 +4799,8 @@ static const struct file_operations gpiolib_operations = { static int __init gpiolib_debugfs_init(void) { /* /sys/kernel/debug/gpio */ - (void) debugfs_create_file("gpio", S_IFREG | S_IRUGO, - NULL, NULL, &gpiolib_operations); + debugfs_create_file("gpio", S_IFREG | S_IRUGO, NULL, NULL, + &gpiolib_operations); return 0; } subsys_initcall(gpiolib_debugfs_init); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 7a65dad43932..7c52c2442173 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -210,7 +210,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, struct gpio_array *array_info, unsigned long *value_bitmap); -extern struct spinlock gpio_lock; +extern spinlock_t gpio_lock; extern struct list_head gpio_devices; struct gpio_desc { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index b610e3b30d95..2f18c64d531f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -1959,25 +1959,6 @@ static void gfx_v9_0_constants_init(struct amdgpu_device *adev) mutex_unlock(&adev->srbm_mutex); gfx_v9_0_init_compute_vmid(adev); - - mutex_lock(&adev->grbm_idx_mutex); - /* - * making sure that the following register writes will be broadcasted - * to all the shaders - */ - gfx_v9_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff); - - WREG32_SOC15(GC, 0, mmPA_SC_FIFO_SIZE, - (adev->gfx.config.sc_prim_fifo_size_frontend << - PA_SC_FIFO_SIZE__SC_FRONTEND_PRIM_FIFO_SIZE__SHIFT) | - (adev->gfx.config.sc_prim_fifo_size_backend << - PA_SC_FIFO_SIZE__SC_BACKEND_PRIM_FIFO_SIZE__SHIFT) | - (adev->gfx.config.sc_hiz_tile_fifo_size << - PA_SC_FIFO_SIZE__SC_HIZ_TILE_FIFO_SIZE__SHIFT) | - (adev->gfx.config.sc_earlyz_tile_fifo_size << - PA_SC_FIFO_SIZE__SC_EARLYZ_TILE_FIFO_SIZE__SHIFT)); - mutex_unlock(&adev->grbm_idx_mutex); - } static void gfx_v9_0_wait_for_rlc_serdes(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 083bd8114db1..dd6b4b0b5f30 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -837,7 +837,7 @@ static int kfd_ioctl_get_clock_counters(struct file *filep, /* No access to rdtsc. Using raw monotonic time */ args->cpu_clock_counter = ktime_get_raw_ns(); - args->system_clock_counter = ktime_get_boot_ns(); + args->system_clock_counter = ktime_get_boottime_ns(); /* Since the counter is in nano-seconds we use 1GHz frequency */ args->system_clock_freq = 1000000000; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index f1d326caf69e..a7e8340baf90 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -326,7 +326,7 @@ int hwmgr_resume(struct pp_hwmgr *hwmgr) if (ret) return ret; - ret = psm_adjust_power_state_dynamic(hwmgr, true, NULL); + ret = psm_adjust_power_state_dynamic(hwmgr, false, NULL); return ret; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c index ae64ff7153d6..1cd5a8b5cdc1 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c @@ -916,8 +916,10 @@ static int init_thermal_controller( PHM_PlatformCaps_ThermalController ); - if (0 == powerplay_table->usFanTableOffset) + if (0 == powerplay_table->usFanTableOffset) { + hwmgr->thermal_controller.use_hw_fan_control = 1; return 0; + } fan_table = (const PPTable_Generic_SubTable_Header *) (((unsigned long)powerplay_table) + diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index c92999aac07c..eccb26fddbd0 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -694,6 +694,7 @@ struct pp_thermal_controller_info { uint8_t ucType; uint8_t ucI2cLine; uint8_t ucI2cAddress; + uint8_t use_hw_fan_control; struct pp_fan_info fanInfo; struct pp_advance_fan_control_parameters advanceFanControlParameters; }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c index 2d4cfe14f72e..29e641c6a5db 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c @@ -2092,6 +2092,10 @@ static int polaris10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) return 0; } + /* use hardware fan control */ + if (hwmgr->thermal_controller.use_hw_fan_control) + return 0; + tmp64 = hwmgr->thermal_controller.advanceFanControlParameters. usPWMMin * duty100; do_div(tmp64, 10000); diff --git a/drivers/gpu/drm/armada/armada_510.c b/drivers/gpu/drm/armada/armada_510.c index 0e91d27921bd..dd5b5cc9a0d4 100644 --- a/drivers/gpu/drm/armada/armada_510.c +++ b/drivers/gpu/drm/armada/armada_510.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Armada 510 (aka Dove) variant support */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index ba4a3fab7745..5d77e51e3181 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Russell King * Rewritten from the dovefb driver, and Armada510 manuals. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> #include <linux/component.h> diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 08761ff01739..86e1ad30ee40 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef ARMADA_CRTC_H #define ARMADA_CRTC_H diff --git a/drivers/gpu/drm/armada/armada_debugfs.c b/drivers/gpu/drm/armada/armada_debugfs.c index 6758c3a83de2..4784e5d99d53 100644 --- a/drivers/gpu/drm/armada/armada_debugfs.c +++ b/drivers/gpu/drm/armada/armada_debugfs.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Russell King * Rewritten from the dovefb driver, and Armada510 manuals. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/ctype.h> #include <linux/debugfs.h> diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index f09083ff15d3..3e60cec4e4b0 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef ARMADA_DRM_H #define ARMADA_DRM_H diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index e660c5ca52ae..4a6e8ed05925 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> #include <linux/component.h> diff --git a/drivers/gpu/drm/armada/armada_fb.c b/drivers/gpu/drm/armada/armada_fb.c index 058ac7d9920f..2029d5f3c0a2 100644 --- a/drivers/gpu/drm/armada/armada_fb.c +++ b/drivers/gpu/drm/armada/armada_fb.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <drm/drm_modeset_helper.h> #include <drm/drm_fb_helper.h> diff --git a/drivers/gpu/drm/armada/armada_fb.h b/drivers/gpu/drm/armada/armada_fb.h index 476daad0a36a..7dda5f2a0af4 100644 --- a/drivers/gpu/drm/armada/armada_fb.h +++ b/drivers/gpu/drm/armada/armada_fb.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef ARMADA_FB_H #define ARMADA_FB_H diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c index 1e7140f005a5..096aff530b01 100644 --- a/drivers/gpu/drm/armada/armada_fbdev.c +++ b/drivers/gpu/drm/armada/armada_fbdev.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Russell King * Written from the i915 driver. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/errno.h> #include <linux/kernel.h> diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c index 642d0e70d0f8..874b2968a866 100644 --- a/drivers/gpu/drm/armada/armada_gem.c +++ b/drivers/gpu/drm/armada/armada_gem.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/dma-buf.h> #include <linux/dma-mapping.h> diff --git a/drivers/gpu/drm/armada/armada_gem.h b/drivers/gpu/drm/armada/armada_gem.h index 1ac90792b166..1dd80540b8ce 100644 --- a/drivers/gpu/drm/armada/armada_gem.h +++ b/drivers/gpu/drm/armada/armada_gem.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef ARMADA_GEM_H #define ARMADA_GEM_H diff --git a/drivers/gpu/drm/armada/armada_hw.h b/drivers/gpu/drm/armada/armada_hw.h index 277580b36758..85b998e8ac7a 100644 --- a/drivers/gpu/drm/armada/armada_hw.h +++ b/drivers/gpu/drm/armada/armada_hw.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Russell King * Rewritten from the dovefb driver, and Armada510 manuals. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef ARMADA_HW_H #define ARMADA_HW_H diff --git a/drivers/gpu/drm/armada/armada_ioctlP.h b/drivers/gpu/drm/armada/armada_ioctlP.h index bd8c4562066c..c266a01d697c 100644 --- a/drivers/gpu/drm/armada/armada_ioctlP.h +++ b/drivers/gpu/drm/armada/armada_ioctlP.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef ARMADA_IOCTLP_H #define ARMADA_IOCTLP_H diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 8d770641fcc4..7857d86a6736 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Russell King * Rewritten from the dovefb driver, and Armada510 manuals. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <drm/drmP.h> #include <drm/drm_atomic.h> diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index 9f36423dd394..09d9400edd7b 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Russell King * Rewritten from the dovefb driver, and Armada510 manuals. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <drm/drmP.h> #include <drm/drm_atomic.h> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index 8070a558d7b1..a128400593a9 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Traphandler * Copyright (C) 2014 Free Electrons * * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com> * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 0be13eceedba..93b485105906 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Traphandler * Copyright (C) 2014 Free Electrons @@ -5,18 +6,6 @@ * * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com> * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h index 70bd540d644e..afa1fd047f74 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2014 Traphandler * Copyright (C) 2014 Free Electrons @@ -5,18 +6,6 @@ * * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com> * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef DRM_ATMEL_HLCDC_H diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c index f73d8a92274e..7e08318b262e 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Traphandler * Copyright (C) 2014 Free Electrons @@ -5,18 +6,6 @@ * * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com> * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/of_graph.h> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index e836e2de35ce..6f18b23c4a28 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Free Electrons * Copyright (C) 2014 Atmel * * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "atmel_hlcdc_dc.h" diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h index 0cf27c731727..e284ee8da58b 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Register definition file for Analogix DP core driver * * Copyright (C) 2012 Samsung Electronics Co., Ltd. * Author: Jingoo Han <jg1.han@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _ANALOGIX_DP_REG_H diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index 0cc293a6ac24..bd3165ee5354 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Silicon Image SiI8620 HDMI/MHL bridge driver * * Copyright (C) 2015, Samsung Electronics Co., Ltd. * Andrzej Hajda <a.hajda@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <asm/unaligned.h> diff --git a/drivers/gpu/drm/bridge/sil-sii8620.h b/drivers/gpu/drm/bridge/sil-sii8620.h index 51ab540cf092..79d61caf383f 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.h +++ b/drivers/gpu/drm/bridge/sil-sii8620.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Registers of Silicon Image SiI8620 Mobile HD Transmitter * @@ -6,10 +7,6 @@ * * Based on MHL driver for Android devices. * Copyright (C) 2013-2014 Silicon Image, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __SIL_SII8620_H__ diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c index ed7af7518b52..a494186ae6ce 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * DesignWare HDMI audio driver * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Written and tested against the Designware HDMI Tx found in iMX6. */ #include <linux/io.h> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c index 6c323510f128..0f949978d3fc 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Designware HDMI CEC driver * * Copyright (C) 2015-2017 Russell King. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/interrupt.h> #include <linux/io.h> diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index 8b0e71bd3ca7..a879aac21246 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Texas Instruments * Author: Jyri Sarha <jsarha@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * */ #include <linux/delay.h> diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index bfc419ed9d6c..ceca79b1468d 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -1340,7 +1340,10 @@ static int copy_one_buf(void *data, int count, struct drm_buf_entry *from) .size = from->buf_size, .low_mark = from->low_mark, .high_mark = from->high_mark}; - return copy_to_user(to, &v, offsetof(struct drm_buf_desc, flags)); + + if (copy_to_user(to, &v, offsetof(struct drm_buf_desc, flags))) + return -EFAULT; + return 0; } int drm_legacy_infobufs(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index 374b372da58a..3972ebe48463 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -375,7 +375,10 @@ static int copy_one_buf32(void *data, int count, struct drm_buf_entry *from) .size = from->buf_size, .low_mark = from->low_mark, .high_mark = from->high_mark}; - return copy_to_user(to + count, &v, offsetof(drm_buf_desc32_t, flags)); + + if (copy_to_user(to + count, &v, offsetof(drm_buf_desc32_t, flags))) + return -EFAULT; + return 0; } static int drm_legacy_infobufs32(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index e054f09ac828..1a636469eeda 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Etnaviv Project - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/dma-fence-array.h> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 72d01e873160..5418a1a87b2c 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -760,7 +760,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) if (IS_ERR(gpu->cmdbuf_suballoc)) { dev_err(gpu->dev, "Failed to create cmdbuf suballocator\n"); ret = PTR_ERR(gpu->cmdbuf_suballoc); - goto fail; + goto destroy_iommu; } /* Create buffer: */ @@ -768,7 +768,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) PAGE_SIZE); if (ret) { dev_err(gpu->dev, "could not create command buffer\n"); - goto destroy_iommu; + goto destroy_suballoc; } if (gpu->mmu->version == ETNAVIV_IOMMU_V1 && @@ -800,6 +800,9 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) free_buffer: etnaviv_cmdbuf_free(&gpu->buffer); gpu->buffer.suballoc = NULL; +destroy_suballoc: + etnaviv_cmdbuf_suballoc_destroy(gpu->cmdbuf_suballoc); + gpu->cmdbuf_suballoc = NULL; destroy_iommu: etnaviv_iommu_destroy(gpu->mmu); gpu->mmu = NULL; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 6ea92173db9f..d6a4bbff0c15 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Exynos DRM Parallel output support. * * Copyright (c) 2014 Samsung Electronics Co., Ltd * * Contacts: Andrzej Hajda <a.hajda@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <drm/drmP.h> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 63a4b5074a99..8f62581e2d0f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung SoC MIPI DSI Master driver. * * Copyright (c) 2014 Samsung Electronics Co., Ltd * * Contacts: Tomasz Figa <t.figa@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <asm/unaligned.h> diff --git a/drivers/gpu/drm/exynos/regs-fimc.h b/drivers/gpu/drm/exynos/regs-fimc.h index d7cbe53c4c01..98e4bc18f160 100644 --- a/drivers/gpu/drm/exynos/regs-fimc.h +++ b/drivers/gpu/drm/exynos/regs-fimc.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* drivers/gpu/drm/exynos/regs-fimc.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * Register definition file for Samsung Camera Interface (FIMC) driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef EXYNOS_REGS_FIMC_H diff --git a/drivers/gpu/drm/exynos/regs-gsc.h b/drivers/gpu/drm/exynos/regs-gsc.h index 16b39734115c..9e203cab93b8 100644 --- a/drivers/gpu/drm/exynos/regs-gsc.h +++ b/drivers/gpu/drm/exynos/regs-gsc.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* linux/drivers/gpu/drm/exynos/regs-gsc.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Register definition file for Samsung G-Scaler driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef EXYNOS_REGS_GSC_H_ diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h index 4420c203ac85..8496f230c0f0 100644 --- a/drivers/gpu/drm/exynos/regs-hdmi.h +++ b/drivers/gpu/drm/exynos/regs-hdmi.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * * Cloned from drivers/media/video/s5p-tv/regs-hdmi.h @@ -6,10 +7,6 @@ * http://www.samsung.com/ * * HDMI register header file for Samsung TVOUT driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef SAMSUNG_REGS_HDMI_H diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h index 5ff095b0c1b3..85ca66b8949b 100644 --- a/drivers/gpu/drm/exynos/regs-mixer.h +++ b/drivers/gpu/drm/exynos/regs-mixer.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * * Cloned from drivers/media/video/s5p-tv/regs-mixer.h @@ -6,10 +7,6 @@ * http://www.samsung.com/ * * Mixer register header file for Samsung Mixer driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef SAMSUNG_REGS_MIXER_H #define SAMSUNG_REGS_MIXER_H diff --git a/drivers/gpu/drm/exynos/regs-rotator.h b/drivers/gpu/drm/exynos/regs-rotator.h index a09ac6e180da..e6559f565547 100644 --- a/drivers/gpu/drm/exynos/regs-rotator.h +++ b/drivers/gpu/drm/exynos/regs-rotator.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* drivers/gpu/drm/exynos/regs-rotator.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * Register definition file for Samsung Rotator Interface (Rotator) driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef EXYNOS_REGS_ROTATOR_H diff --git a/drivers/gpu/drm/exynos/regs-scaler.h b/drivers/gpu/drm/exynos/regs-scaler.h index 512a2baced11..654c5f85f00b 100644 --- a/drivers/gpu/drm/exynos/regs-scaler.h +++ b/drivers/gpu/drm/exynos/regs-scaler.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* drivers/gpu/drm/exynos/regs-scaler.h * * Copyright (c) 2017 Samsung Electronics Co., Ltd. @@ -5,10 +6,6 @@ * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> * * Register definition file for Samsung scaler driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef EXYNOS_REGS_SCALER_H diff --git a/drivers/gpu/drm/exynos/regs-vp.h b/drivers/gpu/drm/exynos/regs-vp.h index 10b737af0a72..43c927e65c2b 100644 --- a/drivers/gpu/drm/exynos/regs-vp.h +++ b/drivers/gpu/drm/exynos/regs-vp.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * * Cloned from drivers/media/video/s5p-tv/regs-vp.h @@ -6,10 +7,6 @@ * http://www.samsung.com/ * * Video processor register header file for Samsung Mixer driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef SAMSUNG_REGS_VP_H diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c index 3d6c45097f51..5bf8138941de 100644 --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * DesignWare MIPI DSI Host Controller v1.02 driver * @@ -8,11 +9,6 @@ * Xinliang Liu <z.liuxinliang@hisilicon.com> * Xinliang Liu <xinliang.liu@linaro.org> * Xinwei Kong <kong.kongxinwei@hisilicon.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h b/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h index 18808fc9f362..19e81ff64fac 100644 --- a/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h +++ b/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h @@ -1,11 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016 Linaro Limited. * Copyright (c) 2014-2016 Hisilicon Limited. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef __DW_DSI_REG_H__ diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h b/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h index 4cf281b7ed63..e2ac09894a6d 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h @@ -1,11 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016 Linaro Limited. * Copyright (c) 2014-2016 Hisilicon Limited. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef __KIRIN_ADE_REG_H__ diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index 73611a92d96c..ad7042ae2241 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Hisilicon Hi6220 SoC ADE(Advanced Display Engine)'s crtc&plane driver * @@ -8,11 +9,6 @@ * Xinliang Liu <z.liuxinliang@hisilicon.com> * Xinliang Liu <xinliang.liu@linaro.org> * Xinwei Kong <kong.kongxinwei@hisilicon.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/bitops.h> diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index 7cb7c042b93f..4a7fe10a37cb 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Hisilicon Kirin SoCs drm master driver * @@ -8,11 +9,6 @@ * Xinliang Liu <z.liuxinliang@hisilicon.com> * Xinliang Liu <xinliang.liu@linaro.org> * Xinwei Kong <kong.kongxinwei@hisilicon.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/of_platform.h> diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h index ad027d1cc826..22d1291668cd 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h @@ -1,11 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016 Linaro Limited. * Copyright (c) 2014-2016 Hisilicon Limited. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef __KIRIN_DRM_DRV_H__ diff --git a/drivers/gpu/drm/i2c/tda9950.c b/drivers/gpu/drm/i2c/tda9950.c index 250b5e02a314..8039fc0d83db 100644 --- a/drivers/gpu/drm/i2c/tda9950.c +++ b/drivers/gpu/drm/i2c/tda9950.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TDA9950 Consumer Electronics Control driver * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The NXP TDA9950 implements the HDMI Consumer Electronics Control * interface. The host interface is similar to a mailbox: the data * registers starting at REG_CDR0 are written to send a command to the diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 7f34601bb515..7fcef5125d16 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Texas Instruments * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/component.h> diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index a6ade66349bd..25f78196b964 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -1254,18 +1254,15 @@ static int send_display_ready_uevent(struct intel_vgpu *vgpu, int ready) static int pvinfo_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, void *p_data, unsigned int bytes) { - u32 data; - int ret; - - write_vreg(vgpu, offset, p_data, bytes); - data = vgpu_vreg(vgpu, offset); + u32 data = *(u32 *)p_data; + bool invalid_write = false; switch (offset) { case _vgtif_reg(display_ready): send_display_ready_uevent(vgpu, data ? 1 : 0); break; case _vgtif_reg(g2v_notify): - ret = handle_g2v_notification(vgpu, data); + handle_g2v_notification(vgpu, data); break; /* add xhot and yhot to handled list to avoid error log */ case _vgtif_reg(cursor_x_hot): @@ -1282,13 +1279,19 @@ static int pvinfo_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, case _vgtif_reg(execlist_context_descriptor_hi): break; case _vgtif_reg(rsv5[0])..._vgtif_reg(rsv5[3]): + invalid_write = true; enter_failsafe_mode(vgpu, GVT_FAILSAFE_INSUFFICIENT_RESOURCE); break; default: + invalid_write = true; gvt_vgpu_err("invalid pvinfo write offset %x bytes %x data %x\n", offset, bytes, data); break; } + + if (!invalid_write) + write_vreg(vgpu, offset, p_data, bytes); + return 0; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b69440cf41ea..75105a2c59ea 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12005,9 +12005,6 @@ intel_compare_link_m_n(const struct intel_link_m_n *m_n, m2_n2->gmch_m, m2_n2->gmch_n, !adjust) && intel_compare_m_n(m_n->link_m, m_n->link_n, m2_n2->link_m, m2_n2->link_n, !adjust)) { - if (adjust) - *m2_n2 = *m_n; - return true; } @@ -13149,6 +13146,33 @@ static int calc_watermark_data(struct intel_atomic_state *state) return 0; } +static void intel_crtc_check_fastset(struct intel_crtc_state *old_crtc_state, + struct intel_crtc_state *new_crtc_state) +{ + struct drm_i915_private *dev_priv = + to_i915(new_crtc_state->base.crtc->dev); + + if (!intel_pipe_config_compare(dev_priv, old_crtc_state, + new_crtc_state, true)) + return; + + new_crtc_state->base.mode_changed = false; + new_crtc_state->update_pipe = true; + + /* + * If we're not doing the full modeset we want to + * keep the current M/N values as they may be + * sufficiently different to the computed values + * to cause problems. + * + * FIXME: should really copy more fuzzy state here + */ + new_crtc_state->fdi_m_n = old_crtc_state->fdi_m_n; + new_crtc_state->dp_m_n = old_crtc_state->dp_m_n; + new_crtc_state->dp_m2_n2 = old_crtc_state->dp_m2_n2; + new_crtc_state->has_drrs = old_crtc_state->has_drrs; +} + /** * intel_atomic_check - validate state object * @dev: drm device @@ -13197,12 +13221,8 @@ static int intel_atomic_check(struct drm_device *dev, return ret; } - if (intel_pipe_config_compare(dev_priv, - to_intel_crtc_state(old_crtc_state), - pipe_config, true)) { - crtc_state->mode_changed = false; - pipe_config->update_pipe = true; - } + intel_crtc_check_fastset(to_intel_crtc_state(old_crtc_state), + pipe_config); if (needs_modeset(crtc_state)) any_ms = true; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 029fd8ec1857..f0d45ccc1aac 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1888,12 +1888,12 @@ static int ring_request_alloc(struct i915_request *request) */ request->reserved_space += LEGACY_REQUEST_SIZE; - ret = switch_context(request); + /* Unconditionally invalidate GPU caches and TLBs. */ + ret = request->engine->emit_flush(request, EMIT_INVALIDATE); if (ret) return ret; - /* Unconditionally invalidate GPU caches and TLBs. */ - ret = request->engine->emit_flush(request, EMIT_INVALIDATE); + ret = switch_context(request); if (ret) return ret; diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index 9cc1d678674f..c436a28d50e4 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -91,14 +91,14 @@ static void ipu_crtc_atomic_disable(struct drm_crtc *crtc, ipu_dc_disable(ipu); ipu_prg_disable(ipu); + drm_crtc_vblank_off(crtc); + spin_lock_irq(&crtc->dev->event_lock); - if (crtc->state->event) { + if (crtc->state->event && !crtc->state->active) { drm_crtc_send_vblank_event(crtc, crtc->state->event); crtc->state->event = NULL; } spin_unlock_irq(&crtc->dev->event_lock); - - drm_crtc_vblank_off(crtc); } static void imx_drm_crtc_reset(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index c3b4bc6e4155..8514f42367f2 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * * Copyright (c) 2014 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifdef CONFIG_MSM_OCMEM diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.h b/drivers/gpu/drm/msm/adreno/a3xx_gpu.h index ab60dc9e344e..5dc33e5ea53b 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __A3XX_GPU_H__ diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index b907245d3d96..b3deb346a42b 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013-2014 Red Hat * Author: Rob Clark <robdclark@gmail.com> * * Copyright (c) 2014,2017 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "adreno_gpu.h" diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 6f7f4114afcf..a9c0ac937b00 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * * Copyright (c) 2014 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/ascii85.h> diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 0925606ec9b5..c5ea1f0e7438 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * * Copyright (c) 2014,2017 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __ADRENO_GPU_H__ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index dfdfa766da8f..ccc298711bae 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index e59d62be4980..5181f079a6a1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _DPU_CRTC_H_ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 82bf16d61a45..0ea150196659 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index d77f74fb26d4..a8bf1147fc56 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __DPU_ENCODER_H__ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 885bf88afa3e..ae885e5dd07d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index 31e9ef96ca5d..30aa00243521 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __DPU_KMS_H__ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index ce1a555e1f31..0df80a592eb4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014-2018 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h index 0e6063acd041..456949713e90 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _DPU_PLANE_H_ diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c index 0cfd4c06b610..668c41975d74 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_crtc.h> diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c index caa39b4621e3..772f0753ed38 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015, The Linux Foundation. All rights reserved. * Copyright (c) 2014, Inforce Computing. All rights reserved. * * Author: Vinay Simha <vinaysimha@inforcecomputing.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_crtc.h> diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c index 259d51971401..5d8956055286 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_crtc.h> diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c index b764d7f10312..62fbca302ac2 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_print.h> diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c index e437aa806f7b..7a9ab55b4608 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h index 0c13f8697bfe..18933bd81c77 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MDP4_KMS_H__ diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c index df6f9803a1d7..62e2ebe455ea 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Red Hat * Author: Rob Clark <robdclark@gmail.com> * Author: Vinay Simha <vinaysimha@inforcecomputing.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_crtc.h> diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c index 5368e621999c..ecef4f5b9f26 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Red Hat * Author: Rob Clark <robdclark@gmail.com> * Author: Vinay Simha <vinaysimha@inforcecomputing.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/gpio.h> diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c index ce4245971673..ab8c0c187fb2 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c index 005066f7154d..894b93b59c9f 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "mdp4_kms.h" diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c index b0cf63c4e3d7..fe7cdb3fe887 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/sort.h> diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c index 820a62c40063..f48827283c2b 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_crtc.h> diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c index 280e368bc9bb..58db08a2abfa 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/irq.h> diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index 97179bec8902..901009e1f219 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/of_irq.h> diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h index 854dfd30e829..d1bf4fdfc815 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MDP5_KMS_H__ diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c index 889c2940692c..09bd46ad820b 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/irqdomain.h> diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c index 113e6b569562..954db683ae44 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "mdp5_kms.h" diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h index 9be94f567fbd..43c9ba43ce18 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2017 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MDP5_LM_H__ diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c index 1ef26bc63163..ba6695963aa6 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "mdp5_kms.h" diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h index bb2b0ac7aa2b..9b26d0761bd4 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2016 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MDP5_PIPE_H__ diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c index b854f471e9e5..d6bb468ab2c8 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014-2015 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_print.h> diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c index 6153514db04c..1b1f4514206d 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_util.h> diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h index b41d0448fbe8..ba5618e136c3 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2014, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MDP5_SMP_H__ diff --git a/drivers/gpu/drm/msm/disp/mdp_format.c b/drivers/gpu/drm/msm/disp/mdp_format.c index 005760bee708..8afb0f9c04bb 100644 --- a/drivers/gpu/drm/msm/disp/mdp_format.c +++ b/drivers/gpu/drm/msm/disp/mdp_format.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ diff --git a/drivers/gpu/drm/msm/disp/mdp_kms.c b/drivers/gpu/drm/msm/disp/mdp_kms.c index 64287304054d..3c35ccfc7331 100644 --- a/drivers/gpu/drm/msm/disp/mdp_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp_kms.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ diff --git a/drivers/gpu/drm/msm/disp/mdp_kms.h b/drivers/gpu/drm/msm/disp/mdp_kms.h index 4fa8dbe4e165..1535c5618491 100644 --- a/drivers/gpu/drm/msm/disp/mdp_kms.h +++ b/drivers/gpu/drm/msm/disp/mdp_kms.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MDP_KMS_H__ diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index e247d6942a49..0e4217be3f00 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/of_irq.h> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index 5c5df6ab2a57..982865866a29 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __HDMI_CONNECTOR_H__ diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c index 9c34b91ae329..4c2058c4adc1 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/hdmi.h> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index 03197b8959ba..c8dbd82854c2 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "hdmi.h" diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c index a6eeab2c4dc3..07b4cb877d82 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/gpio.h> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c b/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c index 25d2fe2c60e8..de182c004843 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "hdmi.h" diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c index 0980da8ec966..cf90a0c1f822 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "hdmi.h" diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c index a68eea4153fc..1acc33ce9d52 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "hdmi.h" diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c index 4a8b8468586a..a2a6940e195a 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "hdmi.h" diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c b/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c index c6dae6e437f9..e24a11d91945 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/clk-provider.h> diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 131c23a267ee..dd16babdd8c0 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_atomic_uapi.h> diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index 67ef300559cf..a0a8df591e93 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013-2016 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifdef CONFIG_DEBUG_FS diff --git a/drivers/gpu/drm/msm/msm_debugfs.h b/drivers/gpu/drm/msm/msm_debugfs.h index f4077e344e3a..2b91f8c178ad 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.h +++ b/drivers/gpu/drm/msm/msm_debugfs.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2016 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MSM_DEBUGFS_H__ diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 31deb87abfc6..f38d7367bd3b 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kthread.h> diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index e20e6b429804..4ba3c67a6932 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MSM_DRV_H__ diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index 136058978e0f..7e2692b0007a 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_crtc.h> diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index d088299babf3..2429d5e6ce9f 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_crtc.h> diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c index 77263cf97b20..ad2703698b05 100644 --- a/drivers/gpu/drm/msm/msm_fence.c +++ b/drivers/gpu/drm/msm/msm_fence.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013-2016 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/dma-fence.h> diff --git a/drivers/gpu/drm/msm/msm_fence.h b/drivers/gpu/drm/msm/msm_fence.h index b9fe059091f2..2d9af66dcca5 100644 --- a/drivers/gpu/drm/msm/msm_fence.h +++ b/drivers/gpu/drm/msm/msm_fence.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013-2016 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MSM_FENCE_H__ diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 35f55dd25994..49a019939ccd 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/spinlock.h> diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 812d1b1369a5..8c70bfc71da5 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MSM_GEM_H__ diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c index 60bb290700ce..5d64e0671f7a 100644 --- a/drivers/gpu/drm/msm/msm_gem_prime.c +++ b/drivers/gpu/drm/msm/msm_gem_prime.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "msm_drv.h" diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c index b72d8e6cd51d..722d61668a97 100644 --- a/drivers/gpu/drm/msm/msm_gem_shrinker.c +++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "msm_drv.h" diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 1b681306aca3..28838808e5d6 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/sync_file.h> diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index fcf7a83f0e6f..1af5354bcd46 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "msm_drv.h" diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index bf4ee2766431..b2a8411c2d84 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "msm_gpu.h" diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index f2739cd97cea..ab8f0f9c9dc8 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MSM_GPU_H__ diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index 12bb54cefd46..1e0cb1e6cf8f 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "msm_drv.h" diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index 2b81b43a4bab..c7588a42635e 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MSM_KMS_H__ diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index d21b26604d0b..871d56303697 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MSM_MMU_H__ diff --git a/drivers/gpu/drm/msm/msm_perf.c b/drivers/gpu/drm/msm/msm_perf.c index 5ab21bd2decb..4812361c689d 100644 --- a/drivers/gpu/drm/msm/msm_perf.c +++ b/drivers/gpu/drm/msm/msm_perf.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ /* For profiling, userspace can: diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index d21172933d92..6f634e697b50 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ /* For debugging crashes, userspace can: diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c index 20a96fe69dcd..e397c44cc011 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.c +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "msm_ringbuffer.h" diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.h b/drivers/gpu/drm/msm/msm_ringbuffer.h index 6434ebb13136..7764373d0ed2 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.h +++ b/drivers/gpu/drm/msm/msm_ringbuffer.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __MSM_RINGBUFFER_H__ diff --git a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c index 6c0561101874..0d20fab605d7 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Analog TV Connector driver * * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/slab.h> diff --git a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c index 68d6f6e44b03..f5d69d810bb8 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI Connector driver * * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/gpio/consumer.h> diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c index 29a5a130ebd1..b992387ed674 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OPA362 analog video amplifier with output/power control * @@ -8,10 +9,6 @@ * * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/gpio/consumer.h> diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c index bc03752d2762..089105c5aa0a 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TPD12S015 HDMI ESD protection & level shifter chip driver * * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/completion.h> diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c index 741a5e324767..8edef8ef23b0 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic DSI Command Mode panel driver * * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ /* #define DEBUG */ diff --git a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c index 99f2350d462c..1fd0d84e6e38 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LG.Philips LB035Q02 LCD Panel driver * * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * Based on a driver by: Steve Sakoman <steve@sakoman.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c index 9c545de430f6..3ab50fd1f3f2 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LCD panel driver for Sharp LS037V7DW01 * * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c index 2038def14ba1..588a1a6bbcc3 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Sony ACX565AKM LCD Panel driver * @@ -6,18 +7,6 @@ * Original Driver Author: Imre Deak <imre.deak@nokia.com> * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@ti.com> * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/backlight.h> diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c index 2ad161e33106..c885018ac6ce 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Toppoly TD028TTEC1 panel support * @@ -10,18 +11,6 @@ * * Ported and adapted from Neo 1973 U-Boot by: * H. Nikolaus Schaller <hns@goldelico.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> diff --git a/drivers/gpu/drm/omapdrm/dss/core.c b/drivers/gpu/drm/omapdrm/dss/core.c index a2edabc9f6b3..6ac497b63711 100644 --- a/drivers/gpu/drm/omapdrm/dss/core.c +++ b/drivers/gpu/drm/omapdrm/dss/core.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "CORE" diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index ba82d916719c..785c5546067a 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DISPC" diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.h b/drivers/gpu/drm/omapdrm/dss/dispc.h index e901dd1e4365..2348faf88768 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.h +++ b/drivers/gpu/drm/omapdrm/dss/dispc.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Archit Taneja <archit@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAP2_DISPC_REG_H diff --git a/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c b/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c index 44804c8c8777..bccb28de5a59 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Chandrabhanu Mahapatra <cmahapatra@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c index e93f61a567a8..8a3f61f5825f 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DISPLAY" diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index cc78dfa07f04..95147437b990 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DPI" diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 5202862d89b5..b30fcaa2d0f5 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DSI" diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 55e68863ef15..5711b7a720e6 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DSS" diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 37790c363128..2b404bcb41dd 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -1,21 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAP2_DSS_H diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h index 7f0dc490a31d..c867552c925c 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * HDMI driver definition for TI OMAP4 Processor. * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _HDMI_H diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 6339e2756b34..0f557fad4513 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI interface DSS driver for TI's OMAP4 family of SoCs. * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ * Authors: Yong Zhi * Mythri pk <mythripk@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "HDMI" diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c index e384b95ad857..5d5d5588ebc1 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI TI81xx, TI38xx, TI OMAP4 etc IP driver Library * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ * Authors: Yong Zhi * Mythri pk <mythripk@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "HDMICORE" diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h index 337a317c1a27..11c4b7ba1eee 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * HDMI header definition for OMAP4 HDMI core IP * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _HDMI4_CORE_H_ diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 2955bbad13bb..d9463b332554 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI driver for OMAP5 * @@ -8,18 +9,6 @@ * Mythri pk * Archit Taneja <archit@ti.com> * Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "HDMI" diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c index 02efabc7ed76..7400fb99d453 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP5 HDMI CORE IP driver library * @@ -7,18 +8,6 @@ * Mythri pk * Archit Taneja <archit@ti.com> * Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h index f2f1022c5516..f10b8a283011 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * HDMI driver definition for TI OMAP5 processors. * * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _HDMI5_CORE_H_ diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c index 9915923a53bd..00bbf24488c1 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI PHY * * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c index e7be3707d147..cf2b000f397f 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI PLL * * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #define DSS_SUBSYS_NAME "HDMIPLL" diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c index 100efb9f08c6..32f45f4f569d 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI wrapper * * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #define DSS_SUBSYS_NAME "HDMIWP" diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c index 2b41c75ce988..07b8a1d4d643 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c +++ b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ /* diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 0c734d1f89e1..79f6b195c7cf 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAP_DRM_DSS_H diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index 10a9ee5cdc61..de0f882f0f7b 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ * Author: Archit Taneja <archit@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> diff --git a/drivers/gpu/drm/omapdrm/dss/pll.c b/drivers/gpu/drm/omapdrm/dss/pll.c index ff362b38bf0d..1212f3cc52d1 100644 --- a/drivers/gpu/drm/omapdrm/dss/pll.c +++ b/drivers/gpu/drm/omapdrm/dss/pll.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "PLL" diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index 7aae52984fed..3b447c01fa2a 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "SDI" diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index da43b865d973..596a297d5813 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * VENC settings from TI's DSS driver - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "VENC" diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index 5967283934e1..5b8799c69f68 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_atomic_helper.h> diff --git a/drivers/gpu/drm/omapdrm/omap_connector.h b/drivers/gpu/drm/omapdrm/omap_connector.h index 608085219336..13607bda33d8 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.h +++ b/drivers/gpu/drm/omapdrm/omap_connector.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * omap_connector.h -- OMAP DRM Connector * * Copyright (C) 2011 Texas Instruments * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAPDRM_CONNECTOR_H__ diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 5a29bf01c0e8..8712af79a49c 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_atomic.h> diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.h b/drivers/gpu/drm/omapdrm/omap_crtc.h index d9de437ba9dd..3963f2db92a9 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.h +++ b/drivers/gpu/drm/omapdrm/omap_crtc.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * omap_crtc.h -- OMAP DRM CRTC * * Copyright (C) 2011 Texas Instruments * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAPDRM_CRTC_H__ diff --git a/drivers/gpu/drm/omapdrm/omap_debugfs.c b/drivers/gpu/drm/omapdrm/omap_debugfs.c index 91cf043f2b6b..2b283f68fab7 100644 --- a/drivers/gpu/drm/omapdrm/omap_debugfs.c +++ b/drivers/gpu/drm/omapdrm/omap_debugfs.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Rob Clark <rob.clark@linaro.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/seq_file.h> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 1b9b6f5e48e1..d1b8075e792f 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/of.h> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 3cca45cb25f3..94d00b47db6b 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAPDRM_DRV_H__ diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index 40512419642b..6fe14111cd95 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/list.h> diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.h b/drivers/gpu/drm/omapdrm/omap_encoder.h index 4aefb3142886..051e590cd3ea 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.h +++ b/drivers/gpu/drm/omapdrm/omap_encoder.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * omap_encoder.h -- OMAP DRM Encoder * * Copyright (C) 2011 Texas Instruments * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAPDRM_ENCODER_H__ diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 4f8eb9d08f99..1c9048e35d90 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/seq_file.h> diff --git a/drivers/gpu/drm/omapdrm/omap_fb.h b/drivers/gpu/drm/omapdrm/omap_fb.h index c20cb4bc714d..c0e19aed8220 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.h +++ b/drivers/gpu/drm/omapdrm/omap_fb.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * omap_fb.h -- OMAP DRM Framebuffer * * Copyright (C) 2011 Texas Instruments * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAPDRM_FB_H__ diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 50aabd854f4d..561c4812545b 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_crtc.h> diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.h b/drivers/gpu/drm/omapdrm/omap_fbdev.h index 7dfd843f73f1..74a68a5a6eab 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.h +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * omap_fbdev.h -- OMAP DRM FBDEV Compatibility * * Copyright (C) 2011 Texas Instruments * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAPDRM_FBDEV_H__ diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 8dcaf9f4aa75..37378dbc50d0 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Rob Clark <rob.clark@linaro.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/seq_file.h> diff --git a/drivers/gpu/drm/omapdrm/omap_gem.h b/drivers/gpu/drm/omapdrm/omap_gem.h index c1c45fbde155..31cf345bf8ae 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.h +++ b/drivers/gpu/drm/omapdrm/omap_gem.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * omap_gem.h -- OMAP DRM GEM Object Management * * Copyright (C) 2011 Texas Instruments * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAPDRM_GEM_H__ diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index 0f8b597ccd10..07c0b1b486f7 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Rob Clark <rob.clark@linaro.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/dma-buf.h> diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c index 329ad26d6d50..0e6b410ee741 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.c +++ b/drivers/gpu/drm/omapdrm/omap_irq.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Rob Clark <rob.clark@linaro.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "omap_drv.h" diff --git a/drivers/gpu/drm/omapdrm/omap_irq.h b/drivers/gpu/drm/omapdrm/omap_irq.h index 9d5441468eca..f7ecd728f7b3 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.h +++ b/drivers/gpu/drm/omapdrm/omap_irq.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * omap_irq.h -- OMAP DRM IRQ Handling * * Copyright (C) 2011 Texas Instruments * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAPDRM_IRQ_H__ diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 161233cbc9a0..84e1be981cfe 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Author: Rob Clark <rob.clark@linaro.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_atomic.h> diff --git a/drivers/gpu/drm/omapdrm/omap_plane.h b/drivers/gpu/drm/omapdrm/omap_plane.h index dc5e82ad061d..0c28fe8ffa20 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.h +++ b/drivers/gpu/drm/omapdrm/omap_plane.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * omap_plane.h -- OMAP DRM Plane * * Copyright (C) 2011 Texas Instruments * Author: Rob Clark <rob@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAPDRM_PLANE_H__ diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c index a1c4cd2940fb..cc2c9981a388 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Ilitek ILI9322 TFT LCD drm_panel driver. * @@ -16,10 +17,6 @@ * * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> * Derived from drivers/drm/gpu/panel/panel-samsung-ld9040.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <drm/drmP.h> diff --git a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c index 99caa7835e7b..04c3a7963c4a 100644 --- a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c +++ b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 InforceComputing * Author: Vinay Simha BN <simhavcs@gmail.com> @@ -8,18 +9,6 @@ * From internet archives, the panel for Nexus 7 2nd Gen, 2013 model is a * JDI model LT070ME05000, and its data sheet is at: * http://panelone.net/en/7-0-inch/JDI_LT070ME05000_7.0_inch-datasheet - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/backlight.h> #include <linux/gpio/consumer.h> diff --git a/drivers/gpu/drm/panel/panel-lg-lg4573.c b/drivers/gpu/drm/panel/panel-lg-lg4573.c index 6989238b276a..ccbd24d32623 100644 --- a/drivers/gpu/drm/panel/panel-lg-lg4573.c +++ b/drivers/gpu/drm/panel/panel-lg-lg4573.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Heiko Schocher <hs@denx.de> * @@ -9,10 +10,6 @@ * Derived from drivers/video/backlight/ld9040.c * * Andrzej Hajda <a.hajda@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <drm/drmP.h> diff --git a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c index cb4dfb98be0f..a2092b0ccebd 100644 --- a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c +++ b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Red Hat * Copyright (C) 2015 Sony Mobile Communications Inc. * Author: Werner Johansson <werner.johansson@sonymobile.com> * * Based on AUO panel driver by Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/backlight.h> diff --git a/drivers/gpu/drm/panel/panel-samsung-ld9040.c b/drivers/gpu/drm/panel/panel-samsung-ld9040.c index 3cf4cf6a6942..1a42983b4ce4 100644 --- a/drivers/gpu/drm/panel/panel-samsung-ld9040.c +++ b/drivers/gpu/drm/panel/panel-samsung-ld9040.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ld9040 AMOLED LCD drm_panel driver. * @@ -5,10 +6,6 @@ * Derived from drivers/video/backlight/ld9040.c * * Andrzej Hajda <a.hajda@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <drm/drmP.h> diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c index 797bbc7a264e..4a2034ea7093 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * MIPI-DSI based s6e3ha2 AMOLED 5.7 inch panel driver. * @@ -5,10 +6,6 @@ * Donghwa Lee <dh09.lee@samsung.com> * Hyungwon Hwang <human.hwang@samsung.com> * Hoegeun Kwon <hoegeun.kwon@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <drm/drmP.h> diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c index aeb32aa58899..4b58098e1918 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * MIPI-DSI based S6E63J0X03 AMOLED lcd 1.63 inch panel driver. * @@ -5,10 +6,6 @@ * * Inki Dae <inki.dae@samsung.com> * Hoegeun Kwon <hoegeun.kwon@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <drm/drmP.h> diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c index 6ad827b93ae1..00fc807c12cd 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * MIPI-DSI based s6e8aa0 AMOLED LCD 5.3 inch panel driver. * @@ -9,10 +10,6 @@ * Eunchul Kim <chulspro.kim@samsung.com> * Tomasz Figa <t.figa@samsung.com> * Andrzej Hajda <a.hajda@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <drm/drmP.h> diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c index 02fc0f5423d4..69d30c2639cc 100644 --- a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c +++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/backlight.h> diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c index e5cae0050f52..9d9e8f16c87d 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Red Hat * Copyright (C) 2015 Sony Mobile Communications Inc. * Author: Werner Johansson <werner.johansson@sonymobile.com> * * Based on AUO panel driver by Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/backlight.h> diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c index 74284e5afc5d..984c7c27997b 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 Free Electrons - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. */ #include <linux/gpio/consumer.h> diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index d11e2281dde6..7e43b25785f7 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -63,7 +63,7 @@ static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data, return 0; err_free: - drm_gem_object_put_unlocked(&shmem->base); + drm_gem_handle_delete(file, args->handle); return ret; } diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c index a5528a360ef4..97d64ceedbb4 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gem.c +++ b/drivers/gpu/drm/panfrost/panfrost_gem.c @@ -19,7 +19,8 @@ static void panfrost_gem_free_object(struct drm_gem_object *obj) struct panfrost_gem_object *bo = to_panfrost_bo(obj); struct panfrost_device *pfdev = obj->dev->dev_private; - panfrost_mmu_unmap(bo); + if (bo->is_mapped) + panfrost_mmu_unmap(bo); spin_lock(&pfdev->mm_lock); drm_mm_remove_node(&bo->node); diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h b/drivers/gpu/drm/panfrost/panfrost_gem.h index 045000eb5fcf..6dbcaba020fc 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gem.h +++ b/drivers/gpu/drm/panfrost/panfrost_gem.h @@ -11,6 +11,7 @@ struct panfrost_gem_object { struct drm_gem_shmem_object base; struct drm_mm_node node; + bool is_mapped; }; static inline diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c index 762b1bd2a8c2..92ac995dd9c6 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c @@ -156,6 +156,9 @@ int panfrost_mmu_map(struct panfrost_gem_object *bo) struct sg_table *sgt; int ret; + if (WARN_ON(bo->is_mapped)) + return 0; + sgt = drm_gem_shmem_get_pages_sgt(obj); if (WARN_ON(IS_ERR(sgt))) return PTR_ERR(sgt); @@ -189,6 +192,7 @@ int panfrost_mmu_map(struct panfrost_gem_object *bo) pm_runtime_mark_last_busy(pfdev->dev); pm_runtime_put_autosuspend(pfdev->dev); + bo->is_mapped = true; return 0; } @@ -203,6 +207,9 @@ void panfrost_mmu_unmap(struct panfrost_gem_object *bo) size_t unmapped_len = 0; int ret; + if (WARN_ON(!bo->is_mapped)) + return; + dev_dbg(pfdev->dev, "unmap: iova=%llx, len=%zx", iova, len); ret = pm_runtime_get_sync(pfdev->dev); @@ -230,6 +237,7 @@ void panfrost_mmu_unmap(struct panfrost_gem_object *bo) pm_runtime_mark_last_busy(pfdev->dev); pm_runtime_put_autosuspend(pfdev->dev); + bo->is_mapped = false; } static void mmu_tlb_inv_context_s1(void *cookie) diff --git a/drivers/gpu/drm/pl111/pl111_debugfs.c b/drivers/gpu/drm/pl111/pl111_debugfs.c index 7ddc7e3b9e7d..8d6a40469f0b 100644 --- a/drivers/gpu/drm/pl111/pl111_debugfs.c +++ b/drivers/gpu/drm/pl111/pl111_debugfs.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2017 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/amba/clcd-regs.h> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 48fef95cb3c6..f18a01e6cbc2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -1,15 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2016 Chris Zhong <zyw@rock-chips.com> * Copyright (C) 2016 ROCKCHIP, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _CDN_DP_CORE_H diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 607a6ea17ecc..826b3f047c0c 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Avionic Design GmbH * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index 1256dfb6b2f5..0c4d17851f47 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Avionic Design GmbH * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef TEGRA_DC_H diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index ee4180d8db14..0395c00b7772 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/tegra/dpaux.h b/drivers/gpu/drm/tegra/dpaux.h index 20783d9f4728..5eced10fad37 100644 --- a/drivers/gpu/drm/tegra/dpaux.h +++ b/drivers/gpu/drm/tegra/dpaux.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef DRM_TEGRA_DPAUX_H diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 0c5f1e6a0446..ddb802bce0a3 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Avionic Design GmbH * Copyright (C) 2012-2016 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 70154c253d45..3844c402ff03 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Avionic Design GmbH * Copyright (C) 2012-2013 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef HOST1X_DRM_H diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index ee6ca8fa1c65..2fbfefe9cb42 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h index 219263615399..f39594e65e97 100644 --- a/drivers/gpu/drm/tegra/dsi.h +++ b/drivers/gpu/drm/tegra/dsi.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef DRM_TEGRA_DSI_H diff --git a/drivers/gpu/drm/tegra/falcon.c b/drivers/gpu/drm/tegra/falcon.c index 352d05feabb0..f49ad36e24db 100644 --- a/drivers/gpu/drm/tegra/falcon.c +++ b/drivers/gpu/drm/tegra/falcon.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/platform_device.h> diff --git a/drivers/gpu/drm/tegra/falcon.h b/drivers/gpu/drm/tegra/falcon.h index 4504ed5a199e..3d1243217410 100644 --- a/drivers/gpu/drm/tegra/falcon.h +++ b/drivers/gpu/drm/tegra/falcon.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _FALCON_H_ diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 1dd83a757dba..44bda75355e2 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012-2013 Avionic Design GmbH * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. * * Based on the KMS/FB CMA helpers * Copyright (C) 2012 Analog Device Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/console.h> diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 4cce11fd8836..df53a46285a3 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NVIDIA Tegra DRM GEM helper functions * @@ -7,10 +8,6 @@ * Based on the GEM/CMA helpers * * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/dma-buf.h> diff --git a/drivers/gpu/drm/tegra/gem.h b/drivers/gpu/drm/tegra/gem.h index 6bd7dd7e55b4..413eae83ad81 100644 --- a/drivers/gpu/drm/tegra/gem.h +++ b/drivers/gpu/drm/tegra/gem.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Tegra host1x GEM implementation * * Copyright (c) 2012-2013, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __HOST1X_GEM_H diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index 673059fd2fcb..8dbfb30344e7 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012-2013, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/tegra/gr2d.h b/drivers/gpu/drm/tegra/gr2d.h index 4d7304fb015e..2398486f0699 100644 --- a/drivers/gpu/drm/tegra/gr2d.h +++ b/drivers/gpu/drm/tegra/gr2d.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef TEGRA_GR2D_H diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index 4778ae999668..8b9a35b1cbb3 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Avionic Design GmbH * Copyright (C) 2013 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/tegra/gr3d.h b/drivers/gpu/drm/tegra/gr3d.h index 0c30a1351c83..ca2921b68c2a 100644 --- a/drivers/gpu/drm/tegra/gr3d.h +++ b/drivers/gpu/drm/tegra/gr3d.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef TEGRA_GR3D_H diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index d23c4bfde790..334c4d7d238b 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Avionic Design GmbH * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/tegra/hdmi.h b/drivers/gpu/drm/tegra/hdmi.h index 2339f134a09a..8deb04223c18 100644 --- a/drivers/gpu/drm/tegra/hdmi.h +++ b/drivers/gpu/drm/tegra/hdmi.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Avionic Design GmbH * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef TEGRA_HDMI_H diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index b3436c2aed68..92f202ec0577 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/tegra/hub.h b/drivers/gpu/drm/tegra/hub.h index 479087c0705a..41541e261c91 100644 --- a/drivers/gpu/drm/tegra/hub.h +++ b/drivers/gpu/drm/tegra/hub.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef TEGRA_HUB_H diff --git a/drivers/gpu/drm/tegra/mipi-phy.c b/drivers/gpu/drm/tegra/mipi-phy.c index ba2ae6511957..4fe05f2df637 100644 --- a/drivers/gpu/drm/tegra/mipi-phy.c +++ b/drivers/gpu/drm/tegra/mipi-phy.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/errno.h> diff --git a/drivers/gpu/drm/tegra/mipi-phy.h b/drivers/gpu/drm/tegra/mipi-phy.h index 012ea8ac36d7..41889a75035c 100644 --- a/drivers/gpu/drm/tegra/mipi-phy.h +++ b/drivers/gpu/drm/tegra/mipi-phy.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef DRM_TEGRA_MIPI_PHY_H diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index 9c2b9dad55c3..4d450ce8aa86 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Avionic Design GmbH * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <drm/drm_atomic_helper.h> diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index d068e8aa3553..df80ca07e46e 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <drm/drm_atomic.h> diff --git a/drivers/gpu/drm/tegra/plane.h b/drivers/gpu/drm/tegra/plane.h index e79e6b4a8e0a..510c394e6d9a 100644 --- a/drivers/gpu/drm/tegra/plane.h +++ b/drivers/gpu/drm/tegra/plane.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef TEGRA_PLANE_H diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index 28a78d3120bc..4be4dfd4a68a 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Avionic Design GmbH * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 5be5a0817dfe..4ffe3794e6d3 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/tegra/sor.h b/drivers/gpu/drm/tegra/sor.h index 13f7e68bec42..f8efd8be4b7c 100644 --- a/drivers/gpu/drm/tegra/sor.h +++ b/drivers/gpu/drm/tegra/sor.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef DRM_TEGRA_SOR_H diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index 982ce37ecde1..958548ef69e7 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/tegra/vic.h b/drivers/gpu/drm/tegra/vic.h index 017584340dd6..be898bee6a57 100644 --- a/drivers/gpu/drm/tegra/vic.h +++ b/drivers/gpu/drm/tegra/vic.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef TEGRA_VIC_H diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 1067e702c22c..650d162e374b 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Texas Instruments * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drm_atomic.h> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 3030af9e7b35..7339bab3a0a1 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Texas Instruments * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ /* LCDC DRM driver, based on da8xx-fb */ diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index d86397da12a9..99432296c0ff 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Texas Instruments * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __TILCDC_DRV_H__ diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c index e9969cd36610..7050eb4cf152 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_external.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Texas Instruments * Author: Jyri Sarha <jsarha@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * */ #include <linux/component.h> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.h b/drivers/gpu/drm/tilcdc/tilcdc_external.h index 763d18f006c7..7024b4877fdf 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_external.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_external.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2015 Texas Instruments * Author: Jyri Sarha <jsarha@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __TILCDC_EXTERNAL_H__ diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c index 5d532a596e1e..22b100d2e174 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Texas Instruments * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/pinctrl/pinmux.h> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.h b/drivers/gpu/drm/tilcdc/tilcdc_panel.h index 7db40aacc74a..65d735d773a4 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Texas Instruments * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __TILCDC_PANEL_H__ diff --git a/drivers/gpu/drm/tilcdc/tilcdc_plane.c b/drivers/gpu/drm/tilcdc/tilcdc_plane.c index 7667b038ae7f..8c2776acdf99 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_plane.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_plane.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Texas Instruments * Author: Jyri Sarha <jsarha@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <drm/drmP.h> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_regs.h b/drivers/gpu/drm/tilcdc/tilcdc_regs.h index 5048ebb86835..f90e2dc3457c 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_regs.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_regs.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Texas Instruments * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __TILCDC_REGS_H__ diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c index fe59fbfdde69..62d014c20988 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Texas Instruments * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/i2c.h> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.h b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.h index 5b800f1f6aa5..f9aaf6911ffc 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Texas Instruments * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __TILCDC_TFP410_H__ diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index 88ebd681d7eb..d185a522da49 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2015 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /** diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 5e09389e1514..5ea8db74418a 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /** diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c index f9dec08267dc..273da7e58d44 100644 --- a/drivers/gpu/drm/vc4/vc4_debugfs.c +++ b/drivers/gpu/drm/vc4/vc4_debugfs.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2014 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/seq_file.h> diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c index 34f90ca8f479..8a27a6acee61 100644 --- a/drivers/gpu/drm/vc4/vc4_dpi.c +++ b/drivers/gpu/drm/vc4/vc4_dpi.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Broadcom Limited - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ /** diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 6d9be20a32be..e88235eeed6c 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014-2015 Broadcom * Copyright (C) 2013 Red Hat - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /** diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 4f13f6262491..24c45f2d9df1 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2015 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/mm_types.h> diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index 2ea4e20b7b8a..1db39b570cf4 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ /** diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 99fc8569e0f5..9f385979d1e6 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Broadcom * Copyright (c) 2014 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ /** @@ -69,6 +58,9 @@ struct vc4_hdmi_audio { struct snd_soc_card card; struct snd_soc_dai_link link; + struct snd_soc_dai_link_component cpu; + struct snd_soc_dai_link_component codec; + struct snd_soc_dai_link_component platform; int samplerate; int channels; struct snd_dmaengine_dai_dma_data dma_data; @@ -1096,12 +1088,20 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi) return ret; } + dai_link->cpus = &hdmi->audio.cpu; + dai_link->codecs = &hdmi->audio.codec; + dai_link->platforms = &hdmi->audio.platform; + + dai_link->num_cpus = 1; + dai_link->num_codecs = 1; + dai_link->num_platforms = 1; + dai_link->name = "MAI"; dai_link->stream_name = "MAI PCM"; - dai_link->codec_dai_name = vc4_hdmi_audio_codec_dai_drv.name; - dai_link->cpu_dai_name = dev_name(dev); - dai_link->codec_name = dev_name(dev); - dai_link->platform_name = dev_name(dev); + dai_link->codecs->dai_name = vc4_hdmi_audio_codec_dai_drv.name; + dai_link->cpus->dai_name = dev_name(dev); + dai_link->codecs->name = dev_name(dev); + dai_link->platforms->name = dev_name(dev); card->dai_link = dai_link; card->num_links = 1; diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index f746e9a7a88c..0f633bef6b9d 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /** diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 295dacc8bcb9..70d079b7b39f 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /** diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index afc80b245ea3..84fd0a31b701 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /** diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h index c0c5fadaf7e3..b5a6b4cdd332 100644 --- a/drivers/gpu/drm/vc4/vc4_regs.h +++ b/drivers/gpu/drm/vc4/vc4_regs.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright © 2014-2015 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef VC4_REGS_H diff --git a/drivers/gpu/drm/vc4/vc4_trace.h b/drivers/gpu/drm/vc4/vc4_trace.h index deafb32923e1..1cccde0b09a7 100644 --- a/drivers/gpu/drm/vc4/vc4_trace.h +++ b/drivers/gpu/drm/vc4/vc4_trace.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2015 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #if !defined(_VC4_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) diff --git a/drivers/gpu/drm/vc4/vc4_trace_points.c b/drivers/gpu/drm/vc4/vc4_trace_points.c index e6278f25716b..126453abe294 100644 --- a/drivers/gpu/drm/vc4/vc4_trace_points.c +++ b/drivers/gpu/drm/vc4/vc4_trace_points.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "vc4_drv.h" diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c index a4b6859e3af6..c36315924b7d 100644 --- a/drivers/gpu/drm/vc4/vc4_v3d.c +++ b/drivers/gpu/drm/vc4/vc4_v3d.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c index 0a27e48fab31..7402bc768664 100644 --- a/drivers/gpu/drm/vc4/vc4_vec.c +++ b/drivers/gpu/drm/vc4/vc4_vec.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ /** diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index e62fe24b1a2e..5bb0f0a084e9 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -619,11 +619,11 @@ static void virtio_gpu_cmd_get_edid_cb(struct virtio_gpu_device *vgdev, output = vgdev->outputs + scanout; new_edid = drm_do_get_edid(&output->conn, virtio_get_edid_block, resp); + drm_connector_update_edid_property(&output->conn, new_edid); spin_lock(&vgdev->display_info_lock); old_edid = output->edid; output->edid = new_edid; - drm_connector_update_edid_property(&output->conn, output->edid); spin_unlock(&vgdev->display_info_lock); kfree(old_edid); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 4ff11a0077e1..9506190a0300 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -747,6 +747,9 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) if (unlikely(ret != 0)) goto out_err0; + dma_set_max_seg_size(dev->dev, min_t(unsigned int, U32_MAX & PAGE_MASK, + SCATTERLIST_MAX_SEGMENT)); + if (dev_priv->capabilities & SVGA_CAP_GMR2) { DRM_INFO("Max GMR ids is %u\n", (unsigned)dev_priv->max_gmr_ids); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index 8b9270f31409..e4e09d47c5c0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -136,6 +136,114 @@ static int vmw_close_channel(struct rpc_channel *channel) return 0; } +/** + * vmw_port_hb_out - Send the message payload either through the + * high-bandwidth port if available, or through the backdoor otherwise. + * @channel: The rpc channel. + * @msg: NULL-terminated message. + * @hb: Whether the high-bandwidth port is available. + * + * Return: The port status. + */ +static unsigned long vmw_port_hb_out(struct rpc_channel *channel, + const char *msg, bool hb) +{ + unsigned long si, di, eax, ebx, ecx, edx; + unsigned long msg_len = strlen(msg); + + if (hb) { + unsigned long bp = channel->cookie_high; + + si = (uintptr_t) msg; + di = channel->cookie_low; + + VMW_PORT_HB_OUT( + (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG, + msg_len, si, di, + VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16), + VMW_HYPERVISOR_MAGIC, bp, + eax, ebx, ecx, edx, si, di); + + return ebx; + } + + /* HB port not available. Send the message 4 bytes at a time. */ + ecx = MESSAGE_STATUS_SUCCESS << 16; + while (msg_len && (HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS)) { + unsigned int bytes = min_t(size_t, msg_len, 4); + unsigned long word = 0; + + memcpy(&word, msg, bytes); + msg_len -= bytes; + msg += bytes; + si = channel->cookie_high; + di = channel->cookie_low; + + VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_SENDPAYLOAD << 16), + word, si, di, + VMW_HYPERVISOR_PORT | (channel->channel_id << 16), + VMW_HYPERVISOR_MAGIC, + eax, ebx, ecx, edx, si, di); + } + + return ecx; +} + +/** + * vmw_port_hb_in - Receive the message payload either through the + * high-bandwidth port if available, or through the backdoor otherwise. + * @channel: The rpc channel. + * @reply: Pointer to buffer holding reply. + * @reply_len: Length of the reply. + * @hb: Whether the high-bandwidth port is available. + * + * Return: The port status. + */ +static unsigned long vmw_port_hb_in(struct rpc_channel *channel, char *reply, + unsigned long reply_len, bool hb) +{ + unsigned long si, di, eax, ebx, ecx, edx; + + if (hb) { + unsigned long bp = channel->cookie_low; + + si = channel->cookie_high; + di = (uintptr_t) reply; + + VMW_PORT_HB_IN( + (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG, + reply_len, si, di, + VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16), + VMW_HYPERVISOR_MAGIC, bp, + eax, ebx, ecx, edx, si, di); + + return ebx; + } + + /* HB port not available. Retrieve the message 4 bytes at a time. */ + ecx = MESSAGE_STATUS_SUCCESS << 16; + while (reply_len) { + unsigned int bytes = min_t(unsigned long, reply_len, 4); + + si = channel->cookie_high; + di = channel->cookie_low; + + VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_RECVPAYLOAD << 16), + MESSAGE_STATUS_SUCCESS, si, di, + VMW_HYPERVISOR_PORT | (channel->channel_id << 16), + VMW_HYPERVISOR_MAGIC, + eax, ebx, ecx, edx, si, di); + + if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) + break; + + memcpy(reply, &ebx, bytes); + reply_len -= bytes; + reply += bytes; + } + + return ecx; +} /** @@ -148,11 +256,10 @@ static int vmw_close_channel(struct rpc_channel *channel) */ static int vmw_send_msg(struct rpc_channel *channel, const char *msg) { - unsigned long eax, ebx, ecx, edx, si, di, bp; + unsigned long eax, ebx, ecx, edx, si, di; size_t msg_len = strlen(msg); int retries = 0; - while (retries < RETRIES) { retries++; @@ -166,23 +273,14 @@ static int vmw_send_msg(struct rpc_channel *channel, const char *msg) VMW_HYPERVISOR_MAGIC, eax, ebx, ecx, edx, si, di); - if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 || - (HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) { - /* Expected success + high-bandwidth. Give up. */ + if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) { + /* Expected success. Give up. */ return -EINVAL; } /* Send msg */ - si = (uintptr_t) msg; - di = channel->cookie_low; - bp = channel->cookie_high; - - VMW_PORT_HB_OUT( - (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG, - msg_len, si, di, - VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16), - VMW_HYPERVISOR_MAGIC, bp, - eax, ebx, ecx, edx, si, di); + ebx = vmw_port_hb_out(channel, msg, + !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB)); if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) != 0) { return 0; @@ -211,7 +309,7 @@ STACK_FRAME_NON_STANDARD(vmw_send_msg); static int vmw_recv_msg(struct rpc_channel *channel, void **msg, size_t *msg_len) { - unsigned long eax, ebx, ecx, edx, si, di, bp; + unsigned long eax, ebx, ecx, edx, si, di; char *reply; size_t reply_len; int retries = 0; @@ -233,8 +331,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg, VMW_HYPERVISOR_MAGIC, eax, ebx, ecx, edx, si, di); - if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 || - (HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) { + if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) { DRM_ERROR("Failed to get reply size for host message.\n"); return -EINVAL; } @@ -252,17 +349,8 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg, /* Receive buffer */ - si = channel->cookie_high; - di = (uintptr_t) reply; - bp = channel->cookie_low; - - VMW_PORT_HB_IN( - (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG, - reply_len, si, di, - VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16), - VMW_HYPERVISOR_MAGIC, bp, - eax, ebx, ecx, edx, si, di); - + ebx = vmw_port_hb_in(channel, reply, reply_len, + !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB)); if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) { kfree(reply); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c index a6ea75b58a83..d8ea3dd10af0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c @@ -441,11 +441,11 @@ static int vmw_ttm_map_dma(struct vmw_ttm_tt *vmw_tt) if (unlikely(ret != 0)) return ret; - ret = sg_alloc_table_from_pages(&vmw_tt->sgt, vsgt->pages, - vsgt->num_pages, 0, - (unsigned long) - vsgt->num_pages << PAGE_SHIFT, - GFP_KERNEL); + ret = __sg_alloc_table_from_pages + (&vmw_tt->sgt, vsgt->pages, vsgt->num_pages, 0, + (unsigned long) vsgt->num_pages << PAGE_SHIFT, + dma_get_max_seg_size(dev_priv->dev->dev), + GFP_KERNEL); if (unlikely(ret != 0)) goto out_sg_alloc_fail; diff --git a/drivers/gpu/drm/zte/zx_common_regs.h b/drivers/gpu/drm/zte/zx_common_regs.h index 2afd80664c51..b7b996db129d 100644 --- a/drivers/gpu/drm/zte/zx_common_regs.h +++ b/drivers/gpu/drm/zte/zx_common_regs.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2017 Sanechips Technology Co., Ltd. * Copyright 2017 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __ZX_COMMON_REGS_H__ diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c index 28e8d6072910..520d7369f85a 100644 --- a/drivers/gpu/drm/zte/zx_drm_drv.c +++ b/drivers/gpu/drm/zte/zx_drm_drv.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2016 Linaro Ltd. * Copyright 2016 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/zte/zx_drm_drv.h b/drivers/gpu/drm/zte/zx_drm_drv.h index 2a8cdc5f8be4..80cdaf479c74 100644 --- a/drivers/gpu/drm/zte/zx_drm_drv.h +++ b/drivers/gpu/drm/zte/zx_drm_drv.h @@ -1,11 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2016 Linaro Ltd. * Copyright 2016 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef __ZX_DRM_DRV_H__ diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c index df522d74bebf..bfe918b27c5c 100644 --- a/drivers/gpu/drm/zte/zx_hdmi.c +++ b/drivers/gpu/drm/zte/zx_hdmi.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2016 Linaro Ltd. * Copyright 2016 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/zte/zx_hdmi_regs.h b/drivers/gpu/drm/zte/zx_hdmi_regs.h index c6d5d8211725..397949e64eff 100644 --- a/drivers/gpu/drm/zte/zx_hdmi_regs.h +++ b/drivers/gpu/drm/zte/zx_hdmi_regs.h @@ -1,11 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2016 Linaro Ltd. * Copyright 2016 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef __ZX_HDMI_REGS_H__ diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c index 83d236fd893c..3a6286294895 100644 --- a/drivers/gpu/drm/zte/zx_plane.c +++ b/drivers/gpu/drm/zte/zx_plane.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2016 Linaro Ltd. * Copyright 2016 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <drm/drm_atomic.h> diff --git a/drivers/gpu/drm/zte/zx_plane.h b/drivers/gpu/drm/zte/zx_plane.h index 933611ddffd0..5a7cc8b3b985 100644 --- a/drivers/gpu/drm/zte/zx_plane.h +++ b/drivers/gpu/drm/zte/zx_plane.h @@ -1,11 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2016 Linaro Ltd. * Copyright 2016 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef __ZX_PLANE_H__ diff --git a/drivers/gpu/drm/zte/zx_plane_regs.h b/drivers/gpu/drm/zte/zx_plane_regs.h index 9c655f59f9f7..ce830637a92d 100644 --- a/drivers/gpu/drm/zte/zx_plane_regs.h +++ b/drivers/gpu/drm/zte/zx_plane_regs.h @@ -1,11 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2016 Linaro Ltd. * Copyright 2016 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef __ZX_PLANE_REGS_H__ diff --git a/drivers/gpu/drm/zte/zx_tvenc.c b/drivers/gpu/drm/zte/zx_tvenc.c index 87b5d86413d2..a768c567b557 100644 --- a/drivers/gpu/drm/zte/zx_tvenc.c +++ b/drivers/gpu/drm/zte/zx_tvenc.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2017 Linaro Ltd. * Copyright 2017 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/zte/zx_tvenc_regs.h b/drivers/gpu/drm/zte/zx_tvenc_regs.h index bd91f5dcc1f3..40f033109374 100644 --- a/drivers/gpu/drm/zte/zx_tvenc_regs.h +++ b/drivers/gpu/drm/zte/zx_tvenc_regs.h @@ -1,11 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2017 Linaro Ltd. * Copyright 2017 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef __ZX_TVENC_REGS_H__ diff --git a/drivers/gpu/drm/zte/zx_vga.c b/drivers/gpu/drm/zte/zx_vga.c index e14c1d709740..1634a08707fb 100644 --- a/drivers/gpu/drm/zte/zx_vga.c +++ b/drivers/gpu/drm/zte/zx_vga.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 Sanechips Technology Co., Ltd. * Copyright 2017 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/zte/zx_vga_regs.h b/drivers/gpu/drm/zte/zx_vga_regs.h index feaa345fe6a6..1e8825ae70a5 100644 --- a/drivers/gpu/drm/zte/zx_vga_regs.h +++ b/drivers/gpu/drm/zte/zx_vga_regs.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2017 Sanechips Technology Co., Ltd. * Copyright 2017 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __ZX_VGA_REGS_H__ diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c index 15400ffb1d22..81b4cf107b75 100644 --- a/drivers/gpu/drm/zte/zx_vou.c +++ b/drivers/gpu/drm/zte/zx_vou.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2016 Linaro Ltd. * Copyright 2016 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/zte/zx_vou.h b/drivers/gpu/drm/zte/zx_vou.h index 5b7f84fbb112..b25f34f865ae 100644 --- a/drivers/gpu/drm/zte/zx_vou.h +++ b/drivers/gpu/drm/zte/zx_vou.h @@ -1,11 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2016 Linaro Ltd. * Copyright 2016 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef __ZX_VOU_H__ diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h b/drivers/gpu/drm/zte/zx_vou_regs.h index 5a218351b497..2ddb199cb912 100644 --- a/drivers/gpu/drm/zte/zx_vou_regs.h +++ b/drivers/gpu/drm/zte/zx_vou_regs.h @@ -1,11 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2016 Linaro Ltd. * Copyright 2016 ZTE Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef __ZX_VOU_REGS_H__ diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c b/drivers/gpu/ipu-v3/ipu-image-convert.c index 36e88434513a..e744f3527ce1 100644 --- a/drivers/gpu/ipu-v3/ipu-image-convert.c +++ b/drivers/gpu/ipu-v3/ipu-image-convert.c @@ -400,12 +400,14 @@ static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx, if (WARN_ON(resized_width == 0 || resized_height == 0)) return -EINVAL; - while (downsized_width >= resized_width * 2) { + while (downsized_width > 1024 || + downsized_width >= resized_width * 2) { downsized_width >>= 1; downsize_coeff_h++; } - while (downsized_height >= resized_height * 2) { + while (downsized_height > 1024 || + downsized_height >= resized_height * 2) { downsized_height >>= 1; downsize_coeff_v++; } @@ -1876,7 +1878,8 @@ void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out, enum ipu_rotate_mode rot_mode) { const struct ipu_image_pixfmt *infmt, *outfmt; - u32 w_align, h_align; + u32 w_align_out, h_align_out; + u32 w_align_in, h_align_in; infmt = get_format(in->pix.pixelformat); outfmt = get_format(out->pix.pixelformat); @@ -1908,22 +1911,33 @@ void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out, } /* align input width/height */ - w_align = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt, rot_mode)); - h_align = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt, rot_mode)); - in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W, w_align); - in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H, h_align); + w_align_in = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt, + rot_mode)); + h_align_in = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt, + rot_mode)); + in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W, + w_align_in); + in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H, + h_align_in); /* align output width/height */ - w_align = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt, rot_mode)); - h_align = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt, rot_mode)); - out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W, w_align); - out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H, h_align); + w_align_out = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt, + rot_mode)); + h_align_out = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt, + rot_mode)); + out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W, + w_align_out); + out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H, + h_align_out); /* set input/output strides and image sizes */ in->pix.bytesperline = infmt->planar ? - clamp_align(in->pix.width, 2 << w_align, MAX_W, w_align) : + clamp_align(in->pix.width, 2 << w_align_in, MAX_W, + w_align_in) : clamp_align((in->pix.width * infmt->bpp) >> 3, - 2 << w_align, MAX_W, w_align); + ((2 << w_align_in) * infmt->bpp) >> 3, + (MAX_W * infmt->bpp) >> 3, + w_align_in); in->pix.sizeimage = infmt->planar ? (in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 : in->pix.height * in->pix.bytesperline; diff --git a/drivers/gpu/vga/Kconfig b/drivers/gpu/vga/Kconfig index 84ab482d0db6..c8c770b05ed9 100644 --- a/drivers/gpu/vga/Kconfig +++ b/drivers/gpu/vga/Kconfig @@ -23,6 +23,7 @@ config VGA_SWITCHEROO depends on X86 depends on ACPI depends on PCI + depends on (FRAMEBUFFER_CONSOLE=n || FB=y) select VGA_ARB help Many laptops released in 2008/9/10 have two GPUs with a multiplexer diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index a132c37d7334..65d7541c413a 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -35,6 +35,7 @@ #include <linux/debugfs.h> #include <linux/fb.h> #include <linux/fs.h> +#include <linux/fbcon.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/pm_domain.h> @@ -736,14 +737,8 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) if (!active->driver_power_control) set_audio_state(active->id, VGA_SWITCHEROO_OFF); - if (new_client->fb_info) { - struct fb_event event; - - console_lock(); - event.info = new_client->fb_info; - fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, &event); - console_unlock(); - } + if (new_client->fb_info) + fbcon_remap_all(new_client->fb_info); mutex_lock(&vgasr_priv.mux_hw_lock); ret = vgasr_priv.handler->switchto(new_client->id); diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index 8bbe3d0cbe5d..2310c96ccf4a 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -16,7 +16,8 @@ * https://www.silabs.com/documents/public/application-notes/an495-cp2112-interface-specification.pdf */ -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/gpio/machine.h> #include <linux/gpio/driver.h> #include <linux/hid.h> #include <linux/hidraw.h> @@ -1195,7 +1196,9 @@ static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev, return -EINVAL; dev->desc[pin] = gpiochip_request_own_desc(&dev->gc, pin, - "HID/I2C:Event", 0); + "HID/I2C:Event", + GPIO_ACTIVE_HIGH, + GPIOD_IN); if (IS_ERR(dev->desc[pin])) { dev_err(dev->gc.parent, "Failed to request GPIO\n"); return PTR_ERR(dev->desc[pin]); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index eac0c54c5970..b032d3899fa3 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -80,6 +80,7 @@ #define HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP 0x1220 #define HID_DEVICE_ID_ALPS_U1 0x1215 #define HID_DEVICE_ID_ALPS_T4_BTNLESS 0x120C +#define HID_DEVICE_ID_ALPS_1222 0x1222 #define USB_VENDOR_ID_AMI 0x046b @@ -269,6 +270,7 @@ #define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d #define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618 #define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE 0x1053 +#define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2 0x0939 #define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123 #define USB_DEVICE_ID_ASUS_AK1D 0x1125 #define USB_DEVICE_ID_CHICONY_TOSHIBA_WT10A 0x1408 @@ -569,6 +571,7 @@ #define USB_VENDOR_ID_HUION 0x256c #define USB_DEVICE_ID_HUION_TABLET 0x006e +#define USB_DEVICE_ID_HUION_HS64 0x006d #define USB_VENDOR_ID_IBM 0x04b3 #define USB_DEVICE_ID_IBM_SCROLLPOINT_III 0x3100 diff --git a/drivers/hid/hid-ite.c b/drivers/hid/hid-ite.c index 98b059d79bc8..a45f2352618d 100644 --- a/drivers/hid/hid-ite.c +++ b/drivers/hid/hid-ite.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HID driver for some ITE "special" devices * Copyright (c) 2017 Hans de Goede <hdegoede@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index e564bff86515..bfcf2ee58d14 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -30,6 +30,7 @@ #define REPORT_ID_HIDPP_SHORT 0x10 #define REPORT_ID_HIDPP_LONG 0x11 +#define REPORT_ID_HIDPP_VERY_LONG 0x12 #define HIDPP_REPORT_SHORT_LENGTH 7 #define HIDPP_REPORT_LONG_LENGTH 20 @@ -1242,7 +1243,8 @@ static int logi_dj_ll_raw_request(struct hid_device *hid, int ret; if ((buf[0] == REPORT_ID_HIDPP_SHORT) || - (buf[0] == REPORT_ID_HIDPP_LONG)) { + (buf[0] == REPORT_ID_HIDPP_LONG) || + (buf[0] == REPORT_ID_HIDPP_VERY_LONG)) { if (count < 2) return -EINVAL; diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 5df5dd56ecc8..b603c14d043b 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1776,6 +1776,10 @@ static const struct hid_device_id mt_devices[] = { HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP) }, + { .driver_data = MT_CLS_WIN_8_DUAL, + HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, + USB_VENDOR_ID_ALPS_JP, + HID_DEVICE_ID_ALPS_1222) }, /* Lenovo X1 TAB Gen 2 */ { .driver_data = MT_CLS_WIN_8_DUAL, diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c index 6897e14e7cb7..e162a668fb7e 100644 --- a/drivers/hid/hid-picolcd_fb.c +++ b/drivers/hid/hid-picolcd_fb.c @@ -512,10 +512,8 @@ int picolcd_init_framebuffer(struct picolcd_data *data) sizeof(struct fb_deferred_io) + sizeof(struct picolcd_fb_data) + PICOLCDFB_SIZE, dev); - if (info == NULL) { - dev_err(dev, "failed to allocate a framebuffer\n"); + if (!info) goto err_nomem; - } info->fbdefio = info->par; *info->fbdefio = picolcd_fb_defio; diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index e5ca6fe2ca57..671a285724f9 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -42,6 +42,7 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD), HID_QUIRK_BADPAD }, { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK), HID_QUIRK_NOGET }, diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index 8fe02d81265d..914fb527ae7a 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -369,6 +369,8 @@ static const struct hid_device_id uclogic_devices[] = { USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) }, { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) }, + { HID_USB_DEVICE(USB_VENDOR_ID_HUION, + USB_DEVICE_ID_HUION_HS64) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 0187c9f8fc22..273d784fff66 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -977,6 +977,8 @@ int uclogic_params_init(struct uclogic_params *params, /* FALL THROUGH */ case VID_PID(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET): + case VID_PID(USB_VENDOR_ID_HUION, + USB_DEVICE_ID_HUION_HS64): case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET): case VID_PID(USB_VENDOR_ID_UCLOGIC, diff --git a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c index 22ba21457035..aa2dbed30fc3 100644 --- a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c +++ b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c @@ -816,9 +816,9 @@ static int load_fw_from_host(struct ishtp_cl_data *client_data) goto end_err_fw_release; release_firmware(fw); - kfree(filename); dev_info(cl_data_to_dev(client_data), "ISH firmware %s loaded\n", filename); + kfree(filename); return 0; end_err_fw_release: diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c index c0487b34d2cf..6ba944b40fdb 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c @@ -891,7 +891,7 @@ static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device) */ static int hid_ishtp_cl_suspend(struct device *device) { - struct ishtp_cl_device *cl_device = dev_get_drvdata(device); + struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device); struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device); struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl); @@ -912,7 +912,7 @@ static int hid_ishtp_cl_suspend(struct device *device) */ static int hid_ishtp_cl_resume(struct device *device) { - struct ishtp_cl_device *cl_device = dev_get_drvdata(device); + struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device); struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device); struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl); diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index 794e700d65f7..c47c3328a0f4 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -471,7 +471,6 @@ static struct ishtp_cl_device *ishtp_bus_add_device(struct ishtp_device *dev, } ishtp_device_ready = true; - dev_set_drvdata(&device->dev, device); return device; } @@ -640,6 +639,20 @@ void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device) EXPORT_SYMBOL(ishtp_get_drvdata); /** + * ishtp_dev_to_cl_device() - get ishtp_cl_device instance from device instance + * @device: device instance + * + * Get ish_cl_device instance which embeds device instance in it. + * + * Return: pointer to ishtp_cl_device instance + */ +struct ishtp_cl_device *ishtp_dev_to_cl_device(struct device *device) +{ + return to_ishtp_cl_device(device); +} +EXPORT_SYMBOL(ishtp_dev_to_cl_device); + +/** * ishtp_bus_new_client() - Create a new client * @dev: ISHTP device instance * diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 1c1a2514d6f3..9a59957922d4 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig @@ -6,10 +6,14 @@ config HYPERV tristate "Microsoft Hyper-V client drivers" depends on X86 && ACPI && X86_LOCAL_APIC && HYPERVISOR_GUEST select PARAVIRT + select X86_HV_CALLBACK_VECTOR help Select this option to run Linux as a Hyper-V client operating system. +config HYPERV_TIMER + def_bool HYPERV + config HYPERV_TSCPAGE def_bool HYPERV && X86_64 diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index a1ea482183e8..6188fb7dda42 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -16,6 +16,7 @@ #include <linux/version.h> #include <linux/random.h> #include <linux/clockchips.h> +#include <clocksource/hyperv_timer.h> #include <asm/mshyperv.h> #include "hyperv_vmbus.h" @@ -23,21 +24,6 @@ struct hv_context hv_context; /* - * If false, we're using the old mechanism for stimer0 interrupts - * where it sends a VMbus message when it expires. The old - * mechanism is used when running on older versions of Hyper-V - * that don't support Direct Mode. While Hyper-V provides - * four stimer's per CPU, Linux uses only stimer0. - */ -static bool direct_mode_enabled; -static int stimer0_irq; -static int stimer0_vector; - -#define HV_TIMER_FREQUENCY (10 * 1000 * 1000) /* 100ns period */ -#define HV_MAX_MAX_DELTA_TICKS 0xffffffff -#define HV_MIN_DELTA_TICKS 1 - -/* * hv_init - Main initialization routine. * * This routine must be called before any other routines in here are called @@ -47,9 +33,6 @@ int hv_init(void) hv_context.cpu_context = alloc_percpu(struct hv_per_cpu_context); if (!hv_context.cpu_context) return -ENOMEM; - - direct_mode_enabled = ms_hyperv.misc_features & - HV_STIMER_DIRECT_MODE_AVAILABLE; return 0; } @@ -88,89 +71,6 @@ int hv_post_message(union hv_connection_id connection_id, return status & 0xFFFF; } -/* - * ISR for when stimer0 is operating in Direct Mode. Direct Mode - * does not use VMbus or any VMbus messages, so process here and not - * in the VMbus driver code. - */ - -static void hv_stimer0_isr(void) -{ - struct hv_per_cpu_context *hv_cpu; - - hv_cpu = this_cpu_ptr(hv_context.cpu_context); - hv_cpu->clk_evt->event_handler(hv_cpu->clk_evt); - add_interrupt_randomness(stimer0_vector, 0); -} - -static int hv_ce_set_next_event(unsigned long delta, - struct clock_event_device *evt) -{ - u64 current_tick; - - WARN_ON(!clockevent_state_oneshot(evt)); - - current_tick = hyperv_cs->read(NULL); - current_tick += delta; - hv_init_timer(0, current_tick); - return 0; -} - -static int hv_ce_shutdown(struct clock_event_device *evt) -{ - hv_init_timer(0, 0); - hv_init_timer_config(0, 0); - if (direct_mode_enabled) - hv_disable_stimer0_percpu_irq(stimer0_irq); - - return 0; -} - -static int hv_ce_set_oneshot(struct clock_event_device *evt) -{ - union hv_stimer_config timer_cfg; - - timer_cfg.as_uint64 = 0; - timer_cfg.enable = 1; - timer_cfg.auto_enable = 1; - if (direct_mode_enabled) { - /* - * When it expires, the timer will directly interrupt - * on the specified hardware vector/IRQ. - */ - timer_cfg.direct_mode = 1; - timer_cfg.apic_vector = stimer0_vector; - hv_enable_stimer0_percpu_irq(stimer0_irq); - } else { - /* - * When it expires, the timer will generate a VMbus message, - * to be handled by the normal VMbus interrupt handler. - */ - timer_cfg.direct_mode = 0; - timer_cfg.sintx = VMBUS_MESSAGE_SINT; - } - hv_init_timer_config(0, timer_cfg.as_uint64); - return 0; -} - -static void hv_init_clockevent_device(struct clock_event_device *dev, int cpu) -{ - dev->name = "Hyper-V clockevent"; - dev->features = CLOCK_EVT_FEAT_ONESHOT; - dev->cpumask = cpumask_of(cpu); - dev->rating = 1000; - /* - * Avoid settint dev->owner = THIS_MODULE deliberately as doing so will - * result in clockevents_config_and_register() taking additional - * references to the hv_vmbus module making it impossible to unload. - */ - - dev->set_state_shutdown = hv_ce_shutdown; - dev->set_state_oneshot = hv_ce_set_oneshot; - dev->set_next_event = hv_ce_set_next_event; -} - - int hv_synic_alloc(void) { int cpu; @@ -199,14 +99,6 @@ int hv_synic_alloc(void) tasklet_init(&hv_cpu->msg_dpc, vmbus_on_msg_dpc, (unsigned long) hv_cpu); - hv_cpu->clk_evt = kzalloc(sizeof(struct clock_event_device), - GFP_KERNEL); - if (hv_cpu->clk_evt == NULL) { - pr_err("Unable to allocate clock event device\n"); - goto err; - } - hv_init_clockevent_device(hv_cpu->clk_evt, cpu); - hv_cpu->synic_message_page = (void *)get_zeroed_page(GFP_ATOMIC); if (hv_cpu->synic_message_page == NULL) { @@ -229,11 +121,6 @@ int hv_synic_alloc(void) INIT_LIST_HEAD(&hv_cpu->chan_list); } - if (direct_mode_enabled && - hv_setup_stimer0_irq(&stimer0_irq, &stimer0_vector, - hv_stimer0_isr)) - goto err; - return 0; err: /* @@ -252,7 +139,6 @@ void hv_synic_free(void) struct hv_per_cpu_context *hv_cpu = per_cpu_ptr(hv_context.cpu_context, cpu); - kfree(hv_cpu->clk_evt); free_page((unsigned long)hv_cpu->synic_event_page); free_page((unsigned long)hv_cpu->synic_message_page); free_page((unsigned long)hv_cpu->post_msg_page); @@ -311,36 +197,9 @@ int hv_synic_init(unsigned int cpu) hv_set_synic_state(sctrl.as_uint64); - /* - * Register the per-cpu clockevent source. - */ - if (ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE) - clockevents_config_and_register(hv_cpu->clk_evt, - HV_TIMER_FREQUENCY, - HV_MIN_DELTA_TICKS, - HV_MAX_MAX_DELTA_TICKS); - return 0; -} - -/* - * hv_synic_clockevents_cleanup - Cleanup clockevent devices - */ -void hv_synic_clockevents_cleanup(void) -{ - int cpu; + hv_stimer_init(cpu); - if (!(ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE)) - return; - - if (direct_mode_enabled) - hv_remove_stimer0_irq(stimer0_irq); - - for_each_present_cpu(cpu) { - struct hv_per_cpu_context *hv_cpu - = per_cpu_ptr(hv_context.cpu_context, cpu); - - clockevents_unbind_device(hv_cpu->clk_evt, cpu); - } + return 0; } /* @@ -388,14 +247,7 @@ int hv_synic_cleanup(unsigned int cpu) if (channel_found && vmbus_connection.conn_state == CONNECTED) return -EBUSY; - /* Turn off clockevent device */ - if (ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE) { - struct hv_per_cpu_context *hv_cpu - = this_cpu_ptr(hv_context.cpu_context); - - clockevents_unbind_device(hv_cpu->clk_evt, cpu); - hv_ce_shutdown(hv_cpu->clk_evt); - } + hv_stimer_cleanup(cpu); hv_get_synint_state(VMBUS_MESSAGE_SINT, shared_sint.as_uint64); diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index 7d3d31f099ea..e32681ee7b9f 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c @@ -17,6 +17,7 @@ #include <linux/hyperv.h> #include <linux/clockchips.h> #include <linux/ptp_clock_kernel.h> +#include <clocksource/hyperv_timer.h> #include <asm/mshyperv.h> #include "hyperv_vmbus.h" diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index b8e1ff05f110..362e70e9d145 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -138,7 +138,6 @@ struct hv_per_cpu_context { * per-cpu list of the channels based on their CPU affinity. */ struct list_head chan_list; - struct clock_event_device *clk_evt; }; struct hv_context { @@ -176,8 +175,6 @@ extern int hv_synic_init(unsigned int cpu); extern int hv_synic_cleanup(unsigned int cpu); -extern void hv_synic_clockevents_cleanup(void); - /* Interface */ void hv_ringbuffer_pre_init(struct vmbus_channel *channel); diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 92b1874b3eb3..72d5a7cde7ea 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -30,6 +30,7 @@ #include <linux/kdebug.h> #include <linux/efi.h> #include <linux/random.h> +#include <clocksource/hyperv_timer.h> #include "hyperv_vmbus.h" struct vmbus_dynid { @@ -955,17 +956,6 @@ static void vmbus_onmessage_work(struct work_struct *work) kfree(ctx); } -static void hv_process_timer_expiration(struct hv_message *msg, - struct hv_per_cpu_context *hv_cpu) -{ - struct clock_event_device *dev = hv_cpu->clk_evt; - - if (dev->event_handler) - dev->event_handler(dev); - - vmbus_signal_eom(msg, HVMSG_TIMER_EXPIRED); -} - void vmbus_on_msg_dpc(unsigned long data) { struct hv_per_cpu_context *hv_cpu = (void *)data; @@ -1159,9 +1149,10 @@ static void vmbus_isr(void) /* Check if there are actual msgs to be processed */ if (msg->header.message_type != HVMSG_NONE) { - if (msg->header.message_type == HVMSG_TIMER_EXPIRED) - hv_process_timer_expiration(msg, hv_cpu); - else + if (msg->header.message_type == HVMSG_TIMER_EXPIRED) { + hv_stimer0_isr(); + vmbus_signal_eom(msg, HVMSG_TIMER_EXPIRED); + } else tasklet_schedule(&hv_cpu->msg_dpc); } @@ -1263,14 +1254,19 @@ static int vmbus_bus_init(void) ret = hv_synic_alloc(); if (ret) goto err_alloc; + + ret = hv_stimer_alloc(VMBUS_MESSAGE_SINT); + if (ret < 0) + goto err_alloc; + /* - * Initialize the per-cpu interrupt state and - * connect to the host. + * Initialize the per-cpu interrupt state and stimer state. + * Then connect to the host. */ ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online", hv_synic_init, hv_synic_cleanup); if (ret < 0) - goto err_alloc; + goto err_cpuhp; hyperv_cpuhp_online = ret; ret = vmbus_connect(); @@ -1318,6 +1314,8 @@ static int vmbus_bus_init(void) err_connect: cpuhp_remove_state(hyperv_cpuhp_online); +err_cpuhp: + hv_stimer_free(); err_alloc: hv_synic_free(); hv_remove_vmbus_irq(); @@ -2064,7 +2062,7 @@ static struct acpi_driver vmbus_acpi_driver = { static void hv_kexec_handler(void) { - hv_synic_clockevents_cleanup(); + hv_stimer_global_cleanup(); vmbus_initiate_unload(false); vmbus_connection.conn_state = DISCONNECTED; /* Make sure conn_state is set as hv_synic_cleanup checks for it */ @@ -2075,6 +2073,8 @@ static void hv_kexec_handler(void) static void hv_crash_handler(struct pt_regs *regs) { + int cpu; + vmbus_initiate_unload(true); /* * In crash handler we can't schedule synic cleanup for all CPUs, @@ -2082,7 +2082,9 @@ static void hv_crash_handler(struct pt_regs *regs) * for kdump. */ vmbus_connection.conn_state = DISCONNECTED; - hv_synic_cleanup(smp_processor_id()); + cpu = smp_processor_id(); + hv_stimer_cleanup(cpu); + hv_synic_cleanup(cpu); hyperv_cleanup(); }; @@ -2131,7 +2133,7 @@ static void __exit vmbus_exit(void) hv_remove_kexec_handler(); hv_remove_crash_handler(); vmbus_connection.conn_state = DISCONNECTED; - hv_synic_clockevents_cleanup(); + hv_stimer_global_cleanup(); vmbus_disconnect(); hv_remove_vmbus_irq(); for_each_online_cpu(cpu) { diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index 44a827b031cb..c7010b91bc13 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for the ADT7411 (I2C/SPI 8 channel 10 bit ADC & temperature-sensor) * * Copyright (C) 2008, 2010 Pengutronix * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * TODO: SPI, use power-down mode for suspend?, interrupt handling? */ diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 7caec127df86..c3c6031a7285 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * adt7475 - Thermal sensor driver for the ADT7475 chip and derivatives * Copyright (C) 2007-2008, Advanced Micro Devices, Inc. @@ -6,10 +7,6 @@ * Copyright (C) 2009 Jean Delvare <jdelvare@suse.de> * * Derived from the lm83 driver by Jean Delvare - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 4d0d6c86c12f..fe6618e49dc4 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -96,10 +96,10 @@ struct platform_data { struct device_attribute name_attr; }; -/* Keep track of how many package pointers we allocated in init() */ -static int max_packages __read_mostly; -/* Array of package pointers. Serialized by cpu hotplug lock */ -static struct platform_device **pkg_devices; +/* Keep track of how many zone pointers we allocated in init() */ +static int max_zones __read_mostly; +/* Array of zone pointers. Serialized by cpu hotplug lock */ +static struct platform_device **zone_devices; static ssize_t show_label(struct device *dev, struct device_attribute *devattr, char *buf) @@ -422,10 +422,10 @@ static int chk_ucode_version(unsigned int cpu) static struct platform_device *coretemp_get_pdev(unsigned int cpu) { - int pkgid = topology_logical_package_id(cpu); + int id = topology_logical_die_id(cpu); - if (pkgid >= 0 && pkgid < max_packages) - return pkg_devices[pkgid]; + if (id >= 0 && id < max_zones) + return zone_devices[id]; return NULL; } @@ -531,7 +531,7 @@ static int coretemp_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct platform_data *pdata; - /* Initialize the per-package data structures */ + /* Initialize the per-zone data structures */ pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL); if (!pdata) return -ENOMEM; @@ -566,13 +566,13 @@ static struct platform_driver coretemp_driver = { static struct platform_device *coretemp_device_add(unsigned int cpu) { - int err, pkgid = topology_logical_package_id(cpu); + int err, zoneid = topology_logical_die_id(cpu); struct platform_device *pdev; - if (pkgid < 0) + if (zoneid < 0) return ERR_PTR(-ENOMEM); - pdev = platform_device_alloc(DRVNAME, pkgid); + pdev = platform_device_alloc(DRVNAME, zoneid); if (!pdev) return ERR_PTR(-ENOMEM); @@ -582,7 +582,7 @@ static struct platform_device *coretemp_device_add(unsigned int cpu) return ERR_PTR(err); } - pkg_devices[pkgid] = pdev; + zone_devices[zoneid] = pdev; return pdev; } @@ -690,7 +690,7 @@ static int coretemp_cpu_offline(unsigned int cpu) * the rest. */ if (cpumask_empty(&pd->cpumask)) { - pkg_devices[topology_logical_package_id(cpu)] = NULL; + zone_devices[topology_logical_die_id(cpu)] = NULL; platform_device_unregister(pdev); return 0; } @@ -728,10 +728,10 @@ static int __init coretemp_init(void) if (!x86_match_cpu(coretemp_ids)) return -ENODEV; - max_packages = topology_max_packages(); - pkg_devices = kcalloc(max_packages, sizeof(struct platform_device *), + max_zones = topology_max_packages() * topology_max_die_per_package(); + zone_devices = kcalloc(max_zones, sizeof(struct platform_device *), GFP_KERNEL); - if (!pkg_devices) + if (!zone_devices) return -ENOMEM; err = platform_driver_register(&coretemp_driver); @@ -747,7 +747,7 @@ static int __init coretemp_init(void) outdrv: platform_driver_unregister(&coretemp_driver); - kfree(pkg_devices); + kfree(zone_devices); return err; } module_init(coretemp_init) @@ -756,7 +756,7 @@ static void __exit coretemp_exit(void) { cpuhp_remove_state(coretemp_hp_online); platform_driver_unregister(&coretemp_driver); - kfree(pkg_devices); + kfree(zone_devices); } module_exit(coretemp_exit) diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index 1770423f7a80..f1c2d5faedf0 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Hwmon client for industrial I/O devices * * Copyright (c) 2011 Jonathan Cameron - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c index dd6a35219a18..56add579e32f 100644 --- a/drivers/hwmon/max197.c +++ b/drivers/hwmon/max197.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Maxim MAX197 A/D Converter driver * * Copyright (c) 2012 Savoir-faire Linux Inc. * Vivien Didelot <vivien.didelot@savoirfairelinux.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * For further information, see the Documentation/hwmon/max197.rst file. */ diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c index fa3763e4b3ee..34bbbb8c52f6 100644 --- a/drivers/i2c/busses/i2c-acorn.c +++ b/drivers/i2c/busses/i2c-acorn.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ARM IOC/IOMD i2c driver. * * Copyright (C) 2000 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * On Acorn machines, the following i2c devices are on the bus: * - PCF8583 real time clock & static RAM */ diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 6c8b38fd6e64..fa66951b05d0 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Aspeed 24XX/25XX I2C Controller. * * Copyright (C) 2012-2017 ASPEED Technology Inc. * Copyright 2017 IBM Corporation * Copyright 2017 Google, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c index 1c7b41f45c83..ff3142b15cab 100644 --- a/drivers/i2c/busses/i2c-axxia.c +++ b/drivers/i2c/busses/i2c-axxia.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * This driver implements I2C master functionality using the LSI API2C * controller. @@ -5,10 +6,6 @@ * NOTE: The controller has a limitation in that it can only do transfers of * maximum 255 bytes at a time. If a larger transfer is attempted, error code * (-EINVAL) is returned. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. */ #include <linux/clk.h> #include <linux/clkdev.h> diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c index 50813a24c541..3adf72540db1 100644 --- a/drivers/i2c/busses/i2c-digicolor.c +++ b/drivers/i2c/busses/i2c-digicolor.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C bus driver for Conexant Digicolor SoCs * * Author: Baruch Siach <baruch@tkos.co.il> * * Copyright (C) 2015 Paradox Innovation Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c index 5f2bab878b2c..a8c6323e7f44 100644 --- a/drivers/i2c/busses/i2c-efm32.c +++ b/drivers/i2c/busses/i2c-efm32.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Uwe Kleine-Koenig for Pengutronix - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. */ #include <linux/module.h> #include <linux/platform_device.h> diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 41de4ee409b6..e4e7932f7800 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /** * i2c-exynos5.c - Samsung Exynos5 I2C Controller Driver * * Copyright (C) 2013 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 9684a0ac2a6d..3a9e840a3546 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Bitbanging I2C bus driver using the GPIO API * * Copyright (C) 2007 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/completion.h> #include <linux/debugfs.h> diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index f038858b6c54..20a4fbc53007 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C adapter for the IMG Serial Control Bus (SCB) IP block. * * Copyright (C) 2009, 2010, 2012, 2014 Imagination Technologies Ltd. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * There are three ways that this I2C controller can be driven: * * - Raw control of the SDA and SCK signals. diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 90f5d0407d73..1e2647f9a2a7 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C bus driver for Amlogic Meson SoCs * * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 4f30a43b63da..01a7d72e5511 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 ST-Ericsson SA * Copyright (C) 2009 STMicroelectronics @@ -7,10 +8,6 @@ * * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> * Author: Sachin Verma <sachin.verma@st.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. */ #include <linux/init.h> #include <linux/module.h> diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index f50afa8e3cba..a7a81846d5b1 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * i2c_pca_platform.c * @@ -5,9 +6,6 @@ * * Copyright (C) 2008 Pengutronix * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/i2c/busses/i2c-puv3.c b/drivers/i2c/busses/i2c-puv3.c index 287088b8c4c8..5cec5a36807d 100644 --- a/drivers/i2c/busses/i2c-puv3.c +++ b/drivers/i2c/busses/i2c-puv3.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C driver for PKUnity-v3 SoC * Code specific to PKUnity SoC and UniCore ISA * * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> * Copyright (C) 2001-2010 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index 72ea8f4c61aa..f614cade432b 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * CE4100 PCI-I2C glue code for PXA's driver * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de> - * License: GPL v2 * * The CE4100's I2C device is more or less the same one as found on PXA. * It does not support slave mode, the register slightly moved. This PCI diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index fbf91d383b40..2c3c3d6935c0 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * i2c_adap_pxa.c * @@ -6,10 +7,6 @@ * Copyright (C) 2002 Intrinsyc Software Inc. * Copyright (C) 2004-2005 Deep Blue Solutions Ltd. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * History: * Apr 2002: Initial version [CS] * Jun 2002: Properly separated algo/adap [FB] diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index b8a2728dd4b6..1a33007b03e9 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for I2C adapter in Rockchip RK3xxx SoC * * Max Schwarz <max.schwarz@online.de> * based on the patches by Rockchip Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c index adca51a99487..458c7bcf1d24 100644 --- a/drivers/i2c/busses/i2c-simtec.c +++ b/drivers/i2c/busses/i2c-simtec.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2005 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * * Simtec Generic I2C Controller - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/kernel.h> diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 9e62f893958a..54e1fc8a495e 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 STMicroelectronics * * I2C master mode controller driver, used in STMicroelectronics devices. * * Author: Maxime Coquelin <maxime.coquelin@st.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c index f1ab2a637ec0..8d980b1374a8 100644 --- a/drivers/i2c/busses/i2c-versatile.c +++ b/drivers/i2c/busses/i2c-versatile.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * i2c-versatile.c * * Copyright (C) 2006 ARM Ltd. * written by Russell King, Deep Blue Solutions Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/i2c/busses/i2c-zx2967.c b/drivers/i2c/busses/i2c-zx2967.c index 7b98d97da3c6..5f3318559b8d 100644 --- a/drivers/i2c/busses/i2c-zx2967.c +++ b/drivers/i2c/busses/i2c-zx2967.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 Sanechips Technology Co., Ltd. * Copyright 2017 Linaro Ltd. * * Author: Baoyou Xie <baoyou.xie@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index d84095591e45..f86065e16772 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -111,8 +111,7 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev, struct list_head resource_list; int ret; - if (acpi_bus_get_status(adev) || !adev->status.present || - acpi_device_enumerated(adev)) + if (acpi_bus_get_status(adev) || !adev->status.present) return -EINVAL; if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0) @@ -147,6 +146,9 @@ static int i2c_acpi_get_info(struct acpi_device *adev, lookup.info = info; lookup.index = -1; + if (acpi_device_enumerated(adev)) + return -EINVAL; + ret = i2c_acpi_do_lookup(adev, &lookup); if (ret) return ret; diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 13882a2a4f60..14dc2deba283 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C multiplexer using GPIO API * * Peter Korsgaard <peter.korsgaard@barco.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/i2c.h> diff --git a/drivers/i2c/muxes/i2c-mux-gpmux.c b/drivers/i2c/muxes/i2c-mux-gpmux.c index f60b670deff7..f830535cff12 100644 --- a/drivers/i2c/muxes/i2c-mux-gpmux.c +++ b/drivers/i2c/muxes/i2c-mux-gpmux.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * General Purpose I2C multiplexer * * Copyright (C) 2017 Axentia Technologies AB * * Author: Peter Rosin <peda@axentia.se> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/i2c.h> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 5f4bd52121fe..d6f8b038a896 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -91,6 +91,12 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus) up_read(&bus->lock); } +static struct i3c_master_controller * +i3c_bus_to_i3c_master(struct i3c_bus *i3cbus) +{ + return container_of(i3cbus, struct i3c_master_controller, bus); +} + static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev) { return container_of(dev, struct i3c_master_controller, dev); @@ -464,6 +470,7 @@ static int i3c_bus_init(struct i3c_bus *i3cbus) static const char * const i3c_bus_mode_strings[] = { [I3C_BUS_MODE_PURE] = "pure", [I3C_BUS_MODE_MIXED_FAST] = "mixed-fast", + [I3C_BUS_MODE_MIXED_LIMITED] = "mixed-limited", [I3C_BUS_MODE_MIXED_SLOW] = "mixed-slow", }; @@ -565,20 +572,39 @@ static const struct device_type i3c_masterdev_type = { .groups = i3c_masterdev_groups, }; -int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode) +int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, + unsigned long max_i2c_scl_rate) { - i3cbus->mode = mode; + struct i3c_master_controller *master = i3c_bus_to_i3c_master(i3cbus); - if (!i3cbus->scl_rate.i3c) - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; + i3cbus->mode = mode; - if (!i3cbus->scl_rate.i2c) { - if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW) - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; - else - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_PLUS_SCL_RATE; + switch (i3cbus->mode) { + case I3C_BUS_MODE_PURE: + if (!i3cbus->scl_rate.i3c) + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; + break; + case I3C_BUS_MODE_MIXED_FAST: + case I3C_BUS_MODE_MIXED_LIMITED: + if (!i3cbus->scl_rate.i3c) + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; + if (!i3cbus->scl_rate.i2c) + i3cbus->scl_rate.i2c = max_i2c_scl_rate; + break; + case I3C_BUS_MODE_MIXED_SLOW: + if (!i3cbus->scl_rate.i2c) + i3cbus->scl_rate.i2c = max_i2c_scl_rate; + if (!i3cbus->scl_rate.i3c || + i3cbus->scl_rate.i3c > i3cbus->scl_rate.i2c) + i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; + break; + default: + return -EINVAL; } + dev_dbg(&master->dev, "i2c-scl = %ld Hz i3c-scl = %ld Hz\n", + i3cbus->scl_rate.i2c, i3cbus->scl_rate.i3c); + /* * I3C/I2C frequency may have been overridden, check that user-provided * values are not exceeding max possible frequency. @@ -924,9 +950,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master) ndevs++; defslvs = i3c_ccc_cmd_dest_init(&dest, I3C_BROADCAST_ADDR, - sizeof(*defslvs) + - ((ndevs - 1) * - sizeof(struct i3c_ccc_dev_desc))); + struct_size(defslvs, slaves, + ndevs - 1)); if (!defslvs) return -ENOMEM; @@ -1963,12 +1988,19 @@ of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master, if (ret) return ret; + /* + * The I3C Specification does not clearly say I2C devices with 10-bit + * address are supported. These devices can't be passed properly through + * DEFSLVS command. + */ + if (boardinfo->base.flags & I2C_CLIENT_TEN) { + dev_err(&master->dev, "I2C device with 10 bit address not supported."); + return -ENOTSUPP; + } + /* LVR is encoded in reg[2]. */ boardinfo->lvr = reg[2]; - if (boardinfo->lvr & I3C_LVR_I2C_FM_MODE) - master->bus.scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; - list_add_tail(&boardinfo->node, &master->boardinfo.i2c); of_node_get(node); @@ -2111,16 +2143,14 @@ static int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap, return ret ? ret : nxfers; } -static u32 i3c_master_i2c_functionalities(struct i2c_adapter *adap) +static u32 i3c_master_i2c_funcs(struct i2c_adapter *adapter) { - struct i3c_master_controller *master = i2c_adapter_to_i3c_master(adap); - - return master->ops->i2c_funcs(master); + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; } static const struct i2c_algorithm i3c_master_i2c_algo = { .master_xfer = i3c_master_i2c_adapter_xfer, - .functionality = i3c_master_i2c_functionalities, + .functionality = i3c_master_i2c_funcs, }; static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master) @@ -2379,8 +2409,7 @@ 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 || !ops->priv_xfers || - !ops->send_ccc_cmd || !ops->do_daa || !ops->i2c_xfers || - !ops->i2c_funcs) + !ops->send_ccc_cmd || !ops->do_daa || !ops->i2c_xfers) return -EINVAL; if (ops->request_ibi && @@ -2417,6 +2446,7 @@ int i3c_master_register(struct i3c_master_controller *master, const struct i3c_master_controller_ops *ops, bool secondary) { + unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_RATE; struct i3c_bus *i3cbus = i3c_master_get_bus(master); enum i3c_bus_mode mode = I3C_BUS_MODE_PURE; struct i2c_dev_boardinfo *i2cbi; @@ -2458,6 +2488,9 @@ int i3c_master_register(struct i3c_master_controller *master, mode = I3C_BUS_MODE_MIXED_FAST; break; case I3C_LVR_I2C_INDEX(1): + if (mode < I3C_BUS_MODE_MIXED_LIMITED) + mode = I3C_BUS_MODE_MIXED_LIMITED; + break; case I3C_LVR_I2C_INDEX(2): if (mode < I3C_BUS_MODE_MIXED_SLOW) mode = I3C_BUS_MODE_MIXED_SLOW; @@ -2466,9 +2499,12 @@ int i3c_master_register(struct i3c_master_controller *master, ret = -EINVAL; goto err_put_dev; } + + if (i2cbi->lvr & I3C_LVR_I2C_FM_MODE) + i2c_scl_rate = I3C_BUS_I2C_FM_SCL_RATE; } - ret = i3c_bus_set_mode(i3cbus, mode); + ret = i3c_bus_set_mode(i3cbus, mode, i2c_scl_rate); if (ret) goto err_put_dev; diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 1d83c97431c7..09912d75c6d5 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -599,6 +599,7 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m) switch (bus->mode) { case I3C_BUS_MODE_MIXED_FAST: + case I3C_BUS_MODE_MIXED_LIMITED: ret = dw_i2c_clk_cfg(master); if (ret) return ret; @@ -1060,11 +1061,6 @@ static void dw_i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev) kfree(data); } -static u32 dw_i3c_master_i2c_funcs(struct i3c_master_controller *m) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - static irqreturn_t dw_i3c_master_irq_handler(int irq, void *dev_id) { struct dw_i3c_master *master = dev_id; @@ -1099,7 +1095,6 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = { .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, - .i2c_funcs = dw_i3c_master_i2c_funcs, }; static int dw_i3c_probe(struct platform_device *pdev) diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c index 8889a4fdb454..237f24adddc6 100644 --- a/drivers/i3c/master/i3c-master-cdns.c +++ b/drivers/i3c/master/i3c-master-cdns.c @@ -864,11 +864,6 @@ static int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, return ret; } -static u32 cdns_i3c_master_i2c_funcs(struct i3c_master_controller *m) -{ - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR; -} - struct cdns_i3c_i2c_dev_data { u16 id; s16 ibi; @@ -1010,9 +1005,7 @@ static int cdns_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev) master->free_rr_slots &= ~BIT(slot); i2c_dev_set_master_data(dev, data); - writel(prepare_rr0_dev_address(dev->boardinfo->base.addr) | - (dev->boardinfo->base.flags & I2C_CLIENT_TEN ? - DEV_ID_RR0_LVR_EXT_ADDR : 0), + writel(prepare_rr0_dev_address(dev->boardinfo->base.addr), master->regs + DEV_ID_RR0(data->id)); writel(dev->boardinfo->lvr, master->regs + DEV_ID_RR2(data->id)); writel(readl(master->regs + DEVS_CTRL) | @@ -1518,7 +1511,6 @@ static const struct i3c_master_controller_ops cdns_i3c_master_ops = { .send_ccc_cmd = cdns_i3c_master_send_ccc_cmd, .priv_xfers = cdns_i3c_master_priv_xfers, .i2c_xfers = cdns_i3c_master_i2c_xfers, - .i2c_funcs = cdns_i3c_master_i2c_funcs, .enable_ibi = cdns_i3c_master_enable_ibi, .disable_ibi = cdns_i3c_master_disable_ibi, .request_ibi = cdns_i3c_master_request_ibi, diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c index cbfe846911d1..7340597a373e 100644 --- a/drivers/ide/amd74xx.c +++ b/drivers/ide/amd74xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04 * IDE driver for Linux. @@ -9,11 +10,6 @@ * Andre Hedrick */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ #include <linux/module.h> #include <linux/kernel.h> diff --git a/drivers/ide/cs5535.c b/drivers/ide/cs5535.c index 3bc5b9a34013..70fdbe3161f8 100644 --- a/drivers/ide/cs5535.c +++ b/drivers/ide/cs5535.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2004-2005 Advanced Micro Devices, Inc. * Copyright (C) 2007 Bartlomiej Zolnierkiewicz @@ -14,10 +15,6 @@ * Development of this chipset driver was funded * by the nice folks at National Semiconductor/AMD. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Documentation: * CS5535 documentation available from AMD */ diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c index 01464f1e2339..977cb00398b0 100644 --- a/drivers/ide/via82cxxx.c +++ b/drivers/ide/via82cxxx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * VIA IDE driver for Linux. Supported southbridges: * @@ -18,11 +19,6 @@ * Current device documentation available under NDA only */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ #include <linux/module.h> #include <linux/kernel.h> diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index 70c60db62247..0b876b2dc5bd 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * kxsd9.c simple support for the Kionix KXSD9 3D * accelerometer. * * Copyright (c) 2008-2009 Jonathan Cameron <jic23@kernel.org> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The i2c interface is very similar, so shouldn't be a problem once * I have a suitable wire made up. * diff --git a/drivers/iio/accel/mma7455.h b/drivers/iio/accel/mma7455.h index 2b1152c53d4f..4e3fa988f690 100644 --- a/drivers/iio/accel/mma7455.h +++ b/drivers/iio/accel/mma7455.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * IIO accel driver for Freescale MMA7455L 3-axis 10-bit accelerometer * Copyright 2015 Joachim Eastwood <manabian@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __MMA7455_H diff --git a/drivers/iio/accel/mma7455_core.c b/drivers/iio/accel/mma7455_core.c index da0ceaac46b5..8b5a6aff9bf4 100644 --- a/drivers/iio/accel/mma7455_core.c +++ b/drivers/iio/accel/mma7455_core.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * IIO accel core driver for Freescale MMA7455L 3-axis 10-bit accelerometer * Copyright 2015 Joachim Eastwood <manabian@gmail.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * UNSUPPORTED hardware features: * - 8-bit mode with different scales * - INT1/INT2 interrupts diff --git a/drivers/iio/accel/mma7455_i2c.c b/drivers/iio/accel/mma7455_i2c.c index 73bf81a8ab14..cddeaa9e230a 100644 --- a/drivers/iio/accel/mma7455_i2c.c +++ b/drivers/iio/accel/mma7455_i2c.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * IIO accel I2C driver for Freescale MMA7455L 3-axis 10-bit accelerometer * Copyright 2015 Joachim Eastwood <manabian@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/i2c.h> diff --git a/drivers/iio/accel/mma7455_spi.c b/drivers/iio/accel/mma7455_spi.c index 79df8f27cf99..eb82cdfa8abc 100644 --- a/drivers/iio/accel/mma7455_spi.c +++ b/drivers/iio/accel/mma7455_spi.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * IIO accel SPI driver for Freescale MMA7455L 3-axis 10-bit accelerometer * Copyright 2015 Joachim Eastwood <manabian@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c index 4964561595f5..274ce2f8bddf 100644 --- a/drivers/iio/accel/sca3000.c +++ b/drivers/iio/accel/sca3000.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * sca3000_core.c -- support VTI sca3000 series accelerometers via SPI * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Copyright (c) 2009 Jonathan Cameron <jic23@kernel.org> * * See industrialio/accels/sca3000.h for comments. diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 7a5b5d00a87d..5a3ca5904ded 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * iio/adc/ad799x.c * Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc. @@ -11,15 +12,10 @@ * based on linux/drivers/acron/char/pcf8583.c * Copyright (C) 2000 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * ad799x.c * * Support for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, * ad7998 and similar chips. - * */ #include <linux/interrupt.h> diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c index 5be789269353..88059480da17 100644 --- a/drivers/iio/adc/axp20x_adc.c +++ b/drivers/iio/adc/axp20x_adc.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* ADC driver for AXP20X and AXP22X PMICs * * Copyright (c) 2016 Free Electrons NextThing Co. * Quentin Schulz <quentin.schulz@free-electrons.com> - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. */ #include <linux/completion.h> diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c index 7af59a4bbd8d..c46c0aa15376 100644 --- a/drivers/iio/adc/bcm_iproc_adc.c +++ b/drivers/iio/adc/bcm_iproc_adc.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ #include <linux/module.h> diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c index 707d8b24b072..f93f1d93b80d 100644 --- a/drivers/iio/adc/cc10001_adc.c +++ b/drivers/iio/adc/cc10001_adc.c @@ -1,10 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014-2015 Imagination Technologies Ltd. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * */ #include <linux/clk.h> diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c index 5036c392cb20..5c97e8a511f2 100644 --- a/drivers/iio/adc/ep93xx_adc.c +++ b/drivers/iio/adc/ep93xx_adc.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for ADC module on the Cirrus Logic EP93xx series of SoCs * * Copyright (C) 2015 Alexander Sverdlin * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The driver uses polling to get the conversion status. According to EP93xx * datasheets, reading ADCResult register starts the conversion, but user is also * responsible for ensuring that delay between adjacent conversion triggers is diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index 929c617db364..df19ecae52f7 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014-2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de> * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. - * * This is the driver for the imx25 GCQ (Generic Conversion Queue) * connected to the imx25 ADC. */ diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c index 3bc4df916420..c1fc1b678e0f 100644 --- a/drivers/iio/adc/lp8788_adc.c +++ b/drivers/iio/adc/lp8788_adc.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LP8788 MFD - ADC driver * * Copyright 2012 Texas Instruments * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/iio/adc/lpc18xx_adc.c b/drivers/iio/adc/lpc18xx_adc.c index 041dc4a3f66c..e400a95f553d 100644 --- a/drivers/iio/adc/lpc18xx_adc.c +++ b/drivers/iio/adc/lpc18xx_adc.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * IIO ADC driver for NXP LPC18xx ADC * * Copyright (C) 2016 Joachim Eastwood <manabian@gmail.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * UNSUPPORTED hardware features: * - Hardware triggers * - Burst mode diff --git a/drivers/iio/adc/ltc2485.c b/drivers/iio/adc/ltc2485.c index b24c14037fd4..c418466d51fd 100644 --- a/drivers/iio/adc/ltc2485.c +++ b/drivers/iio/adc/ltc2485.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ltc2485.c - Driver for Linear Technology LTC2485 ADC * * Copyright (C) 2016 Alison Schofield <amsfield22@gmail.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Datasheet: http://cds.linear.com/docs/en/datasheet/2485fd.pdf */ diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c index 311c1a89c329..da84adfdb819 100644 --- a/drivers/iio/adc/max1027.c +++ b/drivers/iio/adc/max1027.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * iio/adc/max1027.c * Copyright (C) 2014 Philippe Reynes @@ -6,10 +7,6 @@ * Copyright 2011 Analog Devices Inc (from AD7923 Driver) * Copyright 2012 CS Systemes d'Information * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * max1027.c * * Partial support for max1027 and similar chips. diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index a8d35aebee80..5c2cc61b666e 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * iio/adc/max1363.c * Copyright (C) 2008-2010 Jonathan Cameron @@ -9,10 +10,6 @@ * Copyright (C) 2000 Russell King * * Driver for max1363 and similar chips. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/interrupt.h> diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c index a04856d8afdb..38bf10085696 100644 --- a/drivers/iio/adc/mcp320x.c +++ b/drivers/iio/adc/mcp320x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Oskar Andero <oskar.andero@gmail.com> * Copyright (C) 2014 Rose Technology @@ -34,10 +35,6 @@ * http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf mcp3204/08 * http://ww1.microchip.com/downloads/en/DeviceDoc/21700E.pdf mcp3301 * http://ww1.microchip.com/downloads/en/DeviceDoc/21950D.pdf mcp3550/1/3 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index 04d7147e0110..a09e7f5dd8f7 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* ADC driver for sunxi platforms' (A10, A13 and A31) GPADC * * Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com> * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. - * * The Allwinner SoCs all have an ADC that can also act as a touchscreen * controller and a thermal sensor. * The thermal sensor works only when the ADC acts as a touchscreen controller diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index 405e3779c0c5..0235863ff77b 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI ADC081C/ADC101C/ADC121C 8/10/12-bit ADC driver * * Copyright (C) 2012 Avionic Design GmbH * Copyright (C) 2016 Intel * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Datasheets: * http://www.ti.com/lit/ds/symlink/adc081c021.pdf * http://www.ti.com/lit/ds/symlink/adc101c021.pdf diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c index 25504640e126..bdedf456ee05 100644 --- a/drivers/iio/adc/ti-adc084s021.c +++ b/drivers/iio/adc/ti-adc084s021.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /** * Copyright (C) 2017 Axis Communications AB * * Driver for Texas Instruments' ADC084S021 ADC chip. * Datasheets can be found here: * http://www.ti.com/lit/ds/symlink/adc084s021.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c index 8cb7a2034982..14fe7c320b52 100644 --- a/drivers/iio/adc/ti-ads8688.c +++ b/drivers/iio/adc/ti-ads8688.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Prevas A/S - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/iio/adc/ti-tlc4541.c b/drivers/iio/adc/ti-tlc4541.c index 2290024c89fc..4965246808bd 100644 --- a/drivers/iio/adc/ti-tlc4541.c +++ b/drivers/iio/adc/ti-tlc4541.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI tlc4541 ADC Driver * @@ -7,10 +8,6 @@ * http://www.ti.com/lit/gpn/tlc3541 * http://www.ti.com/lit/gpn/tlc4541 * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The tlc4541 requires 24 clock cycles to start a transfer. * Conversion then takes 2.94us to complete before data is ready * Data is returned MSB first. diff --git a/drivers/iio/buffer/industrialio-buffer-cb.c b/drivers/iio/buffer/industrialio-buffer-cb.c index df21e7dbec40..47c96f7f4976 100644 --- a/drivers/iio/buffer/industrialio-buffer-cb.c +++ b/drivers/iio/buffer/industrialio-buffer-cb.c @@ -1,8 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* The industrial I/O callback buffer - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c index d3db1fce54d2..cb322b2f09cd 100644 --- a/drivers/iio/buffer/industrialio-triggered-buffer.c +++ b/drivers/iio/buffer/industrialio-triggered-buffer.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012 Analog Devices, Inc. * Author: Lars-Peter Clausen <lars@metafoo.de> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c index b4a46eb45789..2ebdfc35bcda 100644 --- a/drivers/iio/chemical/ccs811.c +++ b/drivers/iio/chemical/ccs811.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ccs811.c - Support for AMS CCS811 VOC Sensor * @@ -5,10 +6,6 @@ * * Datasheet: ams.com/content/download/951091/2269479/CCS811_DS000459_3-00.pdf * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * IIO driver for AMS CCS811 (I2C address 0x5A/0x5B set by ADDR Low/High) * * TODO: diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.h b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h index 7b614adc5cae..bad09c80e47a 100644 --- a/drivers/iio/common/ms_sensors/ms_sensors_i2c.h +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Measurements Specialties common sensor driver * * Copyright (c) 2015 Measurement-Specialties - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _MS_SENSORS_I2C_H diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c index 714a97f91319..030c51363ad8 100644 --- a/drivers/iio/dac/ds4424.c +++ b/drivers/iio/dac/ds4424.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Maxim Integrated * 7-bit, Multi-Channel Sink/Source Current DAC Driver * Copyright (C) 2017 Maxim Integrated - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c index 7036f77fdf23..883e84e96609 100644 --- a/drivers/iio/dac/lpc18xx_dac.c +++ b/drivers/iio/dac/lpc18xx_dac.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * IIO DAC driver for NXP LPC18xx DAC * * Copyright (C) 2016 Joachim Eastwood <manabian@gmail.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * UNSUPPORTED hardware features: * - Interrupts * - DMA diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c index f0cf6903dcd2..2da086e372af 100644 --- a/drivers/iio/dac/max5821.c +++ b/drivers/iio/dac/max5821.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * iio/dac/max5821.c * Copyright (C) 2014 Philippe Reynes - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/iio/dac/ti-dac082s085.c b/drivers/iio/dac/ti-dac082s085.c index 4e1e28339c84..57b498d2a2a5 100644 --- a/drivers/iio/dac/ti-dac082s085.c +++ b/drivers/iio/dac/ti-dac082s085.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ti-dac082s085.c - Texas Instruments 8/10/12-bit 2/4-channel DAC driver * @@ -9,10 +10,6 @@ * http://www.ti.com/lit/ds/symlink/dac084s085.pdf * http://www.ti.com/lit/ds/symlink/dac104s085.pdf * http://www.ti.com/lit/ds/symlink/dac124s085.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (version 2) as - * published by the Free Software Foundation. */ #include <linux/iio/iio.h> diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c index 891e9cac019e..3a2bb0efe50d 100644 --- a/drivers/iio/dac/ti-dac5571.c +++ b/drivers/iio/dac/ti-dac5571.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ti-dac5571.c - Texas Instruments 8/10/12-bit 1/4-channel DAC driver * @@ -12,10 +13,6 @@ * http://www.ti.com/lit/ds/symlink/dac5573.pdf * http://www.ti.com/lit/ds/symlink/dac6573.pdf * http://www.ti.com/lit/ds/symlink/dac7573.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (version 2) as - * published by the Free Software Foundation. */ #include <linux/iio/iio.h> diff --git a/drivers/iio/dummy/iio_dummy_evgen.c b/drivers/iio/dummy/iio_dummy_evgen.c index c6033e341963..a6edf30567aa 100644 --- a/drivers/iio/dummy/iio_dummy_evgen.c +++ b/drivers/iio/dummy/iio_dummy_evgen.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /** * Copyright (c) 2011 Jonathan Cameron * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Companion module to the iio simple dummy example driver. * The purpose of this is to generate 'fake' event interrupts thus * allowing that driver's code to be as close as possible to that of diff --git a/drivers/iio/dummy/iio_simple_dummy.c b/drivers/iio/dummy/iio_simple_dummy.c index 62052479c349..8f99c005458a 100644 --- a/drivers/iio/dummy/iio_simple_dummy.c +++ b/drivers/iio/dummy/iio_simple_dummy.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /** * Copyright (c) 2011 Jonathan Cameron * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * A reference industrial I/O driver to illustrate the functionality available. * * There are numerous real drivers to illustrate the finer points. diff --git a/drivers/iio/dummy/iio_simple_dummy.h b/drivers/iio/dummy/iio_simple_dummy.h index f7005c3f5df3..a91622ac54e0 100644 --- a/drivers/iio/dummy/iio_simple_dummy.h +++ b/drivers/iio/dummy/iio_simple_dummy.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /** * Copyright (c) 2011 Jonathan Cameron * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Join together the various functionality of iio_simple_dummy driver */ diff --git a/drivers/iio/dummy/iio_simple_dummy_buffer.c b/drivers/iio/dummy/iio_simple_dummy_buffer.c index 744ca92c3c99..17606eca42b4 100644 --- a/drivers/iio/dummy/iio_simple_dummy_buffer.c +++ b/drivers/iio/dummy/iio_simple_dummy_buffer.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /** * Copyright (c) 2011 Jonathan Cameron * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Buffer handling elements of industrial I/O reference driver. * Uses the kfifo buffer. * diff --git a/drivers/iio/dummy/iio_simple_dummy_events.c b/drivers/iio/dummy/iio_simple_dummy_events.c index 7ec2a0bb0807..b3abaaca6f5e 100644 --- a/drivers/iio/dummy/iio_simple_dummy_events.c +++ b/drivers/iio/dummy/iio_simple_dummy_events.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /** * Copyright (c) 2011 Jonathan Cameron * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Event handling elements of industrial I/O reference driver. */ #include <linux/kernel.h> diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c index 59770e5b6660..d3fbe9d86467 100644 --- a/drivers/iio/gyro/itg3200_buffer.c +++ b/drivers/iio/gyro/itg3200_buffer.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * itg3200_buffer.c -- support InvenSense ITG3200 * Digital 3-Axis Gyroscope driver @@ -5,10 +6,6 @@ * Copyright (c) 2011 Christian Strobel <christian.strobel@iis.fraunhofer.de> * Copyright (c) 2011 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> * Copyright (c) 2012 Thorsten Nowak <thorsten.nowak@iis.fraunhofer.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/slab.h> diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c index 203a6be33b70..998fb8d66fe3 100644 --- a/drivers/iio/gyro/itg3200_core.c +++ b/drivers/iio/gyro/itg3200_core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * itg3200_core.c -- support InvenSense ITG3200 * Digital 3-Axis Gyroscope driver @@ -6,10 +7,6 @@ * Copyright (c) 2011 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> * Copyright (c) 2012 Thorsten Nowak <thorsten.nowak@iis.fraunhofer.de> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * TODO: * - Support digital low pass filter * - Support power management diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index c8159205c77d..4e22b3c3e488 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -149,7 +149,7 @@ static int dht11_decode(struct dht11 *dht11, int offset) return -EIO; } - dht11->timestamp = ktime_get_boot_ns(); + dht11->timestamp = ktime_get_boottime_ns(); if (hum_int < 4) { /* DHT22: 100000 = (3*256+232)*100 */ dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) * ((temp_int & 0x80) ? -100 : 100); @@ -177,7 +177,7 @@ static irqreturn_t dht11_handle_irq(int irq, void *data) /* TODO: Consider making the handler safe for IRQ sharing */ if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) { - dht11->edges[dht11->num_edges].ts = ktime_get_boot_ns(); + dht11->edges[dht11->num_edges].ts = ktime_get_boottime_ns(); dht11->edges[dht11->num_edges++].value = gpio_get_value(dht11->gpio); @@ -196,7 +196,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev, int ret, timeres, offset; mutex_lock(&dht11->lock); - if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_boot_ns()) { + if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_boottime_ns()) { timeres = ktime_get_resolution_ns(); dev_dbg(dht11->dev, "current timeresolution: %dns\n", timeres); if (timeres > DHT11_MIN_TIMERES) { @@ -322,7 +322,7 @@ static int dht11_probe(struct platform_device *pdev) return -EINVAL; } - dht11->timestamp = ktime_get_boot_ns() - DHT11_DATA_VALID_TIME - 1; + dht11->timestamp = ktime_get_boottime_ns() - DHT11_DATA_VALID_TIME - 1; dht11->num_edges = -1; platform_set_drvdata(pdev, iio); diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c index 1b2ec8df1a72..b938f07eed64 100644 --- a/drivers/iio/humidity/si7020.c +++ b/drivers/iio/humidity/si7020.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * si7020.c - Silicon Labs Si7013/20/21 Relative Humidity and Temp Sensors * Copyright (c) 2013,2014 Uplogix, Inc. * David Barksdale <dbarksdale@uplogix.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ /* diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index c775fedbcaf6..159ea3f8c02b 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* The industrial I/O core function defs. * * Copyright (c) 2008 Jonathan Cameron * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * These definitions are meant for use only within the IIO core, not individual * drivers. */ diff --git a/drivers/iio/iio_core_trigger.h b/drivers/iio/iio_core_trigger.h index 1fdb1e4ea4a5..e59fe2f36bbb 100644 --- a/drivers/iio/iio_core_trigger.h +++ b/drivers/iio/iio_core_trigger.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* The industrial I/O core, trigger consumer handling functions * * Copyright (c) 2008 Jonathan Cameron - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifdef CONFIG_IIO_TRIGGER diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index beb6919e7180..0575ff706bd4 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * adis16400.c support Analog Devices ADIS16400/5 * 3d 2g Linear Accelerometers, @@ -7,11 +8,6 @@ * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> * Copyright (c) 2011 Analog Devices Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/interrupt.h> diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index ab137c1bbe7b..b99d73887c9f 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ADIS16480 and similar IMUs driver * * Copyright 2012 Analog Devices Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/clk.h> diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 72f72056b328..5e461f0e759c 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -270,6 +270,7 @@ struct st_lsm6dsx_sensor { * @conf_lock: Mutex to prevent concurrent FIFO configuration update. * @page_lock: Mutex to prevent concurrent memory page configuration. * @fifo_mode: FIFO operating mode supported by the device. + * @suspend_mask: Suspended sensor bitmask. * @enable_mask: Enabled sensor bitmask. * @ts_sip: Total number of timestamp samples in a given pattern. * @sip: Total number of samples (acc/gyro/ts) in a given pattern. @@ -287,6 +288,7 @@ struct st_lsm6dsx_hw { struct mutex page_lock; enum st_lsm6dsx_fifo_mode fifo_mode; + u8 suspend_mask; u8 enable_mask; u8 ts_sip; u8 sip; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index b6edc9886d1e..fd95d924a996 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1109,8 +1109,6 @@ static int __maybe_unused st_lsm6dsx_suspend(struct device *dev) { struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); struct st_lsm6dsx_sensor *sensor; - const struct st_lsm6dsx_reg *reg; - unsigned int data; int i, err = 0; for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { @@ -1121,12 +1119,16 @@ static int __maybe_unused st_lsm6dsx_suspend(struct device *dev) if (!(hw->enable_mask & BIT(sensor->id))) continue; - reg = &st_lsm6dsx_odr_table[sensor->id].reg; - data = ST_LSM6DSX_SHIFT_VAL(0, reg->mask); - err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, - data); + if (sensor->id == ST_LSM6DSX_ID_EXT0 || + sensor->id == ST_LSM6DSX_ID_EXT1 || + sensor->id == ST_LSM6DSX_ID_EXT2) + err = st_lsm6dsx_shub_set_enable(sensor, false); + else + err = st_lsm6dsx_sensor_set_enable(sensor, false); if (err < 0) return err; + + hw->suspend_mask |= BIT(sensor->id); } if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS) @@ -1146,12 +1148,19 @@ static int __maybe_unused st_lsm6dsx_resume(struct device *dev) continue; sensor = iio_priv(hw->iio_devs[i]); - if (!(hw->enable_mask & BIT(sensor->id))) + if (!(hw->suspend_mask & BIT(sensor->id))) continue; - err = st_lsm6dsx_set_odr(sensor, sensor->odr); + if (sensor->id == ST_LSM6DSX_ID_EXT0 || + sensor->id == ST_LSM6DSX_ID_EXT1 || + sensor->id == ST_LSM6DSX_ID_EXT2) + err = st_lsm6dsx_shub_set_enable(sensor, true); + else + err = st_lsm6dsx_sensor_set_enable(sensor, true); if (err < 0) return err; + + hw->suspend_mask &= ~BIT(sensor->id); } if (hw->enable_mask) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 4fa273002c03..c193d64e5217 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* The industrial I/O core * * Copyright (c) 2008 Jonathan Cameron * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Handling of buffer allocation / resizing. * - * * Things to look at here. * - Better memory allocation techniques? * - Alternative access techniques? diff --git a/drivers/iio/industrialio-configfs.c b/drivers/iio/industrialio-configfs.c index 5a0aae119369..47900de1f105 100644 --- a/drivers/iio/industrialio-configfs.c +++ b/drivers/iio/industrialio-configfs.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Industrial I/O configfs bits * * Copyright (c) 2015 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/configfs.h> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index f5a4581302f4..401d7ff99853 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* The industrial I/O core * * Copyright (c) 2008 Jonathan Cameron * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Based on elements of hwmon and input subsystems. */ @@ -231,9 +228,9 @@ s64 iio_get_time_ns(const struct iio_dev *indio_dev) ktime_get_coarse_ts64(&tp); return timespec64_to_ns(&tp); case CLOCK_BOOTTIME: - return ktime_get_boot_ns(); + return ktime_get_boottime_ns(); case CLOCK_TAI: - return ktime_get_tai_ns(); + return ktime_get_clocktai_ns(); default: BUG(); } diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index c6dfdf0aaac5..5b17c92d3b50 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Industrial I/O event handling * * Copyright (c) 2008 Jonathan Cameron * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Based on elements of hwmon and input subsystems. */ diff --git a/drivers/iio/industrialio-sw-device.c b/drivers/iio/industrialio-sw-device.c index 90df97c542f6..49f775f16ad5 100644 --- a/drivers/iio/industrialio-sw-device.c +++ b/drivers/iio/industrialio-sw-device.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * The Industrial I/O core, software IIO devices functions * * Copyright (c) 2016 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/iio/industrialio-sw-trigger.c b/drivers/iio/industrialio-sw-trigger.c index bc6b7fb43e3a..9ae793a70b8b 100644 --- a/drivers/iio/industrialio-sw-trigger.c +++ b/drivers/iio/industrialio-sw-trigger.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * The Industrial I/O core, software trigger functions * * Copyright (c) 2015 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index e5b538379ed1..3908a9a90035 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* The industrial I/O core, trigger handling functions * * Copyright (c) 2008 Jonathan Cameron - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 4a5eff3f18bc..2fb2314548e9 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* The industrial I/O core in kernel channel mapping * * Copyright (c) 2011 Jonathan Cameron - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/err.h> #include <linux/export.h> diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c index aebf7dd071af..5f4fb5674fa0 100644 --- a/drivers/iio/light/cm32181.c +++ b/drivers/iio/light/cm32181.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Capella Microsystems Inc. * Author: Kevin Tsai <ktsai@capellamicro.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2, as published - * by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index c639cf276ee6..cd3cfb7d02bd 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * CM3232 Ambient Light Sensor * * Copyright (C) 2014-2015 Capella Microsystems Inc. * Author: Kevin Tsai <ktsai@capellamicro.com> * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2, as published - * by the Free Software Foundation. - * * IIO driver for CM3232 (7-bit I2C slave address 0x10). */ diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 1dd8ed0121b3..7702c2bcbcfa 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Author: Beomho Seo <beomho.seo@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2, as published - * by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 44b13fbcd093..4d70c5bf35da 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Author: Jacek Anaszewski <j.anaszewski@samsung.com> @@ -28,10 +29,6 @@ * with any triggers or illuminance events. Enabling/disabling * one of the proximity events automatically enables/disables * the other one. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. */ #include <linux/debugfs.h> diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c index 30ea1a088dd9..0295783f036a 100644 --- a/drivers/iio/light/pa12203001.c +++ b/drivers/iio/light/pa12203001.c @@ -1,11 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015 Intel Corporation * * Driver for TXC PA12203001 Proximity and Ambient Light Sensor. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. * To do: Interrupt support. */ diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index 68e52943879a..b995f21a3347 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015 Intel Corporation * * Driver for UPISEMI us5182d Proximity and Ambient Light Sensor. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * * To do: Interrupt support. */ diff --git a/drivers/iio/magnetometer/hmc5843.h b/drivers/iio/magnetometer/hmc5843.h index e3e22d2508d3..b0dee87a8b20 100644 --- a/drivers/iio/magnetometer/hmc5843.h +++ b/drivers/iio/magnetometer/hmc5843.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Header file for hmc5843 driver * * Split from hmc5843.c * Copyright (C) Josef Gajdusek <atx@atx.name> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef HMC5843_CORE_H diff --git a/drivers/iio/magnetometer/hmc5843_i2c.c b/drivers/iio/magnetometer/hmc5843_i2c.c index 86abba5827a2..67fe657fdb3e 100644 --- a/drivers/iio/magnetometer/hmc5843_i2c.c +++ b/drivers/iio/magnetometer/hmc5843_i2c.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * i2c driver for hmc5843/5843/5883/5883l/5983 * * Split from hmc5843.c * Copyright (C) Josef Gajdusek <atx@atx.name> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/iio/magnetometer/hmc5843_spi.c b/drivers/iio/magnetometer/hmc5843_spi.c index 79b2b707f90e..d827554c346e 100644 --- a/drivers/iio/magnetometer/hmc5843_spi.c +++ b/drivers/iio/magnetometer/hmc5843_spi.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPI driver for hmc5983 * * Copyright (C) Josef Gajdusek <atx@atx.name> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index 6bf12c9eccbd..d0de78232a93 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Maxim Integrated DS1803 digital potentiometer driver * Copyright (c) 2016 Slawomir Stepien @@ -6,10 +7,6 @@ * * DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address * ds1803 2 256 10, 50, 100 0101xxx - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/iio/potentiometer/max5481.c b/drivers/iio/potentiometer/max5481.c index 6d2f13fa5662..732375b6d131 100644 --- a/drivers/iio/potentiometer/max5481.c +++ b/drivers/iio/potentiometer/max5481.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Maxim Integrated MAX5481-MAX5484 digital potentiometer driver * Copyright 2016 Rockwell Collins * * Datasheet: * http://datasheets.maximintegrated.com/en/ds/MAX5481-MAX5484.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the gnu general public license version 2 as - * published by the free software foundation. - * */ #include <linux/acpi.h> diff --git a/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c index 5042d3e09b12..68ff806d4668 100644 --- a/drivers/iio/potentiometer/max5487.c +++ b/drivers/iio/potentiometer/max5487.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * max5487.c - Support for MAX5487, MAX5488, MAX5489 digital potentiometers * * Copyright (C) 2016 Cristina-Gabriela Moraru <cristina.moraru09@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> #include <linux/spi/spi.h> diff --git a/drivers/iio/potentiometer/mcp4131.c b/drivers/iio/potentiometer/mcp4131.c index efe035ce010d..98df91e97f2f 100644 --- a/drivers/iio/potentiometer/mcp4131.c +++ b/drivers/iio/potentiometer/mcp4131.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Industrial I/O driver for Microchip digital potentiometers * @@ -23,10 +24,6 @@ * mcp4252 2 257 5, 10, 50, 100 * mcp4261 2 257 5, 10, 50, 100 * mcp4262 2 257 5, 10, 50, 100 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ /* diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 3329d740c86c..8d0f15f27dc5 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2010 Christoph Mair <christoph.mair@gmail.com> * Copyright (c) 2012 Bosch Sensortec GmbH @@ -7,10 +8,6 @@ * * Driver for Bosch Sensortec BMP180 and BMP280 digital pressure sensor. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Datasheet: * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP180-DS000-121.pdf * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP280-DS001-12.pdf diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c index 406934ea6228..f00102577fd5 100644 --- a/drivers/iio/pressure/hp03.c +++ b/drivers/iio/pressure/hp03.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016 Marek Vasut <marex@denx.de> * * Driver for Hope RF HP03 digital temperature and pressure sensor. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "hp03: " fmt diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index ff80409e0c44..612f79c53cfc 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 Intel Corporation * * Driver for Semtech's SX9500 capacitive proximity/button solution. * Datasheet available at * <http://www.semtech.com/images/datasheet/sx9500.pdf>. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/iio/resolver/ad2s1200.c b/drivers/iio/resolver/ad2s1200.c index 28e618af9939..17b89623418c 100644 --- a/drivers/iio/resolver/ad2s1200.c +++ b/drivers/iio/resolver/ad2s1200.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ad2s1200.c simple support for the ADI Resolver to Digital Converters: * AD2S1200/1205 * * Copyright (c) 2018-2018 David Veenstra <davidjulianveenstra@gmail.com> * Copyright (c) 2010-2010 Analog Devices Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c index be03be719efe..eaca6ba06864 100644 --- a/drivers/iio/temperature/mlx90632.c +++ b/drivers/iio/temperature/mlx90632.c @@ -81,6 +81,8 @@ /* Magic constants */ #define MLX90632_ID_MEDICAL 0x0105 /* EEPROM DSPv5 Medical device id */ #define MLX90632_ID_CONSUMER 0x0205 /* EEPROM DSPv5 Consumer device id */ +#define MLX90632_DSP_VERSION 5 /* DSP version */ +#define MLX90632_DSP_MASK GENMASK(7, 0) /* DSP version in EE_VERSION */ #define MLX90632_RESET_CMD 0x0006 /* Reset sensor (address or global) */ #define MLX90632_REF_12 12LL /**< ResCtrlRef value of Ch 1 or Ch 2 */ #define MLX90632_REF_3 12LL /**< ResCtrlRef value of Channel 3 */ @@ -667,10 +669,13 @@ static int mlx90632_probe(struct i2c_client *client, } else if (read == MLX90632_ID_CONSUMER) { dev_dbg(&client->dev, "Detected Consumer EEPROM calibration %x\n", read); + } else if ((read & MLX90632_DSP_MASK) == MLX90632_DSP_VERSION) { + dev_dbg(&client->dev, + "Detected Unknown EEPROM calibration %x\n", read); } else { dev_err(&client->dev, - "EEPROM version mismatch %x (expected %x or %x)\n", - read, MLX90632_ID_CONSUMER, MLX90632_ID_MEDICAL); + "Wrong DSP version %x (expected %x)\n", + read, MLX90632_DSP_VERSION); return -EPROTONOSUPPORT; } diff --git a/drivers/iio/trigger/iio-trig-hrtimer.c b/drivers/iio/trigger/iio-trig-hrtimer.c index 7accd0187ba1..a5e670726717 100644 --- a/drivers/iio/trigger/iio-trig-hrtimer.c +++ b/drivers/iio/trigger/iio-trig-hrtimer.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /** * The industrial I/O periodic hrtimer trigger driver * @@ -6,11 +7,6 @@ * Copyright (C) 2012, Analog Device Inc. * Author: Lars-Peter Clausen <lars@metafoo.de> * Copyright (C) 2015, Intel Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * */ #include <linux/kernel.h> #include <linux/slab.h> diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c index 171c4ed03543..94a487caf421 100644 --- a/drivers/iio/trigger/iio-trig-interrupt.c +++ b/drivers/iio/trigger/iio-trig-interrupt.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Industrial I/O - generic interrupt based trigger support * * Copyright (c) 2008-2013 Jonathan Cameron - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 29f7b15c81d9..3352a107b4a3 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -457,7 +457,7 @@ static int alloc_name(struct ib_device *ibdev, const char *name) int rc; int i; - lockdep_assert_held_exclusive(&devices_rwsem); + lockdep_assert_held_write(&devices_rwsem); ida_init(&inuse); xa_for_each (&devices, index, device) { char buf[IB_DEVICE_NAME_MAX]; @@ -2520,7 +2520,7 @@ static int __init ib_core_init(void) goto err_mad; } - ret = register_lsm_notifier(&ibdev_lsm_nb); + ret = register_blocking_lsm_notifier(&ibdev_lsm_nb); if (ret) { pr_warn("Couldn't register LSM notifier. ret %d\n", ret); goto err_sa; @@ -2539,7 +2539,7 @@ static int __init ib_core_init(void) return 0; err_compat: - unregister_lsm_notifier(&ibdev_lsm_nb); + unregister_blocking_lsm_notifier(&ibdev_lsm_nb); err_sa: ib_sa_cleanup(); err_mad: @@ -2565,7 +2565,7 @@ static void __exit ib_core_cleanup(void) nldev_exit(); rdma_nl_unregister(RDMA_NL_LS); unregister_pernet_device(&rdma_dev_net_ops); - unregister_lsm_notifier(&ibdev_lsm_nb); + unregister_blocking_lsm_notifier(&ibdev_lsm_nb); ib_sa_cleanup(); ib_mad_cleanup(); addr_cleanup(); diff --git a/drivers/infiniband/hw/efa/efa_com_cmd.c b/drivers/infiniband/hw/efa/efa_com_cmd.c index 14227725521c..c0016648804c 100644 --- a/drivers/infiniband/hw/efa/efa_com_cmd.c +++ b/drivers/infiniband/hw/efa/efa_com_cmd.c @@ -139,9 +139,11 @@ int efa_com_destroy_qp(struct efa_com_dev *edev, sizeof(qp_cmd), (struct efa_admin_acq_entry *)&cmd_completion, sizeof(cmd_completion)); - if (err) + if (err) { ibdev_err(edev->efa_dev, "Failed to destroy qp-%u [%d]\n", qp_cmd.qp_handle, err); + return err; + } return 0; } @@ -199,9 +201,11 @@ int efa_com_destroy_cq(struct efa_com_dev *edev, (struct efa_admin_acq_entry *)&destroy_resp, sizeof(destroy_resp)); - if (err) + if (err) { ibdev_err(edev->efa_dev, "Failed to destroy CQ-%u [%d]\n", params->cq_idx, err); + return err; + } return 0; } @@ -273,10 +277,12 @@ int efa_com_dereg_mr(struct efa_com_dev *edev, sizeof(mr_cmd), (struct efa_admin_acq_entry *)&cmd_completion, sizeof(cmd_completion)); - if (err) + if (err) { ibdev_err(edev->efa_dev, "Failed to de-register mr(lkey-%u) [%d]\n", mr_cmd.l_key, err); + return err; + } return 0; } @@ -327,9 +333,11 @@ int efa_com_destroy_ah(struct efa_com_dev *edev, sizeof(ah_cmd), (struct efa_admin_acq_entry *)&cmd_completion, sizeof(cmd_completion)); - if (err) + if (err) { ibdev_err(edev->efa_dev, "Failed to destroy ah-%d pd-%d [%d]\n", ah_cmd.ah, ah_cmd.pd, err); + return err; + } return 0; } @@ -387,10 +395,12 @@ static int efa_com_get_feature_ex(struct efa_com_dev *edev, get_resp, sizeof(*get_resp)); - if (err) + if (err) { ibdev_err(edev->efa_dev, "Failed to submit get_feature command %d [%d]\n", feature_id, err); + return err; + } return 0; } @@ -534,10 +544,12 @@ static int efa_com_set_feature_ex(struct efa_com_dev *edev, (struct efa_admin_acq_entry *)set_resp, sizeof(*set_resp)); - if (err) + if (err) { ibdev_err(edev->efa_dev, "Failed to submit set_feature command %d error: %d\n", feature_id, err); + return err; + } return 0; } diff --git a/drivers/infiniband/hw/efa/efa_verbs.c b/drivers/infiniband/hw/efa/efa_verbs.c index 0fea5d63fdbe..fb6115244d4c 100644 --- a/drivers/infiniband/hw/efa/efa_verbs.c +++ b/drivers/infiniband/hw/efa/efa_verbs.c @@ -204,6 +204,7 @@ static u64 mmap_entry_insert(struct efa_dev *dev, struct efa_ucontext *ucontext, void *obj, u64 address, u64 length, u8 mmap_flag) { struct efa_mmap_entry *entry; + u32 next_mmap_page; int err; entry = kmalloc(sizeof(*entry), GFP_KERNEL); @@ -216,15 +217,19 @@ static u64 mmap_entry_insert(struct efa_dev *dev, struct efa_ucontext *ucontext, entry->mmap_flag = mmap_flag; xa_lock(&ucontext->mmap_xa); + if (check_add_overflow(ucontext->mmap_xa_page, + (u32)(length >> PAGE_SHIFT), + &next_mmap_page)) + goto err_unlock; + entry->mmap_page = ucontext->mmap_xa_page; - ucontext->mmap_xa_page += DIV_ROUND_UP(length, PAGE_SIZE); + ucontext->mmap_xa_page = next_mmap_page; err = __xa_insert(&ucontext->mmap_xa, entry->mmap_page, entry, GFP_KERNEL); + if (err) + goto err_unlock; + xa_unlock(&ucontext->mmap_xa); - if (err){ - kfree(entry); - return EFA_MMAP_INVALID; - } ibdev_dbg( &dev->ibdev, @@ -232,6 +237,12 @@ static u64 mmap_entry_insert(struct efa_dev *dev, struct efa_ucontext *ucontext, entry->obj, entry->address, entry->length, get_mmap_key(entry)); return get_mmap_key(entry); + +err_unlock: + xa_unlock(&ucontext->mmap_xa); + kfree(entry); + return EFA_MMAP_INVALID; + } int efa_query_device(struct ib_device *ibdev, diff --git a/drivers/infiniband/hw/hfi1/affinity.c b/drivers/infiniband/hw/hfi1/affinity.c index 4fe662c3bbc1..c142b23bb401 100644 --- a/drivers/infiniband/hw/hfi1/affinity.c +++ b/drivers/infiniband/hw/hfi1/affinity.c @@ -1038,7 +1038,7 @@ int hfi1_get_proc_affinity(int node) struct hfi1_affinity_node *entry; cpumask_var_t diff, hw_thread_mask, available_mask, intrs_mask; const struct cpumask *node_mask, - *proc_mask = ¤t->cpus_allowed; + *proc_mask = current->cpus_ptr; struct hfi1_affinity_node_list *affinity = &node_affinity; struct cpu_mask_set *set = &affinity->proc; @@ -1046,7 +1046,7 @@ int hfi1_get_proc_affinity(int node) * check whether process/context affinity has already * been set */ - if (cpumask_weight(proc_mask) == 1) { + if (current->nr_cpus_allowed == 1) { hfi1_cdbg(PROC, "PID %u %s affinity set to CPU %*pbl", current->pid, current->comm, cpumask_pr_args(proc_mask)); @@ -1057,7 +1057,7 @@ int hfi1_get_proc_affinity(int node) cpu = cpumask_first(proc_mask); cpumask_set_cpu(cpu, &set->used); goto done; - } else if (cpumask_weight(proc_mask) < cpumask_weight(&set->mask)) { + } else if (current->nr_cpus_allowed < cpumask_weight(&set->mask)) { hfi1_cdbg(PROC, "PID %u %s affinity set to CPU set(s) %*pbl", current->pid, current->comm, cpumask_pr_args(proc_mask)); diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 4221a99ee7f4..d5b643a1d9fd 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -14032,6 +14032,19 @@ static void init_kdeth_qp(struct hfi1_devdata *dd) } /** + * hfi1_get_qp_map + * @dd: device data + * @idx: index to read + */ +u8 hfi1_get_qp_map(struct hfi1_devdata *dd, u8 idx) +{ + u64 reg = read_csr(dd, RCV_QP_MAP_TABLE + (idx / 8) * 8); + + reg >>= (idx % 8) * 8; + return reg; +} + +/** * init_qpmap_table * @dd - device data * @first_ctxt - first context diff --git a/drivers/infiniband/hw/hfi1/chip.h b/drivers/infiniband/hw/hfi1/chip.h index 4e6c3556ec48..b76cf81f927f 100644 --- a/drivers/infiniband/hw/hfi1/chip.h +++ b/drivers/infiniband/hw/hfi1/chip.h @@ -1445,6 +1445,7 @@ void clear_all_interrupts(struct hfi1_devdata *dd); void remap_intr(struct hfi1_devdata *dd, int isrc, int msix_intr); void remap_sdma_interrupts(struct hfi1_devdata *dd, int engine, int msix_intr); void reset_interrupts(struct hfi1_devdata *dd); +u8 hfi1_get_qp_map(struct hfi1_devdata *dd, u8 idx); /* * Interrupt source table. diff --git a/drivers/infiniband/hw/hfi1/fault.c b/drivers/infiniband/hw/hfi1/fault.c index 3fd3315d0fb0..93613e5def9b 100644 --- a/drivers/infiniband/hw/hfi1/fault.c +++ b/drivers/infiniband/hw/hfi1/fault.c @@ -153,6 +153,7 @@ static ssize_t fault_opcodes_write(struct file *file, const char __user *buf, char *dash; unsigned long range_start, range_end, i; bool remove = false; + unsigned long bound = 1U << BITS_PER_BYTE; end = strchr(ptr, ','); if (end) @@ -178,6 +179,10 @@ static ssize_t fault_opcodes_write(struct file *file, const char __user *buf, BITS_PER_BYTE); break; } + /* Check the inputs */ + if (range_start >= bound || range_end >= bound) + break; + for (i = range_start; i <= range_end; i++) { if (remove) clear_bit(i, fault->opcodes); diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index b458c218842b..fa45350a9a1d 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -539,6 +539,37 @@ static inline void hfi1_16B_set_qpn(struct opa_16b_mgmt *mgmt, mgmt->src_qpn = cpu_to_be32(src_qp & OPA_16B_MGMT_QPN_MASK); } +/** + * hfi1_get_rc_ohdr - get extended header + * @opah - the opaheader + */ +static inline struct ib_other_headers * +hfi1_get_rc_ohdr(struct hfi1_opa_header *opah) +{ + struct ib_other_headers *ohdr; + struct ib_header *hdr = NULL; + struct hfi1_16b_header *hdr_16b = NULL; + + /* Find out where the BTH is */ + if (opah->hdr_type == HFI1_PKT_TYPE_9B) { + hdr = &opah->ibh; + if (ib_get_lnh(hdr) == HFI1_LRH_BTH) + ohdr = &hdr->u.oth; + else + ohdr = &hdr->u.l.oth; + } else { + u8 l4; + + hdr_16b = &opah->opah; + l4 = hfi1_16B_get_l4(hdr_16b); + if (l4 == OPA_16B_L4_IB_LOCAL) + ohdr = &hdr_16b->u.oth; + else + ohdr = &hdr_16b->u.l.oth; + } + return ohdr; +} + struct rvt_sge_state; /* diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c index 16ba9d52e1b9..4e5c2d1b8cfa 100644 --- a/drivers/infiniband/hw/hfi1/pio.c +++ b/drivers/infiniband/hw/hfi1/pio.c @@ -952,6 +952,22 @@ void sc_disable(struct send_context *sc) } } spin_unlock(&sc->release_lock); + + write_seqlock(&sc->waitlock); + while (!list_empty(&sc->piowait)) { + struct iowait *wait; + struct rvt_qp *qp; + struct hfi1_qp_priv *priv; + + wait = list_first_entry(&sc->piowait, struct iowait, list); + qp = iowait_to_qp(wait); + priv = qp->priv; + list_del_init(&priv->s_iowait.list); + priv->s_iowait.lock = NULL; + hfi1_qp_wakeup(qp, RVT_S_WAIT_PIO | HFI1_S_WAIT_PIO_DRAIN); + } + write_sequnlock(&sc->waitlock); + spin_unlock_irq(&sc->alloc_lock); } @@ -1427,7 +1443,8 @@ void sc_stop(struct send_context *sc, int flag) * @cb: optional callback to call when the buffer is finished sending * @arg: argument for cb * - * Return a pointer to a PIO buffer if successful, NULL if not enough room. + * Return a pointer to a PIO buffer, NULL if not enough room, -ECOMM + * when link is down. */ struct pio_buf *sc_buffer_alloc(struct send_context *sc, u32 dw_len, pio_release_cb cb, void *arg) @@ -1443,7 +1460,7 @@ struct pio_buf *sc_buffer_alloc(struct send_context *sc, u32 dw_len, spin_lock_irqsave(&sc->alloc_lock, flags); if (!(sc->flags & SCF_ENABLED)) { spin_unlock_irqrestore(&sc->alloc_lock, flags); - goto done; + return ERR_PTR(-ECOMM); } retry: diff --git a/drivers/infiniband/hw/hfi1/rc.c b/drivers/infiniband/hw/hfi1/rc.c index a922edcf23d6..7c8cfb149da0 100644 --- a/drivers/infiniband/hw/hfi1/rc.c +++ b/drivers/infiniband/hw/hfi1/rc.c @@ -1432,7 +1432,7 @@ void hfi1_send_rc_ack(struct hfi1_packet *packet, bool is_fecn) pbc = create_pbc(ppd, pbc_flags, qp->srate_mbps, sc_to_vlt(ppd->dd, sc5), plen); pbuf = sc_buffer_alloc(rcd->sc, plen, NULL, NULL); - if (!pbuf) { + if (IS_ERR_OR_NULL(pbuf)) { /* * We have no room to send at the moment. Pass * responsibility for sending the ACK to the send engine @@ -1701,6 +1701,36 @@ static void reset_sending_psn(struct rvt_qp *qp, u32 psn) } } +/** + * hfi1_rc_verbs_aborted - handle abort status + * @qp: the QP + * @opah: the opa header + * + * This code modifies both ACK bit in BTH[2] + * and the s_flags to go into send one mode. + * + * This serves to throttle the send engine to only + * send a single packet in the likely case the + * a link has gone down. + */ +void hfi1_rc_verbs_aborted(struct rvt_qp *qp, struct hfi1_opa_header *opah) +{ + struct ib_other_headers *ohdr = hfi1_get_rc_ohdr(opah); + u8 opcode = ib_bth_get_opcode(ohdr); + u32 psn; + + /* ignore responses */ + if ((opcode >= OP(RDMA_READ_RESPONSE_FIRST) && + opcode <= OP(ATOMIC_ACKNOWLEDGE)) || + opcode == TID_OP(READ_RESP) || + opcode == TID_OP(WRITE_RESP)) + return; + + psn = ib_bth_get_psn(ohdr) | IB_BTH_REQ_ACK; + ohdr->bth[2] = cpu_to_be32(psn); + qp->s_flags |= RVT_S_SEND_ONE; +} + /* * This should be called with the QP s_lock held and interrupts disabled. */ @@ -1709,8 +1739,6 @@ void hfi1_rc_send_complete(struct rvt_qp *qp, struct hfi1_opa_header *opah) struct ib_other_headers *ohdr; struct hfi1_qp_priv *priv = qp->priv; struct rvt_swqe *wqe; - struct ib_header *hdr = NULL; - struct hfi1_16b_header *hdr_16b = NULL; u32 opcode, head, tail; u32 psn; struct tid_rdma_request *req; @@ -1719,24 +1747,7 @@ void hfi1_rc_send_complete(struct rvt_qp *qp, struct hfi1_opa_header *opah) if (!(ib_rvt_state_ops[qp->state] & RVT_SEND_OR_FLUSH_OR_RECV_OK)) return; - /* Find out where the BTH is */ - if (priv->hdr_type == HFI1_PKT_TYPE_9B) { - hdr = &opah->ibh; - if (ib_get_lnh(hdr) == HFI1_LRH_BTH) - ohdr = &hdr->u.oth; - else - ohdr = &hdr->u.l.oth; - } else { - u8 l4; - - hdr_16b = &opah->opah; - l4 = hfi1_16B_get_l4(hdr_16b); - if (l4 == OPA_16B_L4_IB_LOCAL) - ohdr = &hdr_16b->u.oth; - else - ohdr = &hdr_16b->u.l.oth; - } - + ohdr = hfi1_get_rc_ohdr(opah); opcode = ib_bth_get_opcode(ohdr); if ((opcode >= OP(RDMA_READ_RESPONSE_FIRST) && opcode <= OP(ATOMIC_ACKNOWLEDGE)) || diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c index b0110728f541..2395fd4233a7 100644 --- a/drivers/infiniband/hw/hfi1/sdma.c +++ b/drivers/infiniband/hw/hfi1/sdma.c @@ -405,19 +405,33 @@ static void sdma_flush(struct sdma_engine *sde) struct sdma_txreq *txp, *txp_next; LIST_HEAD(flushlist); unsigned long flags; + uint seq; /* flush from head to tail */ sdma_flush_descq(sde); spin_lock_irqsave(&sde->flushlist_lock, flags); /* copy flush list */ - list_for_each_entry_safe(txp, txp_next, &sde->flushlist, list) { - list_del_init(&txp->list); - list_add_tail(&txp->list, &flushlist); - } + list_splice_init(&sde->flushlist, &flushlist); spin_unlock_irqrestore(&sde->flushlist_lock, flags); /* flush from flush list */ list_for_each_entry_safe(txp, txp_next, &flushlist, list) complete_tx(sde, txp, SDMA_TXREQ_S_ABORTED); + /* wakeup QPs orphaned on the dmawait list */ + do { + struct iowait *w, *nw; + + seq = read_seqbegin(&sde->waitlock); + if (!list_empty(&sde->dmawait)) { + write_seqlock(&sde->waitlock); + list_for_each_entry_safe(w, nw, &sde->dmawait, list) { + if (w->wakeup) { + w->wakeup(w, SDMA_AVAIL_REASON); + list_del_init(&w->list); + } + } + write_sequnlock(&sde->waitlock); + } + } while (read_seqretry(&sde->waitlock, seq)); } /* @@ -855,14 +869,13 @@ struct sdma_engine *sdma_select_user_engine(struct hfi1_devdata *dd, { struct sdma_rht_node *rht_node; struct sdma_engine *sde = NULL; - const struct cpumask *current_mask = ¤t->cpus_allowed; unsigned long cpu_id; /* * To ensure that always the same sdma engine(s) will be * selected make sure the process is pinned to this CPU only. */ - if (cpumask_weight(current_mask) != 1) + if (current->nr_cpus_allowed != 1) goto out; cpu_id = smp_processor_id(); @@ -2413,7 +2426,7 @@ unlock_noconn: list_add_tail(&tx->list, &sde->flushlist); spin_unlock(&sde->flushlist_lock); iowait_inc_wait_count(wait, tx->num_desc); - schedule_work(&sde->flush_worker); + queue_work_on(sde->cpu, system_highpri_wq, &sde->flush_worker); ret = -ECOMM; goto unlock; nodesc: @@ -2511,7 +2524,7 @@ unlock_noconn: iowait_inc_wait_count(wait, tx->num_desc); } spin_unlock(&sde->flushlist_lock); - schedule_work(&sde->flush_worker); + queue_work_on(sde->cpu, system_highpri_wq, &sde->flush_worker); ret = -ECOMM; goto update_tail; nodesc: diff --git a/drivers/infiniband/hw/hfi1/tid_rdma.c b/drivers/infiniband/hw/hfi1/tid_rdma.c index 6fb93032fbef..aa9c8d3ef87b 100644 --- a/drivers/infiniband/hw/hfi1/tid_rdma.c +++ b/drivers/infiniband/hw/hfi1/tid_rdma.c @@ -312,9 +312,7 @@ static struct hfi1_ctxtdata *qp_to_rcd(struct rvt_dev_info *rdi, if (qp->ibqp.qp_num == 0) ctxt = 0; else - ctxt = ((qp->ibqp.qp_num >> dd->qos_shift) % - (dd->n_krcv_queues - 1)) + 1; - + ctxt = hfi1_get_qp_map(dd, qp->ibqp.qp_num >> dd->qos_shift); return dd->rcd[ctxt]; } diff --git a/drivers/infiniband/hw/hfi1/ud.c b/drivers/infiniband/hw/hfi1/ud.c index f88ad425664a..4cb0fce5c096 100644 --- a/drivers/infiniband/hw/hfi1/ud.c +++ b/drivers/infiniband/hw/hfi1/ud.c @@ -683,7 +683,7 @@ void return_cnp_16B(struct hfi1_ibport *ibp, struct rvt_qp *qp, pbc = create_pbc(ppd, pbc_flags, qp->srate_mbps, vl, plen); if (ctxt) { pbuf = sc_buffer_alloc(ctxt, plen, NULL, NULL); - if (pbuf) { + if (!IS_ERR_OR_NULL(pbuf)) { trace_pio_output_ibhdr(ppd->dd, &hdr, sc5); ppd->dd->pio_inline_send(ppd->dd, pbuf, pbc, &hdr, hwords); @@ -738,7 +738,7 @@ void return_cnp(struct hfi1_ibport *ibp, struct rvt_qp *qp, u32 remote_qpn, pbc = create_pbc(ppd, pbc_flags, qp->srate_mbps, vl, plen); if (ctxt) { pbuf = sc_buffer_alloc(ctxt, plen, NULL, NULL); - if (pbuf) { + if (!IS_ERR_OR_NULL(pbuf)) { trace_pio_output_ibhdr(ppd->dd, &hdr, sc5); ppd->dd->pio_inline_send(ppd->dd, pbuf, pbc, &hdr, hwords); diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c index 8bfbc6d7ea34..fd754a16475a 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.c +++ b/drivers/infiniband/hw/hfi1/user_sdma.c @@ -130,20 +130,16 @@ static int defer_packet_queue( { struct hfi1_user_sdma_pkt_q *pq = container_of(wait->iow, struct hfi1_user_sdma_pkt_q, busy); - struct user_sdma_txreq *tx = - container_of(txreq, struct user_sdma_txreq, txreq); - if (sdma_progress(sde, seq, txreq)) { - if (tx->busycount++ < MAX_DEFER_RETRY_COUNT) - goto eagain; - } + write_seqlock(&sde->waitlock); + if (sdma_progress(sde, seq, txreq)) + goto eagain; /* * We are assuming that if the list is enqueued somewhere, it * is to the dmawait list since that is the only place where * it is supposed to be enqueued. */ xchg(&pq->state, SDMA_PKT_Q_DEFERRED); - write_seqlock(&sde->waitlock); if (list_empty(&pq->busy.list)) { iowait_get_priority(&pq->busy); iowait_queue(pkts_sent, &pq->busy, &sde->dmawait); @@ -151,6 +147,7 @@ static int defer_packet_queue( write_sequnlock(&sde->waitlock); return -EBUSY; eagain: + write_sequnlock(&sde->waitlock); return -EAGAIN; } @@ -804,7 +801,6 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, u16 maxpkts) tx->flags = 0; tx->req = req; - tx->busycount = 0; INIT_LIST_HEAD(&tx->list); /* diff --git a/drivers/infiniband/hw/hfi1/user_sdma.h b/drivers/infiniband/hw/hfi1/user_sdma.h index 14dfd757dafd..4d8510b0fc38 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.h +++ b/drivers/infiniband/hw/hfi1/user_sdma.h @@ -245,7 +245,6 @@ struct user_sdma_txreq { struct list_head list; struct user_sdma_request *req; u16 flags; - unsigned int busycount; u16 seqnum; }; diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index a2b26a635baf..bad3229bad37 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -638,6 +638,8 @@ static void verbs_sdma_complete( struct hfi1_opa_header *hdr; hdr = &tx->phdr.hdr; + if (unlikely(status == SDMA_TXREQ_S_ABORTED)) + hfi1_rc_verbs_aborted(qp, hdr); hfi1_rc_send_complete(qp, hdr); } spin_unlock(&qp->s_lock); @@ -1037,10 +1039,10 @@ int hfi1_verbs_send_pio(struct rvt_qp *qp, struct hfi1_pkt_state *ps, if (cb) iowait_pio_inc(&priv->s_iowait); pbuf = sc_buffer_alloc(sc, plen, cb, qp); - if (unlikely(!pbuf)) { + if (unlikely(IS_ERR_OR_NULL(pbuf))) { if (cb) verbs_pio_complete(qp, 0); - if (ppd->host_link_state != HLS_UP_ACTIVE) { + if (IS_ERR(pbuf)) { /* * If we have filled the PIO buffers to capacity and are * not in an active state this request is not going to @@ -1095,15 +1097,15 @@ int hfi1_verbs_send_pio(struct rvt_qp *qp, struct hfi1_pkt_state *ps, &ps->s_txreq->phdr.hdr, ib_is_sc5(sc5)); pio_bail: + spin_lock_irqsave(&qp->s_lock, flags); if (qp->s_wqe) { - spin_lock_irqsave(&qp->s_lock, flags); rvt_send_complete(qp, qp->s_wqe, wc_status); - spin_unlock_irqrestore(&qp->s_lock, flags); } else if (qp->ibqp.qp_type == IB_QPT_RC) { - spin_lock_irqsave(&qp->s_lock, flags); + if (unlikely(wc_status == IB_WC_GENERAL_ERR)) + hfi1_rc_verbs_aborted(qp, &ps->s_txreq->phdr.hdr); hfi1_rc_send_complete(qp, &ps->s_txreq->phdr.hdr); - spin_unlock_irqrestore(&qp->s_lock, flags); } + spin_unlock_irqrestore(&qp->s_lock, flags); ret = 0; diff --git a/drivers/infiniband/hw/hfi1/verbs.h b/drivers/infiniband/hw/hfi1/verbs.h index 7ecb8ed4a1d9..ae9582ddbc8f 100644 --- a/drivers/infiniband/hw/hfi1/verbs.h +++ b/drivers/infiniband/hw/hfi1/verbs.h @@ -416,6 +416,7 @@ void hfi1_rc_hdrerr( u8 ah_to_sc(struct ib_device *ibdev, struct rdma_ah_attr *ah_attr); +void hfi1_rc_verbs_aborted(struct rvt_qp *qp, struct hfi1_opa_header *opah); void hfi1_rc_send_complete(struct rvt_qp *qp, struct hfi1_opa_header *opah); void hfi1_ud_rcv(struct hfi1_packet *packet); diff --git a/drivers/infiniband/hw/hfi1/verbs_txreq.c b/drivers/infiniband/hw/hfi1/verbs_txreq.c index c4ab2d5b4502..8f766dd3f61c 100644 --- a/drivers/infiniband/hw/hfi1/verbs_txreq.c +++ b/drivers/infiniband/hw/hfi1/verbs_txreq.c @@ -100,7 +100,7 @@ struct verbs_txreq *__get_txreq(struct hfi1_ibdev *dev, if (ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) { struct hfi1_qp_priv *priv; - tx = kmem_cache_alloc(dev->verbs_txreq_cache, GFP_ATOMIC); + tx = kmem_cache_alloc(dev->verbs_txreq_cache, VERBS_TXREQ_GFP); if (tx) goto out; priv = qp->priv; diff --git a/drivers/infiniband/hw/hfi1/verbs_txreq.h b/drivers/infiniband/hw/hfi1/verbs_txreq.h index b002e96eb335..bfa6e081cb56 100644 --- a/drivers/infiniband/hw/hfi1/verbs_txreq.h +++ b/drivers/infiniband/hw/hfi1/verbs_txreq.h @@ -72,6 +72,7 @@ struct hfi1_ibdev; struct verbs_txreq *__get_txreq(struct hfi1_ibdev *dev, struct rvt_qp *qp); +#define VERBS_TXREQ_GFP (GFP_ATOMIC | __GFP_NOWARN) static inline struct verbs_txreq *get_txreq(struct hfi1_ibdev *dev, struct rvt_qp *qp) __must_hold(&qp->slock) @@ -79,7 +80,7 @@ static inline struct verbs_txreq *get_txreq(struct hfi1_ibdev *dev, struct verbs_txreq *tx; struct hfi1_qp_priv *priv = qp->priv; - tx = kmem_cache_alloc(dev->verbs_txreq_cache, GFP_ATOMIC); + tx = kmem_cache_alloc(dev->verbs_txreq_cache, VERBS_TXREQ_GFP); if (unlikely(!tx)) { /* call slow path to get the lock */ tx = __get_txreq(dev, qp); diff --git a/drivers/infiniband/hw/mlx4/alias_GUID.c b/drivers/infiniband/hw/mlx4/alias_GUID.c index 2a0b59a4b6eb..cca414ecfcd5 100644 --- a/drivers/infiniband/hw/mlx4/alias_GUID.c +++ b/drivers/infiniband/hw/mlx4/alias_GUID.c @@ -310,7 +310,7 @@ static void aliasguid_query_handler(int status, if (status) { pr_debug("(port: %d) failed: status = %d\n", cb_ctx->port, status); - rec->time_to_run = ktime_get_boot_ns() + 1 * NSEC_PER_SEC; + rec->time_to_run = ktime_get_boottime_ns() + 1 * NSEC_PER_SEC; goto out; } @@ -416,7 +416,7 @@ next_entry: be64_to_cpu((__force __be64)rec->guid_indexes), be64_to_cpu((__force __be64)applied_guid_indexes), be64_to_cpu((__force __be64)declined_guid_indexes)); - rec->time_to_run = ktime_get_boot_ns() + + rec->time_to_run = ktime_get_boottime_ns() + resched_delay_sec * NSEC_PER_SEC; } else { rec->status = MLX4_GUID_INFO_STATUS_SET; @@ -709,7 +709,7 @@ static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port, } } if (resched_delay_sec) { - u64 curr_time = ktime_get_boot_ns(); + u64 curr_time = ktime_get_boottime_ns(); *resched_delay_sec = (low_record_time < curr_time) ? 0 : div_u64((low_record_time - curr_time), NSEC_PER_SEC); diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 78fa634de98a..27b6e664e59d 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -1142,7 +1142,7 @@ static __poll_t qib_poll(struct file *fp, struct poll_table_struct *pt) static void assign_ctxt_affinity(struct file *fp, struct qib_devdata *dd) { struct qib_filedata *fd = fp->private_data; - const unsigned int weight = cpumask_weight(¤t->cpus_allowed); + const unsigned int weight = current->nr_cpus_allowed; const struct cpumask *local_mask = cpumask_of_pcibus(dd->pcidev->bus); int local_cpu; @@ -1623,9 +1623,8 @@ static int qib_assign_ctxt(struct file *fp, const struct qib_user_info *uinfo) ret = find_free_ctxt(i_minor - 1, fp, uinfo); else { int unit; - const unsigned int cpu = cpumask_first(¤t->cpus_allowed); - const unsigned int weight = - cpumask_weight(¤t->cpus_allowed); + const unsigned int cpu = cpumask_first(current->cpus_ptr); + const unsigned int weight = current->nr_cpus_allowed; if (weight == 1 && !test_bit(cpu, qib_cpulist)) if (!find_hca(cpu, &unit) && unit >= 0) diff --git a/drivers/input/apm-power.c b/drivers/input/apm-power.c index 650177a3c858..70a9e1dfba33 100644 --- a/drivers/input/apm-power.c +++ b/drivers/input/apm-power.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Input Power Event -> APM Bridge * * Copyright (c) 2007 Richard Purdie - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index d1e25aba8212..867c2cfd0038 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Event char devices, giving access to raw input device events. * * Copyright (c) 1999-2002 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 73862a836062..61fa7e724172 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic gameport layer * @@ -5,11 +6,6 @@ * Copyright (c) 2005 Dmitry Torokhov */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c index fda8d6d2a268..2ccd3eedbd67 100644 --- a/drivers/input/input-compat.c +++ b/drivers/input/input-compat.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 32bit compatibility wrappers for the input subsystem. * * Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/export.h> diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h index 08cd755e73fd..3b7bb12b023b 100644 --- a/drivers/input/input-compat.h +++ b/drivers/input/input-compat.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef _INPUT_COMPAT_H #define _INPUT_COMPAT_H @@ -5,10 +6,6 @@ * 32bit compatibility wrappers for the input subsystem. * * Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/compiler.h> diff --git a/drivers/input/input-leds.c b/drivers/input/input-leds.c index 99cc784e1264..0b11990ade46 100644 --- a/drivers/input/input-leds.c +++ b/drivers/input/input-leds.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED support for the input layer * * Copyright 2010-2015 Samuel Thibault <samuel.thibault@ens-lyon.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index 6c7326c93721..a81e14148407 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Input Multitouch Library * * Copyright (c) 2008-2010 Henrik Rydberg - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/input/mt.h> diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index 78df5a74822e..9bf1c9aeb4c4 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic implementation of a polled input device * Copyright (c) 2007 Dmitry Torokhov - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/input/input.c b/drivers/input/input.c index 3304aaaffe87..7f3c5fcb9ed6 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * The input core * * Copyright (c) 1999-2002 Vojtech Pavlik */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ #define pr_fmt(fmt) KBUILD_BASENAME ": " fmt diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c index dce313dc260a..56abc8c6c763 100644 --- a/drivers/input/joystick/walkera0701.c +++ b/drivers/input/joystick/walkera0701.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Parallel port to Walkera WK-0701 TX joystick * @@ -6,11 +7,6 @@ * More about driver: <file:Documentation/input/devices/walkera0701.rst> */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. -*/ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c index c255af21e71a..9885fd56f5f9 100644 --- a/drivers/input/keyboard/adc-keys.c +++ b/drivers/input/keyboard/adc-keys.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Input driver for resistor ladder connected on ADC * * Copyright (c) 2016 Alexandre Belloni - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 3ad93e3e2f4c..7e3eae54c192 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AT and PS/2 keyboard driver * * Copyright (c) 1999-2002 Vojtech Pavlik */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ /* * This driver can handle standard AT keyboards and PS/2 keyboards in diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c index 73686c2460ce..688e2bef682e 100644 --- a/drivers/input/keyboard/cap11xx.c +++ b/drivers/input/keyboard/cap11xx.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Input driver for Microchip CAP11xx based capacitive touch sensors * * (c) 2014 Daniel Mack <linux@zonque.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index 575dac52f7b4..7c70492d9d6b 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for the Cirrus EP93xx matrix keypad controller. * @@ -5,10 +6,6 @@ * * Based on the pxa27x matrix keypad controller by Rodolfo Giometti. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * NOTE: * * The 3-key reset is triggered by pressing the 3 keys in diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 6cd199e8a370..a23c23979a2e 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for keys on GPIO lines capable of generating interrupts. * * Copyright 2005 Phil Blundell * Copyright 2010, 2011 David Jander <david@protonic.nl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index edc7262103b9..1eafe6b848ba 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for buttons on GPIO lines not capable of generating interrupts * @@ -9,10 +10,6 @@ * * also was based on: /drivers/input/keyboard/gpio_keys.c * Copyright 2005 Phil Blundell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index 539cb670de41..ae9c51cc85f9 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -526,11 +526,12 @@ static int imx_keypad_probe(struct platform_device *pdev) return 0; } -static int __maybe_unused imx_kbd_suspend(struct device *dev) +static int __maybe_unused imx_kbd_noirq_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct imx_keypad *kbd = platform_get_drvdata(pdev); struct input_dev *input_dev = kbd->input_dev; + unsigned short reg_val = readw(kbd->mmio_base + KPSR); /* imx kbd can wake up system even clock is disabled */ mutex_lock(&input_dev->mutex); @@ -540,13 +541,20 @@ static int __maybe_unused imx_kbd_suspend(struct device *dev) mutex_unlock(&input_dev->mutex); - if (device_may_wakeup(&pdev->dev)) + if (device_may_wakeup(&pdev->dev)) { + if (reg_val & KBD_STAT_KPKD) + reg_val |= KBD_STAT_KRIE; + if (reg_val & KBD_STAT_KPKR) + reg_val |= KBD_STAT_KDIE; + writew(reg_val, kbd->mmio_base + KPSR); + enable_irq_wake(kbd->irq); + } return 0; } -static int __maybe_unused imx_kbd_resume(struct device *dev) +static int __maybe_unused imx_kbd_noirq_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct imx_keypad *kbd = platform_get_drvdata(pdev); @@ -570,7 +578,9 @@ err_clk: return ret; } -static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume); +static const struct dev_pm_ops imx_kbd_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_kbd_noirq_suspend, imx_kbd_noirq_resume) +}; static struct platform_driver imx_keypad_driver = { .driver = { diff --git a/drivers/input/keyboard/ipaq-micro-keys.c b/drivers/input/keyboard/ipaq-micro-keys.c index 602900d1f937..e3f9e445e880 100644 --- a/drivers/input/keyboard/ipaq-micro-keys.c +++ b/drivers/input/keyboard/ipaq-micro-keys.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. * * h3600 atmel micro companion support, key subdevice * based on previous kernel 2.4 version * Author : Alessandro Gardich <gremlin@gremlin.it> * Author : Linus Walleij <linus.walleij@linaro.org> - * */ #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c index 0116ac99f44c..4232aa876d2e 100644 --- a/drivers/input/keyboard/jornada680_kbd.c +++ b/drivers/input/keyboard/jornada680_kbd.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/input/keyboard/jornada680_kbd.c * @@ -10,10 +11,6 @@ * Split from drivers/input/keyboard/hp600_keyb.c * Copyright (C) 2000 Yaegashi Takeshi (hp6xx kbd scan routine and translation table) * Copyright (C) 2000 Niibe Yutaka (HP620 Keyb translation table) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 1277c39f9482..cd9af5221c3d 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/input/keyboard/jornada720_kbd.c * @@ -9,11 +10,6 @@ Filip Zyzniewsk <Filip.Zyzniewski@tefnet.plX * based on (C) 2004 jornada 720 kbd driver by Alex Lange <chicken@handhelds.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/device.h> #include <linux/errno.h> diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 3d1cb7bf5e35..30924b57058f 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * GPIO driven matrix keyboard driver * * Copyright (c) 2008 Marek Vasut <marek.vasut@gmail.com> * * Based on corgikbd.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/types.h> diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c index cd44d22d8770..62ce93462955 100644 --- a/drivers/input/keyboard/max7359_keypad.c +++ b/drivers/input/keyboard/max7359_keypad.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * max7359_keypad.c - MAX7359 Key Switch Controller Driver * @@ -6,10 +7,6 @@ * * Based on pxa27x_keypad.c * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Datasheet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/5456 */ diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index 884a74d8a7ed..e9ceaa16b46a 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Touchkey driver for Freescale MPR121 Controllor * @@ -5,11 +6,6 @@ * Author: Zhang Jiejing <jiejing.zhang@freescale.com> * * Based on mcs_touchkey.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/bitops.h> diff --git a/drivers/input/keyboard/nspire-keypad.c b/drivers/input/keyboard/nspire-keypad.c index c7f26fa3034c..57eac91ecd76 100644 --- a/drivers/input/keyboard/nspire-keypad.c +++ b/drivers/input/keyboard/nspire-keypad.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. */ #include <linux/input/matrix_keypad.h> diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index d0bdaeadf86d..39023664d2f2 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/input/keyboard/pxa27x_keypad.c * @@ -9,10 +10,6 @@ * Based on a previous implementations by Kevin O'Connor * <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and * on some suggestions by Nicolas Pitre <nico@fluxnic.net>. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c index 1cf5211fddaa..585e7765cbf0 100644 --- a/drivers/input/keyboard/pxa930_rotary.c +++ b/drivers/input/keyboard/pxa930_rotary.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for the enhanced rotary controller on pxa930 and pxa935 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index 7abf03b4cc9c..08ba41a81f14 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SuperH KEYSC Keypad Driver * * Copyright (C) 2008 Magnus Damm * * Based on gpio_keys.c, Copyright 2005 Phil Blundell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c index 3b85631fde91..f097128b93fe 100644 --- a/drivers/input/keyboard/st-keyscan.c +++ b/drivers/input/keyboard/st-keyscan.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * STMicroelectronics Key Scanning driver * @@ -5,10 +6,6 @@ * Author: Stuart Menefy <stuart.menefy@st.com> * * Based on sh_keysc.c, copyright 2008 Magnus Damm - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c index d69e631cfa0a..7bf97285e30c 100644 --- a/drivers/input/keyboard/stmpe-keypad.c +++ b/drivers/input/keyboard/stmpe-keypad.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) ST-Ericsson SA 2010 * - * License Terms: GNU General Public License, version 2 * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson */ diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index ec0070e97090..89b9575dc75d 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) ST-Ericsson SA 2010 * * Author: Jayeeta Banerjee <jayeeta.banerjee@stericsson.com> * Author: Sundar Iyer <sundar.iyer@stericsson.com> * - * License Terms: GNU General Public License, version 2 - * * TC35893 MFD Keypad Controller driver */ diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index cdeef180aead..2a14769de637 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for keys on TCA6416 I2C IO expander * * Copyright (C) 2010 Texas Instruments * * Author : Sriramakrishnan.A.G. <srk@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/types.h> diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c index d4455f3a5cf1..14b55bacdd0f 100644 --- a/drivers/input/keyboard/tm2-touchkey.c +++ b/drivers/input/keyboard/tm2-touchkey.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TM2 touchkey device driver * @@ -6,10 +7,6 @@ * * Author: Beomho Seo <beomho.seo@samsung.com> * Author: Jaechul Lee <jcsing.lee@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c index c1e66f45d552..53ec40d1b90d 100644 --- a/drivers/input/misc/apanel.c +++ b/drivers/input/misc/apanel.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Fujitsu Lifebook Application Panel button drive * * Copyright (C) 2007 Stephen Hemminger <shemminger@linux-foundation.org> * Copyright (C) 2001-2003 Jochen Eisinger <jochen@penguin-breeder.org> * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Many Fujitsu Lifebook laptops have a small panel of buttons that are * accessible via the i2c/smbus interface. This driver polls those * buttons and generates input events. diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c index 21dc1b8b2a4a..5fa1c9438a85 100644 --- a/drivers/input/misc/arizona-haptics.c +++ b/drivers/input/misc/arizona-haptics.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Arizona haptics driver * * Copyright 2012 Wolfson Microelectronics plc * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index d8fd58fdf050..305f0160506a 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ati_remote2 - ATI/Philips USB RF remote driver * * Copyright (C) 2005-2008 Ville Syrjala <syrjala@sci.fi> * Copyright (C) 2007-2008 Peter Stokes <linux@dadeos.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. */ #include <linux/usb/input.h> diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c index c7d00748277b..e6feb73bb52b 100644 --- a/drivers/input/misc/cma3000_d0x.c +++ b/drivers/input/misc/cma3000_d0x.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * VTI CMA3000_D0x Accelerometer driver * * Copyright (C) 2010 Texas Instruments * Author: Hemanth V <hemanthv@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/types.h> diff --git a/drivers/input/misc/cma3000_d0x.h b/drivers/input/misc/cma3000_d0x.h index 2304ce306e1c..05ad42a564df 100644 --- a/drivers/input/misc/cma3000_d0x.h +++ b/drivers/input/misc/cma3000_d0x.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * VTI CMA3000_D0x Accelerometer driver * * Copyright (C) 2010 Texas Instruments * Author: Hemanth V <hemanthv@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _INPUT_CMA3000_H diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c index c7021916b64b..03fb49127c3a 100644 --- a/drivers/input/misc/cma3000_d0x_i2c.c +++ b/drivers/input/misc/cma3000_d0x_i2c.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Implements I2C interface for VTI CMA300_D0x Accelerometer driver * * Copyright (C) 2010 Texas Instruments * Author: Hemanth V <hemanthv@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> diff --git a/drivers/input/misc/gp2ap002a00f.c b/drivers/input/misc/gp2ap002a00f.c index c6a29e57b5e4..90abda8eea67 100644 --- a/drivers/input/misc/gp2ap002a00f.c +++ b/drivers/input/misc/gp2ap002a00f.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Sony Ericsson Mobile Communications Inc. * * Author: Courtney Cavin <courtney.cavin@sonyericsson.com> * Prepared for up-stream by: Oskar Andero <oskar.andero@sonyericsson.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. */ #include <linux/i2c.h> diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c index 74cf3b612f05..d8dbfc030d0f 100644 --- a/drivers/input/misc/ims-pcu.c +++ b/drivers/input/misc/ims-pcu.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for IMS Passenger Control Unit Devices * * Copyright (C) 2013 The IMS Company - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. */ #include <linux/completion.h> diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c index 4776273fa10b..794ecc9a552d 100644 --- a/drivers/input/misc/ixp4xx-beeper.c +++ b/drivers/input/misc/ixp4xx-beeper.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic IXP4xx beeper driver * @@ -8,11 +9,6 @@ * * Author: Alessandro Zummo <a.zummo@towertech.it> * Maintainers: http://www.nslu2-linux.org/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c index 312d63623038..25fcf1467151 100644 --- a/drivers/input/misc/m68kspkr.c +++ b/drivers/input/misc/m68kspkr.c @@ -1,17 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * m68k beeper driver for Linux * * Copyright (c) 2002 Richard Zidlicky * Copyright (c) 2002 Vojtech Pavlik * Copyright (c) 1992 Orest Zborowski - * */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation - */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/input/misc/pcap_keys.c b/drivers/input/misc/pcap_keys.c index 3b81daf67726..b5a53636d7e2 100644 --- a/drivers/input/misc/pcap_keys.c +++ b/drivers/input/misc/pcap_keys.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Input driver for PCAP events: * * Power key * * Headphone button * * Copyright (c) 2008,2009 Ilya Petrov <ilya.muromec@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 56ddba21de84..e5e0d8ba80e1 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -1,16 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PC Speaker beeper driver for Linux * * Copyright (c) 2002 Vojtech Pavlik * Copyright (c) 1992 Orest Zborowski - * */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation - */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/input/misc/regulator-haptic.c b/drivers/input/misc/regulator-haptic.c index a1db1e5040dc..a661e77545c5 100644 --- a/drivers/input/misc/regulator-haptic.c +++ b/drivers/input/misc/regulator-haptic.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Regulator haptic driver * * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Jaewon Kim <jaewon02.kim@samsung.com> * Author: Hyunhee Kim <hyunhee.kim@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/input.h> diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index d748897bf5e9..6d613f2a017c 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rotary_encoder.c * @@ -8,10 +9,6 @@ * * A generic driver for rotary encoders connected to GPIO lines. * See file:Documentation/input/devices/rotary-encoder.rst for more information - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 2ed559dd5e25..84051f20b18a 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -1038,13 +1038,31 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) #ifdef CONFIG_COMPAT -#define UI_SET_PHYS_COMPAT _IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t) +/* + * These IOCTLs change their size and thus their numbers between + * 32 and 64 bits. + */ +#define UI_SET_PHYS_COMPAT \ + _IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t) +#define UI_BEGIN_FF_UPLOAD_COMPAT \ + _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload_compat) +#define UI_END_FF_UPLOAD_COMPAT \ + _IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload_compat) static long uinput_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - if (cmd == UI_SET_PHYS_COMPAT) + switch (cmd) { + case UI_SET_PHYS_COMPAT: cmd = UI_SET_PHYS; + break; + case UI_BEGIN_FF_UPLOAD_COMPAT: + cmd = UI_BEGIN_FF_UPLOAD; + break; + case UI_END_FF_UPLOAD_COMPAT: + cmd = UI_END_FF_UPLOAD; + break; + } return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg)); } diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 0a6f7ca883e7..8996323ce8d9 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ALPS touchpad PS/2 mouse driver * @@ -9,10 +10,6 @@ * * ALPS detection, tap switching and status querying info is taken from * tpconfig utility (by C. Scott Ananian and Bruce Kall). - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/slab.h> diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 79b6d69d1486..f4bab629739c 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ALPS touchpad PS/2 mouse driver * * Copyright (c) 2003 Peter Osterlund <petero2@telia.com> * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef _ALPS_H diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c index a33437c480e3..a50e50354832 100644 --- a/drivers/input/mouse/amimouse.c +++ b/drivers/input/mouse/amimouse.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Amiga mouse driver for Linux/m68k * @@ -11,11 +12,6 @@ * Russell King */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation - */ #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c index 96f2f51604bd..b1219cc4d9a2 100644 --- a/drivers/input/mouse/atarimouse.c +++ b/drivers/input/mouse/atarimouse.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Atari mouse driver for Linux/m68k * @@ -7,7 +8,6 @@ * Amiga mouse driver for Linux/m68k * * Copyright (c) 2000-2002 Vojtech Pavlik - * */ /* * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c @@ -34,11 +34,6 @@ */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation - */ #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c index f2aabf7f906f..6e0c5f5a2713 100644 --- a/drivers/input/mouse/byd.c +++ b/drivers/input/mouse/byd.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * BYD TouchPad PS/2 mouse driver * @@ -6,10 +7,6 @@ * Copyright (C) 2015 Tai Chi Minh Ralph Eastwood * Copyright (C) 2015 Martin Wimpress * Copyright (C) 2015 Jay Kuri - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c index 21bad3e75fee..5f868009d35b 100644 --- a/drivers/input/mouse/cypress_ps2.c +++ b/drivers/input/mouse/cypress_ps2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Cypress Trackpad PS/2 mouse driver * @@ -9,10 +10,6 @@ * Additional contributors include: * Kamal Mostafa <kamal@canonical.com> * Kyle Fazzari <git@status.e4ward.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index 243e0fa6e3e3..a9074ac9364f 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Elan I2C/SMBus Touchpad driver * @@ -9,10 +10,6 @@ * copyright (c) 2011-2012 Cypress Semiconductor, Inc. * copyright (c) 2011-2012 Google, Inc. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Trademarks are the property of their respective owners. */ diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index f9525d6f0bfe..420efaab3860 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Elan I2C/SMBus Touchpad driver * @@ -11,10 +12,6 @@ * copyright (c) 2011-2012 Cypress Semiconductor, Inc. * copyright (c) 2011-2012 Google, Inc. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Trademarks are the property of their respective owners. */ @@ -981,6 +978,8 @@ static irqreturn_t elan_isr(int irq, void *dev_id) if (error) goto out; + pm_wakeup_event(dev, 0); + switch (report[ETP_REPORT_ID_OFFSET]) { case ETP_REPORT_ID: elan_report_absolute(data, report); diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index e19eb60b3d2f..058b35b1f9a9 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Elan I2C/SMBus Touchpad driver - I2C interface * @@ -9,10 +10,6 @@ * copyright (c) 2011-2012 Cypress Semiconductor, Inc. * copyright (c) 2011-2012 Google, Inc. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Trademarks are the property of their respective owners. */ diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index 88e315d2cfd3..8c3185d54c73 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Elan I2C/SMBus Touchpad driver - SMBus interface * @@ -9,10 +10,6 @@ * copyright (c) 2011-2012 Cypress Semiconductor, Inc. * copyright (c) 2011-2012 Google, Inc. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Trademarks are the property of their respective owners. */ diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index a7f8b1614559..a4345052abd2 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Elantech Touchpad driver (v6) * * Copyright (C) 2007-2009 Arjan Opmeer <arjan@opmeer.net> * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Trademarks are the property of their respective owners. */ @@ -1189,6 +1186,8 @@ static const char * const middle_button_pnp_ids[] = { "LEN2132", /* ThinkPad P52 */ "LEN2133", /* ThinkPad P72 w/ NFC */ "LEN2134", /* ThinkPad P72 */ + "LEN0407", + "LEN0408", NULL }; diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index 119727085a60..12ba5af93145 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Elantech Touchpad driver (v6) * * Copyright (C) 2007-2009 Arjan Opmeer <arjan@opmeer.net> * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Trademarks are the property of their respective owners. */ diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c index a26d8be6f795..461436f6f087 100644 --- a/drivers/input/mouse/gpio_mouse.c +++ b/drivers/input/mouse/gpio_mouse.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for simulating a mouse on GPIO lines. * * Copyright (C) 2007 Atmel Corporation * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index 015509e0b140..72a083f3fc4a 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OLPC HGPK (XO-1) touchpad PS/2 mouse driver * @@ -12,10 +13,6 @@ * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com> * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru> * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /* diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index a5765f747c02..bd9955730176 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Fujitsu B-series Lifebook PS/2 TouchScreen driver * @@ -6,10 +7,6 @@ * * TouchScreen detection, absolute mode setting and packet layout is taken from * Harald Hoyer's description of the device. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/input.h> diff --git a/drivers/input/mouse/lifebook.h b/drivers/input/mouse/lifebook.h index 0baf02a70a99..573f2ca1983d 100644 --- a/drivers/input/mouse/lifebook.h +++ b/drivers/input/mouse/lifebook.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Fujitsu B-series Lifebook PS/2 TouchScreen driver * * Copyright (c) 2005 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef _LIFEBOOK_H diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 3d5637e6fa5f..ed5a848dba9d 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Logitech PS/2++ mouse driver * * Copyright (c) 1999-2003 Vojtech Pavlik <vojtech@suse.cz> * Copyright (c) 2003 Eric Wong <eric@yhbt.net> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/bitops.h> diff --git a/drivers/input/mouse/logips2pp.h b/drivers/input/mouse/logips2pp.h index bf629453e095..5f9344135f70 100644 --- a/drivers/input/mouse/logips2pp.h +++ b/drivers/input/mouse/logips2pp.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Logitech PS/2++ mouse driver header * * Copyright (c) 2003 Vojtech Pavlik <vojtech@suse.cz> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef _LOGIPS2PP_H diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c index d6e8f58a1de3..0b75248c8380 100644 --- a/drivers/input/mouse/navpoint.c +++ b/drivers/input/mouse/navpoint.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Synaptics NavPoint (PXA27x SSP/SPI) driver. * * Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 94f7ca5ad077..527ae0b9a191 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PS/2 mouse driver * @@ -5,11 +6,6 @@ * Copyright (c) 2003-2004 Dmitry Torokhov */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define psmouse_fmt(fmt) fmt diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c index 852d4b486ddb..027efdd2b2ad 100644 --- a/drivers/input/mouse/psmouse-smbus.c +++ b/drivers/input/mouse/psmouse-smbus.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017 Red Hat, Inc - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c index 9b4d9a59e229..87bac8cff6f7 100644 --- a/drivers/input/mouse/pxa930_trkball.c +++ b/drivers/input/mouse/pxa930_trkball.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PXA930 track ball mouse driver * * Copyright (C) 2007 Marvell International Ltd. * 2008-02-28: Yong Yao <yaoyong@marvell.com> * initial version - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/input.h> diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c index 21c60fea5d31..6774029e0a1a 100644 --- a/drivers/input/mouse/rpcmouse.c +++ b/drivers/input/mouse/rpcmouse.c @@ -1,15 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Acorn RiscPC mouse driver for Linux/ARM * * Copyright (c) 2000-2002 Vojtech Pavlik * Copyright (C) 1996-2002 Russell King - * */ /* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. * * This handles the Acorn RiscPCs mouse. We basically have a couple of * hardware registers that track the sensor count for the X-Y movement and diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index b6da0c1267e3..b8ec301025b7 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Synaptics TouchPad PS/2 mouse driver * @@ -16,10 +17,6 @@ * Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com> * code for the special synaptics commands (from the tpconfig-source) * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Trademarks are the property of their respective owners. */ @@ -179,6 +176,8 @@ static const char * const smbus_pnp_ids[] = { "LEN0096", /* X280 */ "LEN0097", /* X280 -> ALPS trackpoint */ "LEN200f", /* T450s */ + "LEN2054", /* E480 */ + "LEN2055", /* E580 */ "SYN3052", /* HP EliteBook 840 G4 */ "SYN3221", /* HP 15-ay000 */ NULL diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index fc00e005c611..08533d1b1b16 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Synaptics TouchPad PS/2 mouse driver - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef _SYNAPTICS_H diff --git a/drivers/input/mouse/touchkit_ps2.h b/drivers/input/mouse/touchkit_ps2.h index 2efe9ea29d0c..5acb76464a5b 100644 --- a/drivers/input/mouse/touchkit_ps2.h +++ b/drivers/input/mouse/touchkit_ps2.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* ---------------------------------------------------------------------------- * touchkit_ps2.h -- Driver for eGalax TouchKit PS/2 Touchscreens * * Copyright (C) 2005 by Stefan Lucke * Copyright (c) 2005 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef _TOUCHKIT_PS2_H diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c index 6590d10f166f..3eefee2ee2a1 100644 --- a/drivers/input/mouse/trackpoint.c +++ b/drivers/input/mouse/trackpoint.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Stephen Evanchik <evanchsa@gmail.com> * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Trademarks are the property of their respective owners. */ diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h index 10a039148234..0afffe8d824f 100644 --- a/drivers/input/mouse/trackpoint.h +++ b/drivers/input/mouse/trackpoint.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * IBM TrackPoint PS/2 mouse driver * * Stephen Evanchik <evanchsa@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef _TRACKPOINT_H diff --git a/drivers/input/mouse/vmmouse.c b/drivers/input/mouse/vmmouse.c index 1ae5c1ef3f5b..871e5b5ab129 100644 --- a/drivers/input/mouse/vmmouse.c +++ b/drivers/input/mouse/vmmouse.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Virtual PS/2 Mouse on VMware and QEMU hypervisors. * * Copyright (C) 2014, VMware, Inc. All Rights Reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Twin device code is hugely inspired by the ALPS driver. * Authors: * Dmitry Torokhov <dmitry.torokhov@gmail.com> diff --git a/drivers/input/mouse/vmmouse.h b/drivers/input/mouse/vmmouse.h index 6f126017a24c..774549a12930 100644 --- a/drivers/input/mouse/vmmouse.h +++ b/drivers/input/mouse/vmmouse.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Driver for Virtual PS/2 Mouse on VMware and QEMU hypervisors. * * Copyright (C) 2014, VMware, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef _VMMOUSE_H diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 412fa71245af..3b73e0f17848 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Input driver to ExplorerPS/2 device driver module. * * Copyright (c) 1999-2002 Vojtech Pavlik * Copyright (c) 2004 Dmitry Torokhov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c index 8eeffa066022..ea549efe4bc4 100644 --- a/drivers/input/rmi4/rmi_2d_sensor.c +++ b/drivers/input/rmi4/rmi_2d_sensor.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011-2016 Synaptics Incorporated * Copyright (c) 2011 Unixphere - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/rmi4/rmi_2d_sensor.h b/drivers/input/rmi4/rmi_2d_sensor.h index c871bef4dac0..7d335d809710 100644 --- a/drivers/input/rmi4/rmi_2d_sensor.h +++ b/drivers/input/rmi4/rmi_2d_sensor.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2011-2016 Synaptics Incorporated * Copyright (c) 2011 Unixphere - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef _RMI_2D_SENSOR_H diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index bd0d5ff01b08..af706a583656 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011-2016 Synaptics Incorporated * Copyright (c) 2011 Unixphere - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h index 96383eab41ba..25df6320f9f1 100644 --- a/drivers/input/rmi4/rmi_bus.h +++ b/drivers/input/rmi4/rmi_bus.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2011-2016 Synaptics Incorporated * Copyright (c) 2011 Unixphere - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef _RMI_BUS_H diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 7fb358f96195..772493b1f665 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011-2016 Synaptics Incorporated * Copyright (c) 2011 Unixphere @@ -8,10 +9,6 @@ * * http://www.synaptics.com/sites/default/files/ * 511-000136-01-Rev-E-RMI4-Interfacing-Guide.pdf - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/bitmap.h> diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h index d31793ae83f0..65bfaa95e193 100644 --- a/drivers/input/rmi4/rmi_driver.h +++ b/drivers/input/rmi4/rmi_driver.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2011-2016 Synaptics Incorporated * Copyright (c) 2011 Unixphere - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef _RMI_DRIVER_H diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c index 4edaa14fe878..e623c956376e 100644 --- a/drivers/input/rmi4/rmi_f01.c +++ b/drivers/input/rmi4/rmi_f01.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011-2016 Synaptics Incorporated * Copyright (c) 2011 Unixphere - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c index aaa1edc95522..c194b1664b10 100644 --- a/drivers/input/rmi4/rmi_f03.c +++ b/drivers/input/rmi4/rmi_f03.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015-2016 Red Hat * Copyright (C) 2015 Lyude Paul <thatslyude@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c index 93901ebd122a..f28a7158b2ef 100644 --- a/drivers/input/rmi4/rmi_f11.c +++ b/drivers/input/rmi4/rmi_f11.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011-2015 Synaptics Incorporated * Copyright (c) 2011 Unixphere - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index 5c7f48915779..bb14369e34a7 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012-2016 Synaptics Incorporated - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/input.h> #include <linux/input/mt.h> diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c index 5e3ed5ac0c3e..a90dad1d9ac7 100644 --- a/drivers/input/rmi4/rmi_f30.c +++ b/drivers/input/rmi4/rmi_f30.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012-2016 Synaptics Incorporated - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c index 87a7d4ba382d..e5dca9868f87 100644 --- a/drivers/input/rmi4/rmi_f34.c +++ b/drivers/input/rmi4/rmi_f34.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2007-2016, Synaptics Incorporated * Copyright (C) 2016 Zodiac Inflight Innovations - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/rmi4/rmi_f34.h b/drivers/input/rmi4/rmi_f34.h index 32c4e9581c68..99faa8c2269d 100644 --- a/drivers/input/rmi4/rmi_f34.h +++ b/drivers/input/rmi4/rmi_f34.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2007-2016, Synaptics Incorporated * Copyright (C) 2016 Zodiac Inflight Innovations - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef _RMI_F34_H diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c index 3991d2943660..a4cabf52740c 100644 --- a/drivers/input/rmi4/rmi_f34v7.c +++ b/drivers/input/rmi4/rmi_f34v7.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016, Zodiac Inflight Innovations * Copyright (c) 2007-2016, Synaptics Incorporated * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/bitops.h> diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c index 516fea06ed59..710b02595486 100644 --- a/drivers/input/rmi4/rmi_f54.c +++ b/drivers/input/rmi4/rmi_f54.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012-2015 Synaptics Incorporated * Copyright (C) 2016 Zodiac Inflight Innovations - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/rmi4/rmi_f55.c b/drivers/input/rmi4/rmi_f55.c index 37390ca6a924..488adaca4dd0 100644 --- a/drivers/input/rmi4/rmi_f55.c +++ b/drivers/input/rmi4/rmi_f55.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012-2015 Synaptics Incorporated * Copyright (C) 2016 Zodiac Inflight Innovations - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/bitops.h> diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c index d4b3f9d0dc2e..a95c2c9bcab4 100644 --- a/drivers/input/rmi4/rmi_i2c.c +++ b/drivers/input/rmi4/rmi_i2c.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011-2016 Synaptics Incorporated * Copyright (c) 2011 Unixphere - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/i2c.h> diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c index b6ccf39c6a7b..2407ea43de59 100644 --- a/drivers/input/rmi4/rmi_smbus.c +++ b/drivers/input/rmi4/rmi_smbus.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015 - 2016 Red Hat, Inc * Copyright (c) 2011, 2012 Synaptics Incorporated * Copyright (c) 2011 Unixphere - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c index 33b8c6e7ac0a..27b68dc79b18 100644 --- a/drivers/input/rmi4/rmi_spi.c +++ b/drivers/input/rmi4/rmi_spi.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011-2016 Synaptics Incorporated * Copyright (c) 2011 Unixphere - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c index 131d7826dc6b..379e9240c2b3 100644 --- a/drivers/input/serio/altera_ps2.c +++ b/drivers/input/serio/altera_ps2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Altera University Program PS2 controller driver * @@ -5,10 +6,6 @@ * * Based on sa1111ps2.c, which is: * Copyright (C) 2002 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c index f8663d7891f2..1c0be299f179 100644 --- a/drivers/input/serio/ams_delta_serio.c +++ b/drivers/input/serio/ams_delta_serio.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Amstrad E3 (Delta) keyboard port driver * * Copyright (c) 2006 Matt Callow * Copyright (c) 2010 Janusz Krzysztofik * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Thanks to Cliff Lawson for his help * * The Amstrad Delta keyboard (aka mailboard) uses normal PC-AT style serial diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c index 99e57a418753..443194a2b9e3 100644 --- a/drivers/input/serio/arc_ps2.c +++ b/drivers/input/serio/arc_ps2.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Driver is originally developed by Pavel Sokolov <psokolov@synopsys.com> */ diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h index 34da81c006b6..da0bf85321de 100644 --- a/drivers/input/serio/i8042-io.h +++ b/drivers/input/serio/i8042-io.h @@ -1,11 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef _I8042_IO_H #define _I8042_IO_H -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ /* * Names. diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h index 08a1c10a1448..6c7efa01745c 100644 --- a/drivers/input/serio/i8042-ip22io.h +++ b/drivers/input/serio/i8042-ip22io.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef _I8042_IP22_H #define _I8042_IP22_H #include <asm/sgi/ioc.h> #include <asm/sgi/ip22.h> -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ /* * Names. diff --git a/drivers/input/serio/i8042-jazzio.h b/drivers/input/serio/i8042-jazzio.h index 13fd7108eb28..4c2a96f9128c 100644 --- a/drivers/input/serio/i8042-jazzio.h +++ b/drivers/input/serio/i8042-jazzio.h @@ -1,13 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef _I8042_JAZZ_H #define _I8042_JAZZ_H #include <asm/jazz.h> -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ /* * Names. diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h index 1aabea43329e..391f94d9e47d 100644 --- a/drivers/input/serio/i8042-ppcio.h +++ b/drivers/input/serio/i8042-ppcio.h @@ -1,11 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef _I8042_PPCIO_H #define _I8042_PPCIO_H -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ #if defined(CONFIG_WALNUT) diff --git a/drivers/input/serio/i8042-snirm.h b/drivers/input/serio/i8042-snirm.h index 409a9341143d..4b7136704338 100644 --- a/drivers/input/serio/i8042-snirm.h +++ b/drivers/input/serio/i8042-snirm.h @@ -1,13 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef _I8042_SNIRM_H #define _I8042_SNIRM_H #include <asm/sni.h> -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ /* * Names. diff --git a/drivers/input/serio/i8042-unicore32io.h b/drivers/input/serio/i8042-unicore32io.h index 455747552f85..50bb3ed94b56 100644 --- a/drivers/input/serio/i8042-unicore32io.h +++ b/drivers/input/serio/i8042-unicore32io.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Code specific to PKUnity SoC and UniCore ISA * * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> * Copyright (C) 2001-2011 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _I8042_UNICORE32_H #define _I8042_UNICORE32_H diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 136f6e7bf797..dc974c288e88 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -1,11 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef _I8042_X86IA64IO_H #define _I8042_X86IA64IO_H -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ #ifdef CONFIG_X86 #include <asm/x86_init.h> diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 6462f1798fbb..b695094290ab 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * i8042 keyboard and mouse controller driver for Linux * * Copyright (c) 1999-2004 Vojtech Pavlik */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -1410,7 +1406,7 @@ static void __init i8042_register_ports(void) * behavior on many platforms using suspend-to-RAM (ACPI S3) * by default. */ - if (pm_suspend_via_s2idle() && i == I8042_KBD_PORT_NO) + if (pm_suspend_default_s2idle() && i == I8042_KBD_PORT_NO) device_set_wakeup_enable(&serio->dev, true); } } diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h index 1db0a40c9bab..38dc27ad3c18 100644 --- a/drivers/input/serio/i8042.h +++ b/drivers/input/serio/i8042.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef _I8042_H #define _I8042_H /* * Copyright (c) 1999-2002 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ /* diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index 22b8e05aa36c..a8c94a940a79 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PS/2 driver library * @@ -5,11 +6,6 @@ * Copyright (c) 2004 Dmitry Torokhov */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ #include <linux/delay.h> #include <linux/module.h> diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index e365c5f4cbc9..629e15089c21 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SGI O2 MACE PS2 controller driver for linux * * Copyright (C) 2002 Vivien Chappelier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation */ #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c index 1edfac78d4ac..ddbbd4afb4a2 100644 --- a/drivers/input/serio/parkbd.c +++ b/drivers/input/serio/parkbd.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Parallel port to Keyboard port adapter driver for Linux * * Copyright (c) 1999-2004 Vojtech Pavlik */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ /* * To connect an AT or XT keyboard to the parallel port, a fairly simple adapter diff --git a/drivers/input/serio/ps2-gpio.c b/drivers/input/serio/ps2-gpio.c index 5e8d8384aa2a..e0f18469d01b 100644 --- a/drivers/input/serio/ps2-gpio.c +++ b/drivers/input/serio/ps2-gpio.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * GPIO based serio bus driver for bit banging the PS/2 protocol * * Author: Danilo Krummrich <danilokrummrich@dk-develop.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/gpio/consumer.h> diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c index a76fb64f03db..0071dd5ebcc2 100644 --- a/drivers/input/serio/ps2mult.c +++ b/drivers/input/serio/ps2mult.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TQC PS/2 Multiplexer driver * * Copyright (C) 2010 Dmitry Eremin-Solenikov - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 17b7fbecd9fe..e9647ebff187 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Raw serio device providing access to a raw byte stream from underlying * serio port. Closely emulates behavior of pre-2.6 /dev/psaux device * * Copyright (c) 2004 Dmitry Torokhov - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kref.h> diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 5977b8a34ebe..8ac970a423de 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Input device TTY line discipline * @@ -7,11 +8,6 @@ * 'serial io port' abstraction that the input device drivers use. */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ #include <linux/uaccess.h> #include <linux/kernel.h> diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index 0cad5e7c559b..530fd15eaeca 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic support for sparse keymaps * @@ -7,10 +8,6 @@ * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org> * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/input.h> diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index 3486d9403805..1d1bbc8da949 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Touchscreen driver for Marvell 88PM860x * * Copyright (C) 2009 Marvell International Ltd. * Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index a2f45aefce08..accbbe8d2966 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ADS7846 based touchscreen and sensor driver * @@ -12,10 +13,6 @@ * Copyright (C) 2002 MontaVista Software * Copyright (C) 2004 Texas Instruments * Copyright (C) 2005 Dirk Behme - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/types.h> #include <linux/hwmon.h> diff --git a/drivers/input/touchscreen/da9034-ts.c b/drivers/input/touchscreen/da9034-ts.c index 8264822dc4b9..2943f6a58388 100644 --- a/drivers/input/touchscreen/da9034-ts.c +++ b/drivers/input/touchscreen/da9034-ts.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Touchscreen driver for Dialog Semiconductor DA9034 * @@ -5,10 +6,6 @@ * Fengwei Yin <fengwei.yin@marvell.com> * Bin Yang <bin.yang@marvell.com> * Eric Miao <eric.miao@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c index 5b1b66fffbe3..dc07fca7c5ed 100644 --- a/drivers/input/touchscreen/dynapro.c +++ b/drivers/input/touchscreen/dynapro.c @@ -1,17 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Dynapro serial touchscreen driver * * Copyright (c) 2009 Tias Guns * Based on the inexio driver (c) Vojtech Pavlik and Dan Streetman and * Richard Lemon - * */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ /* * 2009/09/19 Tias Guns <tias@ulyssis.org> diff --git a/drivers/input/touchscreen/egalax_ts_serial.c b/drivers/input/touchscreen/egalax_ts_serial.c index 657bbae608c8..375922d3a6d1 100644 --- a/drivers/input/touchscreen/egalax_ts_serial.c +++ b/drivers/input/touchscreen/egalax_ts_serial.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * EETI Egalax serial touchscreen driver * @@ -8,11 +9,6 @@ * Hampshire serial touchscreen driver (Copyright (c) 2010 Adam Bennett) */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ #include <linux/errno.h> #include <linux/kernel.h> diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index f2cb23121833..d4ad24ea54c8 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Elan Microelectronics touch panels with I2C interface * @@ -10,7 +11,6 @@ * Copyright (c) 2010-2012 Benjamin Tissoires <benjamin.tissoires@gmail.com> * Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France * - * * This code is partly based on i2c-hid.c: * * Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com> @@ -18,11 +18,6 @@ * Copyright (c) 2012 Red Hat, Inc */ -/* - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - */ #include <linux/module.h> #include <linux/input.h> diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index 7f2942f3cec6..d6772a2c2d09 100644 --- a/drivers/input/touchscreen/elo.c +++ b/drivers/input/touchscreen/elo.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Elo serial touchscreen driver * * Copyright (c) 2004 Vojtech Pavlik */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ /* * This driver can handle serial Elo touchscreens using either the Elo standard diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c index 37437a53cd1a..e007e2e8f626 100644 --- a/drivers/input/touchscreen/exc3000.c +++ b/drivers/input/touchscreen/exc3000.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for I2C connected EETI EXC3000 multiple touch controller * * Copyright (C) 2017 Ahmet Inan <inan@distec.de> * * minimal implementation based on egalax_ts.c and egalax_i2c.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c index a0fbb454499d..3b0b8fccc3f0 100644 --- a/drivers/input/touchscreen/fujitsu_ts.c +++ b/drivers/input/touchscreen/fujitsu_ts.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Fujitsu serial touchscreen driver * * Copyright (c) Dmitry Torokhov <dtor@mail.ru> */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ #include <linux/errno.h> #include <linux/kernel.h> diff --git a/drivers/input/touchscreen/hampshire.c b/drivers/input/touchscreen/hampshire.c index eb052d559e54..5c4d877564ee 100644 --- a/drivers/input/touchscreen/hampshire.c +++ b/drivers/input/touchscreen/hampshire.c @@ -1,16 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Hampshire serial touchscreen driver * * Copyright (c) 2010 Adam Bennett * Based on the dynapro driver (c) Tias Guns - * */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ /* * 2010/04/08 Adam Bennett <abennett72@gmail.com> diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c index f1cd4dd9a4a3..84fbbf415c43 100644 --- a/drivers/input/touchscreen/hideep.c +++ b/drivers/input/touchscreen/hideep.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012-2017 Hideep, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 - * as published by the Free Software Foudation. */ #include <linux/module.h> diff --git a/drivers/input/touchscreen/htcpen.c b/drivers/input/touchscreen/htcpen.c index 8fd909285877..2f261a34f9c2 100644 --- a/drivers/input/touchscreen/htcpen.c +++ b/drivers/input/touchscreen/htcpen.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HTC Shift touchscreen driver * * Copyright (C) 2008 Pau Oliva Fora <pof@eslack.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include <linux/errno.h> diff --git a/drivers/input/touchscreen/inexio.c b/drivers/input/touchscreen/inexio.c index 13bd0bf580a7..1d7e4c3966ce 100644 --- a/drivers/input/touchscreen/inexio.c +++ b/drivers/input/touchscreen/inexio.c @@ -1,16 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * iNexio serial touchscreen driver * * Copyright (c) 2008 Richard Lemon * Based on the mtouch driver (c) Vojtech Pavlik and Dan Streetman - * */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ /* * 2008/06/19 Richard Lemon <richard@codelemon.com> diff --git a/drivers/input/touchscreen/ipaq-micro-ts.c b/drivers/input/touchscreen/ipaq-micro-ts.c index 33c134820ef9..5c3977e1af6f 100644 --- a/drivers/input/touchscreen/ipaq-micro-ts.c +++ b/drivers/input/touchscreen/ipaq-micro-ts.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. * * h3600 atmel micro companion support, touchscreen subdevice * Author : Alessandro Gardich <gremlin@gremlin.it> * Author : Dmitry Artamonow <mad_soft@inbox.ru> * Author : Linus Walleij <linus.walleij@linaro.org> - * */ #include <asm/byteorder.h> diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index b832fe062645..4f6fe8cc8efa 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -502,14 +502,6 @@ static int iqs5xx_axis_init(struct i2c_client *client) input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y); input_set_capability(input, EV_ABS, ABS_MT_PRESSURE); - error = input_mt_init_slots(input, - IQS5XX_NUM_CONTACTS, INPUT_MT_DIRECT); - if (error) { - dev_err(&client->dev, - "Failed to initialize slots: %d\n", error); - return error; - } - input_set_drvdata(input, iqs5xx); iqs5xx->input = input; } @@ -591,9 +583,19 @@ static int iqs5xx_axis_init(struct i2c_client *client) if (error) return error; - return iqs5xx_write_word(client, - prop.swap_x_y ? IQS5XX_X_RES : IQS5XX_Y_RES, - max_y); + error = iqs5xx_write_word(client, + prop.swap_x_y ? IQS5XX_X_RES : IQS5XX_Y_RES, + max_y); + if (error) + return error; + + error = input_mt_init_slots(iqs5xx->input, IQS5XX_NUM_CONTACTS, + INPUT_MT_DIRECT); + if (error) + dev_err(&client->dev, "Failed to initialize slots: %d\n", + error); + + return error; } static int iqs5xx_dev_init(struct i2c_client *client) diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index 729b3c89324c..974521102178 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/input/touchscreen/jornada720_ts.c * @@ -6,10 +7,6 @@ * Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl> * based on HP Jornada 56x touchscreen driver by Alex Lange <chicken@handhelds.org> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * HP Jornada 710/720/729 Touchscreen Driver */ diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c index ef64f36c5ffc..ae0d978c83bf 100644 --- a/drivers/input/touchscreen/mc13783_ts.c +++ b/drivers/input/touchscreen/mc13783_ts.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for the Freescale Semiconductor MC13783 touchscreen. * @@ -6,10 +7,6 @@ * * Initial development of this code was funded by * Phytec Messtechnik GmbH, http://www.phytec.de/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/platform_device.h> #include <linux/mfd/mc13783.h> diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c index c179060525ae..753d9cc1de1f 100644 --- a/drivers/input/touchscreen/mk712.c +++ b/drivers/input/touchscreen/mk712.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ICS MK712 touchscreen controller driver * @@ -6,11 +7,6 @@ * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ /* * This driver supports the ICS MicroClock MK712 TouchScreen controller, diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c index 8278a9058640..28e449eea318 100644 --- a/drivers/input/touchscreen/mtouch.c +++ b/drivers/input/touchscreen/mtouch.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * MicroTouch (3M) serial touchscreen driver * * Copyright (c) 2004 Vojtech Pavlik */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ /* * 2005/02/19 Dan Streetman <ddstreet@ieee.org> diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c index 6d241d45e312..e16ec4c7043a 100644 --- a/drivers/input/touchscreen/of_touchscreen.c +++ b/drivers/input/touchscreen/of_touchscreen.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic DT helper functions for touchscreen devices * * Copyright (c) 2014 Sebastian Reichel <sre@kernel.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/property.h> diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c index 0e3fc419a3cf..b2da0194e02a 100644 --- a/drivers/input/touchscreen/pcap_ts.c +++ b/drivers/input/touchscreen/pcap_ts.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Motorola PCAP2 touchscreen as found in the EZX phone platform. * * Copyright (C) 2006 Harald Welte <laforge@openezx.org> * Copyright (C) 2009 Daniel Ribeiro <drwyrm@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c index 6e6d7fd98cd2..12abb3b36128 100644 --- a/drivers/input/touchscreen/penmount.c +++ b/drivers/input/touchscreen/penmount.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Penmount serial touchscreen driver * @@ -8,11 +9,6 @@ * Copyright (c) 2004 Vojtech Pavlik */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ #include <linux/errno.h> #include <linux/kernel.h> diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c index a67d5e93fb77..ad8b6a2bfd36 100644 --- a/drivers/input/touchscreen/silead.c +++ b/drivers/input/touchscreen/silead.c @@ -609,6 +609,7 @@ static const struct acpi_device_id silead_ts_acpi_match[] = { { "MSSL1680", 0 }, { "MSSL0001", 0 }, { "MSSL0002", 0 }, + { "MSSL0017", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, silead_ts_acpi_match); diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index 8c8ac4dff0d5..00cb1ba2d364 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -929,10 +929,6 @@ static int sur40_vidioc_querycap(struct file *file, void *priv, strlcpy(cap->driver, DRIVER_SHORT, sizeof(cap->driver)); strlcpy(cap->card, DRIVER_LONG, sizeof(cap->card)); usb_make_path(sur40->usbdev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TOUCH | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1162,6 +1158,8 @@ static const struct video_device sur40_video_device = { .fops = &sur40_video_fops, .ioctl_ops = &sur40_video_ioctl_ops, .release = video_device_release_empty, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TOUCH | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING, }; /* USB-specific object needed to register this driver with the USB subsystem. */ diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c index dbdf4898aa17..de85e57b2486 100644 --- a/drivers/input/touchscreen/sx8654.c +++ b/drivers/input/touchscreen/sx8654.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Semtech SX8654 I2C touchscreen controller. * @@ -21,10 +22,6 @@ * Copyright (C) 2002 MontaVista Software * Copyright (C) 2004 Texas Instruments * Copyright (C) 2005 Dirk Behme - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> diff --git a/drivers/input/touchscreen/touchit213.c b/drivers/input/touchscreen/touchit213.c index 98a16698be8e..fb49687da405 100644 --- a/drivers/input/touchscreen/touchit213.c +++ b/drivers/input/touchscreen/touchit213.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Sahara TouchIT-213 serial touchscreen driver * @@ -9,11 +10,6 @@ * and Dan Streetman <ddstreet@ieee.org> */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ #include <linux/errno.h> #include <linux/kernel.h> diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c index 45c325c33f21..3cd58a13e44f 100644 --- a/drivers/input/touchscreen/touchright.c +++ b/drivers/input/touchscreen/touchright.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Touchright serial touchscreen driver * @@ -8,11 +9,6 @@ * and Dan Streetman <ddstreet@ieee.org> */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ #include <linux/errno.h> #include <linux/kernel.h> diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c index 2ba6b4ca28cb..bde3c6ee3c60 100644 --- a/drivers/input/touchscreen/touchwin.c +++ b/drivers/input/touchscreen/touchwin.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Touchwindow serial touchscreen driver * @@ -8,11 +9,6 @@ * and Dan Streetman <ddstreet@ieee.org> */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ /* * 2005/02/19 Rick Koch: diff --git a/drivers/input/touchscreen/tsc2007.h b/drivers/input/touchscreen/tsc2007.h index 30fdf5b04a6b..91c60bf6dcaf 100644 --- a/drivers/input/touchscreen/tsc2007.h +++ b/drivers/input/touchscreen/tsc2007.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2008 MtekVision Co., Ltd. @@ -13,10 +14,6 @@ * Copyright (C) 2002 MontaVista Software * Copyright (C) 2004 Texas Instruments * Copyright (C) 2005 Dirk Behme - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _TSC2007_H diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index 8342e0c48a53..3b80abfc1eca 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/input/touchscreen/tsc2007.c * @@ -14,10 +15,6 @@ * Copyright (C) 2002 MontaVista Software * Copyright (C) 2004 Texas Instruments * Copyright (C) 2005 Dirk Behme - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/input/touchscreen/tsc2007_iio.c b/drivers/input/touchscreen/tsc2007_iio.c index e27a956f5f2b..3b0e3fa87d4c 100644 --- a/drivers/input/touchscreen/tsc2007_iio.c +++ b/drivers/input/touchscreen/tsc2007_iio.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016 Golden Delicious Comp. GmbH&Co. KG * Nikolaus Schaller <hns@goldelico.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/i2c.h> diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 1a86cbd9326f..807d39e18091 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Philips UCB1400 touchscreen driver * @@ -9,10 +10,6 @@ * If something doesn't work and it worked before spliting, e-mail me, * dont bother Nicolas please ;-) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This code is heavily based on ucb1x00-*.c copyrighted by Russell King * covering the UCB1100, UCB1200 and UCB1300.. Support for the UCB1400 has * been made separate from ucb1x00-core/ucb1x00-ts on Russell's request. diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index dce1d8d2e8a4..73740b969e62 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -619,9 +619,9 @@ retry: pasid = ((event[0] >> 16) & 0xFFFF) | ((event[1] << 6) & 0xF0000); tag = event[1] & 0x03FF; - dev_err(dev, "Event logged [INVALID_PPR_REQUEST device=%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x]\n", + dev_err(dev, "Event logged [INVALID_PPR_REQUEST device=%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x tag=0x%03x]\n", PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid), - pasid, address, flags); + pasid, address, flags, tag); break; default: dev_err(dev, "Event logged [UNKNOWN event[0]=0x%08x event[1]=0x%08x event[2]=0x%08x event[3]=0x%08x\n", @@ -1295,6 +1295,16 @@ static void domain_flush_complete(struct protection_domain *domain) } } +/* Flush the not present cache if it exists */ +static void domain_flush_np_cache(struct protection_domain *domain, + dma_addr_t iova, size_t size) +{ + if (unlikely(amd_iommu_np_cache)) { + domain_flush_pages(domain, iova, size); + domain_flush_complete(domain); + } +} + /* * This function flushes the DTEs for all devices in domain @@ -2377,10 +2387,7 @@ static dma_addr_t __map_single(struct device *dev, } address += offset; - if (unlikely(amd_iommu_np_cache)) { - domain_flush_pages(&dma_dom->domain, address, size); - domain_flush_complete(&dma_dom->domain); - } + domain_flush_np_cache(&dma_dom->domain, address, size); out: return address; @@ -2559,6 +2566,9 @@ static int map_sg(struct device *dev, struct scatterlist *sglist, s->dma_length = s->length; } + if (s) + domain_flush_np_cache(domain, s->dma_address, s->dma_length); + return nelems; out_unmap: @@ -2597,7 +2607,7 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist, struct protection_domain *domain; struct dma_ops_domain *dma_dom; unsigned long startaddr; - int npages = 2; + int npages; domain = get_domain(dev); if (IS_ERR(domain)) @@ -3039,6 +3049,8 @@ static int amd_iommu_map(struct iommu_domain *dom, unsigned long iova, ret = iommu_map_page(domain, iova, paddr, page_size, prot, GFP_KERNEL); mutex_unlock(&domain->api_lock); + domain_flush_np_cache(domain, iova, page_size); + return ret; } diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 07d84dbab564..eb104c719629 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -406,6 +406,9 @@ static void iommu_enable(struct amd_iommu *iommu) static void iommu_disable(struct amd_iommu *iommu) { + if (!iommu->mmio_base) + return; + /* Disable command buffer */ iommu_feature_disable(iommu, CONTROL_CMDBUF_EN); @@ -2325,15 +2328,6 @@ static void __init free_iommu_resources(void) amd_iommu_dev_table = NULL; free_iommu_all(); - -#ifdef CONFIG_GART_IOMMU - /* - * We failed to initialize the AMD IOMMU - try fallback to GART - * if possible. - */ - gart_iommu_init(); - -#endif } /* SB IOAPIC is always on this device in AMD systems */ @@ -2625,8 +2619,6 @@ static int __init state_next(void) init_state = ret ? IOMMU_INIT_ERROR : IOMMU_ACPI_FINISHED; if (init_state == IOMMU_ACPI_FINISHED && amd_iommu_disabled) { pr_info("AMD IOMMU disabled on kernel command-line\n"); - free_dma_resources(); - free_iommu_resources(); init_state = IOMMU_CMDLINE_DISABLED; ret = -EINVAL; } @@ -2667,6 +2659,19 @@ static int __init state_next(void) BUG(); } + if (ret) { + free_dma_resources(); + if (!irq_remapping_enabled) { + disable_iommus(); + free_iommu_resources(); + } else { + struct amd_iommu *iommu; + + uninit_device_table_dma(); + for_each_iommu(iommu) + iommu_flush_all_caches(iommu); + } + } return ret; } @@ -2740,17 +2745,15 @@ static int __init amd_iommu_init(void) int ret; ret = iommu_go_to_state(IOMMU_INITIALIZED); - if (ret) { - free_dma_resources(); - if (!irq_remapping_enabled) { - disable_iommus(); - free_iommu_resources(); - } else { - uninit_device_table_dma(); - for_each_iommu(iommu) - iommu_flush_all_caches(iommu); - } +#ifdef CONFIG_GART_IOMMU + if (ret && list_empty(&amd_iommu_list)) { + /* + * We failed to initialize the AMD IOMMU - try fallback + * to GART if possible. + */ + gart_iommu_init(); } +#endif for_each_iommu(iommu) amd_iommu_debugfs_setup(iommu); diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 4d5a694f02c2..2d96cf0023dd 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -192,6 +192,13 @@ #define Q_BASE_ADDR_MASK GENMASK_ULL(51, 5) #define Q_BASE_LOG2SIZE GENMASK(4, 0) +/* Ensure DMA allocations are naturally aligned */ +#ifdef CONFIG_CMA_ALIGNMENT +#define Q_MAX_SZ_SHIFT (PAGE_SHIFT + CONFIG_CMA_ALIGNMENT) +#else +#define Q_MAX_SZ_SHIFT (PAGE_SHIFT + MAX_ORDER - 1) +#endif + /* * Stream table. * @@ -289,8 +296,9 @@ FIELD_GET(ARM64_TCR_##fld, tcr)) /* Command queue */ -#define CMDQ_ENT_DWORDS 2 -#define CMDQ_MAX_SZ_SHIFT 8 +#define CMDQ_ENT_SZ_SHIFT 4 +#define CMDQ_ENT_DWORDS ((1 << CMDQ_ENT_SZ_SHIFT) >> 3) +#define CMDQ_MAX_SZ_SHIFT (Q_MAX_SZ_SHIFT - CMDQ_ENT_SZ_SHIFT) #define CMDQ_CONS_ERR GENMASK(30, 24) #define CMDQ_ERR_CERROR_NONE_IDX 0 @@ -336,14 +344,16 @@ #define CMDQ_SYNC_1_MSIADDR_MASK GENMASK_ULL(51, 2) /* Event queue */ -#define EVTQ_ENT_DWORDS 4 -#define EVTQ_MAX_SZ_SHIFT 7 +#define EVTQ_ENT_SZ_SHIFT 5 +#define EVTQ_ENT_DWORDS ((1 << EVTQ_ENT_SZ_SHIFT) >> 3) +#define EVTQ_MAX_SZ_SHIFT (Q_MAX_SZ_SHIFT - EVTQ_ENT_SZ_SHIFT) #define EVTQ_0_ID GENMASK_ULL(7, 0) /* PRI queue */ -#define PRIQ_ENT_DWORDS 2 -#define PRIQ_MAX_SZ_SHIFT 8 +#define PRIQ_ENT_SZ_SHIFT 4 +#define PRIQ_ENT_DWORDS ((1 << PRIQ_ENT_SZ_SHIFT) >> 3) +#define PRIQ_MAX_SZ_SHIFT (Q_MAX_SZ_SHIFT - PRIQ_ENT_SZ_SHIFT) #define PRIQ_0_SID GENMASK_ULL(31, 0) #define PRIQ_0_SSID GENMASK_ULL(51, 32) @@ -798,7 +808,7 @@ static int queue_remove_raw(struct arm_smmu_queue *q, u64 *ent) /* High-level queue accessors */ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent) { - memset(cmd, 0, CMDQ_ENT_DWORDS << 3); + memset(cmd, 0, 1 << CMDQ_ENT_SZ_SHIFT); cmd[0] |= FIELD_PREP(CMDQ_0_OP, ent->opcode); switch (ent->opcode) { @@ -1785,13 +1795,11 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain) .pgsize_bitmap = smmu->pgsize_bitmap, .ias = ias, .oas = oas, + .coherent_walk = smmu->features & ARM_SMMU_FEAT_COHERENCY, .tlb = &arm_smmu_gather_ops, .iommu_dev = smmu->dev, }; - if (smmu->features & ARM_SMMU_FEAT_COHERENCY) - pgtbl_cfg.quirks = IO_PGTABLE_QUIRK_NO_DMA; - if (smmu_domain->non_strict) pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT; @@ -1884,9 +1892,13 @@ static int arm_smmu_enable_ats(struct arm_smmu_master *master) static void arm_smmu_disable_ats(struct arm_smmu_master *master) { + struct arm_smmu_cmdq_ent cmd; + if (!master->ats_enabled || !dev_is_pci(master->dev)) return; + arm_smmu_atc_inv_to_cmd(0, 0, 0, &cmd); + arm_smmu_atc_inv_master(master, &cmd); pci_disable_ats(to_pci_dev(master->dev)); master->ats_enabled = false; } @@ -1906,7 +1918,6 @@ static void arm_smmu_detach_dev(struct arm_smmu_master *master) master->domain = NULL; arm_smmu_install_ste_for_dev(master); - /* Disabling ATS invalidates all ATC entries */ arm_smmu_disable_ats(master); } @@ -2270,17 +2281,32 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu, struct arm_smmu_queue *q, unsigned long prod_off, unsigned long cons_off, - size_t dwords) + size_t dwords, const char *name) { - size_t qsz = ((1 << q->max_n_shift) * dwords) << 3; + size_t qsz; + + do { + qsz = ((1 << q->max_n_shift) * dwords) << 3; + q->base = dmam_alloc_coherent(smmu->dev, qsz, &q->base_dma, + GFP_KERNEL); + if (q->base || qsz < PAGE_SIZE) + break; + + q->max_n_shift--; + } while (1); - q->base = dmam_alloc_coherent(smmu->dev, qsz, &q->base_dma, GFP_KERNEL); if (!q->base) { - dev_err(smmu->dev, "failed to allocate queue (0x%zx bytes)\n", - qsz); + dev_err(smmu->dev, + "failed to allocate queue (0x%zx bytes) for %s\n", + qsz, name); return -ENOMEM; } + if (!WARN_ON(q->base_dma & (qsz - 1))) { + dev_info(smmu->dev, "allocated %u entries for %s\n", + 1 << q->max_n_shift, name); + } + q->prod_reg = arm_smmu_page1_fixup(prod_off, smmu); q->cons_reg = arm_smmu_page1_fixup(cons_off, smmu); q->ent_dwords = dwords; @@ -2300,13 +2326,15 @@ static int arm_smmu_init_queues(struct arm_smmu_device *smmu) /* cmdq */ spin_lock_init(&smmu->cmdq.lock); ret = arm_smmu_init_one_queue(smmu, &smmu->cmdq.q, ARM_SMMU_CMDQ_PROD, - ARM_SMMU_CMDQ_CONS, CMDQ_ENT_DWORDS); + ARM_SMMU_CMDQ_CONS, CMDQ_ENT_DWORDS, + "cmdq"); if (ret) return ret; /* evtq */ ret = arm_smmu_init_one_queue(smmu, &smmu->evtq.q, ARM_SMMU_EVTQ_PROD, - ARM_SMMU_EVTQ_CONS, EVTQ_ENT_DWORDS); + ARM_SMMU_EVTQ_CONS, EVTQ_ENT_DWORDS, + "evtq"); if (ret) return ret; @@ -2315,7 +2343,8 @@ static int arm_smmu_init_queues(struct arm_smmu_device *smmu) return 0; return arm_smmu_init_one_queue(smmu, &smmu->priq.q, ARM_SMMU_PRIQ_PROD, - ARM_SMMU_PRIQ_CONS, PRIQ_ENT_DWORDS); + ARM_SMMU_PRIQ_CONS, PRIQ_ENT_DWORDS, + "priq"); } static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu) @@ -2879,7 +2908,7 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) return -ENXIO; } - /* Queue sizes, capped at 4k */ + /* Queue sizes, capped to ensure natural alignment */ smmu->cmdq.q.max_n_shift = min_t(u32, CMDQ_MAX_SZ_SHIFT, FIELD_GET(IDR1_CMDQS, reg)); if (!smmu->cmdq.q.max_n_shift) { diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 586dd5a46d9f..653b6b3dcafb 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -892,13 +892,11 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, .pgsize_bitmap = smmu->pgsize_bitmap, .ias = ias, .oas = oas, + .coherent_walk = smmu->features & ARM_SMMU_FEAT_COHERENT_WALK, .tlb = smmu_domain->tlb_ops, .iommu_dev = smmu->dev, }; - if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) - pgtbl_cfg.quirks = IO_PGTABLE_QUIRK_NO_DMA; - if (smmu_domain->non_strict) pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT; diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 129c4badf9ae..f802255219d3 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * A fairly generic DMA-API to IOMMU-API glue layer. * @@ -5,23 +6,13 @@ * * based in part on arch/arm/mm/dma-mapping.c: * Copyright (C) 2000-2004 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/acpi_iort.h> #include <linux/device.h> +#include <linux/dma-contiguous.h> #include <linux/dma-iommu.h> +#include <linux/dma-noncoherent.h> #include <linux/gfp.h> #include <linux/huge_mm.h> #include <linux/iommu.h> @@ -78,11 +69,6 @@ static struct iommu_dma_cookie *cookie_alloc(enum iommu_dma_cookie_type type) return cookie; } -int iommu_dma_init(void) -{ - return iova_cache_get(); -} - /** * iommu_get_dma_cookie - Acquire DMA-API resources for a domain * @domain: IOMMU domain to prepare for DMA-API usage @@ -240,8 +226,8 @@ resv_iova: start = window->res->end - window->offset + 1; /* If window is last entry */ if (window->node.next == &bridge->dma_ranges && - end != ~(dma_addr_t)0) { - end = ~(dma_addr_t)0; + end != ~(phys_addr_t)0) { + end = ~(phys_addr_t)0; goto resv_iova; } } @@ -313,7 +299,7 @@ static void iommu_dma_flush_iotlb_all(struct iova_domain *iovad) * to ensure it is an invalid IOVA. It is safe to reinitialise a domain, but * any change which could make prior IOVAs invalid will fail. */ -int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, +static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, u64 size, struct device *dev) { struct iommu_dma_cookie *cookie = domain->iova_cookie; @@ -364,7 +350,6 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, return iova_reserve_iommu_regions(dev, domain); } -EXPORT_SYMBOL(iommu_dma_init_domain); /** * dma_info_to_prot - Translate DMA API directions and attributes to IOMMU API @@ -375,7 +360,7 @@ EXPORT_SYMBOL(iommu_dma_init_domain); * * Return: corresponding IOMMU API page protection flags */ -int dma_info_to_prot(enum dma_data_direction dir, bool coherent, +static int dma_info_to_prot(enum dma_data_direction dir, bool coherent, unsigned long attrs) { int prot = coherent ? IOMMU_CACHE : 0; @@ -452,9 +437,10 @@ static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie, size >> iova_shift(iovad)); } -static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr, +static void __iommu_dma_unmap(struct device *dev, dma_addr_t dma_addr, size_t size) { + struct iommu_domain *domain = iommu_get_dma_domain(dev); struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iova_domain *iovad = &cookie->iovad; size_t iova_off = iova_offset(iovad, dma_addr); @@ -468,6 +454,30 @@ static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr, iommu_dma_free_iova(cookie, dma_addr, size); } +static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys, + size_t size, int prot) +{ + struct iommu_domain *domain = iommu_get_dma_domain(dev); + struct iommu_dma_cookie *cookie = domain->iova_cookie; + size_t iova_off = 0; + dma_addr_t iova; + + if (cookie->type == IOMMU_DMA_IOVA_COOKIE) { + iova_off = iova_offset(&cookie->iovad, phys); + size = iova_align(&cookie->iovad, size + iova_off); + } + + iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev); + if (!iova) + return DMA_MAPPING_ERROR; + + if (iommu_map(domain, iova, phys - iova_off, size, prot)) { + iommu_dma_free_iova(cookie, iova, size); + return DMA_MAPPING_ERROR; + } + return iova + iova_off; +} + static void __iommu_dma_free_pages(struct page **pages, int count) { while (count--) @@ -533,55 +543,45 @@ static struct page **__iommu_dma_alloc_pages(struct device *dev, return pages; } -/** - * iommu_dma_free - Free a buffer allocated by iommu_dma_alloc() - * @dev: Device which owns this buffer - * @pages: Array of buffer pages as returned by iommu_dma_alloc() - * @size: Size of buffer in bytes - * @handle: DMA address of buffer - * - * Frees both the pages associated with the buffer, and the array - * describing them - */ -void iommu_dma_free(struct device *dev, struct page **pages, size_t size, - dma_addr_t *handle) +static struct page **__iommu_dma_get_pages(void *cpu_addr) { - __iommu_dma_unmap(iommu_get_dma_domain(dev), *handle, size); - __iommu_dma_free_pages(pages, PAGE_ALIGN(size) >> PAGE_SHIFT); - *handle = DMA_MAPPING_ERROR; + struct vm_struct *area = find_vm_area(cpu_addr); + + if (!area || !area->pages) + return NULL; + return area->pages; } /** - * iommu_dma_alloc - Allocate and map a buffer contiguous in IOVA space + * iommu_dma_alloc_remap - Allocate and map a buffer contiguous in IOVA space * @dev: Device to allocate memory for. Must be a real device * attached to an iommu_dma_domain * @size: Size of buffer in bytes + * @dma_handle: Out argument for allocated DMA handle * @gfp: Allocation flags * @attrs: DMA attributes for this allocation - * @prot: IOMMU mapping flags - * @handle: Out argument for allocated DMA handle - * @flush_page: Arch callback which must ensure PAGE_SIZE bytes from the - * given VA/PA are visible to the given non-coherent device. * * If @size is less than PAGE_SIZE, then a full CPU page will be allocated, * but an IOMMU which supports smaller pages might not map the whole thing. * - * Return: Array of struct page pointers describing the buffer, - * or NULL on failure. + * Return: Mapped virtual address, or NULL on failure. */ -struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp, - unsigned long attrs, int prot, dma_addr_t *handle, - void (*flush_page)(struct device *, const void *, phys_addr_t)) +static void *iommu_dma_alloc_remap(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs) { struct iommu_domain *domain = iommu_get_dma_domain(dev); struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iova_domain *iovad = &cookie->iovad; + bool coherent = dev_is_dma_coherent(dev); + int ioprot = dma_info_to_prot(DMA_BIDIRECTIONAL, coherent, attrs); + pgprot_t prot = arch_dma_mmap_pgprot(dev, PAGE_KERNEL, attrs); + unsigned int count, min_size, alloc_sizes = domain->pgsize_bitmap; struct page **pages; struct sg_table sgt; dma_addr_t iova; - unsigned int count, min_size, alloc_sizes = domain->pgsize_bitmap; + void *vaddr; - *handle = DMA_MAPPING_ERROR; + *dma_handle = DMA_MAPPING_ERROR; min_size = alloc_sizes & -alloc_sizes; if (min_size < PAGE_SIZE) { @@ -607,26 +607,29 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp, if (sg_alloc_table_from_pages(&sgt, pages, count, 0, size, GFP_KERNEL)) goto out_free_iova; - if (!(prot & IOMMU_CACHE)) { - struct sg_mapping_iter miter; - /* - * The CPU-centric flushing implied by SG_MITER_TO_SG isn't - * sufficient here, so skip it by using the "wrong" direction. - */ - sg_miter_start(&miter, sgt.sgl, sgt.orig_nents, SG_MITER_FROM_SG); - while (sg_miter_next(&miter)) - flush_page(dev, miter.addr, page_to_phys(miter.page)); - sg_miter_stop(&miter); + if (!(ioprot & IOMMU_CACHE)) { + struct scatterlist *sg; + int i; + + for_each_sg(sgt.sgl, sg, sgt.orig_nents, i) + arch_dma_prep_coherent(sg_page(sg), sg->length); } - if (iommu_map_sg(domain, iova, sgt.sgl, sgt.orig_nents, prot) + if (iommu_map_sg(domain, iova, sgt.sgl, sgt.orig_nents, ioprot) < size) goto out_free_sg; - *handle = iova; + vaddr = dma_common_pages_remap(pages, size, VM_USERMAP, prot, + __builtin_return_address(0)); + if (!vaddr) + goto out_unmap; + + *dma_handle = iova; sg_free_table(&sgt); - return pages; + return vaddr; +out_unmap: + __iommu_dma_unmap(dev, iova, size); out_free_sg: sg_free_table(&sgt); out_free_iova: @@ -637,54 +640,94 @@ out_free_pages: } /** - * iommu_dma_mmap - Map a buffer into provided user VMA - * @pages: Array representing buffer from iommu_dma_alloc() + * __iommu_dma_mmap - Map a buffer into provided user VMA + * @pages: Array representing buffer from __iommu_dma_alloc() * @size: Size of buffer in bytes * @vma: VMA describing requested userspace mapping * * Maps the pages of the buffer in @pages into @vma. The caller is responsible * for verifying the correct size and protection of @vma beforehand. */ - -int iommu_dma_mmap(struct page **pages, size_t size, struct vm_area_struct *vma) +static int __iommu_dma_mmap(struct page **pages, size_t size, + struct vm_area_struct *vma) { return vm_map_pages(vma, pages, PAGE_ALIGN(size) >> PAGE_SHIFT); } -static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys, - size_t size, int prot, struct iommu_domain *domain) +static void iommu_dma_sync_single_for_cpu(struct device *dev, + dma_addr_t dma_handle, size_t size, enum dma_data_direction dir) { - struct iommu_dma_cookie *cookie = domain->iova_cookie; - size_t iova_off = 0; - dma_addr_t iova; + phys_addr_t phys; - if (cookie->type == IOMMU_DMA_IOVA_COOKIE) { - iova_off = iova_offset(&cookie->iovad, phys); - size = iova_align(&cookie->iovad, size + iova_off); - } + if (dev_is_dma_coherent(dev)) + return; - iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev); - if (!iova) - return DMA_MAPPING_ERROR; + phys = iommu_iova_to_phys(iommu_get_dma_domain(dev), dma_handle); + arch_sync_dma_for_cpu(dev, phys, size, dir); +} - if (iommu_map(domain, iova, phys - iova_off, size, prot)) { - iommu_dma_free_iova(cookie, iova, size); - return DMA_MAPPING_ERROR; - } - return iova + iova_off; +static void iommu_dma_sync_single_for_device(struct device *dev, + dma_addr_t dma_handle, size_t size, enum dma_data_direction dir) +{ + phys_addr_t phys; + + if (dev_is_dma_coherent(dev)) + return; + + phys = iommu_iova_to_phys(iommu_get_dma_domain(dev), dma_handle); + arch_sync_dma_for_device(dev, phys, size, dir); +} + +static void iommu_dma_sync_sg_for_cpu(struct device *dev, + struct scatterlist *sgl, int nelems, + enum dma_data_direction dir) +{ + struct scatterlist *sg; + int i; + + if (dev_is_dma_coherent(dev)) + return; + + for_each_sg(sgl, sg, nelems, i) + arch_sync_dma_for_cpu(dev, sg_phys(sg), sg->length, dir); +} + +static void iommu_dma_sync_sg_for_device(struct device *dev, + struct scatterlist *sgl, int nelems, + enum dma_data_direction dir) +{ + struct scatterlist *sg; + int i; + + if (dev_is_dma_coherent(dev)) + return; + + for_each_sg(sgl, sg, nelems, i) + arch_sync_dma_for_device(dev, sg_phys(sg), sg->length, dir); } -dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, int prot) +static dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, enum dma_data_direction dir, + unsigned long attrs) { - return __iommu_dma_map(dev, page_to_phys(page) + offset, size, prot, - iommu_get_dma_domain(dev)); + phys_addr_t phys = page_to_phys(page) + offset; + bool coherent = dev_is_dma_coherent(dev); + int prot = dma_info_to_prot(dir, coherent, attrs); + dma_addr_t dma_handle; + + dma_handle =__iommu_dma_map(dev, phys, size, prot); + if (!coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC) && + dma_handle != DMA_MAPPING_ERROR) + arch_sync_dma_for_device(dev, phys, size, dir); + return dma_handle; } -void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, - enum dma_data_direction dir, unsigned long attrs) +static void iommu_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction dir, unsigned long attrs) { - __iommu_dma_unmap(iommu_get_dma_domain(dev), handle, size); + if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) + iommu_dma_sync_single_for_cpu(dev, dma_handle, size, dir); + __iommu_dma_unmap(dev, dma_handle, size); } /* @@ -769,18 +812,22 @@ static void __invalidate_sg(struct scatterlist *sg, int nents) * impedance-matching, to be able to hand off a suitably-aligned list, * but still preserve the original offsets and sizes for the caller. */ -int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, - int nents, int prot) +static int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir, unsigned long attrs) { struct iommu_domain *domain = iommu_get_dma_domain(dev); struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iova_domain *iovad = &cookie->iovad; struct scatterlist *s, *prev = NULL; + int prot = dma_info_to_prot(dir, dev_is_dma_coherent(dev), attrs); dma_addr_t iova; size_t iova_len = 0; unsigned long mask = dma_get_seg_boundary(dev); int i; + if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) + iommu_dma_sync_sg_for_device(dev, sg, nents, dir); + /* * Work out how much IOVA space we need, and align the segments to * IOVA granules for the IOMMU driver to handle. With some clever @@ -840,12 +887,16 @@ out_restore_sg: return 0; } -void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction dir, unsigned long attrs) +static void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir, unsigned long attrs) { dma_addr_t start, end; struct scatterlist *tmp; int i; + + if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) + iommu_dma_sync_sg_for_cpu(dev, sg, nents, dir); + /* * The scatterlist segments are mapped into a single * contiguous IOVA allocation, so this is incredibly easy. @@ -857,21 +908,231 @@ void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, sg = tmp; } end = sg_dma_address(sg) + sg_dma_len(sg); - __iommu_dma_unmap(iommu_get_dma_domain(dev), start, end - start); + __iommu_dma_unmap(dev, start, end - start); } -dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys, +static dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys, size_t size, enum dma_data_direction dir, unsigned long attrs) { return __iommu_dma_map(dev, phys, size, - dma_info_to_prot(dir, false, attrs) | IOMMU_MMIO, - iommu_get_dma_domain(dev)); + dma_info_to_prot(dir, false, attrs) | IOMMU_MMIO); } -void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle, +static void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir, unsigned long attrs) { - __iommu_dma_unmap(iommu_get_dma_domain(dev), handle, size); + __iommu_dma_unmap(dev, handle, size); +} + +static void __iommu_dma_free(struct device *dev, size_t size, void *cpu_addr) +{ + size_t alloc_size = PAGE_ALIGN(size); + int count = alloc_size >> PAGE_SHIFT; + struct page *page = NULL, **pages = NULL; + + /* Non-coherent atomic allocation? Easy */ + if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) && + dma_free_from_pool(cpu_addr, alloc_size)) + return; + + if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr)) { + /* + * If it the address is remapped, then it's either non-coherent + * or highmem CMA, or an iommu_dma_alloc_remap() construction. + */ + pages = __iommu_dma_get_pages(cpu_addr); + if (!pages) + page = vmalloc_to_page(cpu_addr); + dma_common_free_remap(cpu_addr, alloc_size, VM_USERMAP); + } else { + /* Lowmem means a coherent atomic or CMA allocation */ + page = virt_to_page(cpu_addr); + } + + if (pages) + __iommu_dma_free_pages(pages, count); + if (page && !dma_release_from_contiguous(dev, page, count)) + __free_pages(page, get_order(alloc_size)); +} + +static void iommu_dma_free(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t handle, unsigned long attrs) +{ + __iommu_dma_unmap(dev, handle, size); + __iommu_dma_free(dev, size, cpu_addr); +} + +static void *iommu_dma_alloc_pages(struct device *dev, size_t size, + struct page **pagep, gfp_t gfp, unsigned long attrs) +{ + bool coherent = dev_is_dma_coherent(dev); + size_t alloc_size = PAGE_ALIGN(size); + struct page *page = NULL; + void *cpu_addr; + + if (gfpflags_allow_blocking(gfp)) + page = dma_alloc_from_contiguous(dev, alloc_size >> PAGE_SHIFT, + get_order(alloc_size), + gfp & __GFP_NOWARN); + if (!page) + page = alloc_pages(gfp, get_order(alloc_size)); + if (!page) + return NULL; + + if (IS_ENABLED(CONFIG_DMA_REMAP) && (!coherent || PageHighMem(page))) { + pgprot_t prot = arch_dma_mmap_pgprot(dev, PAGE_KERNEL, attrs); + + cpu_addr = dma_common_contiguous_remap(page, alloc_size, + VM_USERMAP, prot, __builtin_return_address(0)); + if (!cpu_addr) + goto out_free_pages; + + if (!coherent) + arch_dma_prep_coherent(page, size); + } else { + cpu_addr = page_address(page); + } + + *pagep = page; + memset(cpu_addr, 0, alloc_size); + return cpu_addr; +out_free_pages: + if (!dma_release_from_contiguous(dev, page, alloc_size >> PAGE_SHIFT)) + __free_pages(page, get_order(alloc_size)); + return NULL; +} + +static void *iommu_dma_alloc(struct device *dev, size_t size, + dma_addr_t *handle, gfp_t gfp, unsigned long attrs) +{ + bool coherent = dev_is_dma_coherent(dev); + int ioprot = dma_info_to_prot(DMA_BIDIRECTIONAL, coherent, attrs); + struct page *page = NULL; + void *cpu_addr; + + gfp |= __GFP_ZERO; + + if (IS_ENABLED(CONFIG_DMA_REMAP) && gfpflags_allow_blocking(gfp) && + !(attrs & DMA_ATTR_FORCE_CONTIGUOUS)) + return iommu_dma_alloc_remap(dev, size, handle, gfp, attrs); + + if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) && + !gfpflags_allow_blocking(gfp) && !coherent) + cpu_addr = dma_alloc_from_pool(PAGE_ALIGN(size), &page, gfp); + else + cpu_addr = iommu_dma_alloc_pages(dev, size, &page, gfp, attrs); + if (!cpu_addr) + return NULL; + + *handle = __iommu_dma_map(dev, page_to_phys(page), size, ioprot); + if (*handle == DMA_MAPPING_ERROR) { + __iommu_dma_free(dev, size, cpu_addr); + return NULL; + } + + return cpu_addr; +} + +static int iommu_dma_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + unsigned long attrs) +{ + unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; + unsigned long pfn, off = vma->vm_pgoff; + int ret; + + vma->vm_page_prot = arch_dma_mmap_pgprot(dev, vma->vm_page_prot, attrs); + + if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret)) + return ret; + + if (off >= nr_pages || vma_pages(vma) > nr_pages - off) + return -ENXIO; + + if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr)) { + struct page **pages = __iommu_dma_get_pages(cpu_addr); + + if (pages) + return __iommu_dma_mmap(pages, size, vma); + pfn = vmalloc_to_pfn(cpu_addr); + } else { + pfn = page_to_pfn(virt_to_page(cpu_addr)); + } + + return remap_pfn_range(vma, vma->vm_start, pfn + off, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); +} + +static int iommu_dma_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + unsigned long attrs) +{ + struct page *page; + int ret; + + if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr)) { + struct page **pages = __iommu_dma_get_pages(cpu_addr); + + if (pages) { + return sg_alloc_table_from_pages(sgt, pages, + PAGE_ALIGN(size) >> PAGE_SHIFT, + 0, size, GFP_KERNEL); + } + + page = vmalloc_to_page(cpu_addr); + } else { + page = virt_to_page(cpu_addr); + } + + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); + if (!ret) + sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0); + return ret; +} + +static const struct dma_map_ops iommu_dma_ops = { + .alloc = iommu_dma_alloc, + .free = iommu_dma_free, + .mmap = iommu_dma_mmap, + .get_sgtable = iommu_dma_get_sgtable, + .map_page = iommu_dma_map_page, + .unmap_page = iommu_dma_unmap_page, + .map_sg = iommu_dma_map_sg, + .unmap_sg = iommu_dma_unmap_sg, + .sync_single_for_cpu = iommu_dma_sync_single_for_cpu, + .sync_single_for_device = iommu_dma_sync_single_for_device, + .sync_sg_for_cpu = iommu_dma_sync_sg_for_cpu, + .sync_sg_for_device = iommu_dma_sync_sg_for_device, + .map_resource = iommu_dma_map_resource, + .unmap_resource = iommu_dma_unmap_resource, +}; + +/* + * The IOMMU core code allocates the default DMA domain, which the underlying + * IOMMU driver needs to support via the dma-iommu layer. + */ +void iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size) +{ + struct iommu_domain *domain = iommu_get_domain_for_dev(dev); + + if (!domain) + goto out_err; + + /* + * The IOMMU core code allocates the default DMA domain, which the + * underlying IOMMU driver needs to support via the dma-iommu layer. + */ + if (domain->type == IOMMU_DOMAIN_DMA) { + if (iommu_dma_init_domain(domain, dma_base, size, dev)) + goto out_err; + dev->dma_ops = &iommu_dma_ops; + } + + return; +out_err: + pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n", + dev_name(dev)); } static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, @@ -892,7 +1153,7 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, if (!msi_page) return NULL; - iova = __iommu_dma_map(dev, msi_addr, size, prot, domain); + iova = __iommu_dma_map(dev, msi_addr, size, prot); if (iova == DMA_MAPPING_ERROR) goto out_free_page; @@ -954,3 +1215,9 @@ void iommu_dma_compose_msi_msg(struct msi_desc *desc, msg->address_lo &= cookie_msi_granule(domain->iova_cookie) - 1; msg->address_lo += lower_32_bits(msi_page->iova); } + +static int iommu_dma_init(void) +{ + return iova_cache_get(); +} +arch_initcall(iommu_dma_init); diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 05c6bc099d62..b0c1e5f9daae 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011,2016 Samsung Electronics Co., Ltd. * http://www.samsung.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifdef CONFIG_EXYNOS_IOMMU_DEBUG diff --git a/drivers/iommu/intel-iommu-debugfs.c b/drivers/iommu/intel-iommu-debugfs.c index 7fabf9b1c2dc..73a552914455 100644 --- a/drivers/iommu/intel-iommu-debugfs.c +++ b/drivers/iommu/intel-iommu-debugfs.c @@ -14,6 +14,17 @@ #include <asm/irq_remapping.h> +#include "intel-pasid.h" + +struct tbl_walk { + u16 bus; + u16 devfn; + u32 pasid; + struct root_entry *rt_entry; + struct context_entry *ctx_entry; + struct pasid_entry *pasid_tbl_entry; +}; + struct iommu_regset { int offset; const char *regs; @@ -131,16 +142,86 @@ out: } DEFINE_SHOW_ATTRIBUTE(iommu_regset); -static void ctx_tbl_entry_show(struct seq_file *m, struct intel_iommu *iommu, - int bus) +static inline void print_tbl_walk(struct seq_file *m) { - struct context_entry *context; - int devfn; + struct tbl_walk *tbl_wlk = m->private; + + seq_printf(m, "%02x:%02x.%x\t0x%016llx:0x%016llx\t0x%016llx:0x%016llx\t", + tbl_wlk->bus, PCI_SLOT(tbl_wlk->devfn), + PCI_FUNC(tbl_wlk->devfn), tbl_wlk->rt_entry->hi, + tbl_wlk->rt_entry->lo, tbl_wlk->ctx_entry->hi, + tbl_wlk->ctx_entry->lo); + + /* + * A legacy mode DMAR doesn't support PASID, hence default it to -1 + * indicating that it's invalid. Also, default all PASID related fields + * to 0. + */ + if (!tbl_wlk->pasid_tbl_entry) + seq_printf(m, "%-6d\t0x%016llx:0x%016llx:0x%016llx\n", -1, + (u64)0, (u64)0, (u64)0); + else + seq_printf(m, "%-6d\t0x%016llx:0x%016llx:0x%016llx\n", + tbl_wlk->pasid, tbl_wlk->pasid_tbl_entry->val[0], + tbl_wlk->pasid_tbl_entry->val[1], + tbl_wlk->pasid_tbl_entry->val[2]); +} - seq_printf(m, " Context Table Entries for Bus: %d\n", bus); - seq_puts(m, " Entry\tB:D.F\tHigh\tLow\n"); +static void pasid_tbl_walk(struct seq_file *m, struct pasid_entry *tbl_entry, + u16 dir_idx) +{ + struct tbl_walk *tbl_wlk = m->private; + u8 tbl_idx; + + for (tbl_idx = 0; tbl_idx < PASID_TBL_ENTRIES; tbl_idx++) { + if (pasid_pte_is_present(tbl_entry)) { + tbl_wlk->pasid_tbl_entry = tbl_entry; + tbl_wlk->pasid = (dir_idx << PASID_PDE_SHIFT) + tbl_idx; + print_tbl_walk(m); + } + + tbl_entry++; + } +} + +static void pasid_dir_walk(struct seq_file *m, u64 pasid_dir_ptr, + u16 pasid_dir_size) +{ + struct pasid_dir_entry *dir_entry = phys_to_virt(pasid_dir_ptr); + struct pasid_entry *pasid_tbl; + u16 dir_idx; + + for (dir_idx = 0; dir_idx < pasid_dir_size; dir_idx++) { + pasid_tbl = get_pasid_table_from_pde(dir_entry); + if (pasid_tbl) + pasid_tbl_walk(m, pasid_tbl, dir_idx); + + dir_entry++; + } +} + +static void ctx_tbl_walk(struct seq_file *m, struct intel_iommu *iommu, u16 bus) +{ + struct context_entry *context; + u16 devfn, pasid_dir_size; + u64 pasid_dir_ptr; for (devfn = 0; devfn < 256; devfn++) { + struct tbl_walk tbl_wlk = {0}; + + /* + * Scalable mode root entry points to upper scalable mode + * context table and lower scalable mode context table. Each + * scalable mode context table has 128 context entries where as + * legacy mode context table has 256 context entries. So in + * scalable mode, the context entries for former 128 devices are + * in the lower scalable mode context table, while the latter + * 128 devices are in the upper scalable mode context table. + * In scalable mode, when devfn > 127, iommu_context_addr() + * automatically refers to upper scalable mode context table and + * hence the caller doesn't have to worry about differences + * between scalable mode and non scalable mode. + */ context = iommu_context_addr(iommu, bus, devfn, 0); if (!context) return; @@ -148,33 +229,41 @@ static void ctx_tbl_entry_show(struct seq_file *m, struct intel_iommu *iommu, if (!context_present(context)) continue; - seq_printf(m, " %-5d\t%02x:%02x.%x\t%-6llx\t%llx\n", devfn, - bus, PCI_SLOT(devfn), PCI_FUNC(devfn), - context[0].hi, context[0].lo); + tbl_wlk.bus = bus; + tbl_wlk.devfn = devfn; + tbl_wlk.rt_entry = &iommu->root_entry[bus]; + tbl_wlk.ctx_entry = context; + m->private = &tbl_wlk; + + if (pasid_supported(iommu) && is_pasid_enabled(context)) { + pasid_dir_ptr = context->lo & VTD_PAGE_MASK; + pasid_dir_size = get_pasid_dir_size(context); + pasid_dir_walk(m, pasid_dir_ptr, pasid_dir_size); + continue; + } + + print_tbl_walk(m); } } -static void root_tbl_entry_show(struct seq_file *m, struct intel_iommu *iommu) +static void root_tbl_walk(struct seq_file *m, struct intel_iommu *iommu) { unsigned long flags; - int bus; + u16 bus; spin_lock_irqsave(&iommu->lock, flags); - seq_printf(m, "IOMMU %s: Root Table Address:%llx\n", iommu->name, + seq_printf(m, "IOMMU %s: Root Table Address: 0x%llx\n", iommu->name, (u64)virt_to_phys(iommu->root_entry)); - seq_puts(m, "Root Table Entries:\n"); + seq_puts(m, "B.D.F\tRoot_entry\t\t\t\tContext_entry\t\t\t\tPASID\tPASID_table_entry\n"); - for (bus = 0; bus < 256; bus++) { - if (!(iommu->root_entry[bus].lo & 1)) - continue; + /* + * No need to check if the root entry is present or not because + * iommu_context_addr() performs the same check before returning + * context entry. + */ + for (bus = 0; bus < 256; bus++) + ctx_tbl_walk(m, iommu, bus); - seq_printf(m, " Bus: %d H: %llx L: %llx\n", bus, - iommu->root_entry[bus].hi, - iommu->root_entry[bus].lo); - - ctx_tbl_entry_show(m, iommu, bus); - seq_putc(m, '\n'); - } spin_unlock_irqrestore(&iommu->lock, flags); } @@ -185,7 +274,7 @@ static int dmar_translation_struct_show(struct seq_file *m, void *unused) rcu_read_lock(); for_each_active_iommu(iommu, drhd) { - root_tbl_entry_show(m, iommu); + root_tbl_walk(m, iommu); seq_putc(m, '\n'); } rcu_read_unlock(); diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 56297298d6ee..ac4172c02244 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -294,14 +294,16 @@ static inline void context_clear_entry(struct context_entry *context) static struct dmar_domain *si_domain; static int hw_pass_through = 1; +/* si_domain contains mulitple devices */ +#define DOMAIN_FLAG_STATIC_IDENTITY BIT(0) + /* - * Domain represents a virtual machine, more than one devices - * across iommus may be owned in one domain, e.g. kvm guest. + * This is a DMA domain allocated through the iommu domain allocation + * interface. But one or more devices belonging to this domain have + * been chosen to use a private domain. We should avoid to use the + * map/unmap/iova_to_phys APIs on it. */ -#define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 0) - -/* si_domain contains mulitple devices */ -#define DOMAIN_FLAG_STATIC_IDENTITY (1 << 1) +#define DOMAIN_FLAG_LOSE_CHILDREN BIT(1) #define for_each_domain_iommu(idx, domain) \ for (idx = 0; idx < g_num_of_iommus; idx++) \ @@ -314,7 +316,6 @@ struct dmar_rmrr_unit { u64 end_address; /* reserved end address */ struct dmar_dev_scope *devices; /* target devices */ int devices_cnt; /* target device count */ - struct iommu_resv_region *resv; /* reserved region handle */ }; struct dmar_atsr_unit { @@ -342,6 +343,9 @@ static void domain_context_clear(struct intel_iommu *iommu, struct device *dev); static int domain_detach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu); +static bool device_is_rmrr_locked(struct device *dev); +static int intel_iommu_attach_device(struct iommu_domain *domain, + struct device *dev); #ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON int dmar_disabled = 0; @@ -349,6 +353,7 @@ int dmar_disabled = 0; int dmar_disabled = 1; #endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/ +int intel_iommu_sm; int intel_iommu_enabled = 0; EXPORT_SYMBOL_GPL(intel_iommu_enabled); @@ -356,21 +361,17 @@ static int dmar_map_gfx = 1; static int dmar_forcedac; static int intel_iommu_strict; static int intel_iommu_superpage = 1; -static int intel_iommu_sm; static int iommu_identity_mapping; #define IDENTMAP_ALL 1 #define IDENTMAP_GFX 2 #define IDENTMAP_AZALIA 4 -#define sm_supported(iommu) (intel_iommu_sm && ecap_smts((iommu)->ecap)) -#define pasid_supported(iommu) (sm_supported(iommu) && \ - ecap_pasid((iommu)->ecap)) - int intel_iommu_gfx_mapped; EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped); #define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1)) +#define DEFER_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-2)) static DEFINE_SPINLOCK(device_domain_lock); static LIST_HEAD(device_domain_list); @@ -535,22 +536,11 @@ static inline void free_devinfo_mem(void *vaddr) kmem_cache_free(iommu_devinfo_cache, vaddr); } -static inline int domain_type_is_vm(struct dmar_domain *domain) -{ - return domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE; -} - static inline int domain_type_is_si(struct dmar_domain *domain) { return domain->flags & DOMAIN_FLAG_STATIC_IDENTITY; } -static inline int domain_type_is_vm_or_si(struct dmar_domain *domain) -{ - return domain->flags & (DOMAIN_FLAG_VIRTUAL_MACHINE | - DOMAIN_FLAG_STATIC_IDENTITY); -} - static inline int domain_pfn_supported(struct dmar_domain *domain, unsigned long pfn) { @@ -598,7 +588,9 @@ struct intel_iommu *domain_get_iommu(struct dmar_domain *domain) int iommu_id; /* si_domain and vm domain should not get here. */ - BUG_ON(domain_type_is_vm_or_si(domain)); + if (WARN_ON(domain->domain.type != IOMMU_DOMAIN_DMA)) + return NULL; + for_each_domain_iommu(iommu_id, domain) break; @@ -729,12 +721,39 @@ static int iommu_dummy(struct device *dev) return dev->archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO; } +/** + * is_downstream_to_pci_bridge - test if a device belongs to the PCI + * sub-hierarchy of a candidate PCI-PCI bridge + * @dev: candidate PCI device belonging to @bridge PCI sub-hierarchy + * @bridge: the candidate PCI-PCI bridge + * + * Return: true if @dev belongs to @bridge PCI sub-hierarchy, else false. + */ +static bool +is_downstream_to_pci_bridge(struct device *dev, struct device *bridge) +{ + struct pci_dev *pdev, *pbridge; + + if (!dev_is_pci(dev) || !dev_is_pci(bridge)) + return false; + + pdev = to_pci_dev(dev); + pbridge = to_pci_dev(bridge); + + if (pbridge->subordinate && + pbridge->subordinate->number <= pdev->bus->number && + pbridge->subordinate->busn_res.end >= pdev->bus->number) + return true; + + return false; +} + static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn) { struct dmar_drhd_unit *drhd = NULL; struct intel_iommu *iommu; struct device *tmp; - struct pci_dev *ptmp, *pdev = NULL; + struct pci_dev *pdev = NULL; u16 segment = 0; int i; @@ -780,13 +799,7 @@ static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devf goto out; } - if (!pdev || !dev_is_pci(tmp)) - continue; - - ptmp = to_pci_dev(tmp); - if (ptmp->subordinate && - ptmp->subordinate->number <= pdev->bus->number && - ptmp->subordinate->busn_res.end >= pdev->bus->number) + if (is_downstream_to_pci_bridge(dev, tmp)) goto got_pdev; } @@ -908,7 +921,6 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain, return pte; } - /* return address's pte at specific level */ static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain, unsigned long pfn, @@ -1577,7 +1589,6 @@ static void iommu_disable_translation(struct intel_iommu *iommu) raw_spin_unlock_irqrestore(&iommu->register_lock, flag); } - static int iommu_init_domains(struct intel_iommu *iommu) { u32 ndomains, nlongs; @@ -1615,8 +1626,6 @@ static int iommu_init_domains(struct intel_iommu *iommu) return -ENOMEM; } - - /* * If Caching mode is set, then invalid translations are tagged * with domain-id 0, hence we need to pre-allocate it. We also @@ -1646,32 +1655,15 @@ static void disable_dmar_iommu(struct intel_iommu *iommu) if (!iommu->domains || !iommu->domain_ids) return; -again: spin_lock_irqsave(&device_domain_lock, flags); list_for_each_entry_safe(info, tmp, &device_domain_list, global) { - struct dmar_domain *domain; - if (info->iommu != iommu) continue; if (!info->dev || !info->domain) continue; - domain = info->domain; - __dmar_remove_one_dev_info(info); - - if (!domain_type_is_vm_or_si(domain)) { - /* - * The domain_exit() function can't be called under - * device_domain_lock, as it takes this lock itself. - * So release the lock here and re-run the loop - * afterwards. - */ - spin_unlock_irqrestore(&device_domain_lock, flags); - domain_exit(domain); - goto again; - } } spin_unlock_irqrestore(&device_domain_lock, flags); @@ -1841,71 +1833,12 @@ static inline int guestwidth_to_adjustwidth(int gaw) return agaw; } -static int domain_init(struct dmar_domain *domain, struct intel_iommu *iommu, - int guest_width) -{ - int adjust_width, agaw; - unsigned long sagaw; - int err; - - init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN); - - err = init_iova_flush_queue(&domain->iovad, - iommu_flush_iova, iova_entry_free); - if (err) - return err; - - domain_reserve_special_ranges(domain); - - /* calculate AGAW */ - if (guest_width > cap_mgaw(iommu->cap)) - guest_width = cap_mgaw(iommu->cap); - domain->gaw = guest_width; - adjust_width = guestwidth_to_adjustwidth(guest_width); - agaw = width_to_agaw(adjust_width); - sagaw = cap_sagaw(iommu->cap); - if (!test_bit(agaw, &sagaw)) { - /* hardware doesn't support it, choose a bigger one */ - pr_debug("Hardware doesn't support agaw %d\n", agaw); - agaw = find_next_bit(&sagaw, 5, agaw); - if (agaw >= 5) - return -ENODEV; - } - domain->agaw = agaw; - - if (ecap_coherent(iommu->ecap)) - domain->iommu_coherency = 1; - else - domain->iommu_coherency = 0; - - if (ecap_sc_support(iommu->ecap)) - domain->iommu_snooping = 1; - else - domain->iommu_snooping = 0; - - if (intel_iommu_superpage) - domain->iommu_superpage = fls(cap_super_page_val(iommu->cap)); - else - domain->iommu_superpage = 0; - - domain->nid = iommu->node; - - /* always allocate the top pgd */ - domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid); - if (!domain->pgd) - return -ENOMEM; - __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE); - return 0; -} - static void domain_exit(struct dmar_domain *domain) { struct page *freelist; /* Remove associated devices and clear attached or cached domains */ - rcu_read_lock(); domain_remove_dev_info(domain); - rcu_read_unlock(); /* destroy iovas */ put_iova_domain(&domain->iovad); @@ -2336,7 +2269,7 @@ static int domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, struct scatterlist *sg, unsigned long phys_pfn, unsigned long nr_pages, int prot) { - int ret; + int iommu_id, ret; struct intel_iommu *iommu; /* Do the real mapping first */ @@ -2344,18 +2277,8 @@ static int domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, if (ret) return ret; - /* Notify about the new mapping */ - if (domain_type_is_vm(domain)) { - /* VM typed domains can have more than one IOMMUs */ - int iommu_id; - - for_each_domain_iommu(iommu_id, domain) { - iommu = g_iommus[iommu_id]; - __mapping_notify_one(iommu, domain, iov_pfn, nr_pages); - } - } else { - /* General domains only have one IOMMU */ - iommu = domain_get_iommu(domain); + for_each_domain_iommu(iommu_id, domain) { + iommu = g_iommus[iommu_id]; __mapping_notify_one(iommu, domain, iov_pfn, nr_pages); } @@ -2435,8 +2358,18 @@ static struct dmar_domain *find_domain(struct device *dev) { struct device_domain_info *info; + if (unlikely(dev->archdata.iommu == DEFER_DEVICE_DOMAIN_INFO)) { + struct iommu_domain *domain; + + dev->archdata.iommu = NULL; + domain = iommu_get_domain_for_dev(dev); + if (domain) + intel_iommu_attach_device(domain, dev); + } + /* No lock here, assumes no domain exit in normal case */ info = dev->archdata.iommu; + if (likely(info)) return info->domain; return NULL; @@ -2504,7 +2437,6 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, } } - spin_lock(&iommu->lock); spin_lock_irqsave(&device_domain_lock, flags); if (dev) found = find_domain(dev); @@ -2520,16 +2452,17 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, if (found) { spin_unlock_irqrestore(&device_domain_lock, flags); - spin_unlock(&iommu->lock); free_devinfo_mem(info); /* Caller must free the original domain */ return found; } + spin_lock(&iommu->lock); ret = domain_attach_iommu(domain, iommu); + spin_unlock(&iommu->lock); + if (ret) { spin_unlock_irqrestore(&device_domain_lock, flags); - spin_unlock(&iommu->lock); free_devinfo_mem(info); return NULL; } @@ -2539,7 +2472,6 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, if (dev) dev->archdata.iommu = info; spin_unlock_irqrestore(&device_domain_lock, flags); - spin_unlock(&iommu->lock); /* PASID table is mandatory for a PCI device in scalable mode. */ if (dev && dev_is_pci(dev) && sm_supported(iommu)) { @@ -2581,6 +2513,31 @@ static int get_last_alias(struct pci_dev *pdev, u16 alias, void *opaque) return 0; } +static int domain_init(struct dmar_domain *domain, int guest_width) +{ + int adjust_width; + + init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN); + domain_reserve_special_ranges(domain); + + /* calculate AGAW */ + domain->gaw = guest_width; + adjust_width = guestwidth_to_adjustwidth(guest_width); + domain->agaw = width_to_agaw(adjust_width); + + domain->iommu_coherency = 0; + domain->iommu_snooping = 0; + domain->iommu_superpage = 0; + domain->max_addr = 0; + + /* always allocate the top pgd */ + domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid); + if (!domain->pgd) + return -ENOMEM; + domain_flush_cache(domain, domain->pgd, PAGE_SIZE); + return 0; +} + static struct dmar_domain *find_or_alloc_domain(struct device *dev, int gaw) { struct device_domain_info *info; @@ -2618,13 +2575,20 @@ static struct dmar_domain *find_or_alloc_domain(struct device *dev, int gaw) domain = alloc_domain(0); if (!domain) return NULL; - if (domain_init(domain, iommu, gaw)) { + + if (domain_init(domain, gaw)) { domain_exit(domain); return NULL; } -out: + if (init_iova_flush_queue(&domain->iovad, + iommu_flush_iova, + iova_entry_free)) { + pr_warn("iova flush queue initialization failed\n"); + intel_iommu_strict = 1; + } +out: return domain; } @@ -2664,29 +2628,6 @@ static struct dmar_domain *set_domain_for_dev(struct device *dev, return domain; } -static struct dmar_domain *get_domain_for_dev(struct device *dev, int gaw) -{ - struct dmar_domain *domain, *tmp; - - domain = find_domain(dev); - if (domain) - goto out; - - domain = find_or_alloc_domain(dev, gaw); - if (!domain) - goto out; - - tmp = set_domain_for_dev(dev, domain); - if (!tmp || domain != tmp) { - domain_exit(domain); - domain = tmp; - } - -out: - - return domain; -} - static int iommu_domain_identity_map(struct dmar_domain *domain, unsigned long long start, unsigned long long end) @@ -2751,75 +2692,21 @@ static int domain_prepare_identity_map(struct device *dev, return iommu_domain_identity_map(domain, start, end); } -static int iommu_prepare_identity_map(struct device *dev, - unsigned long long start, - unsigned long long end) -{ - struct dmar_domain *domain; - int ret; - - domain = get_domain_for_dev(dev, DEFAULT_DOMAIN_ADDRESS_WIDTH); - if (!domain) - return -ENOMEM; - - ret = domain_prepare_identity_map(dev, domain, start, end); - if (ret) - domain_exit(domain); - - return ret; -} - -static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr, - struct device *dev) -{ - if (dev->archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO) - return 0; - return iommu_prepare_identity_map(dev, rmrr->base_address, - rmrr->end_address); -} - -#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA -static inline void iommu_prepare_isa(void) -{ - struct pci_dev *pdev; - int ret; - - pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL); - if (!pdev) - return; - - pr_info("Prepare 0-16MiB unity mapping for LPC\n"); - ret = iommu_prepare_identity_map(&pdev->dev, 0, 16*1024*1024 - 1); - - if (ret) - pr_err("Failed to create 0-16MiB identity map - floppy might not work\n"); - - pci_dev_put(pdev); -} -#else -static inline void iommu_prepare_isa(void) -{ - return; -} -#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */ - -static int md_domain_init(struct dmar_domain *domain, int guest_width); - static int __init si_domain_init(int hw) { - int nid, ret; + struct dmar_rmrr_unit *rmrr; + struct device *dev; + int i, nid, ret; si_domain = alloc_domain(DOMAIN_FLAG_STATIC_IDENTITY); if (!si_domain) return -EFAULT; - if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) { + if (domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) { domain_exit(si_domain); return -EFAULT; } - pr_debug("Identity mapping domain allocated\n"); - if (hw) return 0; @@ -2835,6 +2722,31 @@ static int __init si_domain_init(int hw) } } + /* + * Normally we use DMA domains for devices which have RMRRs. But we + * loose this requirement for graphic and usb devices. Identity map + * the RMRRs for graphic and USB devices so that they could use the + * si_domain. + */ + for_each_rmrr_units(rmrr) { + for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt, + i, dev) { + unsigned long long start = rmrr->base_address; + unsigned long long end = rmrr->end_address; + + if (device_is_rmrr_locked(dev)) + continue; + + if (WARN_ON(end < start || + end >> agaw_to_width(si_domain->agaw))) + continue; + + ret = iommu_domain_identity_map(si_domain, start, end); + if (ret) + return ret; + } + } + return 0; } @@ -2842,9 +2754,6 @@ static int identity_mapping(struct device *dev) { struct device_domain_info *info; - if (likely(!iommu_identity_mapping)) - return 0; - info = dev->archdata.iommu; if (info && info != DUMMY_DEVICE_DOMAIN_INFO) return (info->domain == si_domain); @@ -2883,7 +2792,8 @@ static bool device_has_rmrr(struct device *dev) */ for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt, i, tmp) - if (tmp == dev) { + if (tmp == dev || + is_downstream_to_pci_bridge(dev, tmp)) { rcu_read_unlock(); return true; } @@ -2892,6 +2802,35 @@ static bool device_has_rmrr(struct device *dev) return false; } +/** + * device_rmrr_is_relaxable - Test whether the RMRR of this device + * is relaxable (ie. is allowed to be not enforced under some conditions) + * @dev: device handle + * + * We assume that PCI USB devices with RMRRs have them largely + * for historical reasons and that the RMRR space is not actively used post + * boot. This exclusion may change if vendors begin to abuse it. + * + * The same exception is made for graphics devices, with the requirement that + * any use of the RMRR regions will be torn down before assigning the device + * to a guest. + * + * Return: true if the RMRR is relaxable, false otherwise + */ +static bool device_rmrr_is_relaxable(struct device *dev) +{ + struct pci_dev *pdev; + + if (!dev_is_pci(dev)) + return false; + + pdev = to_pci_dev(dev); + if (IS_USB_DEVICE(pdev) || IS_GFX_DEVICE(pdev)) + return true; + else + return false; +} + /* * There are a couple cases where we need to restrict the functionality of * devices associated with RMRRs. The first is when evaluating a device for @@ -2906,52 +2845,51 @@ static bool device_has_rmrr(struct device *dev) * We therefore prevent devices associated with an RMRR from participating in * the IOMMU API, which eliminates them from device assignment. * - * In both cases we assume that PCI USB devices with RMRRs have them largely - * for historical reasons and that the RMRR space is not actively used post - * boot. This exclusion may change if vendors begin to abuse it. - * - * The same exception is made for graphics devices, with the requirement that - * any use of the RMRR regions will be torn down before assigning the device - * to a guest. + * In both cases, devices which have relaxable RMRRs are not concerned by this + * restriction. See device_rmrr_is_relaxable comment. */ static bool device_is_rmrr_locked(struct device *dev) { if (!device_has_rmrr(dev)) return false; - if (dev_is_pci(dev)) { - struct pci_dev *pdev = to_pci_dev(dev); - - if (IS_USB_DEVICE(pdev) || IS_GFX_DEVICE(pdev)) - return false; - } + if (device_rmrr_is_relaxable(dev)) + return false; return true; } -static int iommu_should_identity_map(struct device *dev, int startup) +/* + * Return the required default domain type for a specific device. + * + * @dev: the device in query + * @startup: true if this is during early boot + * + * Returns: + * - IOMMU_DOMAIN_DMA: device requires a dynamic mapping domain + * - IOMMU_DOMAIN_IDENTITY: device requires an identical mapping domain + * - 0: both identity and dynamic domains work for this device + */ +static int device_def_domain_type(struct device *dev) { if (dev_is_pci(dev)) { struct pci_dev *pdev = to_pci_dev(dev); if (device_is_rmrr_locked(dev)) - return 0; + return IOMMU_DOMAIN_DMA; /* * Prevent any device marked as untrusted from getting * placed into the statically identity mapping domain. */ if (pdev->untrusted) - return 0; + return IOMMU_DOMAIN_DMA; if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) - return 1; + return IOMMU_DOMAIN_IDENTITY; if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev)) - return 1; - - if (!(iommu_identity_mapping & IDENTMAP_ALL)) - return 0; + return IOMMU_DOMAIN_IDENTITY; /* * We want to start off with all devices in the 1:1 domain, and @@ -2972,94 +2910,18 @@ static int iommu_should_identity_map(struct device *dev, int startup) */ if (!pci_is_pcie(pdev)) { if (!pci_is_root_bus(pdev->bus)) - return 0; + return IOMMU_DOMAIN_DMA; if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) - return 0; + return IOMMU_DOMAIN_DMA; } else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_PCI_BRIDGE) - return 0; + return IOMMU_DOMAIN_DMA; } else { if (device_has_rmrr(dev)) - return 0; - } - - /* - * At boot time, we don't yet know if devices will be 64-bit capable. - * Assume that they will — if they turn out not to be, then we can - * take them out of the 1:1 domain later. - */ - if (!startup) { - /* - * If the device's dma_mask is less than the system's memory - * size then this is not a candidate for identity mapping. - */ - u64 dma_mask = *dev->dma_mask; - - if (dev->coherent_dma_mask && - dev->coherent_dma_mask < dma_mask) - dma_mask = dev->coherent_dma_mask; - - return dma_mask >= dma_get_required_mask(dev); - } - - return 1; -} - -static int __init dev_prepare_static_identity_mapping(struct device *dev, int hw) -{ - int ret; - - if (!iommu_should_identity_map(dev, 1)) - return 0; - - ret = domain_add_dev_info(si_domain, dev); - if (!ret) - dev_info(dev, "%s identity mapping\n", - hw ? "Hardware" : "Software"); - else if (ret == -ENODEV) - /* device not associated with an iommu */ - ret = 0; - - return ret; -} - - -static int __init iommu_prepare_static_identity_mapping(int hw) -{ - struct pci_dev *pdev = NULL; - struct dmar_drhd_unit *drhd; - /* To avoid a -Wunused-but-set-variable warning. */ - struct intel_iommu *iommu __maybe_unused; - struct device *dev; - int i; - int ret = 0; - - for_each_pci_dev(pdev) { - ret = dev_prepare_static_identity_mapping(&pdev->dev, hw); - if (ret) - return ret; + return IOMMU_DOMAIN_DMA; } - for_each_active_iommu(iommu, drhd) - for_each_active_dev_scope(drhd->devices, drhd->devices_cnt, i, dev) { - struct acpi_device_physical_node *pn; - struct acpi_device *adev; - - if (dev->bus != &acpi_bus_type) - continue; - - adev= to_acpi_device(dev); - mutex_lock(&adev->physical_node_lock); - list_for_each_entry(pn, &adev->physical_node_list, node) { - ret = dev_prepare_static_identity_mapping(pn->dev, hw); - if (ret) - break; - } - mutex_unlock(&adev->physical_node_lock); - if (ret) - return ret; - } - - return 0; + return (iommu_identity_mapping & IDENTMAP_ALL) ? + IOMMU_DOMAIN_IDENTITY : 0; } static void intel_iommu_init_qi(struct intel_iommu *iommu) @@ -3284,11 +3146,8 @@ out_unmap: static int __init init_dmars(void) { struct dmar_drhd_unit *drhd; - struct dmar_rmrr_unit *rmrr; - bool copied_tables = false; - struct device *dev; struct intel_iommu *iommu; - int i, ret; + int ret; /* * for each drhd @@ -3321,7 +3180,12 @@ static int __init init_dmars(void) goto error; } - for_each_active_iommu(iommu, drhd) { + for_each_iommu(iommu, drhd) { + if (drhd->ignored) { + iommu_disable_translation(iommu); + continue; + } + /* * Find the max pasid size of all IOMMU's in the system. * We need to ensure the system pasid table is no bigger @@ -3381,7 +3245,6 @@ static int __init init_dmars(void) } else { pr_info("Copied translation tables from previous kernel for %s\n", iommu->name); - copied_tables = true; } } @@ -3417,62 +3280,9 @@ static int __init init_dmars(void) check_tylersburg_isoch(); - if (iommu_identity_mapping) { - ret = si_domain_init(hw_pass_through); - if (ret) - goto free_iommu; - } - - - /* - * If we copied translations from a previous kernel in the kdump - * case, we can not assign the devices to domains now, as that - * would eliminate the old mappings. So skip this part and defer - * the assignment to device driver initialization time. - */ - if (copied_tables) - goto domains_done; - - /* - * If pass through is not set or not enabled, setup context entries for - * identity mappings for rmrr, gfx, and isa and may fall back to static - * identity mapping if iommu_identity_mapping is set. - */ - if (iommu_identity_mapping) { - ret = iommu_prepare_static_identity_mapping(hw_pass_through); - if (ret) { - pr_crit("Failed to setup IOMMU pass-through\n"); - goto free_iommu; - } - } - /* - * For each rmrr - * for each dev attached to rmrr - * do - * locate drhd for dev, alloc domain for dev - * allocate free domain - * allocate page table entries for rmrr - * if context not allocated for bus - * allocate and init context - * set present in root table for this bus - * init context with domain, translation etc - * endfor - * endfor - */ - pr_info("Setting RMRR:\n"); - for_each_rmrr_units(rmrr) { - /* some BIOS lists non-exist devices in DMAR table. */ - for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt, - i, dev) { - ret = iommu_prepare_rmrr_dev(rmrr, dev); - if (ret) - pr_err("Mapping reserved region failed\n"); - } - } - - iommu_prepare_isa(); - -domains_done: + ret = si_domain_init(hw_pass_through); + if (ret) + goto free_iommu; /* * for each drhd @@ -3510,11 +3320,6 @@ domains_done: ret = dmar_set_interrupt(iommu); if (ret) goto free_iommu; - - if (!translation_pre_enabled(iommu)) - iommu_enable_translation(iommu); - - iommu_disable_protect_mem_regions(iommu); } return 0; @@ -3564,16 +3369,17 @@ static unsigned long intel_alloc_iova(struct device *dev, return iova_pfn; } -struct dmar_domain *get_valid_domain_for_dev(struct device *dev) +static struct dmar_domain *get_private_domain_for_dev(struct device *dev) { struct dmar_domain *domain, *tmp; struct dmar_rmrr_unit *rmrr; struct device *i_dev; int i, ret; + /* Device shouldn't be attached by any domains. */ domain = find_domain(dev); if (domain) - goto out; + return NULL; domain = find_or_alloc_domain(dev, DEFAULT_DOMAIN_ADDRESS_WIDTH); if (!domain) @@ -3603,10 +3409,10 @@ struct dmar_domain *get_valid_domain_for_dev(struct device *dev) } out: - if (!domain) dev_err(dev, "Allocating domain failed\n"); - + else + domain->domain.type = IOMMU_DOMAIN_DMA; return domain; } @@ -3614,17 +3420,19 @@ out: /* Check if the dev needs to go through non-identity map and unmap process.*/ static bool iommu_need_mapping(struct device *dev) { - int found; + int ret; if (iommu_dummy(dev)) return false; - if (!iommu_identity_mapping) - return true; + ret = identity_mapping(dev); + if (ret) { + u64 dma_mask = *dev->dma_mask; - found = identity_mapping(dev); - if (found) { - if (iommu_should_identity_map(dev, 0)) + if (dev->coherent_dma_mask && dev->coherent_dma_mask < dma_mask) + dma_mask = dev->coherent_dma_mask; + + if (dma_mask >= dma_get_required_mask(dev)) return false; /* @@ -3632,17 +3440,20 @@ static bool iommu_need_mapping(struct device *dev) * non-identity mapping. */ dmar_remove_one_dev_info(dev); - dev_info(dev, "32bit DMA uses non-identity mapping\n"); - } else { - /* - * In case of a detached 64 bit DMA device from vm, the device - * is put into si_domain for identity mapping. - */ - if (iommu_should_identity_map(dev, 0) && - !domain_add_dev_info(si_domain, dev)) { - dev_info(dev, "64bit DMA uses identity mapping\n"); - return false; + ret = iommu_request_dma_domain_for_dev(dev); + if (ret) { + struct iommu_domain *domain; + struct dmar_domain *dmar_domain; + + domain = iommu_get_domain_for_dev(dev); + if (domain) { + dmar_domain = to_dmar_domain(domain); + dmar_domain->flags |= DOMAIN_FLAG_LOSE_CHILDREN; + } + get_private_domain_for_dev(dev); } + + dev_info(dev, "32bit DMA uses non-identity mapping\n"); } return true; @@ -3661,7 +3472,7 @@ static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr, BUG_ON(dir == DMA_NONE); - domain = get_valid_domain_for_dev(dev); + domain = find_domain(dev); if (!domain) return DMA_MAPPING_ERROR; @@ -3876,7 +3687,7 @@ static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nele if (!iommu_need_mapping(dev)) return dma_direct_map_sg(dev, sglist, nelems, dir, attrs); - domain = get_valid_domain_for_dev(dev); + domain = find_domain(dev); if (!domain) return 0; @@ -4195,13 +4006,10 @@ static void __init init_iommu_pm_ops(void) static inline void init_iommu_pm_ops(void) {} #endif /* CONFIG_PM */ - int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg) { struct acpi_dmar_reserved_memory *rmrr; - int prot = DMA_PTE_READ|DMA_PTE_WRITE; struct dmar_rmrr_unit *rmrru; - size_t length; rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL); if (!rmrru) @@ -4212,23 +4020,15 @@ int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg) rmrru->base_address = rmrr->base_address; rmrru->end_address = rmrr->end_address; - length = rmrr->end_address - rmrr->base_address + 1; - rmrru->resv = iommu_alloc_resv_region(rmrr->base_address, length, prot, - IOMMU_RESV_DIRECT); - if (!rmrru->resv) - goto free_rmrru; - rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1), ((void *)rmrr) + rmrr->header.length, &rmrru->devices_cnt); if (rmrru->devices_cnt && rmrru->devices == NULL) - goto free_all; + goto free_rmrru; list_add(&rmrru->list, &dmar_rmrr_units); return 0; -free_all: - kfree(rmrru->resv); free_rmrru: kfree(rmrru); out: @@ -4446,7 +4246,6 @@ static void intel_iommu_free_dmars(void) list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) { list_del(&rmrru->list); dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt); - kfree(rmrru->resv); kfree(rmrru); } @@ -4551,42 +4350,6 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info) return 0; } -/* - * Here we only respond to action of unbound device from driver. - * - * Added device is not attached to its DMAR domain here yet. That will happen - * when mapping the device to iova. - */ -static int device_notifier(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct device *dev = data; - struct dmar_domain *domain; - - if (iommu_dummy(dev)) - return 0; - - if (action == BUS_NOTIFY_REMOVED_DEVICE) { - domain = find_domain(dev); - if (!domain) - return 0; - - dmar_remove_one_dev_info(dev); - if (!domain_type_is_vm_or_si(domain) && - list_empty(&domain->devices)) - domain_exit(domain); - } else if (action == BUS_NOTIFY_ADD_DEVICE) { - if (iommu_should_identity_map(dev, 1)) - domain_add_dev_info(si_domain, dev); - } - - return 0; -} - -static struct notifier_block device_nb = { - .notifier_call = device_notifier, -}; - static int intel_iommu_memory_notifier(struct notifier_block *nb, unsigned long val, void *v) { @@ -4813,6 +4576,49 @@ static int __init platform_optin_force_iommu(void) return 1; } +static int __init probe_acpi_namespace_devices(void) +{ + struct dmar_drhd_unit *drhd; + /* To avoid a -Wunused-but-set-variable warning. */ + struct intel_iommu *iommu __maybe_unused; + struct device *dev; + int i, ret = 0; + + for_each_active_iommu(iommu, drhd) { + for_each_active_dev_scope(drhd->devices, + drhd->devices_cnt, i, dev) { + struct acpi_device_physical_node *pn; + struct iommu_group *group; + struct acpi_device *adev; + + if (dev->bus != &acpi_bus_type) + continue; + + adev = to_acpi_device(dev); + mutex_lock(&adev->physical_node_lock); + list_for_each_entry(pn, + &adev->physical_node_list, node) { + group = iommu_group_get(pn->dev); + if (group) { + iommu_group_put(group); + continue; + } + + pn->dev->bus->iommu_ops = &intel_iommu_ops; + ret = iommu_probe_device(pn->dev); + if (ret) + break; + } + mutex_unlock(&adev->physical_node_lock); + + if (ret) + return ret; + } + } + + return 0; +} + int __init intel_iommu_init(void) { int ret = -ENODEV; @@ -4902,7 +4708,6 @@ int __init intel_iommu_init(void) goto out_free_reserved_range; } up_write(&dmar_global_lock); - pr_info("Intel(R) Virtualization Technology for Directed I/O\n"); #if defined(CONFIG_X86) && defined(CONFIG_SWIOTLB) swiotlb = 0; @@ -4920,11 +4725,25 @@ int __init intel_iommu_init(void) } bus_set_iommu(&pci_bus_type, &intel_iommu_ops); - bus_register_notifier(&pci_bus_type, &device_nb); if (si_domain && !hw_pass_through) register_memory_notifier(&intel_iommu_memory_nb); cpuhp_setup_state(CPUHP_IOMMU_INTEL_DEAD, "iommu/intel:dead", NULL, intel_iommu_cpu_dead); + + down_read(&dmar_global_lock); + if (probe_acpi_namespace_devices()) + pr_warn("ACPI name space devices didn't probe correctly\n"); + up_read(&dmar_global_lock); + + /* Finally, we enable the DMA remapping hardware. */ + for_each_iommu(iommu, drhd) { + if (!drhd->ignored && !translation_pre_enabled(iommu)) + iommu_enable_translation(iommu); + + iommu_disable_protect_mem_regions(iommu); + } + pr_info("Intel(R) Virtualization Technology for Directed I/O\n"); + intel_iommu_enabled = 1; intel_iommu_debugfs_init(); @@ -4963,6 +4782,7 @@ static void domain_context_clear(struct intel_iommu *iommu, struct device *dev) static void __dmar_remove_one_dev_info(struct device_domain_info *info) { + struct dmar_domain *domain; struct intel_iommu *iommu; unsigned long flags; @@ -4972,6 +4792,7 @@ static void __dmar_remove_one_dev_info(struct device_domain_info *info) return; iommu = info->iommu; + domain = info->domain; if (info->dev) { if (dev_is_pci(info->dev) && sm_supported(iommu)) @@ -4986,9 +4807,14 @@ static void __dmar_remove_one_dev_info(struct device_domain_info *info) unlink_domain_info(info); spin_lock_irqsave(&iommu->lock, flags); - domain_detach_iommu(info->domain, iommu); + domain_detach_iommu(domain, iommu); spin_unlock_irqrestore(&iommu->lock, flags); + /* free the private domain */ + if (domain->flags & DOMAIN_FLAG_LOSE_CHILDREN && + !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) + domain_exit(info->domain); + free_devinfo_mem(info); } @@ -5003,62 +4829,55 @@ static void dmar_remove_one_dev_info(struct device *dev) spin_unlock_irqrestore(&device_domain_lock, flags); } -static int md_domain_init(struct dmar_domain *domain, int guest_width) -{ - int adjust_width; - - init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN); - domain_reserve_special_ranges(domain); - - /* calculate AGAW */ - domain->gaw = guest_width; - adjust_width = guestwidth_to_adjustwidth(guest_width); - domain->agaw = width_to_agaw(adjust_width); - - domain->iommu_coherency = 0; - domain->iommu_snooping = 0; - domain->iommu_superpage = 0; - domain->max_addr = 0; - - /* always allocate the top pgd */ - domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid); - if (!domain->pgd) - return -ENOMEM; - domain_flush_cache(domain, domain->pgd, PAGE_SIZE); - return 0; -} - static struct iommu_domain *intel_iommu_domain_alloc(unsigned type) { struct dmar_domain *dmar_domain; struct iommu_domain *domain; - if (type != IOMMU_DOMAIN_UNMANAGED) - return NULL; + switch (type) { + case IOMMU_DOMAIN_DMA: + /* fallthrough */ + case IOMMU_DOMAIN_UNMANAGED: + dmar_domain = alloc_domain(0); + if (!dmar_domain) { + pr_err("Can't allocate dmar_domain\n"); + return NULL; + } + if (domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) { + pr_err("Domain initialization failed\n"); + domain_exit(dmar_domain); + return NULL; + } - dmar_domain = alloc_domain(DOMAIN_FLAG_VIRTUAL_MACHINE); - if (!dmar_domain) { - pr_err("Can't allocate dmar_domain\n"); - return NULL; - } - if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) { - pr_err("Domain initialization failed\n"); - domain_exit(dmar_domain); + if (type == IOMMU_DOMAIN_DMA && + init_iova_flush_queue(&dmar_domain->iovad, + iommu_flush_iova, iova_entry_free)) { + pr_warn("iova flush queue initialization failed\n"); + intel_iommu_strict = 1; + } + + domain_update_iommu_cap(dmar_domain); + + domain = &dmar_domain->domain; + domain->geometry.aperture_start = 0; + domain->geometry.aperture_end = + __DOMAIN_MAX_ADDR(dmar_domain->gaw); + domain->geometry.force_aperture = true; + + return domain; + case IOMMU_DOMAIN_IDENTITY: + return &si_domain->domain; + default: return NULL; } - domain_update_iommu_cap(dmar_domain); - domain = &dmar_domain->domain; - domain->geometry.aperture_start = 0; - domain->geometry.aperture_end = __DOMAIN_MAX_ADDR(dmar_domain->gaw); - domain->geometry.force_aperture = true; - - return domain; + return NULL; } static void intel_iommu_domain_free(struct iommu_domain *domain) { - domain_exit(to_dmar_domain(domain)); + if (domain != &si_domain->domain) + domain_exit(to_dmar_domain(domain)); } /* @@ -5234,7 +5053,8 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, { int ret; - if (device_is_rmrr_locked(dev)) { + if (domain->type == IOMMU_DOMAIN_UNMANAGED && + device_is_rmrr_locked(dev)) { dev_warn(dev, "Device is ineligible for IOMMU domain attach due to platform RMRR requirement. Contact your platform vendor.\n"); return -EPERM; } @@ -5247,15 +5067,8 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, struct dmar_domain *old_domain; old_domain = find_domain(dev); - if (old_domain) { - rcu_read_lock(); + if (old_domain) dmar_remove_one_dev_info(dev); - rcu_read_unlock(); - - if (!domain_type_is_vm_or_si(old_domain) && - list_empty(&old_domain->devices)) - domain_exit(old_domain); - } } ret = prepare_domain_attach_device(domain, dev); @@ -5301,6 +5114,9 @@ static int intel_iommu_map(struct iommu_domain *domain, int prot = 0; int ret; + if (dmar_domain->flags & DOMAIN_FLAG_LOSE_CHILDREN) + return -EINVAL; + if (iommu_prot & IOMMU_READ) prot |= DMA_PTE_READ; if (iommu_prot & IOMMU_WRITE) @@ -5342,6 +5158,8 @@ static size_t intel_iommu_unmap(struct iommu_domain *domain, /* Cope with horrid API which requires us to unmap more than the size argument if it happens to be a large-page mapping. */ BUG_ON(!pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level)); + if (dmar_domain->flags & DOMAIN_FLAG_LOSE_CHILDREN) + return 0; if (size < VTD_PAGE_SIZE << level_to_offset_bits(level)) size = VTD_PAGE_SIZE << level_to_offset_bits(level); @@ -5373,6 +5191,9 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain, int level = 0; u64 phys = 0; + if (dmar_domain->flags & DOMAIN_FLAG_LOSE_CHILDREN) + return 0; + pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level); if (pte) phys = dma_pte_addr(pte); @@ -5428,9 +5249,12 @@ static bool intel_iommu_capable(enum iommu_cap cap) static int intel_iommu_add_device(struct device *dev) { + struct dmar_domain *dmar_domain; + struct iommu_domain *domain; struct intel_iommu *iommu; struct iommu_group *group; u8 bus, devfn; + int ret; iommu = device_to_iommu(dev, &bus, &devfn); if (!iommu) @@ -5438,12 +5262,45 @@ static int intel_iommu_add_device(struct device *dev) iommu_device_link(&iommu->iommu, dev); + if (translation_pre_enabled(iommu)) + dev->archdata.iommu = DEFER_DEVICE_DOMAIN_INFO; + group = iommu_group_get_for_dev(dev); if (IS_ERR(group)) return PTR_ERR(group); iommu_group_put(group); + + domain = iommu_get_domain_for_dev(dev); + dmar_domain = to_dmar_domain(domain); + if (domain->type == IOMMU_DOMAIN_DMA) { + if (device_def_domain_type(dev) == IOMMU_DOMAIN_IDENTITY) { + ret = iommu_request_dm_for_dev(dev); + if (ret) { + dmar_domain->flags |= DOMAIN_FLAG_LOSE_CHILDREN; + domain_add_dev_info(si_domain, dev); + dev_info(dev, + "Device uses a private identity domain.\n"); + } + } + } else { + if (device_def_domain_type(dev) == IOMMU_DOMAIN_DMA) { + ret = iommu_request_dma_domain_for_dev(dev); + if (ret) { + dmar_domain->flags |= DOMAIN_FLAG_LOSE_CHILDREN; + if (!get_private_domain_for_dev(dev)) { + dev_warn(dev, + "Failed to get a private domain.\n"); + return -ENOMEM; + } + + dev_info(dev, + "Device uses a private dma domain.\n"); + } + } + } + return 0; } @@ -5464,22 +5321,51 @@ static void intel_iommu_remove_device(struct device *dev) static void intel_iommu_get_resv_regions(struct device *device, struct list_head *head) { + int prot = DMA_PTE_READ | DMA_PTE_WRITE; struct iommu_resv_region *reg; struct dmar_rmrr_unit *rmrr; struct device *i_dev; int i; - rcu_read_lock(); + down_read(&dmar_global_lock); for_each_rmrr_units(rmrr) { for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt, i, i_dev) { - if (i_dev != device) + struct iommu_resv_region *resv; + enum iommu_resv_type type; + size_t length; + + if (i_dev != device && + !is_downstream_to_pci_bridge(device, i_dev)) continue; - list_add_tail(&rmrr->resv->list, head); + length = rmrr->end_address - rmrr->base_address + 1; + + type = device_rmrr_is_relaxable(device) ? + IOMMU_RESV_DIRECT_RELAXABLE : IOMMU_RESV_DIRECT; + + resv = iommu_alloc_resv_region(rmrr->base_address, + length, prot, type); + if (!resv) + break; + + list_add_tail(&resv->list, head); } } - rcu_read_unlock(); + up_read(&dmar_global_lock); + +#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA + if (dev_is_pci(device)) { + struct pci_dev *pdev = to_pci_dev(device); + + if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) { + reg = iommu_alloc_resv_region(0, 1UL << 24, 0, + IOMMU_RESV_DIRECT); + if (reg) + list_add_tail(®->list, head); + } + } +#endif /* CONFIG_INTEL_IOMMU_FLOPPY_WA */ reg = iommu_alloc_resv_region(IOAPIC_RANGE_START, IOAPIC_RANGE_END - IOAPIC_RANGE_START + 1, @@ -5494,10 +5380,8 @@ static void intel_iommu_put_resv_regions(struct device *dev, { struct iommu_resv_region *entry, *next; - list_for_each_entry_safe(entry, next, head, list) { - if (entry->type == IOMMU_RESV_MSI) - kfree(entry); - } + list_for_each_entry_safe(entry, next, head, list) + kfree(entry); } int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct device *dev) @@ -5509,7 +5393,7 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct device *dev) u64 ctx_lo; int ret; - domain = get_valid_domain_for_dev(dev); + domain = find_domain(dev); if (!domain) return -EINVAL; @@ -5551,6 +5435,19 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct device *dev) return ret; } +static void intel_iommu_apply_resv_region(struct device *dev, + struct iommu_domain *domain, + struct iommu_resv_region *region) +{ + struct dmar_domain *dmar_domain = to_dmar_domain(domain); + unsigned long start, end; + + start = IOVA_PFN(region->start); + end = IOVA_PFN(region->start + region->length - 1); + + WARN_ON_ONCE(!reserve_iova(&dmar_domain->iovad, start, end)); +} + #ifdef CONFIG_INTEL_IOMMU_SVM struct intel_iommu *intel_svm_device_to_iommu(struct device *dev) { @@ -5700,6 +5597,12 @@ intel_iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev) dmar_domain->default_pasid : -EINVAL; } +static bool intel_iommu_is_attach_deferred(struct iommu_domain *domain, + struct device *dev) +{ + return dev->archdata.iommu == DEFER_DEVICE_DOMAIN_INFO; +} + const struct iommu_ops intel_iommu_ops = { .capable = intel_iommu_capable, .domain_alloc = intel_iommu_domain_alloc, @@ -5716,11 +5619,13 @@ const struct iommu_ops intel_iommu_ops = { .remove_device = intel_iommu_remove_device, .get_resv_regions = intel_iommu_get_resv_regions, .put_resv_regions = intel_iommu_put_resv_regions, + .apply_resv_region = intel_iommu_apply_resv_region, .device_group = pci_device_group, .dev_has_feat = intel_iommu_dev_has_feat, .dev_feat_enabled = intel_iommu_dev_feat_enabled, .dev_enable_feat = intel_iommu_dev_enable_feat, .dev_disable_feat = intel_iommu_dev_disable_feat, + .is_attach_deferred = intel_iommu_is_attach_deferred, .pgsize_bitmap = INTEL_IOMMU_PGSIZES, }; diff --git a/drivers/iommu/intel-pasid.c b/drivers/iommu/intel-pasid.c index fe51d8af457f..040a445be300 100644 --- a/drivers/iommu/intel-pasid.c +++ b/drivers/iommu/intel-pasid.c @@ -169,23 +169,6 @@ attach_out: return 0; } -/* Get PRESENT bit of a PASID directory entry. */ -static inline bool -pasid_pde_is_present(struct pasid_dir_entry *pde) -{ - return READ_ONCE(pde->val) & PASID_PTE_PRESENT; -} - -/* Get PASID table from a PASID directory entry. */ -static inline struct pasid_entry * -get_pasid_table_from_pde(struct pasid_dir_entry *pde) -{ - if (!pasid_pde_is_present(pde)) - return NULL; - - return phys_to_virt(READ_ONCE(pde->val) & PDE_PFN_MASK); -} - void intel_pasid_free_table(struct device *dev) { struct device_domain_info *info; diff --git a/drivers/iommu/intel-pasid.h b/drivers/iommu/intel-pasid.h index 23537b3f34e3..fc8cd8f17de1 100644 --- a/drivers/iommu/intel-pasid.h +++ b/drivers/iommu/intel-pasid.h @@ -18,6 +18,10 @@ #define PDE_PFN_MASK PAGE_MASK #define PASID_PDE_SHIFT 6 #define MAX_NR_PASID_BITS 20 +#define PASID_TBL_ENTRIES BIT(PASID_PDE_SHIFT) + +#define is_pasid_enabled(entry) (((entry)->lo >> 3) & 0x1) +#define get_pasid_dir_size(entry) (1 << ((((entry)->lo >> 9) & 0x7) + 7)) /* * Domain ID reserved for pasid entries programmed for first-level @@ -49,6 +53,28 @@ struct pasid_table { struct list_head dev; /* device list */ }; +/* Get PRESENT bit of a PASID directory entry. */ +static inline bool pasid_pde_is_present(struct pasid_dir_entry *pde) +{ + return READ_ONCE(pde->val) & PASID_PTE_PRESENT; +} + +/* Get PASID table from a PASID directory entry. */ +static inline struct pasid_entry * +get_pasid_table_from_pde(struct pasid_dir_entry *pde) +{ + if (!pasid_pde_is_present(pde)) + return NULL; + + return phys_to_virt(READ_ONCE(pde->val) & PDE_PFN_MASK); +} + +/* Get PRESENT bit of a PASID table entry. */ +static inline bool pasid_pte_is_present(struct pasid_entry *pte) +{ + return READ_ONCE(pte->val[0]) & PASID_PTE_PRESENT; +} + extern u32 intel_pasid_max_id; int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp); void intel_pasid_free_id(int pasid); diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c index eceaa7e968ae..780de0caafe8 100644 --- a/drivers/iommu/intel-svm.c +++ b/drivers/iommu/intel-svm.c @@ -366,6 +366,21 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ } list_add_tail(&svm->list, &global_svm_list); + } else { + /* + * Binding a new device with existing PASID, need to setup + * the PASID entry. + */ + spin_lock(&iommu->lock); + ret = intel_pasid_setup_first_level(iommu, dev, + mm ? mm->pgd : init_mm.pgd, + svm->pasid, FLPT_DEFAULT_DID, + mm ? 0 : PASID_FLAG_SUPERVISOR_MODE); + spin_unlock(&iommu->lock); + if (ret) { + kfree(sdev); + goto out; + } } list_add_rcu(&sdev->list, &svm->devs); diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index 4160aa9f3f80..4786ca061e31 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -101,7 +101,7 @@ static void init_ir_status(struct intel_iommu *iommu) iommu->flags |= VTD_FLAG_IRQ_REMAP_PRE_ENABLED; } -static int alloc_irte(struct intel_iommu *iommu, int irq, +static int alloc_irte(struct intel_iommu *iommu, struct irq_2_iommu *irq_iommu, u16 count) { struct ir_table *table = iommu->ir_table; @@ -1374,7 +1374,7 @@ static int intel_irq_remapping_alloc(struct irq_domain *domain, goto out_free_parent; down_read(&dmar_global_lock); - index = alloc_irte(iommu, virq, &data->irq_2_iommu, nr_irqs); + index = alloc_irte(iommu, &data->irq_2_iommu, nr_irqs); up_read(&dmar_global_lock); if (index < 0) { pr_warn("Failed to allocate IRTE\n"); diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c index 9a8a8870e267..0fc8dfab2abf 100644 --- a/drivers/iommu/io-pgtable-arm-v7s.c +++ b/drivers/iommu/io-pgtable-arm-v7s.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * CPU-agnostic ARM page table allocator. * @@ -14,18 +15,6 @@ * - PXN * - Domains * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * * Copyright (C) 2014-2015 ARM Limited * Copyright (c) 2014-2015 MediaTek Inc. */ @@ -215,7 +204,7 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp, dev_err(dev, "Page table does not fit in PTE: %pa", &phys); goto out_free; } - if (table && !(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)) { + if (table && !cfg->coherent_walk) { dma = dma_map_single(dev, table, size, DMA_TO_DEVICE); if (dma_mapping_error(dev, dma)) goto out_free; @@ -249,7 +238,7 @@ static void __arm_v7s_free_table(void *table, int lvl, struct device *dev = cfg->iommu_dev; size_t size = ARM_V7S_TABLE_SIZE(lvl); - if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)) + if (!cfg->coherent_walk) dma_unmap_single(dev, __arm_v7s_dma_addr(table), size, DMA_TO_DEVICE); if (lvl == 1) @@ -261,7 +250,7 @@ static void __arm_v7s_free_table(void *table, int lvl, static void __arm_v7s_pte_sync(arm_v7s_iopte *ptep, int num_entries, struct io_pgtable_cfg *cfg) { - if (cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA) + if (cfg->coherent_walk) return; dma_sync_single_for_device(cfg->iommu_dev, __arm_v7s_dma_addr(ptep), @@ -727,7 +716,6 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg, IO_PGTABLE_QUIRK_NO_PERMS | IO_PGTABLE_QUIRK_TLBI_ON_MAP | IO_PGTABLE_QUIRK_ARM_MTK_4GB | - IO_PGTABLE_QUIRK_NO_DMA | IO_PGTABLE_QUIRK_NON_STRICT)) return NULL; @@ -790,8 +778,11 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg, /* TTBRs */ cfg->arm_v7s_cfg.ttbr[0] = virt_to_phys(data->pgd) | ARM_V7S_TTBR_S | ARM_V7S_TTBR_NOS | - ARM_V7S_TTBR_IRGN_ATTR(ARM_V7S_RGN_WBWA) | - ARM_V7S_TTBR_ORGN_ATTR(ARM_V7S_RGN_WBWA); + (cfg->coherent_walk ? + (ARM_V7S_TTBR_IRGN_ATTR(ARM_V7S_RGN_WBWA) | + ARM_V7S_TTBR_ORGN_ATTR(ARM_V7S_RGN_WBWA)) : + (ARM_V7S_TTBR_IRGN_ATTR(ARM_V7S_RGN_NC) | + ARM_V7S_TTBR_ORGN_ATTR(ARM_V7S_RGN_NC))); cfg->arm_v7s_cfg.ttbr[1] = 0; return &data->iop; @@ -846,7 +837,8 @@ static int __init arm_v7s_do_selftests(void) .tlb = &dummy_tlb_ops, .oas = 32, .ias = 32, - .quirks = IO_PGTABLE_QUIRK_ARM_NS | IO_PGTABLE_QUIRK_NO_DMA, + .coherent_walk = true, + .quirks = IO_PGTABLE_QUIRK_ARM_NS, .pgsize_bitmap = SZ_4K | SZ_64K | SZ_1M | SZ_16M, }; unsigned int iova, size, iova_start; diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 4e21efbc4459..161a7d56264d 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * CPU-agnostic ARM page table allocator. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * * Copyright (C) 2014 ARM Limited * * Author: Will Deacon <will.deacon@arm.com> @@ -167,10 +156,12 @@ #define ARM_LPAE_MAIR_ATTR_MASK 0xff #define ARM_LPAE_MAIR_ATTR_DEVICE 0x04 #define ARM_LPAE_MAIR_ATTR_NC 0x44 +#define ARM_LPAE_MAIR_ATTR_INC_OWBRWA 0xf4 #define ARM_LPAE_MAIR_ATTR_WBRWA 0xff #define ARM_LPAE_MAIR_ATTR_IDX_NC 0 #define ARM_LPAE_MAIR_ATTR_IDX_CACHE 1 #define ARM_LPAE_MAIR_ATTR_IDX_DEV 2 +#define ARM_LPAE_MAIR_ATTR_IDX_INC_OCACHE 3 #define ARM_MALI_LPAE_TTBR_ADRMODE_TABLE (3u << 0) #define ARM_MALI_LPAE_TTBR_READ_INNER BIT(2) @@ -250,7 +241,7 @@ static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp, return NULL; pages = page_address(p); - if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)) { + if (!cfg->coherent_walk) { dma = dma_map_single(dev, pages, size, DMA_TO_DEVICE); if (dma_mapping_error(dev, dma)) goto out_free; @@ -276,7 +267,7 @@ out_free: static void __arm_lpae_free_pages(void *pages, size_t size, struct io_pgtable_cfg *cfg) { - if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)) + if (!cfg->coherent_walk) dma_unmap_single(cfg->iommu_dev, __arm_lpae_dma_addr(pages), size, DMA_TO_DEVICE); free_pages((unsigned long)pages, get_order(size)); @@ -294,7 +285,7 @@ static void __arm_lpae_set_pte(arm_lpae_iopte *ptep, arm_lpae_iopte pte, { *ptep = pte; - if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)) + if (!cfg->coherent_walk) __arm_lpae_sync_pte(ptep, cfg); } @@ -372,8 +363,7 @@ static arm_lpae_iopte arm_lpae_install_table(arm_lpae_iopte *table, old = cmpxchg64_relaxed(ptep, curr, new); - if ((cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA) || - (old & ARM_LPAE_PTE_SW_SYNC)) + if (cfg->coherent_walk || (old & ARM_LPAE_PTE_SW_SYNC)) return old; /* Even if it's not ours, there's no point waiting; just kick it */ @@ -414,8 +404,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, pte = arm_lpae_install_table(cptep, ptep, 0, cfg); if (pte) __arm_lpae_free_pages(cptep, tblsz, cfg); - } else if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA) && - !(pte & ARM_LPAE_PTE_SW_SYNC)) { + } else if (!cfg->coherent_walk && !(pte & ARM_LPAE_PTE_SW_SYNC)) { __arm_lpae_sync_pte(ptep, cfg); } @@ -470,6 +459,9 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data, else if (prot & IOMMU_CACHE) pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE << ARM_LPAE_PTE_ATTRINDX_SHIFT); + else if (prot & IOMMU_QCOM_SYS_CACHE) + pte |= (ARM_LPAE_MAIR_ATTR_IDX_INC_OCACHE + << ARM_LPAE_PTE_ATTRINDX_SHIFT); } if (prot & IOMMU_NOEXEC) @@ -794,7 +786,7 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) u64 reg; struct arm_lpae_io_pgtable *data; - if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS | IO_PGTABLE_QUIRK_NO_DMA | + if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS | IO_PGTABLE_QUIRK_NON_STRICT)) return NULL; @@ -803,9 +795,15 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) return NULL; /* TCR */ - reg = (ARM_LPAE_TCR_SH_IS << ARM_LPAE_TCR_SH0_SHIFT) | - (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) | - (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT); + if (cfg->coherent_walk) { + reg = (ARM_LPAE_TCR_SH_IS << ARM_LPAE_TCR_SH0_SHIFT) | + (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) | + (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT); + } else { + reg = (ARM_LPAE_TCR_SH_OS << ARM_LPAE_TCR_SH0_SHIFT) | + (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_IRGN0_SHIFT) | + (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_ORGN0_SHIFT); + } switch (ARM_LPAE_GRANULE(data)) { case SZ_4K: @@ -857,7 +855,9 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) (ARM_LPAE_MAIR_ATTR_WBRWA << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_CACHE)) | (ARM_LPAE_MAIR_ATTR_DEVICE - << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_DEV)); + << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_DEV)) | + (ARM_LPAE_MAIR_ATTR_INC_OWBRWA + << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_INC_OCACHE)); cfg->arm_lpae_s1_cfg.mair[0] = reg; cfg->arm_lpae_s1_cfg.mair[1] = 0; @@ -887,8 +887,7 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) struct arm_lpae_io_pgtable *data; /* The NS quirk doesn't apply at stage 2 */ - if (cfg->quirks & ~(IO_PGTABLE_QUIRK_NO_DMA | - IO_PGTABLE_QUIRK_NON_STRICT)) + if (cfg->quirks & ~(IO_PGTABLE_QUIRK_NON_STRICT)) return NULL; data = arm_lpae_alloc_pgtable(cfg); @@ -1223,7 +1222,7 @@ static int __init arm_lpae_do_selftests(void) struct io_pgtable_cfg cfg = { .tlb = &dummy_tlb_ops, .oas = 48, - .quirks = IO_PGTABLE_QUIRK_NO_DMA, + .coherent_walk = true, }; for (i = 0; i < ARRAY_SIZE(pgsize); ++i) { diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c index 5227cfdbb65b..ced53e5b72b5 100644 --- a/drivers/iommu/io-pgtable.c +++ b/drivers/iommu/io-pgtable.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic page table allocator for IOMMUs. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * * Copyright (C) 2014 ARM Limited * * Author: Will Deacon <will.deacon@arm.com> diff --git a/drivers/iommu/iommu-sysfs.c b/drivers/iommu/iommu-sysfs.c index 44127d54e943..e436ff813e7e 100644 --- a/drivers/iommu/iommu-sysfs.c +++ b/drivers/iommu/iommu-sysfs.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * IOMMU sysfs class support * * Copyright (C) 2014 Red Hat, Inc. All rights reserved. * Author: Alex Williamson <alex.williamson@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 9f0a2844371c..0c674d80c37f 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -61,10 +61,11 @@ struct iommu_group_attribute { }; static const char * const iommu_group_resv_type_string[] = { - [IOMMU_RESV_DIRECT] = "direct", - [IOMMU_RESV_RESERVED] = "reserved", - [IOMMU_RESV_MSI] = "msi", - [IOMMU_RESV_SW_MSI] = "msi", + [IOMMU_RESV_DIRECT] = "direct", + [IOMMU_RESV_DIRECT_RELAXABLE] = "direct-relaxable", + [IOMMU_RESV_RESERVED] = "reserved", + [IOMMU_RESV_MSI] = "msi", + [IOMMU_RESV_SW_MSI] = "msi", }; #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \ @@ -95,15 +96,43 @@ void iommu_device_unregister(struct iommu_device *iommu) spin_unlock(&iommu_device_lock); } +static struct iommu_param *iommu_get_dev_param(struct device *dev) +{ + struct iommu_param *param = dev->iommu_param; + + if (param) + return param; + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) + return NULL; + + mutex_init(¶m->lock); + dev->iommu_param = param; + return param; +} + +static void iommu_free_dev_param(struct device *dev) +{ + kfree(dev->iommu_param); + dev->iommu_param = NULL; +} + int iommu_probe_device(struct device *dev) { const struct iommu_ops *ops = dev->bus->iommu_ops; - int ret = -EINVAL; + int ret; WARN_ON(dev->iommu_group); + if (!ops) + return -EINVAL; - if (ops) - ret = ops->add_device(dev); + if (!iommu_get_dev_param(dev)) + return -ENOMEM; + + ret = ops->add_device(dev); + if (ret) + iommu_free_dev_param(dev); return ret; } @@ -114,6 +143,8 @@ void iommu_release_device(struct device *dev) if (dev->iommu_group) ops->remove_device(dev); + + iommu_free_dev_param(dev); } static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus, @@ -225,18 +256,21 @@ static int iommu_insert_resv_region(struct iommu_resv_region *new, pos = pos->next; } else if ((start >= a) && (end <= b)) { if (new->type == type) - goto done; + return 0; else pos = pos->next; } else { if (new->type == type) { phys_addr_t new_start = min(a, start); phys_addr_t new_end = max(b, end); + int ret; list_del(&entry->list); entry->start = new_start; entry->length = new_end - new_start + 1; - iommu_insert_resv_region(entry, regions); + ret = iommu_insert_resv_region(entry, regions); + kfree(entry); + return ret; } else { pos = pos->next; } @@ -249,7 +283,6 @@ insert: return -ENOMEM; list_add_tail(®ion->list, pos); -done: return 0; } @@ -561,7 +594,8 @@ static int iommu_group_create_direct_mappings(struct iommu_group *group, start = ALIGN(entry->start, pg_size); end = ALIGN(entry->start + entry->length, pg_size); - if (entry->type != IOMMU_RESV_DIRECT) + if (entry->type != IOMMU_RESV_DIRECT && + entry->type != IOMMU_RESV_DIRECT_RELAXABLE) continue; for (addr = start; addr < end; addr += pg_size) { @@ -843,6 +877,206 @@ int iommu_group_unregister_notifier(struct iommu_group *group, EXPORT_SYMBOL_GPL(iommu_group_unregister_notifier); /** + * iommu_register_device_fault_handler() - Register a device fault handler + * @dev: the device + * @handler: the fault handler + * @data: private data passed as argument to the handler + * + * When an IOMMU fault event is received, this handler gets called with the + * fault event and data as argument. The handler should return 0 on success. If + * the fault is recoverable (IOMMU_FAULT_PAGE_REQ), the consumer should also + * complete the fault by calling iommu_page_response() with one of the following + * response code: + * - IOMMU_PAGE_RESP_SUCCESS: retry the translation + * - IOMMU_PAGE_RESP_INVALID: terminate the fault + * - IOMMU_PAGE_RESP_FAILURE: terminate the fault and stop reporting + * page faults if possible. + * + * Return 0 if the fault handler was installed successfully, or an error. + */ +int iommu_register_device_fault_handler(struct device *dev, + iommu_dev_fault_handler_t handler, + void *data) +{ + struct iommu_param *param = dev->iommu_param; + int ret = 0; + + if (!param) + return -EINVAL; + + mutex_lock(¶m->lock); + /* Only allow one fault handler registered for each device */ + if (param->fault_param) { + ret = -EBUSY; + goto done_unlock; + } + + get_device(dev); + param->fault_param = kzalloc(sizeof(*param->fault_param), GFP_KERNEL); + if (!param->fault_param) { + put_device(dev); + ret = -ENOMEM; + goto done_unlock; + } + param->fault_param->handler = handler; + param->fault_param->data = data; + mutex_init(¶m->fault_param->lock); + INIT_LIST_HEAD(¶m->fault_param->faults); + +done_unlock: + mutex_unlock(¶m->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(iommu_register_device_fault_handler); + +/** + * iommu_unregister_device_fault_handler() - Unregister the device fault handler + * @dev: the device + * + * Remove the device fault handler installed with + * iommu_register_device_fault_handler(). + * + * Return 0 on success, or an error. + */ +int iommu_unregister_device_fault_handler(struct device *dev) +{ + struct iommu_param *param = dev->iommu_param; + int ret = 0; + + if (!param) + return -EINVAL; + + mutex_lock(¶m->lock); + + if (!param->fault_param) + goto unlock; + + /* we cannot unregister handler if there are pending faults */ + if (!list_empty(¶m->fault_param->faults)) { + ret = -EBUSY; + goto unlock; + } + + kfree(param->fault_param); + param->fault_param = NULL; + put_device(dev); +unlock: + mutex_unlock(¶m->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(iommu_unregister_device_fault_handler); + +/** + * iommu_report_device_fault() - Report fault event to device driver + * @dev: the device + * @evt: fault event data + * + * Called by IOMMU drivers when a fault is detected, typically in a threaded IRQ + * handler. When this function fails and the fault is recoverable, it is the + * caller's responsibility to complete the fault. + * + * Return 0 on success, or an error. + */ +int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt) +{ + struct iommu_param *param = dev->iommu_param; + struct iommu_fault_event *evt_pending = NULL; + struct iommu_fault_param *fparam; + int ret = 0; + + if (!param || !evt) + return -EINVAL; + + /* we only report device fault if there is a handler registered */ + mutex_lock(¶m->lock); + fparam = param->fault_param; + if (!fparam || !fparam->handler) { + ret = -EINVAL; + goto done_unlock; + } + + if (evt->fault.type == IOMMU_FAULT_PAGE_REQ && + (evt->fault.prm.flags & IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE)) { + evt_pending = kmemdup(evt, sizeof(struct iommu_fault_event), + GFP_KERNEL); + if (!evt_pending) { + ret = -ENOMEM; + goto done_unlock; + } + mutex_lock(&fparam->lock); + list_add_tail(&evt_pending->list, &fparam->faults); + mutex_unlock(&fparam->lock); + } + + ret = fparam->handler(&evt->fault, fparam->data); + if (ret && evt_pending) { + mutex_lock(&fparam->lock); + list_del(&evt_pending->list); + mutex_unlock(&fparam->lock); + kfree(evt_pending); + } +done_unlock: + mutex_unlock(¶m->lock); + return ret; +} +EXPORT_SYMBOL_GPL(iommu_report_device_fault); + +int iommu_page_response(struct device *dev, + struct iommu_page_response *msg) +{ + bool pasid_valid; + int ret = -EINVAL; + struct iommu_fault_event *evt; + struct iommu_fault_page_request *prm; + struct iommu_param *param = dev->iommu_param; + struct iommu_domain *domain = iommu_get_domain_for_dev(dev); + + if (!domain || !domain->ops->page_response) + return -ENODEV; + + if (!param || !param->fault_param) + return -EINVAL; + + if (msg->version != IOMMU_PAGE_RESP_VERSION_1 || + msg->flags & ~IOMMU_PAGE_RESP_PASID_VALID) + return -EINVAL; + + /* Only send response if there is a fault report pending */ + mutex_lock(¶m->fault_param->lock); + if (list_empty(¶m->fault_param->faults)) { + dev_warn_ratelimited(dev, "no pending PRQ, drop response\n"); + goto done_unlock; + } + /* + * Check if we have a matching page request pending to respond, + * otherwise return -EINVAL + */ + list_for_each_entry(evt, ¶m->fault_param->faults, list) { + prm = &evt->fault.prm; + pasid_valid = prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID; + + if ((pasid_valid && prm->pasid != msg->pasid) || + prm->grpid != msg->grpid) + continue; + + /* Sanitize the reply */ + msg->flags = pasid_valid ? IOMMU_PAGE_RESP_PASID_VALID : 0; + + ret = domain->ops->page_response(dev, evt, msg); + list_del(&evt->list); + kfree(evt); + break; + } + +done_unlock: + mutex_unlock(¶m->fault_param->lock); + return ret; +} +EXPORT_SYMBOL_GPL(iommu_page_response); + +/** * iommu_group_id - Return ID for a group * @group: the group to ID * @@ -1895,24 +2129,23 @@ struct iommu_resv_region *iommu_alloc_resv_region(phys_addr_t start, return region; } -/* Request that a device is direct mapped by the IOMMU */ -int iommu_request_dm_for_dev(struct device *dev) +static int +request_default_domain_for_dev(struct device *dev, unsigned long type) { - struct iommu_domain *dm_domain; + struct iommu_domain *domain; struct iommu_group *group; int ret; /* Device must already be in a group before calling this function */ - group = iommu_group_get_for_dev(dev); - if (IS_ERR(group)) - return PTR_ERR(group); + group = iommu_group_get(dev); + if (!group) + return -EINVAL; mutex_lock(&group->mutex); /* Check if the default domain is already direct mapped */ ret = 0; - if (group->default_domain && - group->default_domain->type == IOMMU_DOMAIN_IDENTITY) + if (group->default_domain && group->default_domain->type == type) goto out; /* Don't change mappings of existing devices */ @@ -1922,23 +2155,26 @@ int iommu_request_dm_for_dev(struct device *dev) /* Allocate a direct mapped domain */ ret = -ENOMEM; - dm_domain = __iommu_domain_alloc(dev->bus, IOMMU_DOMAIN_IDENTITY); - if (!dm_domain) + domain = __iommu_domain_alloc(dev->bus, type); + if (!domain) goto out; /* Attach the device to the domain */ - ret = __iommu_attach_group(dm_domain, group); + ret = __iommu_attach_group(domain, group); if (ret) { - iommu_domain_free(dm_domain); + iommu_domain_free(domain); goto out; } + iommu_group_create_direct_mappings(group, dev); + /* Make the direct mapped domain the default for this group */ if (group->default_domain) iommu_domain_free(group->default_domain); - group->default_domain = dm_domain; + group->default_domain = domain; - dev_info(dev, "Using iommu direct mapping\n"); + dev_info(dev, "Using iommu %s mapping\n", + type == IOMMU_DOMAIN_DMA ? "dma" : "direct"); ret = 0; out: @@ -1948,6 +2184,18 @@ out: return ret; } +/* Request that a device is direct mapped by the IOMMU */ +int iommu_request_dm_for_dev(struct device *dev) +{ + return request_default_domain_for_dev(dev, IOMMU_DOMAIN_IDENTITY); +} + +/* Request that a device can't be direct mapped by the IOMMU */ +int iommu_request_dma_domain_for_dev(struct device *dev) +{ + return request_default_domain_for_dev(dev, IOMMU_DOMAIN_DMA); +} + const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode) { const struct iommu_ops *ops = NULL; diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 9a380c10655e..ad0098c0c87c 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -36,12 +36,16 @@ #define arm_iommu_detach_device(...) do {} while (0) #endif -#define IPMMU_CTX_MAX 8 +#define IPMMU_CTX_MAX 8U +#define IPMMU_CTX_INVALID -1 + +#define IPMMU_UTLB_MAX 48U struct ipmmu_features { bool use_ns_alias_offset; bool has_cache_leaf_nodes; unsigned int number_of_contexts; + unsigned int num_utlbs; bool setup_imbuscr; bool twobit_imttbcr_sl0; bool reserved_context; @@ -53,11 +57,11 @@ struct ipmmu_vmsa_device { struct iommu_device iommu; struct ipmmu_vmsa_device *root; const struct ipmmu_features *features; - unsigned int num_utlbs; unsigned int num_ctx; spinlock_t lock; /* Protects ctx and domains[] */ DECLARE_BITMAP(ctx, IPMMU_CTX_MAX); struct ipmmu_vmsa_domain *domains[IPMMU_CTX_MAX]; + s8 utlb_ctx[IPMMU_UTLB_MAX]; struct iommu_group *group; struct dma_iommu_mapping *mapping; @@ -186,7 +190,8 @@ static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev) #define IMMAIR_ATTR_IDX_WBRWA 1 #define IMMAIR_ATTR_IDX_DEV 2 -#define IMEAR 0x0030 +#define IMELAR 0x0030 /* IMEAR on R-Car Gen2 */ +#define IMEUAR 0x0034 /* R-Car Gen3 only */ #define IMPCTR 0x0200 #define IMPSTR 0x0208 @@ -334,6 +339,7 @@ static void ipmmu_utlb_enable(struct ipmmu_vmsa_domain *domain, ipmmu_write(mmu, IMUCTR(utlb), IMUCTR_TTSEL_MMU(domain->context_id) | IMUCTR_FLUSH | IMUCTR_MMUEN); + mmu->utlb_ctx[utlb] = domain->context_id; } /* @@ -345,6 +351,7 @@ static void ipmmu_utlb_disable(struct ipmmu_vmsa_domain *domain, struct ipmmu_vmsa_device *mmu = domain->mmu; ipmmu_write(mmu, IMUCTR(utlb), 0); + mmu->utlb_ctx[utlb] = IPMMU_CTX_INVALID; } static void ipmmu_tlb_flush_all(void *cookie) @@ -403,52 +410,10 @@ static void ipmmu_domain_free_context(struct ipmmu_vmsa_device *mmu, spin_unlock_irqrestore(&mmu->lock, flags); } -static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) +static void ipmmu_domain_setup_context(struct ipmmu_vmsa_domain *domain) { u64 ttbr; u32 tmp; - int ret; - - /* - * Allocate the page table operations. - * - * VMSA states in section B3.6.3 "Control of Secure or Non-secure memory - * access, Long-descriptor format" that the NStable bit being set in a - * table descriptor will result in the NStable and NS bits of all child - * entries being ignored and considered as being set. The IPMMU seems - * not to comply with this, as it generates a secure access page fault - * if any of the NStable and NS bits isn't set when running in - * non-secure mode. - */ - domain->cfg.quirks = IO_PGTABLE_QUIRK_ARM_NS; - domain->cfg.pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K; - domain->cfg.ias = 32; - domain->cfg.oas = 40; - domain->cfg.tlb = &ipmmu_gather_ops; - domain->io_domain.geometry.aperture_end = DMA_BIT_MASK(32); - domain->io_domain.geometry.force_aperture = true; - /* - * TODO: Add support for coherent walk through CCI with DVM and remove - * cache handling. For now, delegate it to the io-pgtable code. - */ - domain->cfg.iommu_dev = domain->mmu->root->dev; - - /* - * Find an unused context. - */ - ret = ipmmu_domain_allocate_context(domain->mmu->root, domain); - if (ret < 0) - return ret; - - domain->context_id = ret; - - domain->iop = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &domain->cfg, - domain); - if (!domain->iop) { - ipmmu_domain_free_context(domain->mmu->root, - domain->context_id); - return -EINVAL; - } /* TTBR0 */ ttbr = domain->cfg.arm_lpae_s1_cfg.ttbr[0]; @@ -494,7 +459,55 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) */ ipmmu_ctx_write_all(domain, IMCTR, IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN); +} + +static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) +{ + int ret; + + /* + * Allocate the page table operations. + * + * VMSA states in section B3.6.3 "Control of Secure or Non-secure memory + * access, Long-descriptor format" that the NStable bit being set in a + * table descriptor will result in the NStable and NS bits of all child + * entries being ignored and considered as being set. The IPMMU seems + * not to comply with this, as it generates a secure access page fault + * if any of the NStable and NS bits isn't set when running in + * non-secure mode. + */ + domain->cfg.quirks = IO_PGTABLE_QUIRK_ARM_NS; + domain->cfg.pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K; + domain->cfg.ias = 32; + domain->cfg.oas = 40; + domain->cfg.tlb = &ipmmu_gather_ops; + domain->io_domain.geometry.aperture_end = DMA_BIT_MASK(32); + domain->io_domain.geometry.force_aperture = true; + /* + * TODO: Add support for coherent walk through CCI with DVM and remove + * cache handling. For now, delegate it to the io-pgtable code. + */ + domain->cfg.coherent_walk = false; + domain->cfg.iommu_dev = domain->mmu->root->dev; + + /* + * Find an unused context. + */ + ret = ipmmu_domain_allocate_context(domain->mmu->root, domain); + if (ret < 0) + return ret; + + domain->context_id = ret; + + domain->iop = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &domain->cfg, + domain); + if (!domain->iop) { + ipmmu_domain_free_context(domain->mmu->root, + domain->context_id); + return -EINVAL; + } + ipmmu_domain_setup_context(domain); return 0; } @@ -522,14 +535,16 @@ static irqreturn_t ipmmu_domain_irq(struct ipmmu_vmsa_domain *domain) { const u32 err_mask = IMSTR_MHIT | IMSTR_ABORT | IMSTR_PF | IMSTR_TF; struct ipmmu_vmsa_device *mmu = domain->mmu; + unsigned long iova; u32 status; - u32 iova; status = ipmmu_ctx_read_root(domain, IMSTR); if (!(status & err_mask)) return IRQ_NONE; - iova = ipmmu_ctx_read_root(domain, IMEAR); + iova = ipmmu_ctx_read_root(domain, IMELAR); + if (IS_ENABLED(CONFIG_64BIT)) + iova |= (u64)ipmmu_ctx_read_root(domain, IMEUAR) << 32; /* * Clear the error status flags. Unlike traditional interrupt flag @@ -541,10 +556,10 @@ static irqreturn_t ipmmu_domain_irq(struct ipmmu_vmsa_domain *domain) /* Log fatal errors. */ if (status & IMSTR_MHIT) - dev_err_ratelimited(mmu->dev, "Multiple TLB hits @0x%08x\n", + dev_err_ratelimited(mmu->dev, "Multiple TLB hits @0x%lx\n", iova); if (status & IMSTR_ABORT) - dev_err_ratelimited(mmu->dev, "Page Table Walk Abort @0x%08x\n", + dev_err_ratelimited(mmu->dev, "Page Table Walk Abort @0x%lx\n", iova); if (!(status & (IMSTR_PF | IMSTR_TF))) @@ -560,7 +575,7 @@ static irqreturn_t ipmmu_domain_irq(struct ipmmu_vmsa_domain *domain) return IRQ_HANDLED; dev_err_ratelimited(mmu->dev, - "Unhandled fault: status 0x%08x iova 0x%08x\n", + "Unhandled fault: status 0x%08x iova 0x%lx\n", status, iova); return IRQ_HANDLED; @@ -885,27 +900,37 @@ error: static int ipmmu_add_device(struct device *dev) { + struct ipmmu_vmsa_device *mmu = to_ipmmu(dev); struct iommu_group *group; + int ret; /* * Only let through devices that have been verified in xlate() */ - if (!to_ipmmu(dev)) + if (!mmu) return -ENODEV; - if (IS_ENABLED(CONFIG_ARM) && !IS_ENABLED(CONFIG_IOMMU_DMA)) - return ipmmu_init_arm_mapping(dev); + if (IS_ENABLED(CONFIG_ARM) && !IS_ENABLED(CONFIG_IOMMU_DMA)) { + ret = ipmmu_init_arm_mapping(dev); + if (ret) + return ret; + } else { + group = iommu_group_get_for_dev(dev); + if (IS_ERR(group)) + return PTR_ERR(group); - group = iommu_group_get_for_dev(dev); - if (IS_ERR(group)) - return PTR_ERR(group); + iommu_group_put(group); + } - iommu_group_put(group); + iommu_device_link(&mmu->iommu, dev); return 0; } static void ipmmu_remove_device(struct device *dev) { + struct ipmmu_vmsa_device *mmu = to_ipmmu(dev); + + iommu_device_unlink(&mmu->iommu, dev); arm_iommu_detach_device(dev); iommu_group_remove_device(dev); } @@ -959,6 +984,7 @@ static const struct ipmmu_features ipmmu_features_default = { .use_ns_alias_offset = true, .has_cache_leaf_nodes = false, .number_of_contexts = 1, /* software only tested with one context */ + .num_utlbs = 32, .setup_imbuscr = true, .twobit_imttbcr_sl0 = false, .reserved_context = false, @@ -968,6 +994,7 @@ static const struct ipmmu_features ipmmu_features_rcar_gen3 = { .use_ns_alias_offset = false, .has_cache_leaf_nodes = true, .number_of_contexts = 8, + .num_utlbs = 48, .setup_imbuscr = false, .twobit_imttbcr_sl0 = true, .reserved_context = true, @@ -1020,10 +1047,10 @@ static int ipmmu_probe(struct platform_device *pdev) } mmu->dev = &pdev->dev; - mmu->num_utlbs = 48; spin_lock_init(&mmu->lock); bitmap_zero(mmu->ctx, IPMMU_CTX_MAX); mmu->features = of_device_get_match_data(&pdev->dev); + memset(mmu->utlb_ctx, IPMMU_CTX_INVALID, mmu->features->num_utlbs); dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); /* Map I/O memory and request IRQ. */ @@ -1047,8 +1074,7 @@ static int ipmmu_probe(struct platform_device *pdev) if (mmu->features->use_ns_alias_offset) mmu->base += IM_NS_ALIAS_OFFSET; - mmu->num_ctx = min_t(unsigned int, IPMMU_CTX_MAX, - mmu->features->number_of_contexts); + mmu->num_ctx = min(IPMMU_CTX_MAX, mmu->features->number_of_contexts); irq = platform_get_irq(pdev, 0); @@ -1140,10 +1166,48 @@ static int ipmmu_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int ipmmu_resume_noirq(struct device *dev) +{ + struct ipmmu_vmsa_device *mmu = dev_get_drvdata(dev); + unsigned int i; + + /* Reset root MMU and restore contexts */ + if (ipmmu_is_root(mmu)) { + ipmmu_device_reset(mmu); + + for (i = 0; i < mmu->num_ctx; i++) { + if (!mmu->domains[i]) + continue; + + ipmmu_domain_setup_context(mmu->domains[i]); + } + } + + /* Re-enable active micro-TLBs */ + for (i = 0; i < mmu->features->num_utlbs; i++) { + if (mmu->utlb_ctx[i] == IPMMU_CTX_INVALID) + continue; + + ipmmu_utlb_enable(mmu->root->domains[mmu->utlb_ctx[i]], i); + } + + return 0; +} + +static const struct dev_pm_ops ipmmu_pm = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, ipmmu_resume_noirq) +}; +#define DEV_PM_OPS &ipmmu_pm +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + static struct platform_driver ipmmu_driver = { .driver = { .name = "ipmmu-vmsa", .of_match_table = of_match_ptr(ipmmu_of_ids), + .pm = DEV_PM_OPS, }, .probe = ipmmu_probe, .remove = ipmmu_remove, diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c index 4abc0ef522a8..8e19bfa94121 100644 --- a/drivers/iommu/omap-iommu-debug.c +++ b/drivers/iommu/omap-iommu-debug.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * omap iommu: debugfs interface * * Copyright (C) 2008-2009 Nokia Corporation * * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> @@ -239,17 +236,6 @@ DEBUG_FOPS_RO(regs); DEFINE_SHOW_ATTRIBUTE(tlb); DEFINE_SHOW_ATTRIBUTE(pagetable); -#define __DEBUG_ADD_FILE(attr, mode) \ - { \ - struct dentry *dent; \ - dent = debugfs_create_file(#attr, mode, obj->debug_dir, \ - obj, &attr##_fops); \ - if (!dent) \ - goto err; \ - } - -#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 0400) - void omap_iommu_debugfs_add(struct omap_iommu *obj) { struct dentry *d; @@ -257,23 +243,13 @@ void omap_iommu_debugfs_add(struct omap_iommu *obj) if (!iommu_debug_root) return; - obj->debug_dir = debugfs_create_dir(obj->name, iommu_debug_root); - if (!obj->debug_dir) - return; - - d = debugfs_create_u32("nr_tlb_entries", 0400, obj->debug_dir, - &obj->nr_tlb_entries); - if (!d) - return; - - DEBUG_ADD_FILE_RO(regs); - DEBUG_ADD_FILE_RO(tlb); - DEBUG_ADD_FILE_RO(pagetable); + d = debugfs_create_dir(obj->name, iommu_debug_root); + obj->debug_dir = d; - return; - -err: - debugfs_remove_recursive(obj->debug_dir); + debugfs_create_u32("nr_tlb_entries", 0400, d, &obj->nr_tlb_entries); + debugfs_create_file("regs", 0400, d, obj, ®s_fops); + debugfs_create_file("tlb", 0400, d, obj, &tlb_fops); + debugfs_create_file("pagetable", 0400, d, obj, &pagetable_fops); } void omap_iommu_debugfs_remove(struct omap_iommu *obj) @@ -287,8 +263,6 @@ void omap_iommu_debugfs_remove(struct omap_iommu *obj) void __init omap_iommu_debugfs_init(void) { iommu_debug_root = debugfs_create_dir("omap_iommu", NULL); - if (!iommu_debug_root) - pr_err("can't create debugfs dir\n"); } void __exit omap_iommu_debugfs_exit(void) diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index d2fb347aa4ff..dfb961d8c21b 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * omap iommu: tlb and pagetable primitives * @@ -6,10 +7,6 @@ * * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>, * Paul Mundt and Toshihiro Kobayashi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/dma-mapping.h> @@ -38,8 +35,7 @@ static const struct iommu_ops omap_iommu_ops; -#define to_iommu(dev) \ - ((struct omap_iommu *)platform_get_drvdata(to_platform_device(dev))) +#define to_iommu(dev) ((struct omap_iommu *)dev_get_drvdata(dev)) /* bitmap of the page sizes currently supported */ #define OMAP_IOMMU_PGSIZES (SZ_4K | SZ_64K | SZ_1M | SZ_16M) diff --git a/drivers/iommu/omap-iommu.h b/drivers/iommu/omap-iommu.h index 1703159ef5af..09968a02d291 100644 --- a/drivers/iommu/omap-iommu.h +++ b/drivers/iommu/omap-iommu.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * omap iommu: main structures * * Copyright (C) 2008-2009 Nokia Corporation * * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _OMAP_IOMMU_H diff --git a/drivers/iommu/omap-iopgtable.h b/drivers/iommu/omap-iopgtable.h index 01a315227bf0..1a4adb59a859 100644 --- a/drivers/iommu/omap-iopgtable.h +++ b/drivers/iommu/omap-iopgtable.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * omap iommu: pagetable definitions * * Copyright (C) 2008-2010 Nokia Corporation * * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _OMAP_IOPGTABLE_H diff --git a/drivers/iommu/qcom_iommu.c b/drivers/iommu/qcom_iommu.c index 8cdd3f059513..34d0b9783b3e 100644 --- a/drivers/iommu/qcom_iommu.c +++ b/drivers/iommu/qcom_iommu.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * IOMMU API for QCOM secure IOMMUs. Somewhat based on arm-smmu.c * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * * Copyright (C) 2013 ARM Limited * Copyright (C) 2017 Red Hat */ diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 77d4bd93fe4b..dc26d74d79c2 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * IOMMU API for Rockchip * * Module Authors: Simon Xue <xxm@rock-chips.com> * Daniel Kurtz <djkurtz@chromium.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 463ee08f7d3a..c4a652b227f8 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011-2014 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 659c5e0fb835..80e10f4e213a 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -15,10 +15,10 @@ config ARM_GIC_PM bool depends on PM select ARM_GIC - select PM_CLK config ARM_GIC_MAX_NR int + depends on ARM_GIC default 2 if ARCH_REALVIEW default 1 @@ -87,6 +87,14 @@ config ALPINE_MSI select PCI_MSI select GENERIC_IRQ_CHIP +config AL_FIC + bool "Amazon's Annapurna Labs Fabric Interrupt Controller" + depends on OF || COMPILE_TEST + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + help + Support Amazon's Annapurna Labs Fabric Interrupt Controller. + config ATMEL_AIC_IRQ bool select GENERIC_IRQ_CHIP @@ -217,13 +225,26 @@ config RDA_INTC select IRQ_DOMAIN config RENESAS_INTC_IRQPIN - bool + bool "Renesas INTC External IRQ Pin Support" if COMPILE_TEST select IRQ_DOMAIN + help + Enable support for the Renesas Interrupt Controller for external + interrupt pins, as found on SH/R-Mobile and R-Car Gen1 SoCs. config RENESAS_IRQC - bool + bool "Renesas R-Mobile APE6 and R-Car IRQC support" if COMPILE_TEST select GENERIC_IRQ_CHIP select IRQ_DOMAIN + help + Enable support for the Renesas Interrupt Controller for external + devices, as found on R-Mobile APE6, R-Car Gen2, and R-Car Gen3 SoCs. + +config RENESAS_RZA1_IRQC + bool "Renesas RZ/A1 IRQC support" if COMPILE_TEST + select IRQ_DOMAIN_HIERARCHY + help + Enable support for the Renesas RZ/A1 Interrupt Controller, to use up + to 8 external interrupts with configurable sense select. config ST_IRQCHIP bool @@ -299,8 +320,11 @@ config RENESAS_H8300H_INTC select IRQ_DOMAIN config RENESAS_H8S_INTC - bool + bool "Renesas H8S Interrupt Controller Support" if COMPILE_TEST select IRQ_DOMAIN + help + Enable support for the Renesas H8/300 Interrupt Controller, as found + on Renesas H8S SoCs. config IMX_GPCV2 bool diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 606a003a0000..8d0fcec6ab23 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_IRQCHIP) += irqchip.o +obj-$(CONFIG_AL_FIC) += irq-al-fic.o obj-$(CONFIG_ALPINE_MSI) += irq-alpine-msi.o obj-$(CONFIG_ATH79) += irq-ath79-cpu.o obj-$(CONFIG_ATH79) += irq-ath79-misc.o @@ -49,6 +50,7 @@ obj-$(CONFIG_JCORE_AIC) += irq-jcore-aic.o obj-$(CONFIG_RDA_INTC) += irq-rda-intc.o obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o +obj-$(CONFIG_RENESAS_RZA1_IRQC) += irq-renesas-rza1.o obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index b78a169c9c83..0b85d9a3fbff 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Combiner irqchip for EXYNOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> #include <linux/export.h> diff --git a/drivers/irqchip/irq-al-fic.c b/drivers/irqchip/irq-al-fic.c new file mode 100644 index 000000000000..1a57cee3efab --- /dev/null +++ b/drivers/irqchip/irq-al-fic.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + */ + +#include <linux/bitfield.h> +#include <linux/irq.h> +#include <linux/irqchip.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/irqdomain.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> + +/* FIC Registers */ +#define AL_FIC_CAUSE 0x00 +#define AL_FIC_MASK 0x10 +#define AL_FIC_CONTROL 0x28 + +#define CONTROL_TRIGGER_RISING BIT(3) +#define CONTROL_MASK_MSI_X BIT(5) + +#define NR_FIC_IRQS 32 + +MODULE_AUTHOR("Talel Shenhar"); +MODULE_DESCRIPTION("Amazon's Annapurna Labs Interrupt Controller Driver"); +MODULE_LICENSE("GPL v2"); + +enum al_fic_state { + AL_FIC_UNCONFIGURED = 0, + AL_FIC_CONFIGURED_LEVEL, + AL_FIC_CONFIGURED_RISING_EDGE, +}; + +struct al_fic { + void __iomem *base; + struct irq_domain *domain; + const char *name; + unsigned int parent_irq; + enum al_fic_state state; +}; + +static void al_fic_set_trigger(struct al_fic *fic, + struct irq_chip_generic *gc, + enum al_fic_state new_state) +{ + irq_flow_handler_t handler; + u32 control = readl_relaxed(fic->base + AL_FIC_CONTROL); + + if (new_state == AL_FIC_CONFIGURED_LEVEL) { + handler = handle_level_irq; + control &= ~CONTROL_TRIGGER_RISING; + } else { + handler = handle_edge_irq; + control |= CONTROL_TRIGGER_RISING; + } + gc->chip_types->handler = handler; + fic->state = new_state; + writel_relaxed(control, fic->base + AL_FIC_CONTROL); +} + +static int al_fic_irq_set_type(struct irq_data *data, unsigned int flow_type) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); + struct al_fic *fic = gc->private; + enum al_fic_state new_state; + int ret = 0; + + irq_gc_lock(gc); + + if (((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH) && + ((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_EDGE_RISING)) { + pr_debug("fic doesn't support flow type %d\n", flow_type); + ret = -EINVAL; + goto err; + } + + new_state = (flow_type & IRQ_TYPE_LEVEL_HIGH) ? + AL_FIC_CONFIGURED_LEVEL : AL_FIC_CONFIGURED_RISING_EDGE; + + /* + * A given FIC instance can be either all level or all edge triggered. + * This is generally fixed depending on what pieces of HW it's wired up + * to. + * + * We configure it based on the sensitivity of the first source + * being setup, and reject any subsequent attempt at configuring it in a + * different way. + */ + if (fic->state == AL_FIC_UNCONFIGURED) { + al_fic_set_trigger(fic, gc, new_state); + } else if (fic->state != new_state) { + pr_debug("fic %s state already configured to %d\n", + fic->name, fic->state); + ret = -EINVAL; + goto err; + } + +err: + irq_gc_unlock(gc); + + return ret; +} + +static void al_fic_irq_handler(struct irq_desc *desc) +{ + struct al_fic *fic = irq_desc_get_handler_data(desc); + struct irq_domain *domain = fic->domain; + struct irq_chip *irqchip = irq_desc_get_chip(desc); + struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0); + unsigned long pending; + unsigned int irq; + u32 hwirq; + + chained_irq_enter(irqchip, desc); + + pending = readl_relaxed(fic->base + AL_FIC_CAUSE); + pending &= ~gc->mask_cache; + + for_each_set_bit(hwirq, &pending, NR_FIC_IRQS) { + irq = irq_find_mapping(domain, hwirq); + generic_handle_irq(irq); + } + + chained_irq_exit(irqchip, desc); +} + +static int al_fic_register(struct device_node *node, + struct al_fic *fic) +{ + struct irq_chip_generic *gc; + int ret; + + fic->domain = irq_domain_add_linear(node, + NR_FIC_IRQS, + &irq_generic_chip_ops, + fic); + if (!fic->domain) { + pr_err("fail to add irq domain\n"); + return -ENOMEM; + } + + ret = irq_alloc_domain_generic_chips(fic->domain, + NR_FIC_IRQS, + 1, fic->name, + handle_level_irq, + 0, 0, IRQ_GC_INIT_MASK_CACHE); + if (ret) { + pr_err("fail to allocate generic chip (%d)\n", ret); + goto err_domain_remove; + } + + gc = irq_get_domain_generic_chip(fic->domain, 0); + gc->reg_base = fic->base; + gc->chip_types->regs.mask = AL_FIC_MASK; + gc->chip_types->regs.ack = AL_FIC_CAUSE; + gc->chip_types->chip.irq_mask = irq_gc_mask_set_bit; + gc->chip_types->chip.irq_unmask = irq_gc_mask_clr_bit; + gc->chip_types->chip.irq_ack = irq_gc_ack_clr_bit; + gc->chip_types->chip.irq_set_type = al_fic_irq_set_type; + gc->chip_types->chip.flags = IRQCHIP_SKIP_SET_WAKE; + gc->private = fic; + + irq_set_chained_handler_and_data(fic->parent_irq, + al_fic_irq_handler, + fic); + return 0; + +err_domain_remove: + irq_domain_remove(fic->domain); + + return ret; +} + +/* + * al_fic_wire_init() - initialize and configure fic in wire mode + * @of_node: optional pointer to interrupt controller's device tree node. + * @base: mmio to fic register + * @name: name of the fic + * @parent_irq: interrupt of parent + * + * This API will configure the fic hardware to to work in wire mode. + * In wire mode, fic hardware is generating a wire ("wired") interrupt. + * Interrupt can be generated based on positive edge or level - configuration is + * to be determined based on connected hardware to this fic. + */ +static struct al_fic *al_fic_wire_init(struct device_node *node, + void __iomem *base, + const char *name, + unsigned int parent_irq) +{ + struct al_fic *fic; + int ret; + u32 control = CONTROL_MASK_MSI_X; + + fic = kzalloc(sizeof(*fic), GFP_KERNEL); + if (!fic) + return ERR_PTR(-ENOMEM); + + fic->base = base; + fic->parent_irq = parent_irq; + fic->name = name; + + /* mask out all interrupts */ + writel_relaxed(0xFFFFFFFF, fic->base + AL_FIC_MASK); + + /* clear any pending interrupt */ + writel_relaxed(0, fic->base + AL_FIC_CAUSE); + + writel_relaxed(control, fic->base + AL_FIC_CONTROL); + + ret = al_fic_register(node, fic); + if (ret) { + pr_err("fail to register irqchip\n"); + goto err_free; + } + + pr_debug("%s initialized successfully in Legacy mode (parent-irq=%u)\n", + fic->name, parent_irq); + + return fic; + +err_free: + kfree(fic); + return ERR_PTR(ret); +} + +static int __init al_fic_init_dt(struct device_node *node, + struct device_node *parent) +{ + int ret; + void __iomem *base; + unsigned int parent_irq; + struct al_fic *fic; + + if (!parent) { + pr_err("%s: unsupported - device require a parent\n", + node->name); + return -EINVAL; + } + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s: fail to map memory\n", node->name); + return -ENOMEM; + } + + parent_irq = irq_of_parse_and_map(node, 0); + if (!parent_irq) { + pr_err("%s: fail to map irq\n", node->name); + ret = -EINVAL; + goto err_unmap; + } + + fic = al_fic_wire_init(node, + base, + node->name, + parent_irq); + if (IS_ERR(fic)) { + pr_err("%s: fail to initialize irqchip (%lu)\n", + node->name, + PTR_ERR(fic)); + ret = PTR_ERR(fic); + goto err_irq_dispose; + } + + return 0; + +err_irq_dispose: + irq_dispose_mapping(parent_irq); +err_unmap: + iounmap(base); + + return ret; +} + +IRQCHIP_DECLARE(al_fic, "amazon,al-fic", al_fic_init_dt); diff --git a/drivers/irqchip/irq-aspeed-i2c-ic.c b/drivers/irqchip/irq-aspeed-i2c-ic.c index f20200af0992..8d591c179f81 100644 --- a/drivers/irqchip/irq-aspeed-i2c-ic.c +++ b/drivers/irqchip/irq-aspeed-i2c-ic.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Aspeed 24XX/25XX I2C Interrupt Controller. * * Copyright (C) 2012-2017 ASPEED Technology Inc. * Copyright 2017 IBM Corporation * Copyright 2017 Google, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/irq.h> diff --git a/drivers/irqchip/irq-ath79-cpu.c b/drivers/irqchip/irq-ath79-cpu.c index befe93c5a51a..923e4bba3776 100644 --- a/drivers/irqchip/irq-ath79-cpu.c +++ b/drivers/irqchip/irq-ath79-cpu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Atheros AR71xx/AR724x/AR913x specific interrupt handling * @@ -7,10 +8,6 @@ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> * * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include <linux/interrupt.h> diff --git a/drivers/irqchip/irq-ath79-misc.c b/drivers/irqchip/irq-ath79-misc.c index 0390603170b4..3d641bb6f3f1 100644 --- a/drivers/irqchip/irq-ath79-misc.c +++ b/drivers/irqchip/irq-ath79-misc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Atheros AR71xx/AR724x/AR913x MISC interrupt controller * @@ -7,10 +8,6 @@ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> * * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include <linux/irqchip.h> diff --git a/drivers/irqchip/irq-bcm6345-l1.c b/drivers/irqchip/irq-bcm6345-l1.c index 43f8abe40878..e3483789f4df 100644 --- a/drivers/irqchip/irq-bcm6345-l1.c +++ b/drivers/irqchip/irq-bcm6345-l1.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Broadcom BCM6345 style Level 1 interrupt controller driver * * Copyright (C) 2014 Broadcom Corporation * Copyright 2015 Simon Arlott * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This is based on the BCM7038 (which supports SMP) but with a single * enable register instead of separate mask/set/clear registers. * diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index 0acebac1920b..fc75c61233aa 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Broadcom BCM7038 style Level 1 interrupt controller driver * * Copyright (C) 2014 Broadcom Corporation * Author: Kevin Cernekee - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index 541bdca9f4af..586df3587be0 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Broadcom BCM7120 style Level 2 interrupt controller driver * * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c index 99d97d7e3fd7..a05a7501e107 100644 --- a/drivers/irqchip/irq-crossbar.c +++ b/drivers/irqchip/irq-crossbar.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/irqchip/irq-crossbar.c * * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com * Author: Sricharan R <r.sricharan@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/err.h> #include <linux/io.h> diff --git a/drivers/irqchip/irq-csky-mpintc.c b/drivers/irqchip/irq-csky-mpintc.c index c67c961ab6cc..a1534edef7fa 100644 --- a/drivers/irqchip/irq-csky-mpintc.c +++ b/drivers/irqchip/irq-csky-mpintc.c @@ -32,8 +32,8 @@ static void __iomem *INTCL_base; #define INTCG_CIDSTR 0x1000 #define INTCL_PICTLR 0x0 +#define INTCL_CFGR 0x14 #define INTCL_SIGR 0x60 -#define INTCL_HPPIR 0x68 #define INTCL_RDYIR 0x6c #define INTCL_SENR 0xa0 #define INTCL_CENR 0xa4 @@ -41,21 +41,49 @@ static void __iomem *INTCL_base; static DEFINE_PER_CPU(void __iomem *, intcl_reg); +static unsigned long *__trigger; + +#define IRQ_OFFSET(irq) ((irq < COMM_IRQ_BASE) ? irq : (irq - COMM_IRQ_BASE)) + +#define TRIG_BYTE_OFFSET(i) ((((i) * 2) / 32) * 4) +#define TRIG_BIT_OFFSET(i) (((i) * 2) % 32) + +#define TRIG_VAL(trigger, irq) (trigger << TRIG_BIT_OFFSET(IRQ_OFFSET(irq))) +#define TRIG_VAL_MSK(irq) (~(3 << TRIG_BIT_OFFSET(IRQ_OFFSET(irq)))) + +#define TRIG_BASE(irq) \ + (TRIG_BYTE_OFFSET(IRQ_OFFSET(irq)) + ((irq < COMM_IRQ_BASE) ? \ + (this_cpu_read(intcl_reg) + INTCL_CFGR) : (INTCG_base + INTCG_CICFGR))) + +static DEFINE_SPINLOCK(setup_lock); +static void setup_trigger(unsigned long irq, unsigned long trigger) +{ + unsigned int tmp; + + spin_lock(&setup_lock); + + /* setup trigger */ + tmp = readl_relaxed(TRIG_BASE(irq)) & TRIG_VAL_MSK(irq); + + writel_relaxed(tmp | TRIG_VAL(trigger, irq), TRIG_BASE(irq)); + + spin_unlock(&setup_lock); +} + static void csky_mpintc_handler(struct pt_regs *regs) { void __iomem *reg_base = this_cpu_read(intcl_reg); - do { - handle_domain_irq(root_domain, - readl_relaxed(reg_base + INTCL_RDYIR), - regs); - } while (readl_relaxed(reg_base + INTCL_HPPIR) & BIT(31)); + handle_domain_irq(root_domain, + readl_relaxed(reg_base + INTCL_RDYIR), regs); } static void csky_mpintc_enable(struct irq_data *d) { void __iomem *reg_base = this_cpu_read(intcl_reg); + setup_trigger(d->hwirq, __trigger[d->hwirq]); + writel_relaxed(d->hwirq, reg_base + INTCL_SENR); } @@ -73,6 +101,28 @@ static void csky_mpintc_eoi(struct irq_data *d) writel_relaxed(d->hwirq, reg_base + INTCL_CACR); } +static int csky_mpintc_set_type(struct irq_data *d, unsigned int type) +{ + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_LEVEL_HIGH: + __trigger[d->hwirq] = 0; + break; + case IRQ_TYPE_LEVEL_LOW: + __trigger[d->hwirq] = 1; + break; + case IRQ_TYPE_EDGE_RISING: + __trigger[d->hwirq] = 2; + break; + case IRQ_TYPE_EDGE_FALLING: + __trigger[d->hwirq] = 3; + break; + default: + return -EINVAL; + } + + return 0; +} + #ifdef CONFIG_SMP static int csky_irq_set_affinity(struct irq_data *d, const struct cpumask *mask_val, @@ -89,8 +139,19 @@ static int csky_irq_set_affinity(struct irq_data *d, if (cpu >= nr_cpu_ids) return -EINVAL; - /* Enable interrupt destination */ - cpu |= BIT(31); + /* + * The csky,mpintc could support auto irq deliver, but it only + * could deliver external irq to one cpu or all cpus. So it + * doesn't support deliver external irq to a group of cpus + * with cpu_mask. + * SO we only use auto deliver mode when affinity mask_val is + * equal to cpu_present_mask. + * + */ + if (cpumask_equal(mask_val, cpu_present_mask)) + cpu = 0; + else + cpu |= BIT(31); writel_relaxed(cpu, INTCG_base + INTCG_CIDSTR + offset); @@ -105,6 +166,7 @@ static struct irq_chip csky_irq_chip = { .irq_eoi = csky_mpintc_eoi, .irq_enable = csky_mpintc_enable, .irq_disable = csky_mpintc_disable, + .irq_set_type = csky_mpintc_set_type, #ifdef CONFIG_SMP .irq_set_affinity = csky_irq_set_affinity, #endif @@ -125,9 +187,26 @@ static int csky_irqdomain_map(struct irq_domain *d, unsigned int irq, return 0; } +static int csky_irq_domain_xlate_cells(struct irq_domain *d, + struct device_node *ctrlr, const u32 *intspec, + unsigned int intsize, unsigned long *out_hwirq, + unsigned int *out_type) +{ + if (WARN_ON(intsize < 1)) + return -EINVAL; + + *out_hwirq = intspec[0]; + if (intsize > 1) + *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; + else + *out_type = IRQ_TYPE_LEVEL_HIGH; + + return 0; +} + static const struct irq_domain_ops csky_irqdomain_ops = { .map = csky_irqdomain_map, - .xlate = irq_domain_xlate_onecell, + .xlate = csky_irq_domain_xlate_cells, }; #ifdef CONFIG_SMP @@ -161,6 +240,10 @@ csky_mpintc_init(struct device_node *node, struct device_node *parent) if (ret < 0) nr_irq = INTC_IRQS; + __trigger = kcalloc(nr_irq, sizeof(unsigned long), GFP_KERNEL); + if (__trigger == NULL) + return -ENXIO; + if (INTCG_base == NULL) { INTCG_base = ioremap(mfcr("cr<31, 14>"), INTCL_SIZE*nr_cpu_ids + INTCG_SIZE); diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index 3c93c6f4d1f1..b0a8215a13fc 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2002 ARM Limited, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/interrupt.h> diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h index 97e58fb6c232..5a46b6b57750 100644 --- a/drivers/irqchip/irq-gic-common.h +++ b/drivers/irqchip/irq-gic-common.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2002 ARM Limited, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _IRQ_GIC_COMMON_H diff --git a/drivers/irqchip/irq-gic-pm.c b/drivers/irqchip/irq-gic-pm.c index c4aac0977d8a..1337ceceb59b 100644 --- a/drivers/irqchip/irq-gic-pm.c +++ b/drivers/irqchip/irq-gic-pm.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 NVIDIA CORPORATION, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> #include <linux/clk.h> diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index 3c77ab676e54..7338f90b2f9e 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ARM GIC v2m MSI(-X) support * Support for Message Signaled Interrupts for systems that @@ -7,10 +8,6 @@ * Authors: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> * Harish Kasiviswanathan <harish.kasiviswanathan@amd.com> * Brandon Anderson <brandon.anderson@amd.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #define pr_fmt(fmt) "GICv2m: " fmt @@ -56,6 +53,7 @@ /* List of flags for specific v2m implementation */ #define GICV2M_NEEDS_SPI_OFFSET 0x00000001 +#define GICV2M_GRAVITON_ADDRESS_ONLY 0x00000002 static LIST_HEAD(v2m_nodes); static DEFINE_SPINLOCK(v2m_lock); @@ -98,15 +96,26 @@ static struct msi_domain_info gicv2m_msi_domain_info = { .chip = &gicv2m_msi_irq_chip, }; +static phys_addr_t gicv2m_get_msi_addr(struct v2m_data *v2m, int hwirq) +{ + if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY) + return v2m->res.start | ((hwirq - 32) << 3); + else + return v2m->res.start + V2M_MSI_SETSPI_NS; +} + static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) { struct v2m_data *v2m = irq_data_get_irq_chip_data(data); - phys_addr_t addr = v2m->res.start + V2M_MSI_SETSPI_NS; + phys_addr_t addr = gicv2m_get_msi_addr(v2m, data->hwirq); msg->address_hi = upper_32_bits(addr); msg->address_lo = lower_32_bits(addr); - msg->data = data->hwirq; + if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY) + msg->data = 0; + else + msg->data = data->hwirq; if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET) msg->data -= v2m->spi_offset; @@ -188,7 +197,7 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, hwirq = v2m->spi_start + offset; err = iommu_dma_prepare_msi(info->desc, - v2m->res.start + V2M_MSI_SETSPI_NS); + gicv2m_get_msi_addr(v2m, hwirq)); if (err) return err; @@ -307,7 +316,7 @@ static int gicv2m_allocate_domains(struct irq_domain *parent) static int __init gicv2m_init_one(struct fwnode_handle *fwnode, u32 spi_start, u32 nr_spis, - struct resource *res) + struct resource *res, u32 flags) { int ret; struct v2m_data *v2m; @@ -320,6 +329,7 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode, INIT_LIST_HEAD(&v2m->entry); v2m->fwnode = fwnode; + v2m->flags = flags; memcpy(&v2m->res, res, sizeof(struct resource)); @@ -334,7 +344,14 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode, v2m->spi_start = spi_start; v2m->nr_spis = nr_spis; } else { - u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER); + u32 typer; + + /* Graviton should always have explicit spi_start/nr_spis */ + if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY) { + ret = -EINVAL; + goto err_iounmap; + } + typer = readl_relaxed(v2m->base + V2M_MSI_TYPER); v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer); v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer); @@ -355,18 +372,21 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode, * * Broadom NS2 GICv2m implementation has an erratum where the MSI data * is 'spi_number - 32' + * + * Reading that register fails on the Graviton implementation */ - switch (readl_relaxed(v2m->base + V2M_MSI_IIDR)) { - case XGENE_GICV2M_MSI_IIDR: - v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; - v2m->spi_offset = v2m->spi_start; - break; - case BCM_NS2_GICV2M_MSI_IIDR: - v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; - v2m->spi_offset = 32; - break; + if (!(v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)) { + switch (readl_relaxed(v2m->base + V2M_MSI_IIDR)) { + case XGENE_GICV2M_MSI_IIDR: + v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; + v2m->spi_offset = v2m->spi_start; + break; + case BCM_NS2_GICV2M_MSI_IIDR: + v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; + v2m->spi_offset = 32; + break; + } } - v2m->bm = kcalloc(BITS_TO_LONGS(v2m->nr_spis), sizeof(long), GFP_KERNEL); if (!v2m->bm) { @@ -419,7 +439,8 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle, pr_info("DT overriding V2M MSI_TYPER (base:%u, num:%u)\n", spi_start, nr_spis); - ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis, &res); + ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis, + &res, 0); if (ret) { of_node_put(child); break; @@ -451,6 +472,25 @@ static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev) return data->fwnode; } +static bool acpi_check_amazon_graviton_quirks(void) +{ + static struct acpi_table_madt *madt; + acpi_status status; + bool rc = false; + +#define ACPI_AMZN_OEM_ID "AMAZON" + + status = acpi_get_table(ACPI_SIG_MADT, 0, + (struct acpi_table_header **)&madt); + + if (ACPI_FAILURE(status) || !madt) + return rc; + rc = !memcmp(madt->header.oem_id, ACPI_AMZN_OEM_ID, ACPI_OEM_ID_SIZE); + acpi_put_table((struct acpi_table_header *)madt); + + return rc; +} + static int __init acpi_parse_madt_msi(union acpi_subtable_headers *header, const unsigned long end) @@ -460,6 +500,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header, u32 spi_start = 0, nr_spis = 0; struct acpi_madt_generic_msi_frame *m; struct fwnode_handle *fwnode; + u32 flags = 0; m = (struct acpi_madt_generic_msi_frame *)header; if (BAD_MADT_ENTRY(m, end)) @@ -469,6 +510,13 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header, res.end = m->base_address + SZ_4K - 1; res.flags = IORESOURCE_MEM; + if (acpi_check_amazon_graviton_quirks()) { + pr_info("applying Amazon Graviton quirk\n"); + res.end = res.start + SZ_8K - 1; + flags |= GICV2M_GRAVITON_ADDRESS_ONLY; + gicv2m_msi_domain_info.flags &= ~MSI_FLAG_MULTI_PCI_MSI; + } + if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) { spi_start = m->spi_base; nr_spis = m->spi_count; @@ -483,7 +531,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header, return -EINVAL; } - ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res); + ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res, flags); if (ret) irq_domain_free_fwnode(fwnode); diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c index c81d5b81da56..229d586c3d7a 100644 --- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013-2015 ARM Limited, All Rights Reserved. * Author: Marc Zyngier <marc.zyngier@arm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/acpi_iort.h> diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c index 9cdcda5bb3bd..daa6d5053bc3 100644 --- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013-2015 ARM Limited, All Rights Reserved. * Author: Marc Zyngier <marc.zyngier@arm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/acpi_iort.h> diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index cfb9b4e5f914..35500801dc2b 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013-2017 ARM Limited, All Rights Reserved. * Author: Marc Zyngier <marc.zyngier@arm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/acpi.h> @@ -744,32 +733,43 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd) } static int its_wait_for_range_completion(struct its_node *its, - struct its_cmd_block *from, + u64 prev_idx, struct its_cmd_block *to) { - u64 rd_idx, from_idx, to_idx; + u64 rd_idx, to_idx, linear_idx; u32 count = 1000000; /* 1s! */ - from_idx = its_cmd_ptr_to_offset(its, from); + /* Linearize to_idx if the command set has wrapped around */ to_idx = its_cmd_ptr_to_offset(its, to); + if (to_idx < prev_idx) + to_idx += ITS_CMD_QUEUE_SZ; + + linear_idx = prev_idx; while (1) { + s64 delta; + rd_idx = readl_relaxed(its->base + GITS_CREADR); - /* Direct case */ - if (from_idx < to_idx && rd_idx >= to_idx) - break; + /* + * Compute the read pointer progress, taking the + * potential wrap-around into account. + */ + delta = rd_idx - prev_idx; + if (rd_idx < prev_idx) + delta += ITS_CMD_QUEUE_SZ; - /* Wrapped case */ - if (from_idx >= to_idx && rd_idx >= to_idx && rd_idx < from_idx) + linear_idx += delta; + if (linear_idx >= to_idx) break; count--; if (!count) { - pr_err_ratelimited("ITS queue timeout (%llu %llu %llu)\n", - from_idx, to_idx, rd_idx); + pr_err_ratelimited("ITS queue timeout (%llu %llu)\n", + to_idx, linear_idx); return -1; } + prev_idx = rd_idx; cpu_relax(); udelay(1); } @@ -786,6 +786,7 @@ void name(struct its_node *its, \ struct its_cmd_block *cmd, *sync_cmd, *next_cmd; \ synctype *sync_obj; \ unsigned long flags; \ + u64 rd_idx; \ \ raw_spin_lock_irqsave(&its->lock, flags); \ \ @@ -807,10 +808,11 @@ void name(struct its_node *its, \ } \ \ post: \ + rd_idx = readl_relaxed(its->base + GITS_CREADR); \ next_cmd = its_post_commands(its); \ raw_spin_unlock_irqrestore(&its->lock, flags); \ \ - if (its_wait_for_range_completion(its, cmd, next_cmd)) \ + if (its_wait_for_range_completion(its, rd_idx, next_cmd)) \ pr_err_ratelimited("ITS cmd %ps failed\n", builder); \ } diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index f44cd89cfc40..9bca4896fa6f 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013-2017 ARM Limited, All Rights Reserved. * Author: Marc Zyngier <marc.zyngier@arm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #define pr_fmt(fmt) "GICv3: " fmt @@ -472,8 +461,12 @@ static void gic_deactivate_unhandled(u32 irqnr) static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs) { + bool irqs_enabled = interrupts_enabled(regs); int err; + if (irqs_enabled) + nmi_enter(); + if (static_branch_likely(&supports_deactivate_key)) gic_write_eoir(irqnr); /* @@ -485,6 +478,9 @@ static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs) err = handle_domain_nmi(gic_data.domain, irqnr, regs); if (err) gic_deactivate_unhandled(irqnr); + + if (irqs_enabled) + nmi_exit(); } static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) @@ -1343,6 +1339,9 @@ static int __init gic_init_bases(void __iomem *dist_base, if (gic_dist_supports_lpis()) { its_init(handle, &gic_data.rdists, gic_data.domain); its_cpu_init(); + } else { + if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) + gicv2m_init(handle, gic_data.domain); } if (gic_prio_masking_enabled()) { diff --git a/drivers/irqchip/irq-gic-v4.c b/drivers/irqchip/irq-gic-v4.c index dba9d67cb9c1..563e87ed0766 100644 --- a/drivers/irqchip/irq-gic-v4.c +++ b/drivers/irqchip/irq-gic-v4.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016,2017 ARM Limited, All Rights Reserved. * Author: Marc Zyngier <marc.zyngier@arm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/interrupt.h> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index c6dbe5018972..e45f45e68720 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2002 ARM Limited, All Rights Reserved. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Interrupt architecture for the GIC: * * o There is one Interrupt Distributor, which receives interrupts diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index 5b4fd2f4e5f8..cf705827599c 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Hisilicon HiP04 INTC * @@ -5,10 +6,6 @@ * Copyright (c) 2013-2014 Hisilicon Ltd. * Copyright (c) 2013-2014 Linaro Ltd. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Interrupt architecture for the HIP04 INTC: * * o There is one Interrupt Distributor, which receives interrupts diff --git a/drivers/irqchip/irq-imx-gpcv2.c b/drivers/irqchip/irq-imx-gpcv2.c index 66501ea4fd75..bf2237ac5d09 100644 --- a/drivers/irqchip/irq-imx-gpcv2.c +++ b/drivers/irqchip/irq-imx-gpcv2.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/of_address.h> diff --git a/drivers/irqchip/irq-ixp4xx.c b/drivers/irqchip/irq-ixp4xx.c index d576809429ac..6751c35b7e1d 100644 --- a/drivers/irqchip/irq-ixp4xx.c +++ b/drivers/irqchip/irq-ixp4xx.c @@ -252,10 +252,10 @@ static const struct ixp4xx_irq_chunk ixp4xx_irq_chunks[] = { * @fwnode: Corresponding fwnode abstraction for this controller * @is_356: if this is an IXP43x, IXP45x or IXP46x SoC variant */ -static int ixp4xx_irq_setup(struct ixp4xx_irq *ixi, - void __iomem *irqbase, - struct fwnode_handle *fwnode, - bool is_356) +static int __init ixp4xx_irq_setup(struct ixp4xx_irq *ixi, + void __iomem *irqbase, + struct fwnode_handle *fwnode, + bool is_356) { int nr_irqs; diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 669d29105772..61dbfda08527 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Freescale SCFG MSI(-X) support * * Copyright (C) 2016 Freescale Semiconductor. * * Author: Minghuan Lian <Minghuan.Lian@nxp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c index 98b6e1d4b1a6..3dd28382d5f5 100644 --- a/drivers/irqchip/irq-mbigen.c +++ b/drivers/irqchip/irq-mbigen.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved. * Author: Jun Ma <majun258@huawei.com> * Author: Yun Wu <wuyun.wu@huawei.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/acpi.h> @@ -355,8 +344,7 @@ static int mbigen_device_probe(struct platform_device *pdev) err = -EINVAL; if (err) { - dev_err(&pdev->dev, "Failed to create mbi-gen@%p irqdomain", - mgn_chip->base); + dev_err(&pdev->dev, "Failed to create mbi-gen irqdomain\n"); return err; } diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c index 7b531fd075b8..dcdc23b9dce6 100644 --- a/drivers/irqchip/irq-meson-gpio.c +++ b/drivers/irqchip/irq-meson-gpio.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015 Endless Mobile, Inc. * Author: Carlo Caione <carlo@endlessm.com> * Copyright (c) 2016 BayLibre, SAS. * Author: Jerome Brunet <jbrunet@baylibre.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * The full GNU General Public License is included in this distribution - * in the file called COPYING. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -73,6 +60,7 @@ static const struct of_device_id meson_irq_gpio_matches[] = { { .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params }, { .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params }, { .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params }, + { .compatible = "amlogic,meson-g12a-gpio-intc", .data = &axg_params }, { } }; diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index d32268cc1174..f3985469c221 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -388,7 +388,7 @@ static void gic_all_vpes_irq_cpu_online(struct irq_data *d) intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); cd = irq_data_get_irq_chip_data(d); - write_gic_vl_map(intr, cd->map); + write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map); if (cd->mask) write_gic_vl_smask(BIT(intr)); } @@ -517,7 +517,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, spin_lock_irqsave(&gic_lock, flags); for_each_online_cpu(cpu) { write_gic_vl_other(mips_cm_vp_id(cpu)); - write_gic_vo_map(intr, map); + write_gic_vo_map(mips_gic_vx_map_reg(intr), map); } spin_unlock_irqrestore(&gic_lock, flags); diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c index 8eed478f3b7e..14618dc0bd39 100644 --- a/drivers/irqchip/irq-mmp.c +++ b/drivers/irqchip/irq-mmp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/arch/arm/mach-mmp/irq.c * @@ -6,10 +7,6 @@ * * Author: Bin Yang <bin.yang@marvell.com> * Haojian Zhuang <haojian.zhuang@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/irqchip/irq-nvic.c b/drivers/irqchip/irq-nvic.c index b1777104fd9f..a166d30deea2 100644 --- a/drivers/irqchip/irq-nvic.c +++ b/drivers/irqchip/irq-nvic.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/irq/irq-nvic.c * * Copyright (C) 2008 ARM Limited, All Rights Reserved. * Copyright (C) 2013 Pengutronix * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Support for the Nested Vectored Interrupt Controller found on the * ARMv7-M CPUs (Cortex-M3/M4) */ diff --git a/drivers/irqchip/irq-partition-percpu.c b/drivers/irqchip/irq-partition-percpu.c index 1f7cc5933cd5..0c4c8ed7064e 100644 --- a/drivers/irqchip/irq-partition-percpu.c +++ b/drivers/irqchip/irq-partition-percpu.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 ARM Limited, All Rights Reserved. * Author: Marc Zyngier <marc.zyngier@arm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/bitops.h> diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c index 04c05a18600c..f82bc60a6793 100644 --- a/drivers/irqchip/irq-renesas-intc-irqpin.c +++ b/drivers/irqchip/irq-renesas-intc-irqpin.c @@ -508,7 +508,8 @@ static int intc_irqpin_probe(struct platform_device *pdev) } irq_chip = &p->irq_chip; - irq_chip->name = name; + irq_chip->name = "intc-irqpin"; + irq_chip->parent_device = dev; irq_chip->irq_mask = disable_fn; irq_chip->irq_unmask = enable_fn; irq_chip->irq_set_type = intc_irqpin_irq_set_type; diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index a449a7c839b3..11abc09ef76c 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -7,7 +7,6 @@ #include <linux/init.h> #include <linux/platform_device.h> -#include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/io.h> @@ -48,7 +47,7 @@ struct irqc_priv { void __iomem *cpu_int_base; struct irqc_irq irq[IRQC_IRQ_MAX]; unsigned int number_of_irqs; - struct platform_device *pdev; + struct device *dev; struct irq_chip_generic *gc; struct irq_domain *irq_domain; atomic_t wakeup_path; @@ -61,8 +60,7 @@ static struct irqc_priv *irq_data_to_priv(struct irq_data *data) static void irqc_dbg(struct irqc_irq *i, char *str) { - dev_dbg(&i->p->pdev->dev, "%s (%d:%d)\n", - str, i->requested_irq, i->hw_irq); + dev_dbg(i->p->dev, "%s (%d:%d)\n", str, i->requested_irq, i->hw_irq); } static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = { @@ -125,33 +123,22 @@ static irqreturn_t irqc_irq_handler(int irq, void *dev_id) static int irqc_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + const char *name = dev_name(dev); struct irqc_priv *p; - struct resource *io; struct resource *irq; - const char *name = dev_name(&pdev->dev); int ret; int k; - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) { - dev_err(&pdev->dev, "failed to allocate driver data\n"); - ret = -ENOMEM; - goto err0; - } + p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; - p->pdev = pdev; + p->dev = dev; platform_set_drvdata(pdev, p); - pm_runtime_enable(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); - - /* get hold of manadatory IOMEM */ - io = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!io) { - dev_err(&pdev->dev, "not enough IOMEM resources\n"); - ret = -EINVAL; - goto err1; - } + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); /* allow any number of IRQs between 1 and IRQC_IRQ_MAX */ for (k = 0; k < IRQC_IRQ_MAX; k++) { @@ -166,42 +153,41 @@ static int irqc_probe(struct platform_device *pdev) p->number_of_irqs = k; if (p->number_of_irqs < 1) { - dev_err(&pdev->dev, "not enough IRQ resources\n"); + dev_err(dev, "not enough IRQ resources\n"); ret = -EINVAL; - goto err1; + goto err_runtime_pm_disable; } /* ioremap IOMEM and setup read/write callbacks */ - p->iomem = ioremap_nocache(io->start, resource_size(io)); - if (!p->iomem) { - dev_err(&pdev->dev, "failed to remap IOMEM\n"); - ret = -ENXIO; - goto err2; + p->iomem = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(p->iomem)) { + ret = PTR_ERR(p->iomem); + goto err_runtime_pm_disable; } p->cpu_int_base = p->iomem + IRQC_INT_CPU_BASE(0); /* SYS-SPI */ - p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, - p->number_of_irqs, + p->irq_domain = irq_domain_add_linear(dev->of_node, p->number_of_irqs, &irq_generic_chip_ops, p); if (!p->irq_domain) { ret = -ENXIO; - dev_err(&pdev->dev, "cannot initialize irq domain\n"); - goto err2; + dev_err(dev, "cannot initialize irq domain\n"); + goto err_runtime_pm_disable; } ret = irq_alloc_domain_generic_chips(p->irq_domain, p->number_of_irqs, - 1, name, handle_level_irq, + 1, "irqc", handle_level_irq, 0, 0, IRQ_GC_INIT_NESTED_LOCK); if (ret) { - dev_err(&pdev->dev, "cannot allocate generic chip\n"); - goto err3; + dev_err(dev, "cannot allocate generic chip\n"); + goto err_remove_domain; } p->gc = irq_get_domain_generic_chip(p->irq_domain, 0); p->gc->reg_base = p->cpu_int_base; p->gc->chip_types[0].regs.enable = IRQC_EN_SET; p->gc->chip_types[0].regs.disable = IRQC_EN_STS; + p->gc->chip_types[0].chip.parent_device = dev; p->gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; p->gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; p->gc->chip_types[0].chip.irq_set_type = irqc_irq_set_type; @@ -210,46 +196,33 @@ static int irqc_probe(struct platform_device *pdev) /* request interrupts one by one */ for (k = 0; k < p->number_of_irqs; k++) { - if (request_irq(p->irq[k].requested_irq, irqc_irq_handler, - 0, name, &p->irq[k])) { - dev_err(&pdev->dev, "failed to request IRQ\n"); + if (devm_request_irq(dev, p->irq[k].requested_irq, + irqc_irq_handler, 0, name, &p->irq[k])) { + dev_err(dev, "failed to request IRQ\n"); ret = -ENOENT; - goto err4; + goto err_remove_domain; } } - dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs); + dev_info(dev, "driving %d irqs\n", p->number_of_irqs); return 0; -err4: - while (--k >= 0) - free_irq(p->irq[k].requested_irq, &p->irq[k]); -err3: +err_remove_domain: irq_domain_remove(p->irq_domain); -err2: - iounmap(p->iomem); -err1: - pm_runtime_put(&pdev->dev); - pm_runtime_disable(&pdev->dev); - kfree(p); -err0: +err_runtime_pm_disable: + pm_runtime_put(dev); + pm_runtime_disable(dev); return ret; } static int irqc_remove(struct platform_device *pdev) { struct irqc_priv *p = platform_get_drvdata(pdev); - int k; - - for (k = 0; k < p->number_of_irqs; k++) - free_irq(p->irq[k].requested_irq, &p->irq[k]); irq_domain_remove(p->irq_domain); - iounmap(p->iomem); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - kfree(p); return 0; } diff --git a/drivers/irqchip/irq-renesas-rza1.c b/drivers/irqchip/irq-renesas-rza1.c new file mode 100644 index 000000000000..b1f19b210190 --- /dev/null +++ b/drivers/irqchip/irq-renesas-rza1.c @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/A1 IRQC Driver + * + * Copyright (C) 2019 Glider bvba + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irqdomain.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <dt-bindings/interrupt-controller/arm-gic.h> + +#define IRQC_NUM_IRQ 8 + +#define ICR0 0 /* Interrupt Control Register 0 */ + +#define ICR0_NMIL BIT(15) /* NMI Input Level (0=low, 1=high) */ +#define ICR0_NMIE BIT(8) /* Edge Select (0=falling, 1=rising) */ +#define ICR0_NMIF BIT(1) /* NMI Interrupt Request */ + +#define ICR1 2 /* Interrupt Control Register 1 */ + +#define ICR1_IRQS(n, sense) ((sense) << ((n) * 2)) /* IRQ Sense Select */ +#define ICR1_IRQS_LEVEL_LOW 0 +#define ICR1_IRQS_EDGE_FALLING 1 +#define ICR1_IRQS_EDGE_RISING 2 +#define ICR1_IRQS_EDGE_BOTH 3 +#define ICR1_IRQS_MASK(n) ICR1_IRQS((n), 3) + +#define IRQRR 4 /* IRQ Interrupt Request Register */ + + +struct rza1_irqc_priv { + struct device *dev; + void __iomem *base; + struct irq_chip chip; + struct irq_domain *irq_domain; + struct of_phandle_args map[IRQC_NUM_IRQ]; +}; + +static struct rza1_irqc_priv *irq_data_to_priv(struct irq_data *data) +{ + return data->domain->host_data; +} + +static void rza1_irqc_eoi(struct irq_data *d) +{ + struct rza1_irqc_priv *priv = irq_data_to_priv(d); + u16 bit = BIT(irqd_to_hwirq(d)); + u16 tmp; + + tmp = readw_relaxed(priv->base + IRQRR); + if (tmp & bit) + writew_relaxed(GENMASK(IRQC_NUM_IRQ - 1, 0) & ~bit, + priv->base + IRQRR); + + irq_chip_eoi_parent(d); +} + +static int rza1_irqc_set_type(struct irq_data *d, unsigned int type) +{ + struct rza1_irqc_priv *priv = irq_data_to_priv(d); + unsigned int hw_irq = irqd_to_hwirq(d); + u16 sense, tmp; + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_LEVEL_LOW: + sense = ICR1_IRQS_LEVEL_LOW; + break; + + case IRQ_TYPE_EDGE_FALLING: + sense = ICR1_IRQS_EDGE_FALLING; + break; + + case IRQ_TYPE_EDGE_RISING: + sense = ICR1_IRQS_EDGE_RISING; + break; + + case IRQ_TYPE_EDGE_BOTH: + sense = ICR1_IRQS_EDGE_BOTH; + break; + + default: + return -EINVAL; + } + + tmp = readw_relaxed(priv->base + ICR1); + tmp &= ~ICR1_IRQS_MASK(hw_irq); + tmp |= ICR1_IRQS(hw_irq, sense); + writew_relaxed(tmp, priv->base + ICR1); + return 0; +} + +static int rza1_irqc_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *arg) +{ + struct rza1_irqc_priv *priv = domain->host_data; + struct irq_fwspec *fwspec = arg; + unsigned int hwirq = fwspec->param[0]; + struct irq_fwspec spec; + unsigned int i; + int ret; + + ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &priv->chip, + priv); + if (ret) + return ret; + + spec.fwnode = &priv->dev->of_node->fwnode; + spec.param_count = priv->map[hwirq].args_count; + for (i = 0; i < spec.param_count; i++) + spec.param[i] = priv->map[hwirq].args[i]; + + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &spec); +} + +static int rza1_irqc_translate(struct irq_domain *domain, + struct irq_fwspec *fwspec, unsigned long *hwirq, + unsigned int *type) +{ + if (fwspec->param_count != 2 || fwspec->param[0] >= IRQC_NUM_IRQ) + return -EINVAL; + + *hwirq = fwspec->param[0]; + *type = fwspec->param[1]; + return 0; +} + +static const struct irq_domain_ops rza1_irqc_domain_ops = { + .alloc = rza1_irqc_alloc, + .translate = rza1_irqc_translate, +}; + +static int rza1_irqc_parse_map(struct rza1_irqc_priv *priv, + struct device_node *gic_node) +{ + unsigned int imaplen, i, j, ret; + struct device *dev = priv->dev; + struct device_node *ipar; + const __be32 *imap; + u32 intsize; + + imap = of_get_property(dev->of_node, "interrupt-map", &imaplen); + if (!imap) + return -EINVAL; + + for (i = 0; i < IRQC_NUM_IRQ; i++) { + if (imaplen < 3) + return -EINVAL; + + /* Check interrupt number, ignore sense */ + if (be32_to_cpup(imap) != i) + return -EINVAL; + + ipar = of_find_node_by_phandle(be32_to_cpup(imap + 2)); + if (ipar != gic_node) { + of_node_put(ipar); + return -EINVAL; + } + + imap += 3; + imaplen -= 3; + + ret = of_property_read_u32(ipar, "#interrupt-cells", &intsize); + of_node_put(ipar); + if (ret) + return ret; + + if (imaplen < intsize) + return -EINVAL; + + priv->map[i].args_count = intsize; + for (j = 0; j < intsize; j++) + priv->map[i].args[j] = be32_to_cpup(imap++); + + imaplen -= intsize; + } + + return 0; +} + +static int rza1_irqc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct irq_domain *parent = NULL; + struct device_node *gic_node; + struct rza1_irqc_priv *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + priv->dev = dev; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + gic_node = of_irq_find_parent(np); + if (gic_node) { + parent = irq_find_host(gic_node); + of_node_put(gic_node); + } + + if (!parent) { + dev_err(dev, "cannot find parent domain\n"); + return -ENODEV; + } + + ret = rza1_irqc_parse_map(priv, gic_node); + if (ret) { + dev_err(dev, "cannot parse %s: %d\n", "interrupt-map", ret); + return ret; + } + + priv->chip.name = "rza1-irqc", + priv->chip.irq_mask = irq_chip_mask_parent, + priv->chip.irq_unmask = irq_chip_unmask_parent, + priv->chip.irq_eoi = rza1_irqc_eoi, + priv->chip.irq_retrigger = irq_chip_retrigger_hierarchy, + priv->chip.irq_set_type = rza1_irqc_set_type, + priv->chip.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE; + + priv->irq_domain = irq_domain_add_hierarchy(parent, 0, IRQC_NUM_IRQ, + np, &rza1_irqc_domain_ops, + priv); + if (!priv->irq_domain) { + dev_err(dev, "cannot initialize irq domain\n"); + return -ENOMEM; + } + + return 0; +} + +static int rza1_irqc_remove(struct platform_device *pdev) +{ + struct rza1_irqc_priv *priv = platform_get_drvdata(pdev); + + irq_domain_remove(priv->irq_domain); + return 0; +} + +static const struct of_device_id rza1_irqc_dt_ids[] = { + { .compatible = "renesas,rza1-irqc" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rza1_irqc_dt_ids); + +static struct platform_driver rza1_irqc_device_driver = { + .probe = rza1_irqc_probe, + .remove = rza1_irqc_remove, + .driver = { + .name = "renesas_rza1_irqc", + .of_match_table = rza1_irqc_dt_ids, + } +}; + +static int __init rza1_irqc_init(void) +{ + return platform_driver_register(&rza1_irqc_device_driver); +} +postcore_initcall(rza1_irqc_init); + +static void __exit rza1_irqc_exit(void) +{ + platform_driver_unregister(&rza1_irqc_device_driver); +} +module_exit(rza1_irqc_exit); + +MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>"); +MODULE_DESCRIPTION("Renesas RZ/A1 IRQC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/irqchip/irq-sa11x0.c b/drivers/irqchip/irq-sa11x0.c index 61bb28d7b19b..dbccc7dafbf8 100644 --- a/drivers/irqchip/irq-sa11x0.c +++ b/drivers/irqchip/irq-sa11x0.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Dmitry Eremin-Solenikov * Copyright (C) 1999-2001 Nicolas Pitre * * Generic IRQ handling for the SA11x0. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> #include <linux/module.h> diff --git a/drivers/irqchip/irq-sni-exiu.c b/drivers/irqchip/irq-sni-exiu.c index 1927b2f36ff6..1d027623c776 100644 --- a/drivers/irqchip/irq-sni-exiu.c +++ b/drivers/irqchip/irq-sni-exiu.c @@ -1,15 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Socionext External Interrupt Unit (EXIU) * - * Copyright (c) 2017 Linaro, Ltd. <ard.biesheuvel@linaro.org> + * Copyright (c) 2017-2019 Linaro, Ltd. <ard.biesheuvel@linaro.org> * * Based on irq-tegra.c: * Copyright (C) 2011 Google, Inc. * Copyright (C) 2010,2013, NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/interrupt.h> @@ -20,6 +17,7 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/platform_device.h> #include <dt-bindings/interrupt-controller/arm-gic.h> @@ -134,9 +132,13 @@ static int exiu_domain_translate(struct irq_domain *domain, *hwirq = fwspec->param[1] - info->spi_base; *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; - return 0; + } else { + if (fwspec->param_count != 2) + return -EINVAL; + *hwirq = fwspec->param[0]; + *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; } - return -EINVAL; + return 0; } static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq, @@ -147,16 +149,21 @@ static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq, struct exiu_irq_data *info = dom->host_data; irq_hw_number_t hwirq; - if (fwspec->param_count != 3) - return -EINVAL; /* Not GIC compliant */ - if (fwspec->param[0] != GIC_SPI) - return -EINVAL; /* No PPI should point to this domain */ + parent_fwspec = *fwspec; + if (is_of_node(dom->parent->fwnode)) { + if (fwspec->param_count != 3) + return -EINVAL; /* Not GIC compliant */ + if (fwspec->param[0] != GIC_SPI) + return -EINVAL; /* No PPI should point to this domain */ + hwirq = fwspec->param[1] - info->spi_base; + } else { + hwirq = fwspec->param[0]; + parent_fwspec.param[0] = hwirq + info->spi_base + 32; + } WARN_ON(nr_irqs != 1); - hwirq = fwspec->param[1] - info->spi_base; irq_domain_set_hwirq_and_chip(dom, virq, hwirq, &exiu_irq_chip, info); - parent_fwspec = *fwspec; parent_fwspec.fwnode = dom->parent->fwnode; return irq_domain_alloc_irqs_parent(dom, virq, nr_irqs, &parent_fwspec); } @@ -167,35 +174,23 @@ static const struct irq_domain_ops exiu_domain_ops = { .free = irq_domain_free_irqs_common, }; -static int __init exiu_init(struct device_node *node, - struct device_node *parent) +static struct exiu_irq_data *exiu_init(const struct fwnode_handle *fwnode, + struct resource *res) { - struct irq_domain *parent_domain, *domain; struct exiu_irq_data *data; int err; - if (!parent) { - pr_err("%pOF: no parent, giving up\n", node); - return -ENODEV; - } - - parent_domain = irq_find_host(parent); - if (!parent_domain) { - pr_err("%pOF: unable to obtain parent domain\n", node); - return -ENXIO; - } - data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - if (of_property_read_u32(node, "socionext,spi-base", &data->spi_base)) { - pr_err("%pOF: failed to parse 'spi-base' property\n", node); + if (fwnode_property_read_u32_array(fwnode, "socionext,spi-base", + &data->spi_base, 1)) { err = -ENODEV; goto out_free; } - data->base = of_iomap(node, 0); + data->base = ioremap(res->start, resource_size(res)); if (!data->base) { err = -ENODEV; goto out_free; @@ -205,11 +200,44 @@ static int __init exiu_init(struct device_node *node, writel_relaxed(0xFFFFFFFF, data->base + EIREQCLR); writel_relaxed(0xFFFFFFFF, data->base + EIMASK); + return data; + +out_free: + kfree(data); + return ERR_PTR(err); +} + +static int __init exiu_dt_init(struct device_node *node, + struct device_node *parent) +{ + struct irq_domain *parent_domain, *domain; + struct exiu_irq_data *data; + struct resource res; + + if (!parent) { + pr_err("%pOF: no parent, giving up\n", node); + return -ENODEV; + } + + parent_domain = irq_find_host(parent); + if (!parent_domain) { + pr_err("%pOF: unable to obtain parent domain\n", node); + return -ENXIO; + } + + if (of_address_to_resource(node, 0, &res)) { + pr_err("%pOF: failed to parse memory resource\n", node); + return -ENXIO; + } + + data = exiu_init(of_node_to_fwnode(node), &res); + if (IS_ERR(data)) + return PTR_ERR(data); + domain = irq_domain_add_hierarchy(parent_domain, 0, NUM_IRQS, node, &exiu_domain_ops, data); if (!domain) { pr_err("%pOF: failed to allocate domain\n", node); - err = -ENOMEM; goto out_unmap; } @@ -220,8 +248,57 @@ static int __init exiu_init(struct device_node *node, out_unmap: iounmap(data->base); -out_free: kfree(data); - return err; + return -ENOMEM; +} +IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_dt_init); + +#ifdef CONFIG_ACPI +static int exiu_acpi_probe(struct platform_device *pdev) +{ + struct irq_domain *domain; + struct exiu_irq_data *data; + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to parse memory resource\n"); + return -ENXIO; + } + + data = exiu_init(dev_fwnode(&pdev->dev), res); + if (IS_ERR(data)) + return PTR_ERR(data); + + domain = acpi_irq_create_hierarchy(0, NUM_IRQS, dev_fwnode(&pdev->dev), + &exiu_domain_ops, data); + if (!domain) { + dev_err(&pdev->dev, "failed to create IRQ domain\n"); + goto out_unmap; + } + + dev_info(&pdev->dev, "%d interrupts forwarded\n", NUM_IRQS); + + return 0; + +out_unmap: + iounmap(data->base); + kfree(data); + return -ENOMEM; } -IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_init); + +static const struct acpi_device_id exiu_acpi_ids[] = { + { "SCX0008" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(acpi, exiu_acpi_ids); + +static struct platform_driver exiu_driver = { + .driver = { + .name = "exiu", + .acpi_match_table = exiu_acpi_ids, + }, + .probe = exiu_acpi_probe, +}; +builtin_platform_driver(exiu_driver); +#endif diff --git a/drivers/irqchip/irq-st.c b/drivers/irqchip/irq-st.c index 5e0e250db0be..801551e46a7b 100644 --- a/drivers/irqchip/irq-st.c +++ b/drivers/irqchip/irq-st.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 STMicroelectronics – All Rights Reserved * * Author: Lee Jones <lee.jones@linaro.org> * * This is a re-write of Christophe Kerello's PMU driver. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <dt-bindings/interrupt-controller/irq-st.h> diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c index 011b60a49e3f..ef4d625d2d80 100644 --- a/drivers/irqchip/irq-ti-sci-inta.c +++ b/drivers/irqchip/irq-ti-sci-inta.c @@ -159,9 +159,9 @@ static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_dom parent_fwspec.param[1] = vint_desc->vint_id; parent_virq = irq_create_fwspec_mapping(&parent_fwspec); - if (parent_virq <= 0) { + if (parent_virq == 0) { kfree(vint_desc); - return ERR_PTR(parent_virq); + return ERR_PTR(-EINVAL); } vint_desc->parent_virq = parent_virq; diff --git a/drivers/irqchip/irq-vf610-mscm-ir.c b/drivers/irqchip/irq-vf610-mscm-ir.c index 56b5e3cb9de2..2b9a8ba58e26 100644 --- a/drivers/irqchip/irq-vf610-mscm-ir.c +++ b/drivers/irqchip/irq-vf610-mscm-ir.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014-2015 Toradex AG * Author: Stefan Agner <stefan@agner.ch> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * * IRQ chip driver for MSCM interrupt router available on Vybrid SoC's. * The interrupt router is between the CPU's interrupt controller and the * peripheral. The router allows to route the peripheral interrupts to diff --git a/drivers/irqchip/irq-zevio.c b/drivers/irqchip/irq-zevio.c index cb9d8ec37507..5a7efeb3892d 100644 --- a/drivers/irqchip/irq-zevio.c +++ b/drivers/irqchip/irq-zevio.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/irqchip/irq-zevio.c * * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * */ #include <linux/io.h> diff --git a/drivers/irqchip/qcom-irq-combiner.c b/drivers/irqchip/qcom-irq-combiner.c index 067337ab3f20..d88e993aa66d 100644 --- a/drivers/irqchip/qcom-irq-combiner.c +++ b/drivers/irqchip/qcom-irq-combiner.c @@ -229,7 +229,6 @@ static int get_registers(struct platform_device *pdev, struct combiner *comb) static int __init combiner_probe(struct platform_device *pdev) { struct combiner *combiner; - size_t alloc_sz; int nregs; int err; @@ -239,8 +238,8 @@ static int __init combiner_probe(struct platform_device *pdev) return -EINVAL; } - alloc_sz = sizeof(*combiner) + sizeof(struct combiner_reg) * nregs; - combiner = devm_kzalloc(&pdev->dev, alloc_sz, GFP_KERNEL); + combiner = devm_kzalloc(&pdev->dev, struct_size(combiner, regs, nregs), + GFP_KERNEL); if (!combiner) return -ENOMEM; diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 760f73a49c9f..b0fdeef10bd9 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -784,6 +784,41 @@ config LEDS_NIC78BX To compile this driver as a module, choose M here: the module will be called leds-nic78bx. +config LEDS_SPI_BYTE + tristate "LED support for SPI LED controller with a single byte" + depends on LEDS_CLASS + depends on SPI + depends on OF + help + This option enables support for LED controller which use a single byte + for controlling the brightness. Currently the following controller is + supported: Ubiquiti airCube ISP microcontroller based LED controller. + +config LEDS_TI_LMU_COMMON + tristate "LED driver for TI LMU" + depends on LEDS_CLASS + depends on REGMAP + help + Say Y to enable the LED driver for TI LMU devices. + This supports common features between the TI LM3532, LM3631, LM3632, + LM3633, LM3695 and LM3697. + +config LEDS_LM3697 + tristate "LED driver for LM3697" + depends on LEDS_TI_LMU_COMMON + depends on I2C && OF + help + Say Y to enable the LM3697 LED driver for TI LMU devices. + This supports the LED device LM3697. + +config LEDS_LM36274 + tristate "LED driver for LM36274" + depends on LEDS_TI_LMU_COMMON + depends on MFD_TI_LMU + help + Say Y to enable the LM36274 LED driver for TI LMU devices. + This supports the LED device LM36274. + comment "LED Triggers" source "drivers/leds/trigger/Kconfig" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 1e9702ebffee..41fb073a39c1 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -77,10 +77,14 @@ obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o obj-$(CONFIG_LEDS_MLXREG) += leds-mlxreg.o obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o +obj-$(CONFIG_LEDS_SPI_BYTE) += leds-spi-byte.o obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o +obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o +obj-$(CONFIG_LEDS_LM3697) += leds-lm3697.o +obj-$(CONFIG_LEDS_LM36274) += leds-lm36274.o # LED SPI Drivers obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c index cf398275a53c..94980c654d89 100644 --- a/drivers/leds/led-class-flash.c +++ b/drivers/leds/led-class-flash.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED Flash class interface * * Copyright (C) 2015 Samsung Electronics Co., Ltd. * Author: Jacek Anaszewski <j.anaszewski@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 85848c5da705..4793e77808e2 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED Class Core * * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu> * Copyright (C) 2005-2007 Richard Purdie <rpurdie@openedhand.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/ctype.h> diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index e3da7c03da1b..7107cd7e87cf 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED Class Core * * Copyright 2005-2006 Openedhand Ltd. * * Author: Richard Purdie <rpurdie@openedhand.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 2d451b6c24af..8d11a5e23227 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED Triggers Core * * Copyright 2005-2007 Openedhand Ltd. * * Author: Richard Purdie <rpurdie@openedhand.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/export.h> diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index 036d4a536697..b3044c9a8120 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED driver for Marvell 88PM860x * * Copyright (C) 2009 Marvell International Ltd. * Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/leds/leds-aat1290.c b/drivers/leds/leds-aat1290.c index 43bd8a43f36c..bf26f5bed1f0 100644 --- a/drivers/leds/leds-aat1290.c +++ b/drivers/leds/leds-aat1290.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED Flash class driver for the AAT1290 * 1.5A Step-Up Current Regulator for Flash LEDs * * Copyright (C) 2015, Samsung Electronics Co., Ltd. * Author: Jacek Anaszewski <j.anaszewski@samsung.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/leds/leds-asic3.c b/drivers/leds/leds-asic3.c index 1b71eac639f0..8cbc1b8bafa5 100644 --- a/drivers/leds/leds-asic3.c +++ b/drivers/leds/leds-asic3.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Paul Parsons <lost.distance@yahoo.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c index 6b4de762a760..e7ec6bff2b5f 100644 --- a/drivers/leds/leds-bd2802.c +++ b/drivers/leds/leds-bd2802.c @@ -1,15 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * leds-bd2802.c - RGB LED Driver * * Copyright (C) 2009 Samsung Electronics * Kim Kyuwon <q1.kim@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Datasheet: http://www.rohm.com/products/databook/driver/pdf/bd2802gu-e.pdf - * */ #include <linux/module.h> diff --git a/drivers/leds/leds-da903x.c b/drivers/leds/leds-da903x.c index 5ff7d72f73aa..ed1b303f699f 100644 --- a/drivers/leds/leds-da903x.c +++ b/drivers/leds/leds-da903x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LEDs driver for Dialog Semiconductor DA9030/DA9034 * @@ -6,10 +7,6 @@ * * Copyright (C) 2006-2008 Marvell International Ltd. * Eric Miao <eric.miao@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/leds/leds-fsg.c b/drivers/leds/leds-fsg.c index 257a813c73f3..bc6b420637d6 100644 --- a/drivers/leds/leds-fsg.c +++ b/drivers/leds/leds-fsg.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED Driver for the Freecom FSG-3 * @@ -8,11 +9,6 @@ * Based on leds-spitz.c * Copyright 2005-2006 Openedhand Ltd. * Author: Richard Purdie <rpurdie@openedhand.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/leds/leds-gpio-register.c b/drivers/leds/leds-gpio-register.c index 75717ba68ae0..b9187e71e0cf 100644 --- a/drivers/leds/leds-gpio-register.c +++ b/drivers/leds/leds-gpio-register.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Pengutronix * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. */ #include <linux/err.h> #include <linux/leds.h> diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index 998f2ff6914d..bdc98ddca1dc 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LEDs driver for GPIOs * * Copyright (C) 2007 8D Technologies inc. * Raphael Assenat <raph@8d.com> * Copyright (C) 2008 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/err.h> #include <linux/gpio.h> diff --git a/drivers/leds/leds-hp6xx.c b/drivers/leds/leds-hp6xx.c index 137969fcecbb..54af9e63c09c 100644 --- a/drivers/leds/leds-hp6xx.c +++ b/drivers/leds/leds-hp6xx.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED Triggers Core * For the HP Jornada 620/660/680/690 handhelds * * Copyright 2008 Kristoffer Ericson <kristoffer.ericson@gmail.com> * this driver is based on leds-spitz.c by Richard Purdie. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/leds/leds-ipaq-micro.c b/drivers/leds/leds-ipaq-micro.c index 02f17331379d..504a95b6ef45 100644 --- a/drivers/leds/leds-ipaq-micro.c +++ b/drivers/leds/leds-ipaq-micro.c @@ -1,7 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. * * h3xxx atmel micro companion support, notification LED subdevice * diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c index 31a9d749c8be..6fbab70dfb04 100644 --- a/drivers/leds/leds-is31fl32xx.c +++ b/drivers/leds/leds-is31fl32xx.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for ISSI IS31FL32xx family of I2C LED controllers * * Copyright 2015 Allworx Corp. * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Datasheets: * http://www.issi.com/US/product-analog-fxled-driver.shtml * http://www.si-en.com/product.asp?parentid=890 diff --git a/drivers/leds/leds-ktd2692.c b/drivers/leds/leds-ktd2692.c index 45296aaca9da..f63918206bfb 100644 --- a/drivers/leds/leds-ktd2692.c +++ b/drivers/leds/leds-ktd2692.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED driver : leds-ktd2692.c * * Copyright (C) 2015 Samsung Electronics * Ingi Kim <ingi2.kim@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/leds/leds-lm355x.c b/drivers/leds/leds-lm355x.c index 6cb94f9a2f3f..a5abb499574b 100644 --- a/drivers/leds/leds-lm355x.c +++ b/drivers/leds/leds-lm355x.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Simple driver for Texas Instruments LM355x LED Flash driver chip * Copyright (C) 2012 Texas Instruments -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c new file mode 100644 index 000000000000..ed9dc857ec8f --- /dev/null +++ b/drivers/leds/leds-lm36274.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0 +// TI LM36274 LED chip family driver +// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ + +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/leds.h> +#include <linux/leds-ti-lmu-common.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> + +#include <linux/mfd/ti-lmu.h> +#include <linux/mfd/ti-lmu-register.h> + +#include <uapi/linux/uleds.h> + +#define LM36274_MAX_STRINGS 4 +#define LM36274_BL_EN BIT(4) + +/** + * struct lm36274 + * @pdev: platform device + * @led_dev: led class device + * @lmu_data: Register and setting values for common code + * @regmap: Devices register map + * @dev: Pointer to the devices device struct + * @led_sources - The LED strings supported in this array + * @num_leds - Number of LED strings are supported in this array + */ +struct lm36274 { + struct platform_device *pdev; + struct led_classdev led_dev; + struct ti_lmu_bank lmu_data; + struct regmap *regmap; + struct device *dev; + + u32 led_sources[LM36274_MAX_STRINGS]; + int num_leds; +}; + +static int lm36274_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brt_val) +{ + struct lm36274 *led = container_of(led_cdev, struct lm36274, led_dev); + + return ti_lmu_common_set_brightness(&led->lmu_data, brt_val); +} + +static int lm36274_init(struct lm36274 *lm36274_data) +{ + int enable_val = 0; + int i; + + for (i = 0; i < lm36274_data->num_leds; i++) + enable_val |= (1 << lm36274_data->led_sources[i]); + + if (!enable_val) { + dev_err(lm36274_data->dev, "No LEDs were enabled\n"); + return -EINVAL; + } + + enable_val |= LM36274_BL_EN; + + return regmap_write(lm36274_data->regmap, LM36274_REG_BL_EN, + enable_val); +} + +static int lm36274_parse_dt(struct lm36274 *lm36274_data) +{ + struct fwnode_handle *child = NULL; + char label[LED_MAX_NAME_SIZE]; + struct device *dev = &lm36274_data->pdev->dev; + const char *name; + int child_cnt; + int ret = -EINVAL; + + /* There should only be 1 node */ + child_cnt = device_get_child_node_count(dev); + if (child_cnt != 1) + return -EINVAL; + + device_for_each_child_node(dev, child) { + ret = fwnode_property_read_string(child, "label", &name); + if (ret) + snprintf(label, sizeof(label), + "%s::", lm36274_data->pdev->name); + else + snprintf(label, sizeof(label), + "%s:%s", lm36274_data->pdev->name, name); + + lm36274_data->num_leds = fwnode_property_read_u32_array(child, + "led-sources", + NULL, 0); + if (lm36274_data->num_leds <= 0) + return -ENODEV; + + ret = fwnode_property_read_u32_array(child, "led-sources", + lm36274_data->led_sources, + lm36274_data->num_leds); + if (ret) { + dev_err(dev, "led-sources property missing\n"); + return ret; + } + + fwnode_property_read_string(child, "linux,default-trigger", + &lm36274_data->led_dev.default_trigger); + + } + + lm36274_data->lmu_data.regmap = lm36274_data->regmap; + lm36274_data->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT; + lm36274_data->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB; + lm36274_data->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB; + + lm36274_data->led_dev.name = label; + lm36274_data->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT; + lm36274_data->led_dev.brightness_set_blocking = lm36274_brightness_set; + + return 0; +} + +static int lm36274_probe(struct platform_device *pdev) +{ + struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent); + struct lm36274 *lm36274_data; + int ret; + + lm36274_data = devm_kzalloc(&pdev->dev, sizeof(*lm36274_data), + GFP_KERNEL); + if (!lm36274_data) + return -ENOMEM; + + lm36274_data->pdev = pdev; + lm36274_data->dev = lmu->dev; + lm36274_data->regmap = lmu->regmap; + dev_set_drvdata(&pdev->dev, lm36274_data); + + ret = lm36274_parse_dt(lm36274_data); + if (ret) { + dev_err(lm36274_data->dev, "Failed to parse DT node\n"); + return ret; + } + + ret = lm36274_init(lm36274_data); + if (ret) { + dev_err(lm36274_data->dev, "Failed to init the device\n"); + return ret; + } + + return devm_led_classdev_register(lm36274_data->dev, + &lm36274_data->led_dev); +} + +static const struct of_device_id of_lm36274_leds_match[] = { + { .compatible = "ti,lm36274-backlight", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_lm36274_leds_match); + +static struct platform_driver lm36274_driver = { + .probe = lm36274_probe, + .driver = { + .name = "lm36274-leds", + }, +}; +module_platform_driver(lm36274_driver) + +MODULE_DESCRIPTION("Texas Instruments LM36274 LED driver"); +MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/leds-lm3642.c b/drivers/leds/leds-lm3642.c index cada0848db7b..480575442ed8 100644 --- a/drivers/leds/leds-lm3642.c +++ b/drivers/leds/leds-lm3642.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Simple driver for Texas Instruments LM3642 LED Flash driver chip * Copyright (C) 2012 Texas Instruments -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* */ #include <linux/module.h> #include <linux/delay.h> diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c new file mode 100644 index 000000000000..54e0e35df824 --- /dev/null +++ b/drivers/leds/leds-lm3697.c @@ -0,0 +1,395 @@ +// SPDX-License-Identifier: GPL-2.0 +// TI LM3697 LED chip family driver +// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/regulator/consumer.h> +#include <linux/leds-ti-lmu-common.h> + +#define LM3697_REV 0x0 +#define LM3697_RESET 0x1 +#define LM3697_OUTPUT_CONFIG 0x10 +#define LM3697_CTRL_A_RAMP 0x11 +#define LM3697_CTRL_B_RAMP 0x12 +#define LM3697_CTRL_A_B_RT_RAMP 0x13 +#define LM3697_CTRL_A_B_RAMP_CFG 0x14 +#define LM3697_CTRL_A_B_BRT_CFG 0x16 +#define LM3697_CTRL_A_FS_CURR_CFG 0x17 +#define LM3697_CTRL_B_FS_CURR_CFG 0x18 +#define LM3697_PWM_CFG 0x1c +#define LM3697_CTRL_A_BRT_LSB 0x20 +#define LM3697_CTRL_A_BRT_MSB 0x21 +#define LM3697_CTRL_B_BRT_LSB 0x22 +#define LM3697_CTRL_B_BRT_MSB 0x23 +#define LM3697_CTRL_ENABLE 0x24 + +#define LM3697_SW_RESET BIT(0) + +#define LM3697_CTRL_A_EN BIT(0) +#define LM3697_CTRL_B_EN BIT(1) +#define LM3697_CTRL_A_B_EN (LM3697_CTRL_A_EN | LM3697_CTRL_B_EN) + +#define LM3697_MAX_LED_STRINGS 3 + +#define LM3697_CONTROL_A 0 +#define LM3697_CONTROL_B 1 +#define LM3697_MAX_CONTROL_BANKS 2 + +/** + * struct lm3697_led - + * @hvled_strings: Array of LED strings associated with a control bank + * @label: LED label + * @led_dev: LED class device + * @priv: Pointer to the device struct + * @lmu_data: Register and setting values for common code + * @control_bank: Control bank the LED is associated to. 0 is control bank A + * 1 is control bank B + */ +struct lm3697_led { + u32 hvled_strings[LM3697_MAX_LED_STRINGS]; + char label[LED_MAX_NAME_SIZE]; + struct led_classdev led_dev; + struct lm3697 *priv; + struct ti_lmu_bank lmu_data; + int control_bank; + int enabled; + int num_leds; +}; + +/** + * struct lm3697 - + * @enable_gpio: Hardware enable gpio + * @regulator: LED supply regulator pointer + * @client: Pointer to the I2C client + * @regmap: Devices register map + * @dev: Pointer to the devices device struct + * @lock: Lock for reading/writing the device + * @leds: Array of LED strings + */ +struct lm3697 { + struct gpio_desc *enable_gpio; + struct regulator *regulator; + struct i2c_client *client; + struct regmap *regmap; + struct device *dev; + struct mutex lock; + + int bank_cfg; + + struct lm3697_led leds[]; +}; + +static const struct reg_default lm3697_reg_defs[] = { + {LM3697_OUTPUT_CONFIG, 0x6}, + {LM3697_CTRL_A_RAMP, 0x0}, + {LM3697_CTRL_B_RAMP, 0x0}, + {LM3697_CTRL_A_B_RT_RAMP, 0x0}, + {LM3697_CTRL_A_B_RAMP_CFG, 0x0}, + {LM3697_CTRL_A_B_BRT_CFG, 0x0}, + {LM3697_CTRL_A_FS_CURR_CFG, 0x13}, + {LM3697_CTRL_B_FS_CURR_CFG, 0x13}, + {LM3697_PWM_CFG, 0xc}, + {LM3697_CTRL_A_BRT_LSB, 0x0}, + {LM3697_CTRL_A_BRT_MSB, 0x0}, + {LM3697_CTRL_B_BRT_LSB, 0x0}, + {LM3697_CTRL_B_BRT_MSB, 0x0}, + {LM3697_CTRL_ENABLE, 0x0}, +}; + +static const struct regmap_config lm3697_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = LM3697_CTRL_ENABLE, + .reg_defaults = lm3697_reg_defs, + .num_reg_defaults = ARRAY_SIZE(lm3697_reg_defs), + .cache_type = REGCACHE_FLAT, +}; + +static int lm3697_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brt_val) +{ + struct lm3697_led *led = container_of(led_cdev, struct lm3697_led, + led_dev); + int ctrl_en_val = (1 << led->control_bank); + int ret; + + mutex_lock(&led->priv->lock); + + if (brt_val == LED_OFF) { + ret = regmap_update_bits(led->priv->regmap, LM3697_CTRL_ENABLE, + ctrl_en_val, ~ctrl_en_val); + if (ret) { + dev_err(&led->priv->client->dev, "Cannot write ctrl register\n"); + goto brightness_out; + } + + led->enabled = LED_OFF; + } else { + ret = ti_lmu_common_set_brightness(&led->lmu_data, brt_val); + if (ret) { + dev_err(&led->priv->client->dev, + "Cannot write brightness\n"); + goto brightness_out; + } + + if (!led->enabled) { + ret = regmap_update_bits(led->priv->regmap, + LM3697_CTRL_ENABLE, + ctrl_en_val, ctrl_en_val); + if (ret) { + dev_err(&led->priv->client->dev, + "Cannot enable the device\n"); + goto brightness_out; + } + + led->enabled = brt_val; + } + } + +brightness_out: + mutex_unlock(&led->priv->lock); + return ret; +} + +static int lm3697_init(struct lm3697 *priv) +{ + struct lm3697_led *led; + int i, ret; + + if (priv->enable_gpio) { + gpiod_direction_output(priv->enable_gpio, 1); + } else { + ret = regmap_write(priv->regmap, LM3697_RESET, LM3697_SW_RESET); + if (ret) { + dev_err(&priv->client->dev, "Cannot reset the device\n"); + goto out; + } + } + + ret = regmap_write(priv->regmap, LM3697_CTRL_ENABLE, 0x0); + if (ret) { + dev_err(&priv->client->dev, "Cannot write ctrl enable\n"); + goto out; + } + + ret = regmap_write(priv->regmap, LM3697_OUTPUT_CONFIG, priv->bank_cfg); + if (ret) + dev_err(&priv->client->dev, "Cannot write OUTPUT config\n"); + + for (i = 0; i < LM3697_MAX_CONTROL_BANKS; i++) { + led = &priv->leds[i]; + ret = ti_lmu_common_set_ramp(&led->lmu_data); + if (ret) + dev_err(&priv->client->dev, "Setting the ramp rate failed\n"); + } +out: + return ret; +} + +static int lm3697_probe_dt(struct lm3697 *priv) +{ + struct fwnode_handle *child = NULL; + struct lm3697_led *led; + const char *name; + int control_bank; + size_t i = 0; + int ret = -EINVAL; + int j; + + priv->enable_gpio = devm_gpiod_get_optional(&priv->client->dev, + "enable", GPIOD_OUT_LOW); + if (IS_ERR(priv->enable_gpio)) { + ret = PTR_ERR(priv->enable_gpio); + dev_err(&priv->client->dev, "Failed to get enable gpio: %d\n", + ret); + return ret; + } + + priv->regulator = devm_regulator_get(&priv->client->dev, "vled"); + if (IS_ERR(priv->regulator)) + priv->regulator = NULL; + + device_for_each_child_node(priv->dev, child) { + ret = fwnode_property_read_u32(child, "reg", &control_bank); + if (ret) { + dev_err(&priv->client->dev, "reg property missing\n"); + fwnode_handle_put(child); + goto child_out; + } + + if (control_bank > LM3697_CONTROL_B) { + dev_err(&priv->client->dev, "reg property is invalid\n"); + ret = -EINVAL; + fwnode_handle_put(child); + goto child_out; + } + + led = &priv->leds[i]; + + ret = ti_lmu_common_get_brt_res(&priv->client->dev, + child, &led->lmu_data); + if (ret) + dev_warn(&priv->client->dev, "brightness resolution property missing\n"); + + led->control_bank = control_bank; + led->lmu_data.regmap = priv->regmap; + led->lmu_data.runtime_ramp_reg = LM3697_CTRL_A_RAMP + + control_bank; + led->lmu_data.msb_brightness_reg = LM3697_CTRL_A_BRT_MSB + + led->control_bank * 2; + led->lmu_data.lsb_brightness_reg = LM3697_CTRL_A_BRT_LSB + + led->control_bank * 2; + + led->num_leds = fwnode_property_read_u32_array(child, + "led-sources", + NULL, 0); + + if (led->num_leds > LM3697_MAX_LED_STRINGS) { + dev_err(&priv->client->dev, "To many LED strings defined\n"); + continue; + } + + ret = fwnode_property_read_u32_array(child, "led-sources", + led->hvled_strings, + led->num_leds); + if (ret) { + dev_err(&priv->client->dev, "led-sources property missing\n"); + fwnode_handle_put(child); + goto child_out; + } + + for (j = 0; j < led->num_leds; j++) + priv->bank_cfg |= + (led->control_bank << led->hvled_strings[j]); + + ret = ti_lmu_common_get_ramp_params(&priv->client->dev, + child, &led->lmu_data); + if (ret) + dev_warn(&priv->client->dev, "runtime-ramp properties missing\n"); + + fwnode_property_read_string(child, "linux,default-trigger", + &led->led_dev.default_trigger); + + ret = fwnode_property_read_string(child, "label", &name); + if (ret) + snprintf(led->label, sizeof(led->label), + "%s::", priv->client->name); + else + snprintf(led->label, sizeof(led->label), + "%s:%s", priv->client->name, name); + + led->priv = priv; + led->led_dev.name = led->label; + led->led_dev.max_brightness = led->lmu_data.max_brightness; + led->led_dev.brightness_set_blocking = lm3697_brightness_set; + + ret = devm_led_classdev_register(priv->dev, &led->led_dev); + if (ret) { + dev_err(&priv->client->dev, "led register err: %d\n", + ret); + fwnode_handle_put(child); + goto child_out; + } + + i++; + } + +child_out: + return ret; +} + +static int lm3697_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lm3697 *led; + int count; + int ret; + + count = device_get_child_node_count(&client->dev); + if (!count) { + dev_err(&client->dev, "LEDs are not defined in device tree!"); + return -ENODEV; + } + + led = devm_kzalloc(&client->dev, struct_size(led, leds, count), + GFP_KERNEL); + if (!led) + return -ENOMEM; + + mutex_init(&led->lock); + i2c_set_clientdata(client, led); + + led->client = client; + led->dev = &client->dev; + led->regmap = devm_regmap_init_i2c(client, &lm3697_regmap_config); + if (IS_ERR(led->regmap)) { + ret = PTR_ERR(led->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = lm3697_probe_dt(led); + if (ret) + return ret; + + return lm3697_init(led); +} + +static int lm3697_remove(struct i2c_client *client) +{ + struct lm3697 *led = i2c_get_clientdata(client); + int ret; + + ret = regmap_update_bits(led->regmap, LM3697_CTRL_ENABLE, + LM3697_CTRL_A_B_EN, 0); + if (ret) { + dev_err(&led->client->dev, "Failed to disable the device\n"); + return ret; + } + + if (led->enable_gpio) + gpiod_direction_output(led->enable_gpio, 0); + + if (led->regulator) { + ret = regulator_disable(led->regulator); + if (ret) + dev_err(&led->client->dev, + "Failed to disable regulator\n"); + } + + mutex_destroy(&led->lock); + + return 0; +} + +static const struct i2c_device_id lm3697_id[] = { + { "lm3697", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm3697_id); + +static const struct of_device_id of_lm3697_leds_match[] = { + { .compatible = "ti,lm3697", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_lm3697_leds_match); + +static struct i2c_driver lm3697_driver = { + .driver = { + .name = "lm3697", + .of_match_table = of_lm3697_leds_match, + }, + .probe = lm3697_probe, + .remove = lm3697_remove, + .id_table = lm3697_id, +}; +module_i2c_driver(lm3697_driver); + +MODULE_DESCRIPTION("Texas Instruments LM3697 LED driver"); +MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c index 24c4b53a6b93..42dc46e3f00f 100644 --- a/drivers/leds/leds-locomo.c +++ b/drivers/leds/leds-locomo.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/leds/leds-locomo.c * * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c index be60c181222a..838e6f19d37e 100644 --- a/drivers/leds/leds-lp3944.c +++ b/drivers/leds/leds-lp3944.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * leds-lp3944.c - driver for National Semiconductor LP3944 Funlight Chip * * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ /* diff --git a/drivers/leds/leds-lp3952.c b/drivers/leds/leds-lp3952.c index 847f7f282126..4e4e542774cb 100644 --- a/drivers/leds/leds-lp3952.c +++ b/drivers/leds/leds-lp3952.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED driver for TI lp3952 controller * * Copyright (C) 2016, DAQRI, LLC. * Author: Tony Makkiel <tony.makkiel@daqri.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/delay.h> diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c index 2a9009fe5545..37632fc63741 100644 --- a/drivers/leds/leds-lp5562.c +++ b/drivers/leds/leds-lp5562.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LP5562 LED driver * * Copyright (C) 2013 Texas Instruments * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index 723f2f17497a..44ced02b49f9 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LP5521/LP5523/LP55231/LP5562 Common Driver * @@ -5,10 +6,6 @@ * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Derived from leds-lp5521.c, leds-lp5523.c */ diff --git a/drivers/leds/leds-lp55xx-common.h b/drivers/leds/leds-lp55xx-common.h index abf1fb5da37d..783ed5103ce5 100644 --- a/drivers/leds/leds-lp55xx-common.h +++ b/drivers/leds/leds-lp55xx-common.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * LP55XX Common Driver Header * @@ -5,10 +6,6 @@ * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * * Derived from leds-lp5521.c, leds-lp5523.c */ diff --git a/drivers/leds/leds-lp8501.c b/drivers/leds/leds-lp8501.c index 4c800b5989a9..2638dbf0e8ac 100644 --- a/drivers/leds/leds-lp8501.c +++ b/drivers/leds/leds-lp8501.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LP8501 9 channel LED Driver * * Copyright (C) 2013 Texas Instruments * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * */ #include <linux/delay.h> diff --git a/drivers/leds/leds-lp8788.c b/drivers/leds/leds-lp8788.c index 38c253a43700..9b9525ccca15 100644 --- a/drivers/leds/leds-lp8788.c +++ b/drivers/leds/leds-lp8788.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LP8788 MFD - keyled driver * * Copyright 2012 Texas Instruments * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c index 39c72a908f3b..ed680d0c15b0 100644 --- a/drivers/leds/leds-lp8860.c +++ b/drivers/leds/leds-lp8860.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LP8860 4-Channel LED Driver * * Copyright (C) 2014 Texas Instruments * * Author: Dan Murphy <dmurphy@ti.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * */ #include <linux/i2c.h> diff --git a/drivers/leds/leds-max77650.c b/drivers/leds/leds-max77650.c index 6b74ce9cac12..8a8e5c65b157 100644 --- a/drivers/leds/leds-max77650.c +++ b/drivers/leds/leds-max77650.c @@ -64,7 +64,6 @@ static int max77650_led_probe(struct platform_device *pdev) { struct device_node *of_node, *child; struct max77650_led *leds, *led; - struct device *parent; struct device *dev; struct regmap *map; const char *label; @@ -72,7 +71,6 @@ static int max77650_led_probe(struct platform_device *pdev) u32 reg; dev = &pdev->dev; - parent = dev->parent; of_node = dev->of_node; if (!of_node) diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c index adf0f191f794..fec56090c2ba 100644 --- a/drivers/leds/leds-max77693.c +++ b/drivers/leds/leds-max77693.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED Flash class driver for the flash cell of max77693 mfd. * @@ -5,10 +6,6 @@ * * Authors: Jacek Anaszewski <j.anaszewski@samsung.com> * Andrzej Hajda <a.hajda@samsung.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #include <linux/led-class-flash.h> diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c index 8c019c28f9f5..512a11d142d0 100644 --- a/drivers/leds/leds-max8997.c +++ b/drivers/leds/leds-max8997.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * leds-max8997.c - LED class driver for MAX8997 LEDs. * * Copyright (C) 2011 Samsung Electronics * Donggeun Kim <dg77.kim@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index 47ad7de9553c..5cd810c545f3 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LEDs driver for Freescale MC13783/MC13892/MC34708 * @@ -9,10 +10,6 @@ * * Copyright (C) 2006-2008 Marvell International Ltd. * Eric Miao <eric.miao@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/leds/leds-net48xx.c b/drivers/leds/leds-net48xx.c index 0d214c2e403c..a93468c13772 100644 --- a/drivers/leds/leds-net48xx.c +++ b/drivers/leds/leds-net48xx.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LEDs driver for Soekris net48xx * * Copyright (C) 2006 Chris Boot <bootc@bootc.net> * * Based on leds-ams-delta.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index c2bc8f569760..4037c504589c 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -429,7 +429,7 @@ static int pca955x_probe(struct i2c_client *client, int ngpios = 0; chip = &pca955x_chipdefs[id->driver_data]; - adapter = to_i2c_adapter(client->dev.parent); + adapter = client->adapter; pdata = dev_get_platdata(&client->dev); if (!pdata) { pdata = pca955x_get_pdata(client, chip); diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index af08bcdc4fd8..48d068f80f11 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/leds-pwm.c * @@ -6,10 +7,6 @@ * Copyright 2009 Luotao Fu @ Pengutronix (l.fu@pengutronix.de) * * based on leds-gpio.c by Raphael Assenat <raph@8d.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> @@ -75,7 +72,7 @@ static inline size_t sizeof_pwm_leds_priv(int num_leds) } static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, - struct led_pwm *led, struct device_node *child) + struct led_pwm *led, struct fwnode_handle *fwnode) { struct led_pwm_data *led_data = &priv->leds[priv->num_leds]; struct pwm_args pargs; @@ -88,8 +85,8 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, led_data->cdev.max_brightness = led->max_brightness; led_data->cdev.flags = LED_CORE_SUSPENDRESUME; - if (child) - led_data->pwm = devm_of_pwm_get(dev, child, NULL); + if (fwnode) + led_data->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL); else led_data->pwm = devm_pwm_get(dev, led->name); if (IS_ERR(led_data->pwm)) { @@ -114,7 +111,8 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, if (!led_data->period && (led->pwm_period_ns > 0)) led_data->period = led->pwm_period_ns; - ret = devm_of_led_classdev_register(dev, child, &led_data->cdev); + ret = devm_of_led_classdev_register(dev, to_of_node(fwnode), + &led_data->cdev); if (ret == 0) { priv->num_leds++; led_pwm_set(&led_data->cdev, led_data->cdev.brightness); @@ -126,27 +124,35 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, return ret; } -static int led_pwm_create_of(struct device *dev, struct led_pwm_priv *priv) +static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv) { - struct device_node *child; + struct fwnode_handle *fwnode; struct led_pwm led; int ret = 0; memset(&led, 0, sizeof(led)); - for_each_child_of_node(dev->of_node, child) { - led.name = of_get_property(child, "label", NULL) ? : - child->name; + device_for_each_child_node(dev, fwnode) { + ret = fwnode_property_read_string(fwnode, "label", &led.name); + if (ret && is_of_node(fwnode)) + led.name = to_of_node(fwnode)->name; + + if (!led.name) { + fwnode_handle_put(fwnode); + return -EINVAL; + } + + fwnode_property_read_string(fwnode, "linux,default-trigger", + &led.default_trigger); - led.default_trigger = of_get_property(child, - "linux,default-trigger", NULL); - led.active_low = of_property_read_bool(child, "active-low"); - of_property_read_u32(child, "max-brightness", - &led.max_brightness); + led.active_low = fwnode_property_read_bool(fwnode, + "active-low"); + fwnode_property_read_u32(fwnode, "max-brightness", + &led.max_brightness); - ret = led_pwm_add(dev, priv, &led, child); + ret = led_pwm_add(dev, priv, &led, fwnode); if (ret) { - of_node_put(child); + fwnode_handle_put(fwnode); break; } } @@ -164,7 +170,7 @@ static int led_pwm_probe(struct platform_device *pdev) if (pdata) count = pdata->num_leds; else - count = of_get_child_count(pdev->dev.of_node); + count = device_get_child_node_count(&pdev->dev); if (!count) return -EINVAL; @@ -182,7 +188,7 @@ static int led_pwm_probe(struct platform_device *pdev) break; } } else { - ret = led_pwm_create_of(&pdev->dev, priv); + ret = led_pwm_create_fwnode(&pdev->dev, priv); } if (ret) diff --git a/drivers/leds/leds-regulator.c b/drivers/leds/leds-regulator.c index acf77ca47558..208c98918433 100644 --- a/drivers/leds/leds-regulator.c +++ b/drivers/leds/leds-regulator.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * leds-regulator.c - LED class driver for regulator driven LEDs. * * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it> * * Inspired by leds-wm8350 driver. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c index 404da451cb88..f8b8d6e313ee 100644 --- a/drivers/leds/leds-s3c24xx.c +++ b/drivers/leds/leds-s3c24xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/leds/leds-s3c24xx.c * * (c) 2006 Simtec Electronics @@ -5,10 +6,6 @@ * Ben Dooks <ben@simtec.co.uk> * * S3C24XX - LEDs GPIO driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/leds/leds-spi-byte.c b/drivers/leds/leds-spi-byte.c new file mode 100644 index 000000000000..b231b563b7bb --- /dev/null +++ b/drivers/leds/leds-spi-byte.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Christian Mauderer <oss@c-mauderer.de> + +/* + * The driver supports controllers with a very simple SPI protocol: + * - one LED is controlled by a single byte on MOSI + * - the value of the byte gives the brightness between two values (lowest to + * highest) + * - no return value is necessary (no MISO signal) + * + * The value for minimum and maximum brightness depends on the device + * (compatible string). + * + * Supported devices: + * - "ubnt,acb-spi-led": Microcontroller (SONiX 8F26E611LA) based device used + * for example in Ubiquiti airCube ISP. Reverse engineered protocol for this + * controller: + * * Higher two bits set a mode. Lower six bits are a parameter. + * * Mode: 00 -> set brightness between 0x00 (min) and 0x3F (max) + * * Mode: 01 -> pulsing pattern (min -> max -> min) with an interval. From + * some tests, the period is about (50ms + 102ms * parameter). There is a + * slightly different pattern starting from 0x10 (longer gap between the + * pulses) but the time still follows that calculation. + * * Mode: 10 -> same as 01 but with only a ramp from min to max. Again a + * slight jump in the pattern at 0x10. + * * Mode: 11 -> blinking (off -> 25% -> off -> 25% -> ...) with a period of + * (105ms * parameter) + * NOTE: This driver currently only supports mode 00. + */ + +#include <linux/leds.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/spi/spi.h> +#include <linux/mutex.h> +#include <uapi/linux/uleds.h> + +struct spi_byte_chipdef { + /* SPI byte that will be send to switch the LED off */ + u8 off_value; + /* SPI byte that will be send to switch the LED to maximum brightness */ + u8 max_value; +}; + +struct spi_byte_led { + struct led_classdev ldev; + struct spi_device *spi; + char name[LED_MAX_NAME_SIZE]; + struct mutex mutex; + const struct spi_byte_chipdef *cdef; +}; + +static const struct spi_byte_chipdef ubnt_acb_spi_led_cdef = { + .off_value = 0x0, + .max_value = 0x3F, +}; + +static const struct of_device_id spi_byte_dt_ids[] = { + { .compatible = "ubnt,acb-spi-led", .data = &ubnt_acb_spi_led_cdef }, + {}, +}; + +MODULE_DEVICE_TABLE(of, spi_byte_dt_ids); + +static int spi_byte_brightness_set_blocking(struct led_classdev *dev, + enum led_brightness brightness) +{ + struct spi_byte_led *led = container_of(dev, struct spi_byte_led, ldev); + u8 value; + int ret; + + value = (u8) brightness + led->cdef->off_value; + + mutex_lock(&led->mutex); + ret = spi_write(led->spi, &value, sizeof(value)); + mutex_unlock(&led->mutex); + + return ret; +} + +static int spi_byte_probe(struct spi_device *spi) +{ + const struct of_device_id *of_dev_id; + struct device_node *child; + struct device *dev = &spi->dev; + struct spi_byte_led *led; + const char *name = "leds-spi-byte::"; + const char *state; + int ret; + + of_dev_id = of_match_device(spi_byte_dt_ids, dev); + if (!of_dev_id) + return -EINVAL; + + if (of_get_child_count(dev->of_node) != 1) { + dev_err(dev, "Device must have exactly one LED sub-node."); + return -EINVAL; + } + child = of_get_next_child(dev->of_node, NULL); + + led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + of_property_read_string(child, "label", &name); + strlcpy(led->name, name, sizeof(led->name)); + led->spi = spi; + mutex_init(&led->mutex); + led->cdef = of_dev_id->data; + led->ldev.name = led->name; + led->ldev.brightness = LED_OFF; + led->ldev.max_brightness = led->cdef->max_value - led->cdef->off_value; + led->ldev.brightness_set_blocking = spi_byte_brightness_set_blocking; + + state = of_get_property(child, "default-state", NULL); + if (state) { + if (!strcmp(state, "on")) { + led->ldev.brightness = led->ldev.max_brightness; + } else if (strcmp(state, "off")) { + /* all other cases except "off" */ + dev_err(dev, "default-state can only be 'on' or 'off'"); + return -EINVAL; + } + } + spi_byte_brightness_set_blocking(&led->ldev, + led->ldev.brightness); + + ret = devm_led_classdev_register(&spi->dev, &led->ldev); + if (ret) { + mutex_destroy(&led->mutex); + return ret; + } + spi_set_drvdata(spi, led); + + return 0; +} + +static int spi_byte_remove(struct spi_device *spi) +{ + struct spi_byte_led *led = spi_get_drvdata(spi); + + mutex_destroy(&led->mutex); + + return 0; +} + +static struct spi_driver spi_byte_driver = { + .probe = spi_byte_probe, + .remove = spi_byte_remove, + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = spi_byte_dt_ids, + }, +}; + +module_spi_driver(spi_byte_driver); + +MODULE_AUTHOR("Christian Mauderer <oss@c-mauderer.de>"); +MODULE_DESCRIPTION("single byte SPI LED driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:leds-spi-byte"); diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index c59035e157d1..58be20cae183 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -758,7 +758,7 @@ static int tca6507_probe(struct i2c_client *client, int err; int i = 0; - adapter = to_i2c_adapter(client->dev.parent); + adapter = client->adapter; pdata = dev_get_platdata(&client->dev); if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) diff --git a/drivers/leds/leds-ti-lmu-common.c b/drivers/leds/leds-ti-lmu-common.c new file mode 100644 index 000000000000..adc7293004f1 --- /dev/null +++ b/drivers/leds/leds-ti-lmu-common.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright 2015 Texas Instruments +// Copyright 2018 Sebastian Reichel +// Copyright 2018 Pavel Machek <pavel@ucw.cz> +// TI LMU LED common framework, based on previous work from +// Milo Kim <milo.kim@ti.com> + +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/of_device.h> + +#include <linux/leds-ti-lmu-common.h> + +const static int ramp_table[16] = {2048, 262000, 524000, 1049000, 2090000, + 4194000, 8389000, 16780000, 33550000, 41940000, + 50330000, 58720000, 67110000, 83880000, + 100660000, 117440000}; + +static int ti_lmu_common_update_brightness(struct ti_lmu_bank *lmu_bank, + int brightness) +{ + struct regmap *regmap = lmu_bank->regmap; + u8 reg, val; + int ret; + + /* + * Brightness register update + * + * 11 bit dimming: update LSB bits and write MSB byte. + * MSB brightness should be shifted. + * 8 bit dimming: write MSB byte. + */ + if (lmu_bank->max_brightness == MAX_BRIGHTNESS_11BIT) { + reg = lmu_bank->lsb_brightness_reg; + ret = regmap_update_bits(regmap, reg, + LMU_11BIT_LSB_MASK, + brightness); + if (ret) + return ret; + + val = brightness >> LMU_11BIT_MSB_SHIFT; + } else { + val = brightness; + } + + reg = lmu_bank->msb_brightness_reg; + + return regmap_write(regmap, reg, val); +} + +int ti_lmu_common_set_brightness(struct ti_lmu_bank *lmu_bank, int brightness) +{ + return ti_lmu_common_update_brightness(lmu_bank, brightness); +} +EXPORT_SYMBOL(ti_lmu_common_set_brightness); + +static int ti_lmu_common_convert_ramp_to_index(unsigned int usec) +{ + int size = ARRAY_SIZE(ramp_table); + int i; + + if (usec <= ramp_table[0]) + return 0; + + if (usec > ramp_table[size - 1]) + return size - 1; + + for (i = 1; i < size; i++) { + if (usec == ramp_table[i]) + return i; + + /* Find an approximate index by looking up the table */ + if (usec > ramp_table[i - 1] && usec < ramp_table[i]) { + if (usec - ramp_table[i - 1] < ramp_table[i] - usec) + return i - 1; + else + return i; + } + } + + return -EINVAL; +} + +int ti_lmu_common_set_ramp(struct ti_lmu_bank *lmu_bank) +{ + struct regmap *regmap = lmu_bank->regmap; + u8 ramp, ramp_up, ramp_down; + + if (lmu_bank->ramp_up_usec == 0 && lmu_bank->ramp_down_usec == 0) { + ramp_up = 0; + ramp_down = 0; + } else { + ramp_up = ti_lmu_common_convert_ramp_to_index(lmu_bank->ramp_up_usec); + ramp_down = ti_lmu_common_convert_ramp_to_index(lmu_bank->ramp_down_usec); + } + + if (ramp_up < 0 || ramp_down < 0) + return -EINVAL; + + ramp = (ramp_up << 4) | ramp_down; + + return regmap_write(regmap, lmu_bank->runtime_ramp_reg, ramp); + +} +EXPORT_SYMBOL(ti_lmu_common_set_ramp); + +int ti_lmu_common_get_ramp_params(struct device *dev, + struct fwnode_handle *child, + struct ti_lmu_bank *lmu_data) +{ + int ret; + + ret = fwnode_property_read_u32(child, "ramp-up-us", + &lmu_data->ramp_up_usec); + if (ret) + dev_warn(dev, "ramp-up-us property missing\n"); + + + ret = fwnode_property_read_u32(child, "ramp-down-us", + &lmu_data->ramp_down_usec); + if (ret) + dev_warn(dev, "ramp-down-us property missing\n"); + + return 0; +} +EXPORT_SYMBOL(ti_lmu_common_get_ramp_params); + +int ti_lmu_common_get_brt_res(struct device *dev, struct fwnode_handle *child, + struct ti_lmu_bank *lmu_data) +{ + int ret; + + ret = device_property_read_u32(dev, "ti,brightness-resolution", + &lmu_data->max_brightness); + if (ret) + ret = fwnode_property_read_u32(child, + "ti,brightness-resolution", + &lmu_data->max_brightness); + if (lmu_data->max_brightness <= 0) { + lmu_data->max_brightness = MAX_BRIGHTNESS_8BIT; + return ret; + } + + if (lmu_data->max_brightness > MAX_BRIGHTNESS_11BIT) + lmu_data->max_brightness = MAX_BRIGHTNESS_11BIT; + + + return 0; +} +EXPORT_SYMBOL(ti_lmu_common_get_brt_res); + +MODULE_DESCRIPTION("TI LMU common LED framework"); +MODULE_AUTHOR("Sebastian Reichel"); +MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("ti-lmu-led-common"); diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c index c5798b92e4d3..082df7f1dd90 100644 --- a/drivers/leds/leds-wm831x-status.c +++ b/drivers/leds/leds-wm831x-status.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED driver for WM831x status LEDs * * Copyright(C) 2009 Wolfson Microelectronics PLC. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c index e1e4e9d0b8b1..8f243c413723 100644 --- a/drivers/leds/leds-wm8350.c +++ b/drivers/leds/leds-wm8350.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED driver for WM8350 driven LEDS. * * Copyright(C) 2007, 2008 Wolfson Microelectronics PLC. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/leds/leds-wrap.c b/drivers/leds/leds-wrap.c index 473fb6b97ed4..794697e16068 100644 --- a/drivers/leds/leds-wrap.c +++ b/drivers/leds/leds-wrap.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LEDs driver for PCEngines WRAP * * Copyright (C) 2006 Kristian Kielhofner <kris@krisk.org> * * Based on leds-net48xx.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h index 7d38e6b9a740..47b229469069 100644 --- a/drivers/leds/leds.h +++ b/drivers/leds/leds.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * LED Core * * Copyright 2005 Openedhand Ltd. * * Author: Richard Purdie <rpurdie@openedhand.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef __LEDS_H_INCLUDED #define __LEDS_H_INCLUDED diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index 7fa9d174a40c..ce9429ca6dde 100644 --- a/drivers/leds/trigger/Kconfig +++ b/drivers/leds/trigger/Kconfig @@ -15,7 +15,7 @@ config LEDS_TRIGGER_TIMER This allows LEDs to be controlled by a programmable timer via sysfs. Some LED hardware can be programmed to start blinking the LED without any further software interaction. - For more details read Documentation/leds/leds-class.txt. + For more details read Documentation/leds/leds-class.rst. If unsure, say Y. diff --git a/drivers/leds/trigger/ledtrig-activity.c b/drivers/leds/trigger/ledtrig-activity.c index bcbf41c90c30..6a72b7e13719 100644 --- a/drivers/leds/trigger/ledtrig-activity.c +++ b/drivers/leds/trigger/ledtrig-activity.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Activity LED trigger * * Copyright (C) 2017 Willy Tarreau <w@1wt.eu> * Partially based on Atsushi Nemoto's ledtrig-heartbeat.c. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> @@ -73,7 +70,7 @@ static void led_activity_function(struct timer_list *t) * down to 16us, ensuring we won't overflow 32-bit computations below * even up to 3k CPUs, while keeping divides cheap on smaller systems. */ - curr_boot = ktime_get_boot_ns() * cpus; + curr_boot = ktime_get_boottime_ns() * cpus; diff_boot = (curr_boot - activity_data->last_boot) >> 16; diff_used = (curr_used - activity_data->last_used) >> 16; activity_data->last_boot = curr_boot; diff --git a/drivers/leds/trigger/ledtrig-backlight.c b/drivers/leds/trigger/ledtrig-backlight.c index c2b57beef718..487577d22cfc 100644 --- a/drivers/leds/trigger/ledtrig-backlight.c +++ b/drivers/leds/trigger/ledtrig-backlight.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Backlight emulation LED trigger * * Copyright 2008 (C) Rodolfo Giometti <giometti@linux.it> * Copyright 2008 (C) Eurotech S.p.A. <info@eurotech.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/leds/trigger/ledtrig-camera.c b/drivers/leds/trigger/ledtrig-camera.c index 091a09a20c58..ab1c410872ff 100644 --- a/drivers/leds/trigger/ledtrig-camera.c +++ b/drivers/leds/trigger/ledtrig-camera.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Camera Flash and Torch On/Off Trigger * @@ -6,10 +7,6 @@ * Copyright 2013 Texas Instruments * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/leds/trigger/ledtrig-cpu.c b/drivers/leds/trigger/ledtrig-cpu.c index 66a626091936..869976d1b734 100644 --- a/drivers/leds/trigger/ledtrig-cpu.c +++ b/drivers/leds/trigger/ledtrig-cpu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ledtrig-cpu.c - LED trigger based on CPU activity * @@ -12,11 +13,6 @@ * * Copyright 2011 Linus Walleij <linus.walleij@linaro.org> * Copyright 2011 - 2012 Bryan Wu <bryan.wu@canonical.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/leds/trigger/ledtrig-default-on.c b/drivers/leds/trigger/ledtrig-default-on.c index 7f6d9219711e..8207f85eceb1 100644 --- a/drivers/leds/trigger/ledtrig-default-on.c +++ b/drivers/leds/trigger/ledtrig-default-on.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED Kernel Default ON Trigger * * Copyright 2008 Nick Forbes <nick.forbes@incepta.com> * * Based on Richard Purdie's ledtrig-timer.c. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/leds/trigger/ledtrig-disk.c b/drivers/leds/trigger/ledtrig-disk.c index 9816b0d60270..0741910785bb 100644 --- a/drivers/leds/trigger/ledtrig-disk.c +++ b/drivers/leds/trigger/ledtrig-disk.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED Disk Activity Trigger * * Copyright 2006 Openedhand Ltd. * * Author: Richard Purdie <rpurdie@openedhand.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/leds/trigger/ledtrig-gpio.c b/drivers/leds/trigger/ledtrig-gpio.c index ed0db8ed825f..33cc99a1a16a 100644 --- a/drivers/leds/trigger/ledtrig-gpio.c +++ b/drivers/leds/trigger/ledtrig-gpio.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ledtrig-gio.c - LED Trigger Based on GPIO events * * Copyright 2009 Felipe Balbi <me@felipebalbi.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/leds/trigger/ledtrig-heartbeat.c b/drivers/leds/trigger/ledtrig-heartbeat.c index 7a2b12e19329..36b6709afe9f 100644 --- a/drivers/leds/trigger/ledtrig-heartbeat.c +++ b/drivers/leds/trigger/ledtrig-heartbeat.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED Heartbeat Trigger * @@ -5,10 +6,6 @@ * * Based on Richard Purdie's ledtrig-timer.c and some arch's * CONFIG_HEARTBEAT code. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/leds/trigger/ledtrig-mtd.c b/drivers/leds/trigger/ledtrig-mtd.c index 99b5b0a4d826..8fa763c2269b 100644 --- a/drivers/leds/trigger/ledtrig-mtd.c +++ b/drivers/leds/trigger/ledtrig-mtd.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED MTD trigger * @@ -8,11 +9,6 @@ * Copyright 2006 Openedhand Ltd. * * Author: Richard Purdie <rpurdie@openedhand.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/leds/trigger/ledtrig-oneshot.c b/drivers/leds/trigger/ledtrig-oneshot.c index 8808f0ad7339..bee3bd452abf 100644 --- a/drivers/leds/trigger/ledtrig-oneshot.c +++ b/drivers/leds/trigger/ledtrig-oneshot.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * One-shot LED Trigger * * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com> * * Based on ledtrig-timer.c by Richard Purdie <rpurdie@openedhand.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/leds/trigger/ledtrig-panic.c b/drivers/leds/trigger/ledtrig-panic.c index d735526b9db4..5751cd032f9d 100644 --- a/drivers/leds/trigger/ledtrig-panic.c +++ b/drivers/leds/trigger/ledtrig-panic.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Kernel Panic LED Trigger * * Copyright 2016 Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/leds/trigger/ledtrig-timer.c b/drivers/leds/trigger/ledtrig-timer.c index 427fc3c303d5..34a68604c46c 100644 --- a/drivers/leds/trigger/ledtrig-timer.c +++ b/drivers/leds/trigger/ledtrig-timer.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LED Kernel Timer Trigger * * Copyright 2005-2006 Openedhand Ltd. * * Author: Richard Purdie <rpurdie@openedhand.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/leds/trigger/ledtrig-transient.c b/drivers/leds/trigger/ledtrig-transient.c index a80bb82aacc2..80635183fac8 100644 --- a/drivers/leds/trigger/ledtrig-transient.c +++ b/drivers/leds/trigger/ledtrig-transient.c @@ -3,7 +3,7 @@ // LED Kernel Transient Trigger // // Transient trigger allows one shot timer activation. Please refer to -// Documentation/leds/ledtrig-transient.txt for details +// Documentation/leds/ledtrig-transient.rst for details // Copyright (C) 2012 Shuah Khan <shuahkhan@gmail.com> // // Based on Richard Purdie's ledtrig-timer.c and Atsushi Nemoto's diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 7d555b110ecd..a600934fdd9c 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -478,7 +478,7 @@ static void __nvm_remove_target(struct nvm_target *t, bool graceful) */ static int nvm_remove_tgt(struct nvm_ioctl_remove *remove) { - struct nvm_target *t; + struct nvm_target *t = NULL; struct nvm_dev *dev; down_read(&nvm_lock); diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c index 773537804319..f546e6f28b8a 100644 --- a/drivers/lightnvm/pblk-core.c +++ b/drivers/lightnvm/pblk-core.c @@ -323,14 +323,16 @@ void pblk_free_rqd(struct pblk *pblk, struct nvm_rq *rqd, int type) void pblk_bio_free_pages(struct pblk *pblk, struct bio *bio, int off, int nr_pages) { - struct bio_vec bv; - int i; - - WARN_ON(off + nr_pages != bio->bi_vcnt); - - for (i = off; i < nr_pages + off; i++) { - bv = bio->bi_io_vec[i]; - mempool_free(bv.bv_page, &pblk->page_bio_pool); + struct bio_vec *bv; + struct page *page; + int i, e, nbv = 0; + + for (i = 0; i < bio->bi_vcnt; i++) { + bv = &bio->bi_io_vec[i]; + page = bv->bv_page; + for (e = 0; e < bv->bv_len; e += PBLK_EXPOSED_PAGE_SIZE, nbv++) + if (nbv >= off) + mempool_free(page++, &pblk->page_bio_pool); } } diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index 3940e2a032f7..4134e580f786 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c @@ -1,18 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * RackMac vu-meter driver * * (c) Copyright 2006 Benjamin Herrenschmidt, IBM Corp. * <benh@kernel.crashing.org> * - * Released under the term of the GNU GPL v2. - * * Support the CPU-meter LEDs of the Xserve G5 * * TODO: Implement PWM to do variable intensity and provide userland * interface for fun. Also, the CPU-meter could be made nicer by being * a bit less "immediate" but giving instead a more average load over * time. Patches welcome :-) - * */ #undef DEBUG diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index 6a844125cf2d..01e298f620f3 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PowerMac G5 SMU driver * * Copyright 2004 J. Mayer <l_indien@magic.fr> * Copyright 2005 Benjamin Herrenschmidt, IBM Corp. - * - * Released under the term of the GNU GPL v2. */ /* diff --git a/drivers/macintosh/windfarm.h b/drivers/macintosh/windfarm.h index 901c42f71b5a..5eb480d84e9a 100644 --- a/drivers/macintosh/windfarm.h +++ b/drivers/macintosh/windfarm.h @@ -1,10 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Windfarm PowerMac thermal control. * * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. * <benh@kernel.crashing.org> - * - * Released under the term of the GNU GPL v2. */ #ifndef __WINDFARM_H__ diff --git a/drivers/macintosh/windfarm_ad7417_sensor.c b/drivers/macintosh/windfarm_ad7417_sensor.c index 7c28b71246c9..125605987b44 100644 --- a/drivers/macintosh/windfarm_ad7417_sensor.c +++ b/drivers/macintosh/windfarm_ad7417_sensor.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. AD7417 sensors * * Copyright 2012 Benjamin Herrenschmidt, IBM Corp. - * - * Released under the term of the GNU GPL v2. */ #include <linux/types.h> diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index 5e013d781a74..77612303841e 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. Core * * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. * <benh@kernel.crashing.org> * - * Released under the term of the GNU GPL v2. - * * This core code tracks the list of sensors & controls, register * clients, and holds the kernel thread used for control. * diff --git a/drivers/macintosh/windfarm_fcu_controls.c b/drivers/macintosh/windfarm_fcu_controls.c index 629f19875d7f..3c971297b6dc 100644 --- a/drivers/macintosh/windfarm_fcu_controls.c +++ b/drivers/macintosh/windfarm_fcu_controls.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. FCU fan control * * Copyright 2012 Benjamin Herrenschmidt, IBM Corp. - * - * Released under the term of the GNU GPL v2. */ #undef DEBUG diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index 6cdfe714901d..282c28a17ea1 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. LM75 sensor * * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. * <benh@kernel.crashing.org> - * - * Released under the term of the GNU GPL v2. */ #include <linux/types.h> diff --git a/drivers/macintosh/windfarm_lm87_sensor.c b/drivers/macintosh/windfarm_lm87_sensor.c index 09724acd70b6..e44525b19071 100644 --- a/drivers/macintosh/windfarm_lm87_sensor.c +++ b/drivers/macintosh/windfarm_lm87_sensor.c @@ -1,10 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. LM87 sensor * * Copyright 2012 Benjamin Herrenschmidt, IBM Corp. - * - * Released under the term of the GNU GPL v2. - * */ #include <linux/types.h> diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index 6ad035e13c08..e666cc020683 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. MAX6690 sensor. * * Copyright (C) 2005 Paul Mackerras, IBM Corp. <paulus@samba.org> - * - * Use and redistribute under the terms of the GNU GPL v2. */ #include <linux/types.h> #include <linux/errno.h> diff --git a/drivers/macintosh/windfarm_mpu.h b/drivers/macintosh/windfarm_mpu.h index 046edc8c2ec5..157ce6e3f32e 100644 --- a/drivers/macintosh/windfarm_mpu.h +++ b/drivers/macintosh/windfarm_mpu.h @@ -1,9 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Windfarm PowerMac thermal control * * Copyright 2012 Benjamin Herrenschmidt, IBM Corp. - * - * Released under the term of the GNU GPL v2. */ #ifndef __WINDFARM_MPU_H diff --git a/drivers/macintosh/windfarm_pid.c b/drivers/macintosh/windfarm_pid.c index f10efb28cae4..bb31b0e93fad 100644 --- a/drivers/macintosh/windfarm_pid.c +++ b/drivers/macintosh/windfarm_pid.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. Generic PID helpers * * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. * <benh@kernel.crashing.org> - * - * Released under the term of the GNU GPL v2. */ #include <linux/types.h> diff --git a/drivers/macintosh/windfarm_pid.h b/drivers/macintosh/windfarm_pid.h index bbccc22d42b8..83f747dbeafc 100644 --- a/drivers/macintosh/windfarm_pid.h +++ b/drivers/macintosh/windfarm_pid.h @@ -1,11 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Windfarm PowerMac thermal control. Generic PID helpers * * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. * <benh@kernel.crashing.org> * - * Released under the term of the GNU GPL v2. - * * This is a pair of generic PID helpers that can be used by * control loops. One is the basic PID implementation, the * other one is more specifically tailored to the loops used diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c index fec91db1142e..4150301a89a5 100644 --- a/drivers/macintosh/windfarm_pm112.c +++ b/drivers/macintosh/windfarm_pm112.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. * Control loops for machines with SMU and PPC970MP processors. * * Copyright (C) 2005 Paul Mackerras, IBM Corp. <paulus@samba.org> * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp. - * - * Use and redistribute under the terms of the GNU GPL v2. */ #include <linux/types.h> #include <linux/errno.h> diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c index 97634e030991..ab467b9c31be 100644 --- a/drivers/macintosh/windfarm_pm121.c +++ b/drivers/macintosh/windfarm_pm121.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. iMac G5 iSight * @@ -6,14 +7,9 @@ * Bits & pieces from windfarm_pm81.c by (c) Copyright 2005 Benjamin * Herrenschmidt, IBM Corp. <benh@kernel.crashing.org> * - * Released under the term of the GNU GPL v2. - * - * - * * PowerMac12,1 * ============ * - * * The algorithm used is the PID control algorithm, used the same way * the published Darwin code does, using the same values that are * present in the Darwin 8.10 snapshot property lists (note however @@ -25,7 +21,6 @@ * controls with a tiny difference. The control-ids of hard-drive-fan * and cpu-fan is swapped. * - * * Target Correction : * * controls have a target correction calculated as : @@ -63,7 +58,6 @@ * offset : -15650652 * slope : 1565065 * - * * Target rubber-banding : * * Some controls have a target correction which depends on another @@ -76,7 +70,6 @@ * * new_target = max (new_target, new_min >> 16) * - * * # model_id : 2 * control : cpu-fan * ref : optical-drive-fan @@ -89,12 +82,10 @@ * offset : -32768000 * slope : 65536 * - * * In order to have the moste efficient correction with those * dependencies, we must trigger HD loop before OD loop before CPU * loop. * - * * The various control loops found in Darwin config file are: * * HD Fan control loop. @@ -191,12 +182,10 @@ * sensors : cpu-temp, cpu-power * PID params : from SDB partition * - * * CPU Slew control loop. * * control : cpufreq-clamp * sensor : cpu-temp - * */ #undef DEBUG diff --git a/drivers/macintosh/windfarm_pm72.c b/drivers/macintosh/windfarm_pm72.c index 833021508c05..c5da0fc24884 100644 --- a/drivers/macintosh/windfarm_pm72.c +++ b/drivers/macintosh/windfarm_pm72.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. * Control loops for PowerMac7,2 and 7,3 * * Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp. - * - * Use and redistribute under the terms of the GNU GPL v2. */ #include <linux/types.h> #include <linux/errno.h> diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c index 346c91744442..82c67a4ee5f7 100644 --- a/drivers/macintosh/windfarm_pm81.c +++ b/drivers/macintosh/windfarm_pm81.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. iMac G5 * * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. * <benh@kernel.crashing.org> * - * Released under the term of the GNU GPL v2. - * * The algorithm used is the PID control algorithm, used the same * way the published Darwin code does, using the same values that * are present in the Darwin 8.2 snapshot property lists (note however @@ -90,7 +89,6 @@ * from the SDB partition. If we ever end up with actually slewing the system * clock and thus changing operating points, we'll have to find a way to * communicate with the CPU freq driver; - * */ #include <linux/types.h> diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c index a8a47c62a74b..3f346af9e3f7 100644 --- a/drivers/macintosh/windfarm_pm91.c +++ b/drivers/macintosh/windfarm_pm91.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. SMU based 1 CPU desktop control loops * * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. * <benh@kernel.crashing.org> * - * Released under the term of the GNU GPL v2. - * * The algorithm used is the PID control algorithm, used the same * way the published Darwin code does, using the same values that * are present in the Darwin 8.2 snapshot property lists (note however diff --git a/drivers/macintosh/windfarm_rm31.c b/drivers/macintosh/windfarm_rm31.c index 9ce87cc0597f..8456eb67184b 100644 --- a/drivers/macintosh/windfarm_rm31.c +++ b/drivers/macintosh/windfarm_rm31.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. * Control loops for RackMack3,1 (Xserve G5) * * Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp. - * - * Use and redistribute under the terms of the GNU GPL v2. */ #include <linux/types.h> #include <linux/errno.h> diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c index 2cb9652a9998..79cb1ad09bfd 100644 --- a/drivers/macintosh/windfarm_smu_controls.c +++ b/drivers/macintosh/windfarm_smu_controls.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. SMU based controls * * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. * <benh@kernel.crashing.org> - * - * Released under the term of the GNU GPL v2. */ #include <linux/types.h> diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c index a58f6733381a..3e6059eaa138 100644 --- a/drivers/macintosh/windfarm_smu_sensors.c +++ b/drivers/macintosh/windfarm_smu_sensors.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Windfarm PowerMac thermal control. SMU based sensors * * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. * <benh@kernel.crashing.org> - * - * Released under the term of the GNU GPL v2. */ #include <linux/types.h> diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index ccf3d62af7e7..8513c42f7091 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ /* diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 38d9df3fb199..f4b1950d35f3 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Mailbox: Common code for Mailbox controllers and users * * Copyright (C) 2013-2014 Linaro Ltd. * Author: Jassi Brar <jassisinghbrar@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/interrupt.h> diff --git a/drivers/mailbox/mailbox.h b/drivers/mailbox/mailbox.h index 456ba68513bb..4e3cc4426513 100644 --- a/drivers/mailbox/mailbox.h +++ b/drivers/mailbox/mailbox.h @@ -1,8 +1,4 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef __MAILBOX_H #define __MAILBOX_H diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c index f8986effcb50..6f776823b9ba 100644 --- a/drivers/md/bcache/alloc.c +++ b/drivers/md/bcache/alloc.c @@ -393,6 +393,11 @@ long bch_bucket_alloc(struct cache *ca, unsigned int reserve, bool wait) struct bucket *b; long r; + + /* No allocation if CACHE_SET_IO_DISABLE bit is set */ + if (unlikely(test_bit(CACHE_SET_IO_DISABLE, &ca->set->flags))) + return -1; + /* fastpath */ if (fifo_pop(&ca->free[RESERVE_NONE], r) || fifo_pop(&ca->free[reserve], r)) @@ -484,6 +489,10 @@ int __bch_bucket_alloc_set(struct cache_set *c, unsigned int reserve, { int i; + /* No allocation if CACHE_SET_IO_DISABLE bit is set */ + if (unlikely(test_bit(CACHE_SET_IO_DISABLE, &c->flags))) + return -1; + lockdep_assert_held(&c->bucket_lock); BUG_ON(!n || n > c->caches_loaded || n > MAX_CACHES_PER_SET); diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index fdf75352e16a..013e35a9e317 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -705,8 +705,8 @@ struct cache_set { atomic_long_t writeback_keys_failed; atomic_long_t reclaim; + atomic_long_t reclaimed_journal_buckets; atomic_long_t flush_write; - atomic_long_t retry_flush_write; enum { ON_ERROR_UNREGISTER, @@ -726,8 +726,6 @@ struct cache_set { #define BUCKET_HASH_BITS 12 struct hlist_head bucket_hash[1 << BUCKET_HASH_BITS]; - - DECLARE_HEAP(struct btree *, flush_btree); }; struct bbio { @@ -1006,7 +1004,7 @@ int bch_flash_dev_create(struct cache_set *c, uint64_t size); int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, uint8_t *set_uuid); void bch_cached_dev_detach(struct cached_dev *dc); -void bch_cached_dev_run(struct cached_dev *dc); +int bch_cached_dev_run(struct cached_dev *dc); void bcache_device_stop(struct bcache_device *d); void bch_cache_set_unregister(struct cache_set *c); diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c index 268f1b685084..08768796b543 100644 --- a/drivers/md/bcache/bset.c +++ b/drivers/md/bcache/bset.c @@ -347,22 +347,19 @@ EXPORT_SYMBOL(bch_btree_keys_alloc); void bch_btree_keys_init(struct btree_keys *b, const struct btree_keys_ops *ops, bool *expensive_debug_checks) { - unsigned int i; - b->ops = ops; b->expensive_debug_checks = expensive_debug_checks; b->nsets = 0; b->last_set_unwritten = 0; - /* XXX: shouldn't be needed */ - for (i = 0; i < MAX_BSETS; i++) - b->set[i].size = 0; /* - * Second loop starts at 1 because b->keys[0]->data is the memory we - * allocated + * struct btree_keys in embedded in struct btree, and struct + * bset_tree is embedded into struct btree_keys. They are all + * initialized as 0 by kzalloc() in mca_bucket_alloc(), and + * b->set[0].data is allocated in bch_btree_keys_alloc(), so we + * don't have to initiate b->set[].size and b->set[].data here + * any more. */ - for (i = 1; i < MAX_BSETS; i++) - b->set[i].data = NULL; } EXPORT_SYMBOL(bch_btree_keys_init); @@ -970,45 +967,25 @@ static struct bset_search_iter bset_search_tree(struct bset_tree *t, unsigned int inorder, j, n = 1; do { - /* - * A bit trick here. - * If p < t->size, (int)(p - t->size) is a minus value and - * the most significant bit is set, right shifting 31 bits - * gets 1. If p >= t->size, the most significant bit is - * not set, right shifting 31 bits gets 0. - * So the following 2 lines equals to - * if (p >= t->size) - * p = 0; - * but a branch instruction is avoided. - */ unsigned int p = n << 4; - p &= ((int) (p - t->size)) >> 31; - - prefetch(&t->tree[p]); + if (p < t->size) + prefetch(&t->tree[p]); j = n; f = &t->tree[j]; - /* - * Similar bit trick, use subtract operation to avoid a branch - * instruction. - * - * n = (f->mantissa > bfloat_mantissa()) - * ? j * 2 - * : j * 2 + 1; - * - * We need to subtract 1 from f->mantissa for the sign bit trick - * to work - that's done in make_bfloat() - */ - if (likely(f->exponent != 127)) - n = j * 2 + (((unsigned int) - (f->mantissa - - bfloat_mantissa(search, f))) >> 31); - else - n = (bkey_cmp(tree_to_bkey(t, j), search) > 0) - ? j * 2 - : j * 2 + 1; + if (likely(f->exponent != 127)) { + if (f->mantissa >= bfloat_mantissa(search, f)) + n = j * 2; + else + n = j * 2 + 1; + } else { + if (bkey_cmp(tree_to_bkey(t, j), search) > 0) + n = j * 2; + else + n = j * 2 + 1; + } } while (n < t->size); inorder = to_inorder(j, t); diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 773f5fdad25f..ba434d9ac720 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -35,7 +35,7 @@ #include <linux/rcupdate.h> #include <linux/sched/clock.h> #include <linux/rculist.h> - +#include <linux/delay.h> #include <trace/events/bcache.h> /* @@ -613,6 +613,10 @@ static void mca_data_alloc(struct btree *b, struct bkey *k, gfp_t gfp) static struct btree *mca_bucket_alloc(struct cache_set *c, struct bkey *k, gfp_t gfp) { + /* + * kzalloc() is necessary here for initialization, + * see code comments in bch_btree_keys_init(). + */ struct btree *b = kzalloc(sizeof(struct btree), gfp); if (!b) @@ -655,7 +659,25 @@ static int mca_reap(struct btree *b, unsigned int min_order, bool flush) up(&b->io_mutex); } +retry: + /* + * BTREE_NODE_dirty might be cleared in btree_flush_btree() by + * __bch_btree_node_write(). To avoid an extra flush, acquire + * b->write_lock before checking BTREE_NODE_dirty bit. + */ mutex_lock(&b->write_lock); + /* + * If this btree node is selected in btree_flush_write() by journal + * code, delay and retry until the node is flushed by journal code + * and BTREE_NODE_journal_flush bit cleared by btree_flush_write(). + */ + if (btree_node_journal_flush(b)) { + pr_debug("bnode %p is flushing by journal, retry", b); + mutex_unlock(&b->write_lock); + udelay(1); + goto retry; + } + if (btree_node_dirty(b)) __bch_btree_node_write(b, &cl); mutex_unlock(&b->write_lock); @@ -778,10 +800,15 @@ void bch_btree_cache_free(struct cache_set *c) while (!list_empty(&c->btree_cache)) { b = list_first_entry(&c->btree_cache, struct btree, list); - if (btree_node_dirty(b)) + /* + * This function is called by cache_set_free(), no I/O + * request on cache now, it is unnecessary to acquire + * b->write_lock before clearing BTREE_NODE_dirty anymore. + */ + if (btree_node_dirty(b)) { btree_complete_write(b, btree_current_write(b)); - clear_bit(BTREE_NODE_dirty, &b->flags); - + clear_bit(BTREE_NODE_dirty, &b->flags); + } mca_data_free(b); } @@ -1067,11 +1094,25 @@ static void btree_node_free(struct btree *b) BUG_ON(b == b->c->root); +retry: mutex_lock(&b->write_lock); + /* + * If the btree node is selected and flushing in btree_flush_write(), + * delay and retry until the BTREE_NODE_journal_flush bit cleared, + * then it is safe to free the btree node here. Otherwise this btree + * node will be in race condition. + */ + if (btree_node_journal_flush(b)) { + mutex_unlock(&b->write_lock); + pr_debug("bnode %p journal_flush set, retry", b); + udelay(1); + goto retry; + } - if (btree_node_dirty(b)) + if (btree_node_dirty(b)) { btree_complete_write(b, btree_current_write(b)); - clear_bit(BTREE_NODE_dirty, &b->flags); + clear_bit(BTREE_NODE_dirty, &b->flags); + } mutex_unlock(&b->write_lock); diff --git a/drivers/md/bcache/btree.h b/drivers/md/bcache/btree.h index d1c72ef64edf..76cfd121a486 100644 --- a/drivers/md/bcache/btree.h +++ b/drivers/md/bcache/btree.h @@ -158,11 +158,13 @@ enum btree_flags { BTREE_NODE_io_error, BTREE_NODE_dirty, BTREE_NODE_write_idx, + BTREE_NODE_journal_flush, }; BTREE_FLAG(io_error); BTREE_FLAG(dirty); BTREE_FLAG(write_idx); +BTREE_FLAG(journal_flush); static inline struct btree_write *btree_current_write(struct btree *b) { diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index c25097968319..4d93f07f63e5 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -58,6 +58,18 @@ void bch_count_backing_io_errors(struct cached_dev *dc, struct bio *bio) WARN_ONCE(!dc, "NULL pointer of struct cached_dev"); + /* + * Read-ahead requests on a degrading and recovering md raid + * (e.g. raid6) device might be failured immediately by md + * raid code, which is not a real hardware media failure. So + * we shouldn't count failed REQ_RAHEAD bio to dc->io_errors. + */ + if (bio->bi_opf & REQ_RAHEAD) { + pr_warn_ratelimited("%s: Read-ahead I/O failed on backing device, ignore", + dc->backing_dev_name); + return; + } + errors = atomic_add_return(1, &dc->io_errors); if (errors < dc->error_limit) pr_err("%s: IO error on backing device, unrecoverable", diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c index 12dae9348147..be2a2a201603 100644 --- a/drivers/md/bcache/journal.c +++ b/drivers/md/bcache/journal.c @@ -100,6 +100,20 @@ reread: left = ca->sb.bucket_size - offset; blocks = set_blocks(j, block_bytes(ca->set)); + /* + * Nodes in 'list' are in linear increasing order of + * i->j.seq, the node on head has the smallest (oldest) + * journal seq, the node on tail has the biggest + * (latest) journal seq. + */ + + /* + * Check from the oldest jset for last_seq. If + * i->j.seq < j->last_seq, it means the oldest jset + * in list is expired and useless, remove it from + * this list. Otherwise, j is a condidate jset for + * further following checks. + */ while (!list_empty(list)) { i = list_first_entry(list, struct journal_replay, list); @@ -109,13 +123,22 @@ reread: left = ca->sb.bucket_size - offset; kfree(i); } + /* iterate list in reverse order (from latest jset) */ list_for_each_entry_reverse(i, list, list) { if (j->seq == i->j.seq) goto next_set; + /* + * if j->seq is less than any i->j.last_seq + * in list, j is an expired and useless jset. + */ if (j->seq < i->j.last_seq) goto next_set; + /* + * 'where' points to first jset in list which + * is elder then j. + */ if (j->seq > i->j.seq) { where = &i->list; goto add; @@ -129,10 +152,12 @@ add: if (!i) return -ENOMEM; memcpy(&i->j, j, bytes); + /* Add to the location after 'where' points to */ list_add(&i->list, where); ret = 1; - ja->seq[bucket_index] = j->seq; + if (j->seq > ja->seq[bucket_index]) + ja->seq[bucket_index] = j->seq; next_set: offset += blocks * ca->sb.block_size; len -= blocks * ca->sb.block_size; @@ -268,7 +293,7 @@ bsearch: struct journal_replay, list)->j.seq; - return ret; + return 0; #undef read_bucket } @@ -391,60 +416,90 @@ err: } /* Journalling */ -#define journal_max_cmp(l, r) \ - (fifo_idx(&c->journal.pin, btree_current_write(l)->journal) < \ - fifo_idx(&(c)->journal.pin, btree_current_write(r)->journal)) -#define journal_min_cmp(l, r) \ - (fifo_idx(&c->journal.pin, btree_current_write(l)->journal) > \ - fifo_idx(&(c)->journal.pin, btree_current_write(r)->journal)) static void btree_flush_write(struct cache_set *c) { - /* - * Try to find the btree node with that references the oldest journal - * entry, best is our current candidate and is locked if non NULL: - */ - struct btree *b; - int i; + struct btree *b, *t, *btree_nodes[BTREE_FLUSH_NR]; + unsigned int i, n; + + if (c->journal.btree_flushing) + return; + + spin_lock(&c->journal.flush_write_lock); + if (c->journal.btree_flushing) { + spin_unlock(&c->journal.flush_write_lock); + return; + } + c->journal.btree_flushing = true; + spin_unlock(&c->journal.flush_write_lock); atomic_long_inc(&c->flush_write); + memset(btree_nodes, 0, sizeof(btree_nodes)); + n = 0; -retry: - spin_lock(&c->journal.lock); - if (heap_empty(&c->flush_btree)) { - for_each_cached_btree(b, c, i) - if (btree_current_write(b)->journal) { - if (!heap_full(&c->flush_btree)) - heap_add(&c->flush_btree, b, - journal_max_cmp); - else if (journal_max_cmp(b, - heap_peek(&c->flush_btree))) { - c->flush_btree.data[0] = b; - heap_sift(&c->flush_btree, 0, - journal_max_cmp); - } - } + mutex_lock(&c->bucket_lock); + list_for_each_entry_safe_reverse(b, t, &c->btree_cache, list) { + if (btree_node_journal_flush(b)) + pr_err("BUG: flush_write bit should not be set here!"); + + mutex_lock(&b->write_lock); - for (i = c->flush_btree.used / 2 - 1; i >= 0; --i) - heap_sift(&c->flush_btree, i, journal_min_cmp); + if (!btree_node_dirty(b)) { + mutex_unlock(&b->write_lock); + continue; + } + + if (!btree_current_write(b)->journal) { + mutex_unlock(&b->write_lock); + continue; + } + + set_btree_node_journal_flush(b); + + mutex_unlock(&b->write_lock); + + btree_nodes[n++] = b; + if (n == BTREE_FLUSH_NR) + break; } + mutex_unlock(&c->bucket_lock); - b = NULL; - heap_pop(&c->flush_btree, b, journal_min_cmp); - spin_unlock(&c->journal.lock); + for (i = 0; i < n; i++) { + b = btree_nodes[i]; + if (!b) { + pr_err("BUG: btree_nodes[%d] is NULL", i); + continue; + } + + /* safe to check without holding b->write_lock */ + if (!btree_node_journal_flush(b)) { + pr_err("BUG: bnode %p: journal_flush bit cleaned", b); + continue; + } - if (b) { mutex_lock(&b->write_lock); if (!btree_current_write(b)->journal) { + clear_bit(BTREE_NODE_journal_flush, &b->flags); + mutex_unlock(&b->write_lock); + pr_debug("bnode %p: written by others", b); + continue; + } + + if (!btree_node_dirty(b)) { + clear_bit(BTREE_NODE_journal_flush, &b->flags); mutex_unlock(&b->write_lock); - /* We raced */ - atomic_long_inc(&c->retry_flush_write); - goto retry; + pr_debug("bnode %p: dirty bit cleaned by others", b); + continue; } __bch_btree_node_write(b, NULL); + clear_bit(BTREE_NODE_journal_flush, &b->flags); mutex_unlock(&b->write_lock); } + + spin_lock(&c->journal.flush_write_lock); + c->journal.btree_flushing = false; + spin_unlock(&c->journal.flush_write_lock); } #define last_seq(j) ((j)->seq - fifo_used(&(j)->pin) + 1) @@ -559,6 +614,7 @@ static void journal_reclaim(struct cache_set *c) k->ptr[n++] = MAKE_PTR(0, bucket_to_sector(c, ca->sb.d[ja->cur_idx]), ca->sb.nr_this_dev); + atomic_long_inc(&c->reclaimed_journal_buckets); } if (n) { @@ -811,6 +867,10 @@ atomic_t *bch_journal(struct cache_set *c, struct journal_write *w; atomic_t *ret; + /* No journaling if CACHE_SET_IO_DISABLE set already */ + if (unlikely(test_bit(CACHE_SET_IO_DISABLE, &c->flags))) + return NULL; + if (!CACHE_SYNC(&c->sb)) return NULL; @@ -855,7 +915,6 @@ void bch_journal_free(struct cache_set *c) free_pages((unsigned long) c->journal.w[1].data, JSET_BITS); free_pages((unsigned long) c->journal.w[0].data, JSET_BITS); free_fifo(&c->journal.pin); - free_heap(&c->flush_btree); } int bch_journal_alloc(struct cache_set *c) @@ -863,6 +922,7 @@ int bch_journal_alloc(struct cache_set *c) struct journal *j = &c->journal; spin_lock_init(&j->lock); + spin_lock_init(&j->flush_write_lock); INIT_DELAYED_WORK(&j->work, journal_write_work); c->journal_delay_ms = 100; @@ -870,8 +930,7 @@ int bch_journal_alloc(struct cache_set *c) j->w[0].c = c; j->w[1].c = c; - if (!(init_heap(&c->flush_btree, 128, GFP_KERNEL)) || - !(init_fifo(&j->pin, JOURNAL_PIN, GFP_KERNEL)) || + if (!(init_fifo(&j->pin, JOURNAL_PIN, GFP_KERNEL)) || !(j->w[0].data = (void *) __get_free_pages(GFP_KERNEL, JSET_BITS)) || !(j->w[1].data = (void *) __get_free_pages(GFP_KERNEL, JSET_BITS))) return -ENOMEM; diff --git a/drivers/md/bcache/journal.h b/drivers/md/bcache/journal.h index 66f0facff84b..f2ea34d5f431 100644 --- a/drivers/md/bcache/journal.h +++ b/drivers/md/bcache/journal.h @@ -103,6 +103,8 @@ struct journal_write { /* Embedded in struct cache_set */ struct journal { spinlock_t lock; + spinlock_t flush_write_lock; + bool btree_flushing; /* used when waiting because the journal was full */ struct closure_waitlist wait; struct closure io; @@ -154,6 +156,8 @@ struct journal_device { struct bio_vec bv[8]; }; +#define BTREE_FLUSH_NR 8 + #define journal_pin_cmp(c, l, r) \ (fifo_idx(&(c)->journal.pin, (l)) > fifo_idx(&(c)->journal.pin, (r))) diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 1b63ac876169..26e374fbf57c 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -40,6 +40,7 @@ static const char invalid_uuid[] = { static struct kobject *bcache_kobj; struct mutex bch_register_lock; +bool bcache_is_reboot; LIST_HEAD(bch_cache_sets); static LIST_HEAD(uncached_devices); @@ -49,6 +50,7 @@ static wait_queue_head_t unregister_wait; struct workqueue_struct *bcache_wq; struct workqueue_struct *bch_journal_wq; + #define BTREE_MAX_PAGES (256 * 1024 / PAGE_SIZE) /* limitation of partitions number on single bcache device */ #define BCACHE_MINORS 128 @@ -197,7 +199,9 @@ err: static void write_bdev_super_endio(struct bio *bio) { struct cached_dev *dc = bio->bi_private; - /* XXX: error checking */ + + if (bio->bi_status) + bch_count_backing_io_errors(dc, bio); closure_put(&dc->sb_write); } @@ -691,6 +695,7 @@ static void bcache_device_link(struct bcache_device *d, struct cache_set *c, { unsigned int i; struct cache *ca; + int ret; for_each_cache(ca, d->c, i) bd_link_disk_holder(ca->bdev, d->disk); @@ -698,9 +703,13 @@ static void bcache_device_link(struct bcache_device *d, struct cache_set *c, snprintf(d->name, BCACHEDEVNAME_SIZE, "%s%u", name, d->id); - WARN(sysfs_create_link(&d->kobj, &c->kobj, "cache") || - sysfs_create_link(&c->kobj, &d->kobj, d->name), - "Couldn't create device <-> cache set symlinks"); + ret = sysfs_create_link(&d->kobj, &c->kobj, "cache"); + if (ret < 0) + pr_err("Couldn't create device -> cache set symlink"); + + ret = sysfs_create_link(&c->kobj, &d->kobj, d->name); + if (ret < 0) + pr_err("Couldn't create cache set -> device symlink"); clear_bit(BCACHE_DEV_UNLINK_DONE, &d->flags); } @@ -908,7 +917,7 @@ static int cached_dev_status_update(void *arg) } -void bch_cached_dev_run(struct cached_dev *dc) +int bch_cached_dev_run(struct cached_dev *dc) { struct bcache_device *d = &dc->disk; char *buf = kmemdup_nul(dc->sb.label, SB_LABEL_SIZE, GFP_KERNEL); @@ -919,11 +928,19 @@ void bch_cached_dev_run(struct cached_dev *dc) NULL, }; + if (dc->io_disable) { + pr_err("I/O disabled on cached dev %s", + dc->backing_dev_name); + return -EIO; + } + if (atomic_xchg(&dc->running, 1)) { kfree(env[1]); kfree(env[2]); kfree(buf); - return; + pr_info("cached dev %s is running already", + dc->backing_dev_name); + return -EBUSY; } if (!d->c && @@ -949,8 +966,11 @@ void bch_cached_dev_run(struct cached_dev *dc) kfree(buf); if (sysfs_create_link(&d->kobj, &disk_to_dev(d->disk)->kobj, "dev") || - sysfs_create_link(&disk_to_dev(d->disk)->kobj, &d->kobj, "bcache")) - pr_debug("error creating sysfs link"); + sysfs_create_link(&disk_to_dev(d->disk)->kobj, + &d->kobj, "bcache")) { + pr_err("Couldn't create bcache dev <-> disk sysfs symlinks"); + return -ENOMEM; + } dc->status_update_thread = kthread_run(cached_dev_status_update, dc, "bcache_status_update"); @@ -959,6 +979,8 @@ void bch_cached_dev_run(struct cached_dev *dc) "continue to run without monitoring backing " "device status"); } + + return 0; } /* @@ -996,7 +1018,6 @@ static void cached_dev_detach_finish(struct work_struct *w) BUG_ON(!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags)); BUG_ON(refcount_read(&dc->count)); - mutex_lock(&bch_register_lock); if (test_and_clear_bit(BCACHE_DEV_WB_RUNNING, &dc->disk.flags)) cancel_writeback_rate_update_dwork(dc); @@ -1012,6 +1033,8 @@ static void cached_dev_detach_finish(struct work_struct *w) bch_write_bdev_super(dc, &cl); closure_sync(&cl); + mutex_lock(&bch_register_lock); + calc_cached_dev_sectors(dc->disk.c); bcache_device_detach(&dc->disk); list_move(&dc->list, &uncached_devices); @@ -1054,6 +1077,7 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, uint32_t rtime = cpu_to_le32((u32)ktime_get_real_seconds()); struct uuid_entry *u; struct cached_dev *exist_dc, *t; + int ret = 0; if ((set_uuid && memcmp(set_uuid, c->sb.set_uuid, 16)) || (!set_uuid && memcmp(dc->sb.set_uuid, c->sb.set_uuid, 16))) @@ -1153,6 +1177,8 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, down_write(&dc->writeback_lock); if (bch_cached_dev_writeback_start(dc)) { up_write(&dc->writeback_lock); + pr_err("Couldn't start writeback facilities for %s", + dc->disk.disk->disk_name); return -ENOMEM; } @@ -1163,7 +1189,22 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, bch_sectors_dirty_init(&dc->disk); - bch_cached_dev_run(dc); + ret = bch_cached_dev_run(dc); + if (ret && (ret != -EBUSY)) { + up_write(&dc->writeback_lock); + /* + * bch_register_lock is held, bcache_device_stop() is not + * able to be directly called. The kthread and kworker + * created previously in bch_cached_dev_writeback_start() + * have to be stopped manually here. + */ + kthread_stop(dc->writeback_thread); + cancel_writeback_rate_update_dwork(dc); + pr_err("Couldn't run cached device %s", + dc->backing_dev_name); + return ret; + } + bcache_device_link(&dc->disk, c, "bdev"); atomic_inc(&c->attached_dev_nr); @@ -1190,18 +1231,16 @@ static void cached_dev_free(struct closure *cl) { struct cached_dev *dc = container_of(cl, struct cached_dev, disk.cl); - mutex_lock(&bch_register_lock); - if (test_and_clear_bit(BCACHE_DEV_WB_RUNNING, &dc->disk.flags)) cancel_writeback_rate_update_dwork(dc); if (!IS_ERR_OR_NULL(dc->writeback_thread)) kthread_stop(dc->writeback_thread); - if (dc->writeback_write_wq) - destroy_workqueue(dc->writeback_write_wq); if (!IS_ERR_OR_NULL(dc->status_update_thread)) kthread_stop(dc->status_update_thread); + mutex_lock(&bch_register_lock); + if (atomic_read(&dc->running)) bd_unlink_disk_holder(dc->bdev, dc->disk.disk); bcache_device_free(&dc->disk); @@ -1290,6 +1329,7 @@ static int register_bdev(struct cache_sb *sb, struct page *sb_page, { const char *err = "cannot allocate memory"; struct cache_set *c; + int ret = -ENOMEM; bdevname(bdev, dc->backing_dev_name); memcpy(&dc->sb, sb, sizeof(struct cache_sb)); @@ -1319,14 +1359,18 @@ static int register_bdev(struct cache_sb *sb, struct page *sb_page, bch_cached_dev_attach(dc, c, NULL); if (BDEV_STATE(&dc->sb) == BDEV_STATE_NONE || - BDEV_STATE(&dc->sb) == BDEV_STATE_STALE) - bch_cached_dev_run(dc); + BDEV_STATE(&dc->sb) == BDEV_STATE_STALE) { + err = "failed to run cached device"; + ret = bch_cached_dev_run(dc); + if (ret) + goto err; + } return 0; err: pr_notice("error %s: %s", dc->backing_dev_name, err); bcache_device_stop(&dc->disk); - return -EIO; + return ret; } /* Flash only volumes */ @@ -1437,8 +1481,6 @@ int bch_flash_dev_create(struct cache_set *c, uint64_t size) bool bch_cached_dev_error(struct cached_dev *dc) { - struct cache_set *c; - if (!dc || test_bit(BCACHE_DEV_CLOSING, &dc->disk.flags)) return false; @@ -1449,21 +1491,6 @@ bool bch_cached_dev_error(struct cached_dev *dc) pr_err("stop %s: too many IO errors on backing device %s\n", dc->disk.disk->disk_name, dc->backing_dev_name); - /* - * If the cached device is still attached to a cache set, - * even dc->io_disable is true and no more I/O requests - * accepted, cache device internal I/O (writeback scan or - * garbage collection) may still prevent bcache device from - * being stopped. So here CACHE_SET_IO_DISABLE should be - * set to c->flags too, to make the internal I/O to cache - * device rejected and stopped immediately. - * If c is NULL, that means the bcache device is not attached - * to any cache set, then no CACHE_SET_IO_DISABLE bit to set. - */ - c = dc->disk.c; - if (c && test_and_set_bit(CACHE_SET_IO_DISABLE, &c->flags)) - pr_info("CACHE_SET_IO_DISABLE already set"); - bcache_device_stop(&dc->disk); return true; } @@ -1564,19 +1591,23 @@ static void cache_set_flush(struct closure *cl) kobject_put(&c->internal); kobject_del(&c->kobj); - if (c->gc_thread) + if (!IS_ERR_OR_NULL(c->gc_thread)) kthread_stop(c->gc_thread); if (!IS_ERR_OR_NULL(c->root)) list_add(&c->root->list, &c->btree_cache); - /* Should skip this if we're unregistering because of an error */ - list_for_each_entry(b, &c->btree_cache, list) { - mutex_lock(&b->write_lock); - if (btree_node_dirty(b)) - __bch_btree_node_write(b, NULL); - mutex_unlock(&b->write_lock); - } + /* + * Avoid flushing cached nodes if cache set is retiring + * due to too many I/O errors detected. + */ + if (!test_bit(CACHE_SET_IO_DISABLE, &c->flags)) + list_for_each_entry(b, &c->btree_cache, list) { + mutex_lock(&b->write_lock); + if (btree_node_dirty(b)) + __bch_btree_node_write(b, NULL); + mutex_unlock(&b->write_lock); + } for_each_cache(ca, c, i) if (ca->alloc_thread) @@ -1849,6 +1880,23 @@ static int run_cache_set(struct cache_set *c) if (bch_btree_check(c)) goto err; + /* + * bch_btree_check() may occupy too much system memory which + * has negative effects to user space application (e.g. data + * base) performance. Shrink the mca cache memory proactively + * here to avoid competing memory with user space workloads.. + */ + if (!c->shrinker_disabled) { + struct shrink_control sc; + + sc.gfp_mask = GFP_KERNEL; + sc.nr_to_scan = c->btree_cache_used * c->btree_pages; + /* first run to clear b->accessed tag */ + c->shrink.scan_objects(&c->shrink, &sc); + /* second run to reap non-accessed nodes */ + c->shrink.scan_objects(&c->shrink, &sc); + } + bch_journal_mark(c, &journal); bch_initial_gc_finish(c); pr_debug("btree_check() done"); @@ -1957,7 +2005,7 @@ err: } closure_sync(&cl); - /* XXX: test this, it's broken */ + bch_cache_set_error(c, "%s", err); return -EIO; @@ -2251,9 +2299,13 @@ err: static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, const char *buffer, size_t size); +static ssize_t bch_pending_bdevs_cleanup(struct kobject *k, + struct kobj_attribute *attr, + const char *buffer, size_t size); kobj_attribute_write(register, register_bcache); kobj_attribute_write(register_quiet, register_bcache); +kobj_attribute_write(pendings_cleanup, bch_pending_bdevs_cleanup); static bool bch_is_open_backing(struct block_device *bdev) { @@ -2301,6 +2353,11 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, if (!try_module_get(THIS_MODULE)) return -EBUSY; + /* For latest state of bcache_is_reboot */ + smp_mb(); + if (bcache_is_reboot) + return -EBUSY; + path = kstrndup(buffer, size, GFP_KERNEL); if (!path) goto err; @@ -2378,8 +2435,61 @@ err: goto out; } + +struct pdev { + struct list_head list; + struct cached_dev *dc; +}; + +static ssize_t bch_pending_bdevs_cleanup(struct kobject *k, + struct kobj_attribute *attr, + const char *buffer, + size_t size) +{ + LIST_HEAD(pending_devs); + ssize_t ret = size; + struct cached_dev *dc, *tdc; + struct pdev *pdev, *tpdev; + struct cache_set *c, *tc; + + mutex_lock(&bch_register_lock); + list_for_each_entry_safe(dc, tdc, &uncached_devices, list) { + pdev = kmalloc(sizeof(struct pdev), GFP_KERNEL); + if (!pdev) + break; + pdev->dc = dc; + list_add(&pdev->list, &pending_devs); + } + + list_for_each_entry_safe(pdev, tpdev, &pending_devs, list) { + list_for_each_entry_safe(c, tc, &bch_cache_sets, list) { + char *pdev_set_uuid = pdev->dc->sb.set_uuid; + char *set_uuid = c->sb.uuid; + + if (!memcmp(pdev_set_uuid, set_uuid, 16)) { + list_del(&pdev->list); + kfree(pdev); + break; + } + } + } + mutex_unlock(&bch_register_lock); + + list_for_each_entry_safe(pdev, tpdev, &pending_devs, list) { + pr_info("delete pdev %p", pdev); + list_del(&pdev->list); + bcache_device_stop(&pdev->dc->disk); + kfree(pdev); + } + + return ret; +} + static int bcache_reboot(struct notifier_block *n, unsigned long code, void *x) { + if (bcache_is_reboot) + return NOTIFY_DONE; + if (code == SYS_DOWN || code == SYS_HALT || code == SYS_POWER_OFF) { @@ -2392,19 +2502,45 @@ static int bcache_reboot(struct notifier_block *n, unsigned long code, void *x) mutex_lock(&bch_register_lock); + if (bcache_is_reboot) + goto out; + + /* New registration is rejected since now */ + bcache_is_reboot = true; + /* + * Make registering caller (if there is) on other CPU + * core know bcache_is_reboot set to true earlier + */ + smp_mb(); + if (list_empty(&bch_cache_sets) && list_empty(&uncached_devices)) goto out; + mutex_unlock(&bch_register_lock); + pr_info("Stopping all devices:"); + /* + * The reason bch_register_lock is not held to call + * bch_cache_set_stop() and bcache_device_stop() is to + * avoid potential deadlock during reboot, because cache + * set or bcache device stopping process will acqurie + * bch_register_lock too. + * + * We are safe here because bcache_is_reboot sets to + * true already, register_bcache() will reject new + * registration now. bcache_is_reboot also makes sure + * bcache_reboot() won't be re-entered on by other thread, + * so there is no race in following list iteration by + * list_for_each_entry_safe(). + */ list_for_each_entry_safe(c, tc, &bch_cache_sets, list) bch_cache_set_stop(c); list_for_each_entry_safe(dc, tdc, &uncached_devices, list) bcache_device_stop(&dc->disk); - mutex_unlock(&bch_register_lock); /* * Give an early chance for other kthreads and @@ -2496,6 +2632,7 @@ static int __init bcache_init(void) static const struct attribute *files[] = { &ksysfs_register.attr, &ksysfs_register_quiet.attr, + &ksysfs_pendings_cleanup.attr, NULL }; @@ -2531,6 +2668,8 @@ static int __init bcache_init(void) bch_debug_init(); closure_debug_init(); + bcache_is_reboot = false; + return 0; err: bcache_exit(); diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c index bfb437ffb13c..9f0826712845 100644 --- a/drivers/md/bcache/sysfs.c +++ b/drivers/md/bcache/sysfs.c @@ -16,33 +16,31 @@ #include <linux/sort.h> #include <linux/sched/clock.h> +extern bool bcache_is_reboot; + /* Default is 0 ("writethrough") */ static const char * const bch_cache_modes[] = { "writethrough", "writeback", "writearound", - "none", - NULL + "none" }; /* Default is 0 ("auto") */ static const char * const bch_stop_on_failure_modes[] = { "auto", - "always", - NULL + "always" }; static const char * const cache_replacement_policies[] = { "lru", "fifo", - "random", - NULL + "random" }; static const char * const error_actions[] = { "unregister", - "panic", - NULL + "panic" }; write_attribute(attach); @@ -84,8 +82,8 @@ read_attribute(bset_tree_stats); read_attribute(state); read_attribute(cache_read_races); read_attribute(reclaim); +read_attribute(reclaimed_journal_buckets); read_attribute(flush_write); -read_attribute(retry_flush_write); read_attribute(writeback_keys_done); read_attribute(writeback_keys_failed); read_attribute(io_errors); @@ -180,7 +178,7 @@ SHOW(__bch_cached_dev) var_print(writeback_percent); sysfs_hprint(writeback_rate, wb ? atomic_long_read(&dc->writeback_rate.rate) << 9 : 0); - sysfs_hprint(io_errors, atomic_read(&dc->io_errors)); + sysfs_printf(io_errors, "%i", atomic_read(&dc->io_errors)); sysfs_printf(io_error_limit, "%i", dc->error_limit); sysfs_printf(io_disable, "%i", dc->io_disable); var_print(writeback_rate_update_seconds); @@ -271,6 +269,10 @@ STORE(__cached_dev) struct cache_set *c; struct kobj_uevent_env *env; + /* no user space access if system is rebooting */ + if (bcache_is_reboot) + return -EBUSY; + #define d_strtoul(var) sysfs_strtoul(var, dc->var) #define d_strtoul_nonzero(var) sysfs_strtoul_clamp(var, dc->var, 1, INT_MAX) #define d_strtoi_h(var) sysfs_hatoi(var, dc->var) @@ -329,11 +331,14 @@ STORE(__cached_dev) bch_cache_accounting_clear(&dc->accounting); if (attr == &sysfs_running && - strtoul_or_return(buf)) - bch_cached_dev_run(dc); + strtoul_or_return(buf)) { + v = bch_cached_dev_run(dc); + if (v) + return v; + } if (attr == &sysfs_cache_mode) { - v = __sysfs_match_string(bch_cache_modes, -1, buf); + v = sysfs_match_string(bch_cache_modes, buf); if (v < 0) return v; @@ -344,7 +349,7 @@ STORE(__cached_dev) } if (attr == &sysfs_stop_when_cache_set_failed) { - v = __sysfs_match_string(bch_stop_on_failure_modes, -1, buf); + v = sysfs_match_string(bch_stop_on_failure_modes, buf); if (v < 0) return v; @@ -408,6 +413,10 @@ STORE(bch_cached_dev) struct cached_dev *dc = container_of(kobj, struct cached_dev, disk.kobj); + /* no user space access if system is rebooting */ + if (bcache_is_reboot) + return -EBUSY; + mutex_lock(&bch_register_lock); size = __cached_dev_store(kobj, attr, buf, size); @@ -464,7 +473,7 @@ static struct attribute *bch_cached_dev_files[] = { &sysfs_writeback_rate_p_term_inverse, &sysfs_writeback_rate_minimum, &sysfs_writeback_rate_debug, - &sysfs_errors, + &sysfs_io_errors, &sysfs_io_error_limit, &sysfs_io_disable, &sysfs_dirty_data, @@ -511,6 +520,10 @@ STORE(__bch_flash_dev) kobj); struct uuid_entry *u = &d->c->uuids[d->id]; + /* no user space access if system is rebooting */ + if (bcache_is_reboot) + return -EBUSY; + sysfs_strtoul(data_csum, d->data_csum); if (attr == &sysfs_size) { @@ -693,12 +706,12 @@ SHOW(__bch_cache_set) sysfs_print(reclaim, atomic_long_read(&c->reclaim)); + sysfs_print(reclaimed_journal_buckets, + atomic_long_read(&c->reclaimed_journal_buckets)); + sysfs_print(flush_write, atomic_long_read(&c->flush_write)); - sysfs_print(retry_flush_write, - atomic_long_read(&c->retry_flush_write)); - sysfs_print(writeback_keys_done, atomic_long_read(&c->writeback_keys_done)); sysfs_print(writeback_keys_failed, @@ -746,6 +759,10 @@ STORE(__bch_cache_set) struct cache_set *c = container_of(kobj, struct cache_set, kobj); ssize_t v; + /* no user space access if system is rebooting */ + if (bcache_is_reboot) + return -EBUSY; + if (attr == &sysfs_unregister) bch_cache_set_unregister(c); @@ -799,7 +816,7 @@ STORE(__bch_cache_set) 0, UINT_MAX); if (attr == &sysfs_errors) { - v = __sysfs_match_string(error_actions, -1, buf); + v = sysfs_match_string(error_actions, buf); if (v < 0) return v; @@ -865,6 +882,10 @@ STORE(bch_cache_set_internal) { struct cache_set *c = container_of(kobj, struct cache_set, internal); + /* no user space access if system is rebooting */ + if (bcache_is_reboot) + return -EBUSY; + return bch_cache_set_store(&c->kobj, attr, buf, size); } @@ -914,8 +935,8 @@ static struct attribute *bch_cache_set_internal_files[] = { &sysfs_bset_tree_stats, &sysfs_cache_read_races, &sysfs_reclaim, + &sysfs_reclaimed_journal_buckets, &sysfs_flush_write, - &sysfs_retry_flush_write, &sysfs_writeback_keys_done, &sysfs_writeback_keys_failed, @@ -1050,6 +1071,10 @@ STORE(__bch_cache) struct cache *ca = container_of(kobj, struct cache, kobj); ssize_t v; + /* no user space access if system is rebooting */ + if (bcache_is_reboot) + return -EBUSY; + if (attr == &sysfs_discard) { bool v = strtoul_or_return(buf); @@ -1063,7 +1088,7 @@ STORE(__bch_cache) } if (attr == &sysfs_cache_replacement_policy) { - v = __sysfs_match_string(cache_replacement_policies, -1, buf); + v = sysfs_match_string(cache_replacement_policies, buf); if (v < 0) return v; diff --git a/drivers/md/bcache/util.h b/drivers/md/bcache/util.h index 1fbced94e4cc..c029f7443190 100644 --- a/drivers/md/bcache/util.h +++ b/drivers/md/bcache/util.h @@ -113,8 +113,6 @@ do { \ #define heap_full(h) ((h)->used == (h)->size) -#define heap_empty(h) ((h)->used == 0) - #define DECLARE_FIFO(type, name) \ struct { \ size_t front, back, size, mask; \ diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index 73f0efac2b9f..d60268fe49e1 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -122,6 +122,9 @@ static void __update_writeback_rate(struct cached_dev *dc) static bool set_at_max_writeback_rate(struct cache_set *c, struct cached_dev *dc) { + /* Don't set max writeback rate if gc is running */ + if (!c->gc_mark_valid) + return false; /* * Idle_counter is increased everytime when update_writeback_rate() is * called. If all backing devices attached to the same cache set have @@ -735,6 +738,10 @@ static int bch_writeback_thread(void *arg) } } + if (dc->writeback_write_wq) { + flush_workqueue(dc->writeback_write_wq); + destroy_workqueue(dc->writeback_write_wq); + } cached_dev_put(dc); wait_for_kthread_stop(); @@ -830,6 +837,7 @@ int bch_cached_dev_writeback_start(struct cached_dev *dc) "bcache_writeback"); if (IS_ERR(dc->writeback_thread)) { cached_dev_put(dc); + destroy_workqueue(dc->writeback_write_wq); return PTR_ERR(dc->writeback_thread); } dc->writeback_running = true; diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 1b16d34bb785..0fd3ca9bfe54 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -2035,7 +2035,7 @@ static int crypt_set_keyring_key(struct crypt_config *cc, const char *key_string return -ENOMEM; key = request_key(key_string[0] == 'l' ? &key_type_logon : &key_type_user, - key_desc + 1, NULL); + key_desc + 1, NULL, NULL); if (IS_ERR(key)) { kzfree(new_key_string); return PTR_ERR(key); diff --git a/drivers/md/dm-init.c b/drivers/md/dm-init.c index 352e803f566e..728733a514c7 100644 --- a/drivers/md/dm-init.c +++ b/drivers/md/dm-init.c @@ -140,8 +140,8 @@ static char __init *dm_parse_table_entry(struct dm_device *dev, char *str) return ERR_PTR(-EINVAL); } /* target_args */ - dev->target_args_array[n] = kstrndup(field[3], GFP_KERNEL, - DM_MAX_STR_SIZE); + dev->target_args_array[n] = kstrndup(field[3], DM_MAX_STR_SIZE, + GFP_KERNEL); if (!dev->target_args_array[n]) return ERR_PTR(-ENOMEM); @@ -272,10 +272,10 @@ static int __init dm_init_init(void) return 0; if (strlen(create) >= DM_MAX_STR_SIZE) { - DMERR("Argument is too big. Limit is %d\n", DM_MAX_STR_SIZE); + DMERR("Argument is too big. Limit is %d", DM_MAX_STR_SIZE); return -EINVAL; } - str = kstrndup(create, GFP_KERNEL, DM_MAX_STR_SIZE); + str = kstrndup(create, DM_MAX_STR_SIZE, GFP_KERNEL); if (!str) return -ENOMEM; @@ -283,7 +283,7 @@ static int __init dm_init_init(void) if (r) goto out; - DMINFO("waiting for all devices to be available before creating mapped devices\n"); + DMINFO("waiting for all devices to be available before creating mapped devices"); wait_for_device_probe(); list_for_each_entry(dev, &devices, list) { diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c index 9ea2b0291f20..e549392e0ea5 100644 --- a/drivers/md/dm-log-writes.c +++ b/drivers/md/dm-log-writes.c @@ -60,6 +60,7 @@ #define WRITE_LOG_VERSION 1ULL #define WRITE_LOG_MAGIC 0x6a736677736872ULL +#define WRITE_LOG_SUPER_SECTOR 0 /* * The disk format for this is braindead simple. @@ -115,6 +116,7 @@ struct log_writes_c { struct list_head logging_blocks; wait_queue_head_t wait; struct task_struct *log_kthread; + struct completion super_done; }; struct pending_block { @@ -180,6 +182,14 @@ static void log_end_io(struct bio *bio) bio_put(bio); } +static void log_end_super(struct bio *bio) +{ + struct log_writes_c *lc = bio->bi_private; + + complete(&lc->super_done); + log_end_io(bio); +} + /* * Meant to be called if there is an error, it will free all the pages * associated with the block. @@ -215,7 +225,8 @@ static int write_metadata(struct log_writes_c *lc, void *entry, bio->bi_iter.bi_size = 0; bio->bi_iter.bi_sector = sector; bio_set_dev(bio, lc->logdev->bdev); - bio->bi_end_io = log_end_io; + bio->bi_end_io = (sector == WRITE_LOG_SUPER_SECTOR) ? + log_end_super : log_end_io; bio->bi_private = lc; bio_set_op_attrs(bio, REQ_OP_WRITE, 0); @@ -418,11 +429,18 @@ static int log_super(struct log_writes_c *lc) super.nr_entries = cpu_to_le64(lc->logged_entries); super.sectorsize = cpu_to_le32(lc->sectorsize); - if (write_metadata(lc, &super, sizeof(super), NULL, 0, 0)) { + if (write_metadata(lc, &super, sizeof(super), NULL, 0, + WRITE_LOG_SUPER_SECTOR)) { DMERR("Couldn't write super"); return -1; } + /* + * Super sector should be writen in-order, otherwise the + * nr_entries could be rewritten incorrectly by an old bio. + */ + wait_for_completion_io(&lc->super_done); + return 0; } @@ -531,6 +549,7 @@ static int log_writes_ctr(struct dm_target *ti, unsigned int argc, char **argv) INIT_LIST_HEAD(&lc->unflushed_blocks); INIT_LIST_HEAD(&lc->logging_blocks); init_waitqueue_head(&lc->wait); + init_completion(&lc->super_done); atomic_set(&lc->io_blocks, 0); atomic_set(&lc->pending_blocks, 0); diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 350cf0451456..ec8b27e20de3 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -561,7 +561,7 @@ static char **realloc_argv(unsigned *size, char **old_argv) gfp = GFP_NOIO; } argv = kmalloc_array(new_size, sizeof(*argv), gfp); - if (argv) { + if (argv && old_argv) { memcpy(argv, old_argv, *size * sizeof(*argv)); *size = new_size; } diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index 720d06531aa3..ea24ff0612e3 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -235,8 +235,8 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type, BUG(); } - DMERR("%s: %s block %llu is corrupted", v->data_dev->name, type_str, - block); + DMERR_LIMIT("%s: %s block %llu is corrupted", v->data_dev->name, + type_str, block); if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS) DMERR("%s: reached maximum errors", v->data_dev->name); diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c index c01d41198f5e..b092c7b5282f 100644 --- a/drivers/md/md-bitmap.c +++ b/drivers/md/md-bitmap.c @@ -1790,6 +1790,8 @@ void md_bitmap_destroy(struct mddev *mddev) return; md_bitmap_wait_behind_writes(mddev); + mempool_destroy(mddev->wb_info_pool); + mddev->wb_info_pool = NULL; mutex_lock(&mddev->bitmap_info.mutex); spin_lock(&mddev->lock); @@ -1900,10 +1902,14 @@ int md_bitmap_load(struct mddev *mddev) sector_t start = 0; sector_t sector = 0; struct bitmap *bitmap = mddev->bitmap; + struct md_rdev *rdev; if (!bitmap) goto out; + rdev_for_each(rdev, mddev) + mddev_create_wb_pool(mddev, rdev, true); + if (mddev_is_clustered(mddev)) md_cluster_ops->load_bitmaps(mddev, mddev->bitmap_info.nodes); @@ -2462,12 +2468,26 @@ static ssize_t backlog_store(struct mddev *mddev, const char *buf, size_t len) { unsigned long backlog; + unsigned long old_mwb = mddev->bitmap_info.max_write_behind; int rv = kstrtoul(buf, 10, &backlog); if (rv) return rv; if (backlog > COUNTER_MAX) return -EINVAL; mddev->bitmap_info.max_write_behind = backlog; + if (!backlog && mddev->wb_info_pool) { + /* wb_info_pool is not needed if backlog is zero */ + mempool_destroy(mddev->wb_info_pool); + mddev->wb_info_pool = NULL; + } else if (backlog && !mddev->wb_info_pool) { + /* wb_info_pool is needed since backlog is not zero */ + struct md_rdev *rdev; + + rdev_for_each(rdev, mddev) + mddev_create_wb_pool(mddev, rdev, false); + } + if (old_mwb != backlog) + md_bitmap_update_sb(mddev->bitmap); return len; } diff --git a/drivers/md/md.c b/drivers/md/md.c index 04f4f131f9d6..a114b05e3db4 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -37,6 +37,7 @@ */ +#include <linux/sched/mm.h> #include <linux/sched/signal.h> #include <linux/kthread.h> #include <linux/blkdev.h> @@ -124,6 +125,77 @@ static inline int speed_max(struct mddev *mddev) mddev->sync_speed_max : sysctl_speed_limit_max; } +static int rdev_init_wb(struct md_rdev *rdev) +{ + if (rdev->bdev->bd_queue->nr_hw_queues == 1) + return 0; + + spin_lock_init(&rdev->wb_list_lock); + INIT_LIST_HEAD(&rdev->wb_list); + init_waitqueue_head(&rdev->wb_io_wait); + set_bit(WBCollisionCheck, &rdev->flags); + + return 1; +} + +/* + * Create wb_info_pool if rdev is the first multi-queue device flaged + * with writemostly, also write-behind mode is enabled. + */ +void mddev_create_wb_pool(struct mddev *mddev, struct md_rdev *rdev, + bool is_suspend) +{ + if (mddev->bitmap_info.max_write_behind == 0) + return; + + if (!test_bit(WriteMostly, &rdev->flags) || !rdev_init_wb(rdev)) + return; + + if (mddev->wb_info_pool == NULL) { + unsigned int noio_flag; + + if (!is_suspend) + mddev_suspend(mddev); + noio_flag = memalloc_noio_save(); + mddev->wb_info_pool = mempool_create_kmalloc_pool(NR_WB_INFOS, + sizeof(struct wb_info)); + memalloc_noio_restore(noio_flag); + if (!mddev->wb_info_pool) + pr_err("can't alloc memory pool for writemostly\n"); + if (!is_suspend) + mddev_resume(mddev); + } +} +EXPORT_SYMBOL_GPL(mddev_create_wb_pool); + +/* + * destroy wb_info_pool if rdev is the last device flaged with WBCollisionCheck. + */ +static void mddev_destroy_wb_pool(struct mddev *mddev, struct md_rdev *rdev) +{ + if (!test_and_clear_bit(WBCollisionCheck, &rdev->flags)) + return; + + if (mddev->wb_info_pool) { + struct md_rdev *temp; + int num = 0; + + /* + * Check if other rdevs need wb_info_pool. + */ + rdev_for_each(temp, mddev) + if (temp != rdev && + test_bit(WBCollisionCheck, &temp->flags)) + num++; + if (!num) { + mddev_suspend(rdev->mddev); + mempool_destroy(mddev->wb_info_pool); + mddev->wb_info_pool = NULL; + mddev_resume(rdev->mddev); + } + } +} + static struct ctl_table_header *raid_table_header; static struct ctl_table raid_table[] = { @@ -2210,6 +2282,9 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev) rdev->mddev = mddev; pr_debug("md: bind<%s>\n", b); + if (mddev->raid_disks) + mddev_create_wb_pool(mddev, rdev, false); + if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b))) goto fail; @@ -2246,6 +2321,7 @@ static void unbind_rdev_from_array(struct md_rdev *rdev) bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk); list_del_rcu(&rdev->same_set); pr_debug("md: unbind<%s>\n", bdevname(rdev->bdev,b)); + mddev_destroy_wb_pool(rdev->mddev, rdev); rdev->mddev = NULL; sysfs_remove_link(&rdev->kobj, "block"); sysfs_put(rdev->sysfs_state); @@ -2758,8 +2834,10 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len) } } else if (cmd_match(buf, "writemostly")) { set_bit(WriteMostly, &rdev->flags); + mddev_create_wb_pool(rdev->mddev, rdev, false); err = 0; } else if (cmd_match(buf, "-writemostly")) { + mddev_destroy_wb_pool(rdev->mddev, rdev); clear_bit(WriteMostly, &rdev->flags); err = 0; } else if (cmd_match(buf, "blocked")) { @@ -3356,7 +3434,7 @@ rdev_attr_show(struct kobject *kobj, struct attribute *attr, char *page) if (!entry->show) return -EIO; if (!rdev->mddev) - return -EBUSY; + return -ENODEV; return entry->show(rdev, page); } @@ -5588,15 +5666,28 @@ int md_run(struct mddev *mddev) mddev->bitmap = bitmap; } - if (err) { - mddev_detach(mddev); - if (mddev->private) - pers->free(mddev, mddev->private); - mddev->private = NULL; - module_put(pers->owner); - md_bitmap_destroy(mddev); - goto abort; + if (err) + goto bitmap_abort; + + if (mddev->bitmap_info.max_write_behind > 0) { + bool creat_pool = false; + + rdev_for_each(rdev, mddev) { + if (test_bit(WriteMostly, &rdev->flags) && + rdev_init_wb(rdev)) + creat_pool = true; + } + if (creat_pool && mddev->wb_info_pool == NULL) { + mddev->wb_info_pool = + mempool_create_kmalloc_pool(NR_WB_INFOS, + sizeof(struct wb_info)); + if (!mddev->wb_info_pool) { + err = -ENOMEM; + goto bitmap_abort; + } + } } + if (mddev->queue) { bool nonrot = true; @@ -5639,8 +5730,7 @@ int md_run(struct mddev *mddev) spin_unlock(&mddev->lock); rdev_for_each(rdev, mddev) if (rdev->raid_disk >= 0) - if (sysfs_link_rdev(mddev, rdev)) - /* failure here is OK */; + sysfs_link_rdev(mddev, rdev); /* failure here is OK */ if (mddev->degraded && !mddev->ro) /* This ensures that recovering status is reported immediately @@ -5658,6 +5748,13 @@ int md_run(struct mddev *mddev) sysfs_notify(&mddev->kobj, NULL, "degraded"); return 0; +bitmap_abort: + mddev_detach(mddev); + if (mddev->private) + pers->free(mddev, mddev->private); + mddev->private = NULL; + module_put(pers->owner); + md_bitmap_destroy(mddev); abort: bioset_exit(&mddev->bio_set); bioset_exit(&mddev->sync_set); @@ -5826,6 +5923,8 @@ static void __md_stop_writes(struct mddev *mddev) mddev->in_sync = 1; md_update_sb(mddev, 1); } + mempool_destroy(mddev->wb_info_pool); + mddev->wb_info_pool = NULL; } void md_stop_writes(struct mddev *mddev) @@ -7607,9 +7706,9 @@ static void status_unused(struct seq_file *seq) static int status_resync(struct seq_file *seq, struct mddev *mddev) { sector_t max_sectors, resync, res; - unsigned long dt, db; - sector_t rt; - int scale; + unsigned long dt, db = 0; + sector_t rt, curr_mark_cnt, resync_mark_cnt; + int scale, recovery_active; unsigned int per_milli; if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) || @@ -7698,22 +7797,30 @@ static int status_resync(struct seq_file *seq, struct mddev *mddev) * db: blocks written from mark until now * rt: remaining time * - * rt is a sector_t, so could be 32bit or 64bit. - * So we divide before multiply in case it is 32bit and close - * to the limit. - * We scale the divisor (db) by 32 to avoid losing precision - * near the end of resync when the number of remaining sectors - * is close to 'db'. - * We then divide rt by 32 after multiplying by db to compensate. - * The '+1' avoids division by zero if db is very small. + * rt is a sector_t, which is always 64bit now. We are keeping + * the original algorithm, but it is not really necessary. + * + * Original algorithm: + * So we divide before multiply in case it is 32bit and close + * to the limit. + * We scale the divisor (db) by 32 to avoid losing precision + * near the end of resync when the number of remaining sectors + * is close to 'db'. + * We then divide rt by 32 after multiplying by db to compensate. + * The '+1' avoids division by zero if db is very small. */ dt = ((jiffies - mddev->resync_mark) / HZ); if (!dt) dt++; - db = (mddev->curr_mark_cnt - atomic_read(&mddev->recovery_active)) - - mddev->resync_mark_cnt; + + curr_mark_cnt = mddev->curr_mark_cnt; + recovery_active = atomic_read(&mddev->recovery_active); + resync_mark_cnt = mddev->resync_mark_cnt; + + if (curr_mark_cnt >= (recovery_active + resync_mark_cnt)) + db = curr_mark_cnt - (recovery_active + resync_mark_cnt); rt = max_sectors - resync; /* number of remaining sectors */ - sector_div(rt, db/32+1); + rt = div64_u64(rt, db/32+1); rt *= dt; rt >>= 5; @@ -8190,8 +8297,7 @@ void md_do_sync(struct md_thread *thread) { struct mddev *mddev = thread->mddev; struct mddev *mddev2; - unsigned int currspeed = 0, - window; + unsigned int currspeed = 0, window; sector_t max_sectors,j, io_sectors, recovery_done; unsigned long mark[SYNC_MARKS]; unsigned long update_time; @@ -8248,7 +8354,7 @@ void md_do_sync(struct md_thread *thread) * 0 == not engaged in resync at all * 2 == checking that there is no conflict with another sync * 1 == like 2, but have yielded to allow conflicting resync to - * commense + * commence * other == active in resync - this many blocks * * Before starting a resync we must have set curr_resync to @@ -8379,7 +8485,7 @@ void md_do_sync(struct md_thread *thread) /* * Tune reconstruction: */ - window = 32*(PAGE_SIZE/512); + window = 32 * (PAGE_SIZE / 512); pr_debug("md: using %dk window, over a total of %lluk.\n", window/2, (unsigned long long)max_sectors/2); @@ -9192,7 +9298,6 @@ static void check_sb_changes(struct mddev *mddev, struct md_rdev *rdev) * perform resync with the new activated disk */ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); - } /* device faulty * We just want to do the minimum to mark the disk diff --git a/drivers/md/md.h b/drivers/md/md.h index 7c930c091193..10f98200e2f8 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -109,6 +109,14 @@ struct md_rdev { * for reporting to userspace and storing * in superblock. */ + + /* + * The members for check collision of write behind IOs. + */ + struct list_head wb_list; + spinlock_t wb_list_lock; + wait_queue_head_t wb_io_wait; + struct work_struct del_work; /* used for delayed sysfs removal */ struct kernfs_node *sysfs_state; /* handle for 'state' @@ -193,6 +201,10 @@ enum flag_bits { * it didn't fail, so don't use FailFast * any more for metadata */ + WBCollisionCheck, /* + * multiqueue device should check if there + * is collision between write behind bios. + */ }; static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors, @@ -245,6 +257,14 @@ enum mddev_sb_flags { MD_SB_NEED_REWRITE, /* metadata write needs to be repeated */ }; +#define NR_WB_INFOS 8 +/* record current range of write behind IOs */ +struct wb_info { + sector_t lo; + sector_t hi; + struct list_head list; +}; + struct mddev { void *private; struct md_personality *pers; @@ -461,6 +481,7 @@ struct mddev { */ struct work_struct flush_work; struct work_struct event_work; /* used by dm to report failure event */ + mempool_t *wb_info_pool; void (*sync_super)(struct mddev *mddev, struct md_rdev *rdev); struct md_cluster_info *cluster_info; unsigned int good_device_nr; /* good device num within cluster raid */ @@ -709,6 +730,8 @@ extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, extern void md_reload_sb(struct mddev *mddev, int raid_disk); extern void md_update_sb(struct mddev *mddev, int force); extern void md_kick_rdev_from_array(struct md_rdev * rdev); +extern void mddev_create_wb_pool(struct mddev *mddev, struct md_rdev *rdev, + bool is_suspend); struct md_rdev *md_find_rdev_nr_rcu(struct mddev *mddev, int nr); struct md_rdev *md_find_rdev_rcu(struct mddev *mddev, dev_t dev); diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c index 400001b815db..54db34163968 100644 --- a/drivers/md/raid1-10.c +++ b/drivers/md/raid1-10.c @@ -3,12 +3,42 @@ #define RESYNC_BLOCK_SIZE (64*1024) #define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE) +/* + * Number of guaranteed raid bios in case of extreme VM load: + */ +#define NR_RAID_BIOS 256 + +/* when we get a read error on a read-only array, we redirect to another + * device without failing the first device, or trying to over-write to + * correct the read error. To keep track of bad blocks on a per-bio + * level, we store IO_BLOCKED in the appropriate 'bios' pointer + */ +#define IO_BLOCKED ((struct bio *)1) +/* When we successfully write to a known bad-block, we need to remove the + * bad-block marking which must be done from process context. So we record + * the success by setting devs[n].bio to IO_MADE_GOOD + */ +#define IO_MADE_GOOD ((struct bio *)2) + +#define BIO_SPECIAL(bio) ((unsigned long)bio <= 2) + +/* When there are this many requests queue to be written by + * the raid thread, we become 'congested' to provide back-pressure + * for writeback. + */ +static int max_queued_requests = 1024; + /* for managing resync I/O pages */ struct resync_pages { void *raid_bio; struct page *pages[RESYNC_PAGES]; }; +static void rbio_pool_free(void *rbio, void *data) +{ + kfree(rbio); +} + static inline int resync_alloc_pages(struct resync_pages *rp, gfp_t gfp_flags) { diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 2aa36e570e04..34e26834ad28 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -42,31 +42,6 @@ (1L << MD_HAS_PPL) | \ (1L << MD_HAS_MULTIPLE_PPLS)) -/* - * Number of guaranteed r1bios in case of extreme VM load: - */ -#define NR_RAID1_BIOS 256 - -/* when we get a read error on a read-only array, we redirect to another - * device without failing the first device, or trying to over-write to - * correct the read error. To keep track of bad blocks on a per-bio - * level, we store IO_BLOCKED in the appropriate 'bios' pointer - */ -#define IO_BLOCKED ((struct bio *)1) -/* When we successfully write to a known bad-block, we need to remove the - * bad-block marking which must be done from process context. So we record - * the success by setting devs[n].bio to IO_MADE_GOOD - */ -#define IO_MADE_GOOD ((struct bio *)2) - -#define BIO_SPECIAL(bio) ((unsigned long)bio <= 2) - -/* When there are this many requests queue to be written by - * the raid1 thread, we become 'congested' to provide back-pressure - * for writeback. - */ -static int max_queued_requests = 1024; - static void allow_barrier(struct r1conf *conf, sector_t sector_nr); static void lower_barrier(struct r1conf *conf, sector_t sector_nr); @@ -75,6 +50,57 @@ static void lower_barrier(struct r1conf *conf, sector_t sector_nr); #include "raid1-10.c" +static int check_and_add_wb(struct md_rdev *rdev, sector_t lo, sector_t hi) +{ + struct wb_info *wi, *temp_wi; + unsigned long flags; + int ret = 0; + struct mddev *mddev = rdev->mddev; + + wi = mempool_alloc(mddev->wb_info_pool, GFP_NOIO); + + spin_lock_irqsave(&rdev->wb_list_lock, flags); + list_for_each_entry(temp_wi, &rdev->wb_list, list) { + /* collision happened */ + if (hi > temp_wi->lo && lo < temp_wi->hi) { + ret = -EBUSY; + break; + } + } + + if (!ret) { + wi->lo = lo; + wi->hi = hi; + list_add(&wi->list, &rdev->wb_list); + } else + mempool_free(wi, mddev->wb_info_pool); + spin_unlock_irqrestore(&rdev->wb_list_lock, flags); + + return ret; +} + +static void remove_wb(struct md_rdev *rdev, sector_t lo, sector_t hi) +{ + struct wb_info *wi; + unsigned long flags; + int found = 0; + struct mddev *mddev = rdev->mddev; + + spin_lock_irqsave(&rdev->wb_list_lock, flags); + list_for_each_entry(wi, &rdev->wb_list, list) + if (hi == wi->hi && lo == wi->lo) { + list_del(&wi->list); + mempool_free(wi, mddev->wb_info_pool); + found = 1; + break; + } + + if (!found) + WARN(1, "The write behind IO is not recorded\n"); + spin_unlock_irqrestore(&rdev->wb_list_lock, flags); + wake_up(&rdev->wb_io_wait); +} + /* * for resync bio, r1bio pointer can be retrieved from the per-bio * 'struct resync_pages'. @@ -93,11 +119,6 @@ static void * r1bio_pool_alloc(gfp_t gfp_flags, void *data) return kzalloc(size, gfp_flags); } -static void r1bio_pool_free(void *r1_bio, void *data) -{ - kfree(r1_bio); -} - #define RESYNC_DEPTH 32 #define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9) #define RESYNC_WINDOW (RESYNC_BLOCK_SIZE * RESYNC_DEPTH) @@ -173,7 +194,7 @@ out_free_bio: kfree(rps); out_free_r1bio: - r1bio_pool_free(r1_bio, data); + rbio_pool_free(r1_bio, data); return NULL; } @@ -193,7 +214,7 @@ static void r1buf_pool_free(void *__r1_bio, void *data) /* resync pages array stored in the 1st bio's .bi_private */ kfree(rp); - r1bio_pool_free(r1bio, data); + rbio_pool_free(r1bio, data); } static void put_all_bios(struct r1conf *conf, struct r1bio *r1_bio) @@ -476,6 +497,12 @@ static void raid1_end_write_request(struct bio *bio) } if (behind) { + if (test_bit(WBCollisionCheck, &rdev->flags)) { + sector_t lo = r1_bio->sector; + sector_t hi = r1_bio->sector + r1_bio->sectors; + + remove_wb(rdev, lo, hi); + } if (test_bit(WriteMostly, &rdev->flags)) atomic_dec(&r1_bio->behind_remaining); @@ -1449,7 +1476,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, if (!r1_bio->bios[i]) continue; - if (first_clone) { /* do behind I/O ? * Not if there are too many, or cannot @@ -1474,7 +1500,16 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, mbio = bio_clone_fast(bio, GFP_NOIO, &mddev->bio_set); if (r1_bio->behind_master_bio) { - if (test_bit(WriteMostly, &conf->mirrors[i].rdev->flags)) + struct md_rdev *rdev = conf->mirrors[i].rdev; + + if (test_bit(WBCollisionCheck, &rdev->flags)) { + sector_t lo = r1_bio->sector; + sector_t hi = r1_bio->sector + r1_bio->sectors; + + wait_event(rdev->wb_io_wait, + check_and_add_wb(rdev, lo, hi) == 0); + } + if (test_bit(WriteMostly, &rdev->flags)) atomic_inc(&r1_bio->behind_remaining); } @@ -1729,9 +1764,8 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev) first = last = rdev->saved_raid_disk; for (mirror = first; mirror <= last; mirror++) { - p = conf->mirrors+mirror; + p = conf->mirrors + mirror; if (!p->rdev) { - if (mddev->gendisk) disk_stack_limits(mddev->gendisk, rdev->bdev, rdev->data_offset << 9); @@ -2888,7 +2922,6 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr, if (read_targets == 1) bio->bi_opf &= ~MD_FAILFAST; generic_make_request(bio); - } return nr_sectors; } @@ -2947,8 +2980,8 @@ static struct r1conf *setup_conf(struct mddev *mddev) if (!conf->poolinfo) goto abort; conf->poolinfo->raid_disks = mddev->raid_disks * 2; - err = mempool_init(&conf->r1bio_pool, NR_RAID1_BIOS, r1bio_pool_alloc, - r1bio_pool_free, conf->poolinfo); + err = mempool_init(&conf->r1bio_pool, NR_RAID_BIOS, r1bio_pool_alloc, + rbio_pool_free, conf->poolinfo); if (err) goto abort; @@ -3089,7 +3122,7 @@ static int raid1_run(struct mddev *mddev) } mddev->degraded = 0; - for (i=0; i < conf->raid_disks; i++) + for (i = 0; i < conf->raid_disks; i++) if (conf->mirrors[i].rdev == NULL || !test_bit(In_sync, &conf->mirrors[i].rdev->flags) || test_bit(Faulty, &conf->mirrors[i].rdev->flags)) @@ -3124,7 +3157,7 @@ static int raid1_run(struct mddev *mddev) mddev->queue); } - ret = md_integrity_register(mddev); + ret = md_integrity_register(mddev); if (ret) { md_unregister_thread(&mddev->thread); raid1_free(mddev, conf); @@ -3232,8 +3265,8 @@ static int raid1_reshape(struct mddev *mddev) newpoolinfo->mddev = mddev; newpoolinfo->raid_disks = raid_disks * 2; - ret = mempool_init(&newpool, NR_RAID1_BIOS, r1bio_pool_alloc, - r1bio_pool_free, newpoolinfo); + ret = mempool_init(&newpool, NR_RAID_BIOS, r1bio_pool_alloc, + rbio_pool_free, newpoolinfo); if (ret) { kfree(newpoolinfo); return ret; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index aea11476fee6..8a1354a08a1a 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -64,31 +64,6 @@ * [B A] [D C] [B A] [E C D] */ -/* - * Number of guaranteed r10bios in case of extreme VM load: - */ -#define NR_RAID10_BIOS 256 - -/* when we get a read error on a read-only array, we redirect to another - * device without failing the first device, or trying to over-write to - * correct the read error. To keep track of bad blocks on a per-bio - * level, we store IO_BLOCKED in the appropriate 'bios' pointer - */ -#define IO_BLOCKED ((struct bio *)1) -/* When we successfully write to a known bad-block, we need to remove the - * bad-block marking which must be done from process context. So we record - * the success by setting devs[n].bio to IO_MADE_GOOD - */ -#define IO_MADE_GOOD ((struct bio *)2) - -#define BIO_SPECIAL(bio) ((unsigned long)bio <= 2) - -/* When there are this many requests queued to be written by - * the raid10 thread, we become 'congested' to provide back-pressure - * for writeback. - */ -static int max_queued_requests = 1024; - static void allow_barrier(struct r10conf *conf); static void lower_barrier(struct r10conf *conf); static int _enough(struct r10conf *conf, int previous, int ignore); @@ -123,11 +98,6 @@ static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data) return kzalloc(size, gfp_flags); } -static void r10bio_pool_free(void *r10_bio, void *data) -{ - kfree(r10_bio); -} - #define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9) /* amount of memory to reserve for resync requests */ #define RESYNC_WINDOW (1024*1024) @@ -233,7 +203,7 @@ out_free_bio: } kfree(rps); out_free_r10bio: - r10bio_pool_free(r10_bio, conf); + rbio_pool_free(r10_bio, conf); return NULL; } @@ -261,7 +231,7 @@ static void r10buf_pool_free(void *__r10_bio, void *data) /* resync pages array stored in the 1st bio's .bi_private */ kfree(rp); - r10bio_pool_free(r10bio, conf); + rbio_pool_free(r10bio, conf); } static void put_all_bios(struct r10conf *conf, struct r10bio *r10_bio) @@ -737,15 +707,19 @@ static struct md_rdev *read_balance(struct r10conf *conf, int sectors = r10_bio->sectors; int best_good_sectors; sector_t new_distance, best_dist; - struct md_rdev *best_rdev, *rdev = NULL; + struct md_rdev *best_dist_rdev, *best_pending_rdev, *rdev = NULL; int do_balance; - int best_slot; + int best_dist_slot, best_pending_slot; + bool has_nonrot_disk = false; + unsigned int min_pending; struct geom *geo = &conf->geo; raid10_find_phys(conf, r10_bio); rcu_read_lock(); - best_slot = -1; - best_rdev = NULL; + best_dist_slot = -1; + min_pending = UINT_MAX; + best_dist_rdev = NULL; + best_pending_rdev = NULL; best_dist = MaxSector; best_good_sectors = 0; do_balance = 1; @@ -767,6 +741,8 @@ static struct md_rdev *read_balance(struct r10conf *conf, sector_t first_bad; int bad_sectors; sector_t dev_sector; + unsigned int pending; + bool nonrot; if (r10_bio->devs[slot].bio == IO_BLOCKED) continue; @@ -803,8 +779,8 @@ static struct md_rdev *read_balance(struct r10conf *conf, first_bad - dev_sector; if (good_sectors > best_good_sectors) { best_good_sectors = good_sectors; - best_slot = slot; - best_rdev = rdev; + best_dist_slot = slot; + best_dist_rdev = rdev; } if (!do_balance) /* Must read from here */ @@ -817,14 +793,23 @@ static struct md_rdev *read_balance(struct r10conf *conf, if (!do_balance) break; - if (best_slot >= 0) + nonrot = blk_queue_nonrot(bdev_get_queue(rdev->bdev)); + has_nonrot_disk |= nonrot; + pending = atomic_read(&rdev->nr_pending); + if (min_pending > pending && nonrot) { + min_pending = pending; + best_pending_slot = slot; + best_pending_rdev = rdev; + } + + if (best_dist_slot >= 0) /* At least 2 disks to choose from so failfast is OK */ set_bit(R10BIO_FailFast, &r10_bio->state); /* This optimisation is debatable, and completely destroys * sequential read speed for 'far copies' arrays. So only * keep it for 'near' arrays, and review those later. */ - if (geo->near_copies > 1 && !atomic_read(&rdev->nr_pending)) + if (geo->near_copies > 1 && !pending) new_distance = 0; /* for far > 1 always use the lowest address */ @@ -833,15 +818,21 @@ static struct md_rdev *read_balance(struct r10conf *conf, else new_distance = abs(r10_bio->devs[slot].addr - conf->mirrors[disk].head_position); + if (new_distance < best_dist) { best_dist = new_distance; - best_slot = slot; - best_rdev = rdev; + best_dist_slot = slot; + best_dist_rdev = rdev; } } if (slot >= conf->copies) { - slot = best_slot; - rdev = best_rdev; + if (has_nonrot_disk) { + slot = best_pending_slot; + rdev = best_pending_rdev; + } else { + slot = best_dist_slot; + rdev = best_dist_rdev; + } } if (slot >= 0) { @@ -3675,8 +3666,8 @@ static struct r10conf *setup_conf(struct mddev *mddev) conf->geo = geo; conf->copies = copies; - err = mempool_init(&conf->r10bio_pool, NR_RAID10_BIOS, r10bio_pool_alloc, - r10bio_pool_free, conf); + err = mempool_init(&conf->r10bio_pool, NR_RAID_BIOS, r10bio_pool_alloc, + rbio_pool_free, conf); if (err) goto out; @@ -4780,8 +4771,7 @@ static int handle_reshape_read_error(struct mddev *mddev, int idx = 0; struct page **pages; - r10b = kmalloc(sizeof(*r10b) + - sizeof(struct r10dev) * conf->copies, GFP_NOIO); + r10b = kmalloc(struct_size(r10b, devs, conf->copies), GFP_NOIO); if (!r10b) { set_bit(MD_RECOVERY_INTR, &mddev->recovery); return -ENOMEM; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index b83bce2beb66..3de4e13bde98 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5251,7 +5251,6 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio) rcu_read_unlock(); raid_bio->bi_next = (void*)rdev; bio_set_dev(align_bi, rdev->bdev); - bio_clear_flag(align_bi, BIO_SEG_VALID); if (is_badblock(rdev, align_bi->bi_iter.bi_sector, bio_sectors(align_bi), @@ -7672,7 +7671,7 @@ abort: static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev) { struct r5conf *conf = mddev->private; - int err = -EEXIST; + int ret, err = -EEXIST; int disk; struct disk_info *p; int first = 0; @@ -7687,7 +7686,14 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev) * The array is in readonly mode if journal is missing, so no * write requests running. We should be safe */ - log_init(conf, rdev, false); + ret = log_init(conf, rdev, false); + if (ret) + return ret; + + ret = r5l_start(conf->log); + if (ret) + return ret; + return 0; } if (mddev->recovery_disabled == conf->recovery_disabled) diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 092e7509af9b..21cd9c02960b 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -89,40 +89,7 @@ config MEDIA_CEC_SUPPORT source "drivers/media/cec/Kconfig" -# -# Media controller -# Selectable only for webcam/grabbers, as other drivers don't use it -# - -config MEDIA_CONTROLLER - bool "Media Controller API" - depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT - help - Enable the media controller API used to query media devices internal - topology and configure it dynamically. - - This API is mostly used by camera interfaces in embedded platforms. - -config MEDIA_CONTROLLER_DVB - bool "Enable Media controller for DVB (EXPERIMENTAL)" - depends on MEDIA_CONTROLLER && DVB_CORE - help - Enable the media controller API support for DVB. - - This is currently experimental. - -config MEDIA_CONTROLLER_REQUEST_API - bool "Enable Media controller Request API (EXPERIMENTAL)" - depends on MEDIA_CONTROLLER && STAGING_MEDIA - default n - help - DO NOT ENABLE THIS OPTION UNLESS YOU KNOW WHAT YOU'RE DOING. - - This option enables the Request API for the Media controller and V4L2 - interfaces. It is currently needed by a few stateless codec drivers. - - There is currently no intention to provide API or ABI stability for - this new API as of yet. +source "drivers/media/mc/Kconfig" # # Video4Linux support @@ -164,7 +131,6 @@ config DVB_MMAP depends on DVB_CORE depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_CORE select VIDEOBUF2_VMALLOC - default n help This option enables DVB experimental memory-mapped API, which reduces the number of context switches to read DVB buffers, as @@ -190,7 +156,6 @@ config DVB_NET config TTPCI_EEPROM tristate depends on I2C - default n source "drivers/media/dvb-core/Kconfig" diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 4a330d0e5e40..f215f0a89f9e 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -3,15 +3,6 @@ # Makefile for the kernel multimedia device drivers. # -media-objs := media-device.o media-devnode.o media-entity.o \ - media-request.o - -ifeq ($(CONFIG_MEDIA_CONTROLLER),y) - ifeq ($(CONFIG_USB),y) - media-objs += media-dev-allocator.o - endif -endif - # # I2C drivers should come before other drivers, otherwise they'll fail # when compiled as builtin drivers @@ -20,10 +11,10 @@ obj-y += i2c/ tuners/ obj-$(CONFIG_DVB_CORE) += dvb-frontends/ # -# Now, let's link-in the media core +# Now, let's link-in the media controller core # ifeq ($(CONFIG_MEDIA_CONTROLLER),y) - obj-$(CONFIG_MEDIA_SUPPORT) += media.o + obj-$(CONFIG_MEDIA_SUPPORT) += mc/ endif obj-$(CONFIG_VIDEO_DEV) += v4l2-core/ diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index f1261cc2b6fa..451c61bde4d4 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -16,7 +16,10 @@ #include <linux/string.h> #include <linux/types.h> +#include <drm/drm_connector.h> +#include <drm/drm_device.h> #include <drm/drm_edid.h> +#include <drm/drm_file.h> #include "cec-priv.h" @@ -75,6 +78,16 @@ u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size, } EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr); +void cec_fill_conn_info_from_drm(struct cec_connector_info *conn_info, + const struct drm_connector *connector) +{ + memset(conn_info, 0, sizeof(*conn_info)); + conn_info->type = CEC_CONNECTOR_TYPE_DRM; + conn_info->drm.card_no = connector->dev->primary->index; + conn_info->drm.connector_id = connector->base.id; +} +EXPORT_SYMBOL_GPL(cec_fill_conn_info_from_drm); + /* * Queue a new event for this filehandle. If ts == 0, then set it * to the current time. @@ -720,6 +733,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, struct cec_fh *fh, bool block) { struct cec_data *data; + bool is_raw = msg_is_raw(msg); msg->rx_ts = 0; msg->tx_ts = 0; @@ -735,15 +749,10 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, /* Make sure the timeout isn't 0. */ msg->timeout = 1000; } - if (msg->timeout) - msg->flags &= CEC_MSG_FL_REPLY_TO_FOLLOWERS; - else - msg->flags = 0; + msg->flags &= CEC_MSG_FL_REPLY_TO_FOLLOWERS | CEC_MSG_FL_RAW; - if (msg->len > 1 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) { - msg->msg[2] = adap->phys_addr >> 8; - msg->msg[3] = adap->phys_addr & 0xff; - } + if (!msg->timeout) + msg->flags &= ~CEC_MSG_FL_REPLY_TO_FOLLOWERS; /* Sanity checks */ if (msg->len == 0 || msg->len > CEC_MAX_MSG_SIZE) { @@ -765,44 +774,80 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, dprintk(1, "%s: can't reply to poll msg\n", __func__); return -EINVAL; } - if (msg->len == 1) { - if (cec_msg_destination(msg) == 0xf) { - dprintk(1, "%s: invalid poll message\n", __func__); + + if (is_raw) { + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + } else { + /* A CDC-Only device can only send CDC messages */ + if ((adap->log_addrs.flags & CEC_LOG_ADDRS_FL_CDC_ONLY) && + (msg->len == 1 || msg->msg[1] != CEC_MSG_CDC_MESSAGE)) { + dprintk(1, "%s: not a CDC message\n", __func__); return -EINVAL; } - if (cec_has_log_addr(adap, cec_msg_destination(msg))) { - /* - * If the destination is a logical address our adapter - * has already claimed, then just NACK this. - * It depends on the hardware what it will do with a - * POLL to itself (some OK this), so it is just as - * easy to handle it here so the behavior will be - * consistent. - */ - msg->tx_ts = ktime_get_ns(); - msg->tx_status = CEC_TX_STATUS_NACK | - CEC_TX_STATUS_MAX_RETRIES; - msg->tx_nack_cnt = 1; - msg->sequence = ++adap->sequence; - if (!msg->sequence) + + if (msg->len >= 4 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) { + msg->msg[2] = adap->phys_addr >> 8; + msg->msg[3] = adap->phys_addr & 0xff; + } + + if (msg->len == 1) { + if (cec_msg_destination(msg) == 0xf) { + dprintk(1, "%s: invalid poll message\n", + __func__); + return -EINVAL; + } + if (cec_has_log_addr(adap, cec_msg_destination(msg))) { + /* + * If the destination is a logical address our + * adapter has already claimed, then just NACK + * this. It depends on the hardware what it will + * do with a POLL to itself (some OK this), so + * it is just as easy to handle it here so the + * behavior will be consistent. + */ + msg->tx_ts = ktime_get_ns(); + msg->tx_status = CEC_TX_STATUS_NACK | + CEC_TX_STATUS_MAX_RETRIES; + msg->tx_nack_cnt = 1; msg->sequence = ++adap->sequence; - return 0; + if (!msg->sequence) + msg->sequence = ++adap->sequence; + return 0; + } + } + if (msg->len > 1 && !cec_msg_is_broadcast(msg) && + cec_has_log_addr(adap, cec_msg_destination(msg))) { + dprintk(1, "%s: destination is the adapter itself\n", + __func__); + return -EINVAL; + } + if (msg->len > 1 && adap->is_configured && + !cec_has_log_addr(adap, cec_msg_initiator(msg))) { + dprintk(1, "%s: initiator has unknown logical address %d\n", + __func__, cec_msg_initiator(msg)); + return -EINVAL; + } + /* + * Special case: allow Ping and IMAGE/TEXT_VIEW_ON to be + * transmitted to a TV, even if the adapter is unconfigured. + * This makes it possible to detect or wake up displays that + * pull down the HPD when in standby. + */ + if (!adap->is_configured && !adap->is_configuring && + (msg->len > 2 || + cec_msg_destination(msg) != CEC_LOG_ADDR_TV || + (msg->len == 2 && msg->msg[1] != CEC_MSG_IMAGE_VIEW_ON && + msg->msg[1] != CEC_MSG_TEXT_VIEW_ON))) { + dprintk(1, "%s: adapter is unconfigured\n", __func__); + return -ENONET; } } - if (msg->len > 1 && !cec_msg_is_broadcast(msg) && - cec_has_log_addr(adap, cec_msg_destination(msg))) { - dprintk(1, "%s: destination is the adapter itself\n", __func__); - return -EINVAL; - } - if (msg->len > 1 && adap->is_configured && - !cec_has_log_addr(adap, cec_msg_initiator(msg))) { - dprintk(1, "%s: initiator has unknown logical address %d\n", - __func__, cec_msg_initiator(msg)); - return -EINVAL; - } + if (!adap->is_configured && !adap->is_configuring) { - if (adap->needs_hpd || msg->msg[0] != 0xf0) { - dprintk(1, "%s: adapter is unconfigured\n", __func__); + if (adap->needs_hpd) { + dprintk(1, "%s: adapter is unconfigured and needs HPD\n", + __func__); return -ENONET; } if (msg->reply) { @@ -1566,6 +1611,22 @@ void cec_s_phys_addr_from_edid(struct cec_adapter *adap, } EXPORT_SYMBOL_GPL(cec_s_phys_addr_from_edid); +void cec_s_conn_info(struct cec_adapter *adap, + const struct cec_connector_info *conn_info) +{ + if (!(adap->capabilities & CEC_CAP_CONNECTOR_INFO)) + return; + + mutex_lock(&adap->lock); + if (conn_info) + adap->conn_info = *conn_info; + else + memset(&adap->conn_info, 0, sizeof(adap->conn_info)); + cec_post_state_event(adap); + mutex_unlock(&adap->lock); +} +EXPORT_SYMBOL_GPL(cec_s_conn_info); + /* * Called from either the ioctl or a driver to set the logical addresses. * diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 156a0d76ab2a..12d676484472 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -198,19 +198,11 @@ static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh, if (copy_from_user(&msg, parg, sizeof(msg))) return -EFAULT; - /* A CDC-Only device can only send CDC messages */ - if ((adap->log_addrs.flags & CEC_LOG_ADDRS_FL_CDC_ONLY) && - (msg.len == 1 || msg.msg[1] != CEC_MSG_CDC_MESSAGE)) - return -EINVAL; - mutex_lock(&adap->lock); if (adap->log_addrs.num_log_addrs == 0) err = -EPERM; else if (adap->is_configuring) err = -ENONET; - else if (!adap->is_configured && - (adap->needs_hpd || msg.msg[0] != 0xf0)) - err = -ENONET; else if (cec_is_busy(adap, fh)) err = -EBUSY; else diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index f5d1578e256a..9c610e1e99b8 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -128,13 +128,14 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode, devnode->cdev.owner = owner; kobject_set_name(&devnode->cdev.kobj, "cec%d", devnode->minor); + devnode->registered = true; ret = cdev_device_add(&devnode->cdev, &devnode->dev); if (ret) { + devnode->registered = false; pr_err("%s: cdev_device_add failed\n", __func__); goto clr_bit; } - devnode->registered = true; return 0; clr_bit: @@ -256,6 +257,11 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, struct cec_adapter *adap; int res; + /* + * Disable this capability until the connector info public API + * is ready. + */ + caps &= ~CEC_CAP_CONNECTOR_INFO; #ifndef CONFIG_MEDIA_CEC_RC caps &= ~CEC_CAP_RC; #endif diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c index 9598c7778871..52a867bde15f 100644 --- a/drivers/media/cec/cec-notifier.c +++ b/drivers/media/cec/cec-notifier.c @@ -21,8 +21,9 @@ struct cec_notifier { struct mutex lock; struct list_head head; struct kref kref; - struct device *dev; - const char *conn; + struct device *hdmi_dev; + struct cec_connector_info conn_info; + const char *conn_name; struct cec_adapter *cec_adap; void (*callback)(struct cec_adapter *adap, u16 pa); @@ -32,14 +33,16 @@ struct cec_notifier { static LIST_HEAD(cec_notifiers); static DEFINE_MUTEX(cec_notifiers_lock); -struct cec_notifier *cec_notifier_get_conn(struct device *dev, const char *conn) +struct cec_notifier * +cec_notifier_get_conn(struct device *hdmi_dev, const char *conn_name) { struct cec_notifier *n; mutex_lock(&cec_notifiers_lock); list_for_each_entry(n, &cec_notifiers, head) { - if (n->dev == dev && - (!conn || !strcmp(n->conn, conn))) { + if (n->hdmi_dev == hdmi_dev && + (!conn_name || + (n->conn_name && !strcmp(n->conn_name, conn_name)))) { kref_get(&n->kref); mutex_unlock(&cec_notifiers_lock); return n; @@ -48,10 +51,17 @@ struct cec_notifier *cec_notifier_get_conn(struct device *dev, const char *conn) n = kzalloc(sizeof(*n), GFP_KERNEL); if (!n) goto unlock; - n->dev = dev; - if (conn) - n->conn = kstrdup(conn, GFP_KERNEL); + n->hdmi_dev = hdmi_dev; + if (conn_name) { + n->conn_name = kstrdup(conn_name, GFP_KERNEL); + if (!n->conn_name) { + kfree(n); + n = NULL; + goto unlock; + } + } n->phys_addr = CEC_PHYS_ADDR_INVALID; + mutex_init(&n->lock); kref_init(&n->kref); list_add_tail(&n->head, &cec_notifiers); @@ -67,7 +77,7 @@ static void cec_notifier_release(struct kref *kref) container_of(kref, struct cec_notifier, kref); list_del(&n->head); - kfree(n->conn); + kfree(n->conn_name); kfree(n); } @@ -79,6 +89,84 @@ void cec_notifier_put(struct cec_notifier *n) } EXPORT_SYMBOL_GPL(cec_notifier_put); +struct cec_notifier * +cec_notifier_conn_register(struct device *hdmi_dev, const char *conn_name, + const struct cec_connector_info *conn_info) +{ + struct cec_notifier *n = cec_notifier_get_conn(hdmi_dev, conn_name); + + if (!n) + return n; + + mutex_lock(&n->lock); + n->phys_addr = CEC_PHYS_ADDR_INVALID; + if (conn_info) + n->conn_info = *conn_info; + else + memset(&n->conn_info, 0, sizeof(n->conn_info)); + if (n->cec_adap) { + cec_phys_addr_invalidate(n->cec_adap); + cec_s_conn_info(n->cec_adap, conn_info); + } + mutex_unlock(&n->lock); + return n; +} +EXPORT_SYMBOL_GPL(cec_notifier_conn_register); + +void cec_notifier_conn_unregister(struct cec_notifier *n) +{ + if (!n) + return; + + mutex_lock(&n->lock); + memset(&n->conn_info, 0, sizeof(n->conn_info)); + n->phys_addr = CEC_PHYS_ADDR_INVALID; + if (n->cec_adap) { + cec_phys_addr_invalidate(n->cec_adap); + cec_s_conn_info(n->cec_adap, NULL); + } + mutex_unlock(&n->lock); + cec_notifier_put(n); +} +EXPORT_SYMBOL_GPL(cec_notifier_conn_unregister); + +struct cec_notifier * +cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name, + struct cec_adapter *adap) +{ + struct cec_notifier *n; + + if (WARN_ON(!adap)) + return NULL; + + n = cec_notifier_get_conn(hdmi_dev, conn_name); + if (!n) + return n; + + mutex_lock(&n->lock); + n->cec_adap = adap; + adap->conn_info = n->conn_info; + adap->notifier = n; + cec_s_phys_addr(adap, n->phys_addr, false); + mutex_unlock(&n->lock); + return n; +} +EXPORT_SYMBOL_GPL(cec_notifier_cec_adap_register); + +void cec_notifier_cec_adap_unregister(struct cec_notifier *n) +{ + if (!n) + return; + + mutex_lock(&n->lock); + n->cec_adap->notifier = NULL; + n->cec_adap = NULL; + n->callback = NULL; + mutex_unlock(&n->lock); + cec_notifier_put(n); +} +EXPORT_SYMBOL_GPL(cec_notifier_cec_adap_unregister); + void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) { if (n == NULL) @@ -88,6 +176,8 @@ void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) n->phys_addr = pa; if (n->callback) n->callback(n->cec_adap, n->phys_addr); + else if (n->cec_adap) + cec_s_phys_addr(n->cec_adap, n->phys_addr, false); mutex_unlock(&n->lock); } EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr); @@ -122,6 +212,10 @@ EXPORT_SYMBOL_GPL(cec_notifier_register); void cec_notifier_unregister(struct cec_notifier *n) { + /* Do nothing unless cec_notifier_register was called first */ + if (!n->callback) + return; + mutex_lock(&n->lock); n->callback = NULL; mutex_unlock(&n->lock); diff --git a/drivers/media/cec/cec-priv.h b/drivers/media/cec/cec-priv.h index 804e38f849c7..7bdf855aaecd 100644 --- a/drivers/media/cec/cec-priv.h +++ b/drivers/media/cec/cec-priv.h @@ -20,6 +20,11 @@ /* devnode to cec_adapter */ #define to_cec_adapter(node) container_of(node, struct cec_adapter, devnode) +static inline bool msg_is_raw(const struct cec_msg *msg) +{ + return msg->flags & CEC_MSG_FL_RAW; +} + /* cec-core.c */ extern int cec_debug; int cec_get_device(struct cec_devnode *devnode); diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index be4f80a40214..aabb830e7468 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -608,6 +608,15 @@ int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev, for (i = 0; i < dev->ext_vv_data->num_stds; i++) vfd->tvnorms |= dev->ext_vv_data->stds[i].id; strscpy(vfd->name, name, sizeof(vfd->name)); + vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + vfd->device_caps |= dev->ext_vv_data->capabilities; + if (type == VFL_TYPE_GRABBER) + vfd->device_caps &= + ~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT); + else + vfd->device_caps &= + ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO); video_set_drvdata(vfd, dev); err = video_register_device(vfd, type, -1); diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index a0f0b5eef0bd..4c399a42e874 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -448,25 +448,15 @@ static int video_end(struct saa7146_fh *fh, struct file *file) static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; strscpy((char *)cap->driver, "saa7146 v4l2", sizeof(cap->driver)); strscpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->device_caps = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VIDEO_OVERLAY | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - cap->device_caps |= dev->ext_vv_data->capabilities; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - if (vdev->vfl_type == VFL_TYPE_GRABBER) - cap->device_caps &= - ~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT); - else - cap->device_caps &= - ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_DEVICE_CAPS; + cap->capabilities |= dev->ext_vv_data->capabilities; return 0; } diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 3cf25abf5807..4489744fbbd9 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -205,8 +205,13 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) * NOTE: mmapped areas should be page aligned */ for (plane = 0; plane < vb->num_planes; ++plane) { + /* Memops alloc requires size to be page aligned. */ unsigned long size = PAGE_ALIGN(vb->planes[plane].length); + /* Did it wrap around? */ + if (size < vb->planes[plane].length) + goto free; + mem_priv = call_ptr_memop(vb, alloc, q->alloc_devs[plane] ? : q->dev, q->dma_attrs, size, q->dma_dir, q->gfp_flags); diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index ecbef266130b..7d77e4d30c8a 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -475,8 +475,7 @@ static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr, buf->dma_dir = dma_dir; offset = lower_32_bits(offset_in_page(vaddr)); - vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE || - dma_dir == DMA_BIDIRECTIONAL); + vec = vb2_create_framevec(vaddr, size); if (IS_ERR(vec)) { ret = PTR_ERR(vec); goto fail_buf; diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index 4a4c49d6085c..ed706b2a263c 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -59,7 +59,7 @@ static int vb2_dma_sg_alloc_compacted(struct vb2_dma_sg_buf *buf, gfp_t gfp_flags) { unsigned int last_page = 0; - int size = buf->size; + unsigned long size = buf->size; while (size > 0) { struct page *pages; @@ -239,8 +239,7 @@ static void *vb2_dma_sg_get_userptr(struct device *dev, unsigned long vaddr, buf->offset = vaddr & ~PAGE_MASK; buf->size = size; buf->dma_sgt = &buf->sg_table; - vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE || - dma_dir == DMA_BIDIRECTIONAL); + vec = vb2_create_framevec(vaddr, size); if (IS_ERR(vec)) goto userptr_fail_pfnvec; buf->vec = vec; diff --git a/drivers/media/common/videobuf2/videobuf2-memops.c b/drivers/media/common/videobuf2/videobuf2-memops.c index c4a85be48ac2..6e9e05153f4e 100644 --- a/drivers/media/common/videobuf2/videobuf2-memops.c +++ b/drivers/media/common/videobuf2/videobuf2-memops.c @@ -26,7 +26,6 @@ * vb2_create_framevec() - map virtual addresses to pfns * @start: Virtual user address where we start mapping * @length: Length of a range to map - * @write: Should we map for writing into the area * * This function allocates and fills in a vector with pfns corresponding to * virtual address range passed in arguments. If pfns have corresponding pages, @@ -35,17 +34,13 @@ * failure. Returned vector needs to be freed via vb2_destroy_pfnvec(). */ struct frame_vector *vb2_create_framevec(unsigned long start, - unsigned long length, - bool write) + unsigned long length) { int ret; unsigned long first, last; unsigned long nr; struct frame_vector *vec; - unsigned int flags = FOLL_FORCE; - - if (write) - flags |= FOLL_WRITE; + unsigned int flags = FOLL_FORCE | FOLL_WRITE; first = start >> PAGE_SHIFT; last = (start + length - 1) >> PAGE_SHIFT; diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index fb9ac7696fc6..40d76eb4c2fe 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -563,11 +563,6 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) b->flags |= V4L2_BUF_FLAG_REQUEST_FD; b->request_fd = vbuf->request_fd; } - - if (!q->is_output && - b->flags & V4L2_BUF_FLAG_DONE && - b->flags & V4L2_BUF_FLAG_LAST) - q->last_buffer_dequeued = true; } /* @@ -786,6 +781,11 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) ret = vb2_core_dqbuf(q, NULL, b, nonblocking); + if (!q->is_output && + b->flags & V4L2_BUF_FLAG_DONE && + b->flags & V4L2_BUF_FLAG_LAST) + q->last_buffer_dequeued = true; + /* * After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be * cleared. diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 1c6659f7c394..04d51ca63223 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -87,8 +87,7 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr, buf->dma_dir = dma_dir; offset = vaddr & ~PAGE_MASK; buf->size = size; - vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE || - dma_dir == DMA_BIDIRECTIONAL); + vec = vb2_create_framevec(vaddr, size); if (IS_ERR(vec)) { ret = PTR_ERR(vec); goto fail_pfnvec_create; diff --git a/drivers/media/dvb-core/Kconfig b/drivers/media/dvb-core/Kconfig index aac4bebb35f7..90e038d5ffd9 100644 --- a/drivers/media/dvb-core/Kconfig +++ b/drivers/media/dvb-core/Kconfig @@ -19,7 +19,6 @@ config DVB_MAX_ADAPTERS config DVB_DYNAMIC_MINORS bool "Dynamic DVB minor allocation" depends on DVB_CORE - default n help If you say Y here, the DVB subsystem will use dynamic minor allocation for any device that uses the DVB major number. @@ -32,7 +31,6 @@ config DVB_DYNAMIC_MINORS config DVB_DEMUX_SECTION_LOSS_LOG bool "Enable DVB demux section packet loss log" depends on DVB_CORE - default n help Enable extra log messages meant to detect packet loss inside the Kernel. @@ -45,7 +43,6 @@ config DVB_DEMUX_SECTION_LOSS_LOG config DVB_ULE_DEBUG bool "Enable DVB net ULE packet debug messages" depends on DVB_CORE - default n help Enable extra log messages meant to detect problems while handling DVB network ULE packet loss inside the Kernel. diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 6351a97f3d18..209186c5cd9b 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2311,6 +2311,78 @@ static int dtv_set_frontend(struct dvb_frontend *fe) return 0; } +static int dvb_get_property(struct dvb_frontend *fe, struct file *file, + struct dtv_properties *tvps) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dtv_property *tvp = NULL; + struct dtv_frontend_properties getp; + int i, err; + + memcpy(&getp, &fe->dtv_property_cache, sizeof(getp)); + + dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", + __func__, tvps->num); + dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", + __func__, tvps->props); + + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || tvps->num > DTV_IOCTL_MAX_MSGS) + return -EINVAL; + + tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp)); + if (IS_ERR(tvp)) + return PTR_ERR(tvp); + + /* + * Let's use our own copy of property cache, in order to + * avoid mangling with DTV zigzag logic, as drivers might + * return crap, if they don't check if the data is available + * before updating the properties cache. + */ + if (fepriv->state != FESTATE_IDLE) { + err = dtv_get_frontend(fe, &getp, NULL); + if (err < 0) + goto out; + } + for (i = 0; i < tvps->num; i++) { + err = dtv_property_process_get(fe, &getp, + tvp + i, file); + if (err < 0) + goto out; + } + + if (copy_to_user((void __user *)tvps->props, tvp, + tvps->num * sizeof(struct dtv_property))) { + err = -EFAULT; + goto out; + } + + err = 0; +out: + kfree(tvp); + return err; +} + +static int dvb_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p_out) +{ + struct dtv_frontend_properties getp; + + /* + * Let's use our own copy of property cache, in order to + * avoid mangling with DTV zigzag logic, as drivers might + * return crap, if they don't check if the data is available + * before updating the properties cache. + */ + memcpy(&getp, &fe->dtv_property_cache, sizeof(getp)); + + return dtv_get_frontend(fe, &getp, p_out); +} + static int dvb_frontend_handle_ioctl(struct file *file, unsigned int cmd, void *parg) { @@ -2356,58 +2428,9 @@ static int dvb_frontend_handle_ioctl(struct file *file, err = 0; break; } - case FE_GET_PROPERTY: { - struct dtv_properties *tvps = parg; - struct dtv_property *tvp = NULL; - struct dtv_frontend_properties getp = fe->dtv_property_cache; - - dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", - __func__, tvps->num); - dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", - __func__, tvps->props); - - /* - * Put an arbitrary limit on the number of messages that can - * be sent at once - */ - if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) - return -EINVAL; - - tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp)); - if (IS_ERR(tvp)) - return PTR_ERR(tvp); - - /* - * Let's use our own copy of property cache, in order to - * avoid mangling with DTV zigzag logic, as drivers might - * return crap, if they don't check if the data is available - * before updating the properties cache. - */ - if (fepriv->state != FESTATE_IDLE) { - err = dtv_get_frontend(fe, &getp, NULL); - if (err < 0) { - kfree(tvp); - return err; - } - } - for (i = 0; i < tvps->num; i++) { - err = dtv_property_process_get(fe, &getp, - tvp + i, file); - if (err < 0) { - kfree(tvp); - return err; - } - } - - if (copy_to_user((void __user *)tvps->props, tvp, - tvps->num * sizeof(struct dtv_property))) { - kfree(tvp); - return -EFAULT; - } - kfree(tvp); - err = 0; + case FE_GET_PROPERTY: + err = dvb_get_property(fe, file, parg); break; - } case FE_GET_INFO: { struct dvb_frontend_info *info = parg; @@ -2545,7 +2568,6 @@ static int dvb_frontend_handle_ioctl(struct file *file, fepriv->tune_mode_flags = (unsigned long)parg; err = 0; break; - /* DEPRECATED dish control ioctls */ case FE_DISHNETWORK_SEND_LEGACY_CMD: @@ -2664,22 +2686,14 @@ static int dvb_frontend_handle_ioctl(struct file *file, break; err = dtv_set_frontend(fe); break; + case FE_GET_EVENT: err = dvb_frontend_get_event(fe, parg, file->f_flags); break; - case FE_GET_FRONTEND: { - struct dtv_frontend_properties getp = fe->dtv_property_cache; - - /* - * Let's use our own copy of property cache, in order to - * avoid mangling with DTV zigzag logic, as drivers might - * return crap, if they don't check if the data is available - * before updating the properties cache. - */ - err = dtv_get_frontend(fe, &getp, parg); + case FE_GET_FRONTEND: + err = dvb_get_frontend(fe, parg); break; - } default: return -ENOTSUPP; diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 847da72d1256..dc43749177df 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -1,5 +1,5 @@ menu "Customise DVB Frontends" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST + visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT comment "Multistandard (satellite) frontends" depends on DVB_CORE @@ -945,5 +945,4 @@ comment "Tools to develop new frontends" config DVB_DUMMY_FE tristate "Dummy frontend driver" depends on DVB_CORE - default n endmenu diff --git a/drivers/media/dvb-frontends/dib3000.h b/drivers/media/dvb-frontends/dib3000.h index d2b7523a22b5..9118a7a48ef2 100644 --- a/drivers/media/dvb-frontends/dib3000.h +++ b/drivers/media/dvb-frontends/dib3000.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * public header file of the frontend drivers for mobile DVB-T demodulators * DiBcom 3000M-B and DiBcom 3000P/M-C (http://www.dibcom.fr/) @@ -8,17 +9,12 @@ * * Copyright (C) 2004 Amaury Demol for DiBcom * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * * Acknowledgements * * Amaury Demol from DiBcom for providing specs and driver * sources, on which this driver (and the dvb-dibusb) are based. * * see Documentation/media/dvb-drivers/dvb-usb.rst for more information - * */ #ifndef DIB3000_H diff --git a/drivers/media/dvb-frontends/dib3000mb.c b/drivers/media/dvb-frontends/dib3000mb.c index bbbd53280477..46ed0e20c8fa 100644 --- a/drivers/media/dvb-frontends/dib3000mb.c +++ b/drivers/media/dvb-frontends/dib3000mb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Frontend driver for mobile DVB-T demodulator DiBcom 3000M-B * DiBcom (http://www.dibcom.fr/) @@ -8,17 +9,12 @@ * * Copyright (C) 2004 Amaury Demol for DiBcom * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * * Acknowledgements * * Amaury Demol from DiBcom for providing specs and driver * sources, on which this driver (and the dvb-dibusb) are based. * * see Documentation/media/dvb-drivers/dvb-usb.rst for more information - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/media/dvb-frontends/drxd.h b/drivers/media/dvb-frontends/drxd.h index 1d4b89488ac4..ba54fd9adab9 100644 --- a/drivers/media/dvb-frontends/drxd.h +++ b/drivers/media/dvb-frontends/drxd.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * drxd.h: DRXD DVB-T demodulator driver * * Copyright (C) 2005-2007 Micronas - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ #ifndef _DRXD_H_ diff --git a/drivers/media/dvb-frontends/drxd_firm.c b/drivers/media/dvb-frontends/drxd_firm.c index 412871d6636b..8aae3e0350d3 100644 --- a/drivers/media/dvb-frontends/drxd_firm.c +++ b/drivers/media/dvb-frontends/drxd_firm.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drxd_firm.c : DRXD firmware tables * * Copyright (C) 2006-2007 Micronas - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ /* TODO: generate this file with a script from a settings file */ diff --git a/drivers/media/dvb-frontends/drxd_firm.h b/drivers/media/dvb-frontends/drxd_firm.h index 7d9f9fa7ab3c..b3f04dfe248c 100644 --- a/drivers/media/dvb-frontends/drxd_firm.h +++ b/drivers/media/dvb-frontends/drxd_firm.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * drxd_firm.h * * Copyright (C) 2006-2007 Micronas - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ #ifndef _DRXD_FIRM_H_ diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index c597d6fc3046..fae6f3763364 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drxd_hard.c: DVB-T Demodulator Micronas DRX3975D-A2,DRX397xD-B1 * * Copyright (C) 2003-2007 Micronas - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ #include <linux/kernel.h> diff --git a/drivers/media/dvb-frontends/drxd_map_firm.h b/drivers/media/dvb-frontends/drxd_map_firm.h index 8e5bd2e8de40..bdcc63576df1 100644 --- a/drivers/media/dvb-frontends/drxd_map_firm.h +++ b/drivers/media/dvb-frontends/drxd_map_firm.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * drx3973d_map_firm.h * * Copyright (C) 2006-2007 Micronas - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ #ifndef __DRX3973D_MAP__H__ diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 86652a4ef9ce..0a4875b391d9 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drxk_hard: DRX-K DVB-C/T demodulator driver * * Copyright (C) 2010-2011 Digital Devices GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index cf1a8f77ee02..e05c21d35dc8 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -428,9 +428,6 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh, strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, dev->vdev.name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE | V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1242,6 +1239,8 @@ static struct video_device rtl2832_sdr_template = { .release = video_device_release_empty, .fops = &rtl2832_sdr_fops, .ioctl_ops = &rtl2832_sdr_ioctl_ops, + .device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE | V4L2_CAP_TUNER, }; static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 5dae571e2f62..168c503e9154 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -674,8 +674,11 @@ static const struct dvb_frontend_ops si2168_ops = { .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A}, .info = { .name = "Silicon Labs Si2168", - .symbol_rate_min = 1000000, - .symbol_rate_max = 7200000, + .frequency_min_hz = 48 * MHz, + .frequency_max_hz = 870 * MHz, + .frequency_stepsize_hz = 62500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 7200000, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | diff --git a/drivers/media/dvb-frontends/stv0297.c b/drivers/media/dvb-frontends/stv0297.c index dac396c95a59..6d5962d5697a 100644 --- a/drivers/media/dvb-frontends/stv0297.c +++ b/drivers/media/dvb-frontends/stv0297.c @@ -682,7 +682,7 @@ static const struct dvb_frontend_ops stv0297_ops = { .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "ST STV0297 DVB-C", - .frequency_min_hz = 470 * MHz, + .frequency_min_hz = 47 * MHz, .frequency_max_hz = 862 * MHz, .frequency_stepsize_hz = 62500, .symbol_rate_min = 870000, diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c index d1261571dbe4..90d24131d335 100644 --- a/drivers/media/dvb-frontends/stv090x.c +++ b/drivers/media/dvb-frontends/stv090x.c @@ -4889,6 +4889,66 @@ static int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg); } +static int stv090x_setup_compound(struct stv090x_state *state) +{ + struct stv090x_dev *temp_int; + + temp_int = find_dev(state->i2c, + state->config->address); + + if (temp_int && state->demod_mode == STV090x_DUAL) { + state->internal = temp_int->internal; + state->internal->num_used++; + dprintk(FE_INFO, 1, "Found Internal Structure!"); + } else { + state->internal = kmalloc(sizeof(*state->internal), GFP_KERNEL); + if (!state->internal) + goto error; + temp_int = append_internal(state->internal); + if (!temp_int) { + kfree(state->internal); + goto error; + } + state->internal->num_used = 1; + state->internal->mclk = 0; + state->internal->dev_ver = 0; + state->internal->i2c_adap = state->i2c; + state->internal->i2c_addr = state->config->address; + dprintk(FE_INFO, 1, "Create New Internal Structure!"); + + mutex_init(&state->internal->demod_lock); + mutex_init(&state->internal->tuner_lock); + + if (stv090x_setup(&state->frontend) < 0) { + dprintk(FE_ERROR, 1, "Error setting up device"); + goto err_remove; + } + } + + if (state->internal->dev_ver >= 0x30) + state->frontend.ops.info.caps |= FE_CAN_MULTISTREAM; + + /* workaround for stuck DiSEqC output */ + if (state->config->diseqc_envelope_mode) + stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A); + + state->config->set_gpio = stv090x_set_gpio; + + dprintk(FE_ERROR, 1, "Probing %s demodulator(%d) Cut=0x%02x", + state->device == STV0900 ? "STV0900" : "STV0903", + state->config->demod, + state->internal->dev_ver); + + return 0; + +error: + return -ENOMEM; +err_remove: + remove_dev(state->internal); + kfree(state->internal); + return -ENODEV; +} + static const struct dvb_frontend_ops stv090x_ops = { .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, .info = { @@ -4921,85 +4981,118 @@ static const struct dvb_frontend_ops stv090x_ops = { .read_snr = stv090x_read_cnr, }; +static struct dvb_frontend *stv090x_get_dvb_frontend(struct i2c_client *client) +{ + struct stv090x_state *state = i2c_get_clientdata(client); -struct dvb_frontend *stv090x_attach(struct stv090x_config *config, - struct i2c_adapter *i2c, - enum stv090x_demodulator demod) + dev_dbg(&client->dev, "\n"); + + return &state->frontend; +} + +static int stv090x_probe(struct i2c_client *client, + const struct i2c_device_id *id) { + int ret = 0; + struct stv090x_config *config = client->dev.platform_data; + struct stv090x_state *state = NULL; - struct stv090x_dev *temp_int; - state = kzalloc(sizeof (struct stv090x_state), GFP_KERNEL); - if (state == NULL) + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) { + ret = -ENOMEM; goto error; + } state->verbose = &verbose; state->config = config; - state->i2c = i2c; + state->i2c = client->adapter; state->frontend.ops = stv090x_ops; state->frontend.demodulator_priv = state; - state->demod = demod; - state->demod_mode = config->demod_mode; /* Single or Dual mode */ + state->demod = config->demod; + /* Single or Dual mode */ + state->demod_mode = config->demod_mode; state->device = config->device; - state->rolloff = STV090x_RO_35; /* default */ + /* default */ + state->rolloff = STV090x_RO_35; - temp_int = find_dev(state->i2c, - state->config->address); + ret = stv090x_setup_compound(state); + if (ret) + goto error; - if ((temp_int != NULL) && (state->demod_mode == STV090x_DUAL)) { - state->internal = temp_int->internal; - state->internal->num_used++; - dprintk(FE_INFO, 1, "Found Internal Structure!"); - } else { - state->internal = kmalloc(sizeof(struct stv090x_internal), - GFP_KERNEL); - if (!state->internal) - goto error; - temp_int = append_internal(state->internal); - if (!temp_int) { - kfree(state->internal); - goto error; - } - state->internal->num_used = 1; - state->internal->mclk = 0; - state->internal->dev_ver = 0; - state->internal->i2c_adap = state->i2c; - state->internal->i2c_addr = state->config->address; - dprintk(FE_INFO, 1, "Create New Internal Structure!"); + i2c_set_clientdata(client, state); - mutex_init(&state->internal->demod_lock); - mutex_init(&state->internal->tuner_lock); + /* setup callbacks */ + config->get_dvb_frontend = stv090x_get_dvb_frontend; - if (stv090x_setup(&state->frontend) < 0) { - dprintk(FE_ERROR, 1, "Error setting up device"); - goto err_remove; - } - } + return 0; - if (state->internal->dev_ver >= 0x30) - state->frontend.ops.info.caps |= FE_CAN_MULTISTREAM; +error: + kfree(state); + return ret; +} - /* workaround for stuck DiSEqC output */ - if (config->diseqc_envelope_mode) - stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A); +static int stv090x_remove(struct i2c_client *client) +{ + struct stv090x_state *state = i2c_get_clientdata(client); + + stv090x_release(&state->frontend); + return 0; +} - config->set_gpio = stv090x_set_gpio; +struct dvb_frontend *stv090x_attach(struct stv090x_config *config, + struct i2c_adapter *i2c, + enum stv090x_demodulator demod) +{ + int ret = 0; + struct stv090x_state *state = NULL; - dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x", - state->device == STV0900 ? "STV0900" : "STV0903", - demod, - state->internal->dev_ver); + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + goto error; + + state->verbose = &verbose; + state->config = config; + state->i2c = i2c; + state->frontend.ops = stv090x_ops; + state->frontend.demodulator_priv = state; + state->demod = demod; + /* Single or Dual mode */ + state->demod_mode = config->demod_mode; + state->device = config->device; + /* default */ + state->rolloff = STV090x_RO_35; + + ret = stv090x_setup_compound(state); + if (ret) + goto error; return &state->frontend; -err_remove: - remove_dev(state->internal); - kfree(state->internal); error: kfree(state); return NULL; } EXPORT_SYMBOL(stv090x_attach); + +static const struct i2c_device_id stv090x_id_table[] = { + {"stv090x", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, stv090x_id_table); + +static struct i2c_driver stv090x_driver = { + .driver = { + .name = "stv090x", + .suppress_bind_attrs = true, + }, + .probe = stv090x_probe, + .remove = stv090x_remove, + .id_table = stv090x_id_table, +}; + +module_i2c_driver(stv090x_driver); + MODULE_PARM_DESC(verbose, "Set Verbosity level"); MODULE_AUTHOR("Manu Abraham"); MODULE_DESCRIPTION("STV090x Multi-Std Broadcast frontend"); diff --git a/drivers/media/dvb-frontends/stv090x.h b/drivers/media/dvb-frontends/stv090x.h index 13f251a08abd..89f45d9fa427 100644 --- a/drivers/media/dvb-frontends/stv090x.h +++ b/drivers/media/dvb-frontends/stv090x.h @@ -57,6 +57,7 @@ struct stv090x_config { enum stv090x_device device; enum stv090x_mode demod_mode; enum stv090x_clkmode clk_mode; + enum stv090x_demodulator demod; u32 xtal; /* default: 8000000 */ u8 address; /* default: 0x68 */ @@ -93,6 +94,8 @@ struct stv090x_config { /* dir = 0 -> output, dir = 1 -> input/open-drain */ int (*set_gpio)(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value, u8 xor_value); + + struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *i2c); }; #if IS_REACHABLE(CONFIG_DVB_STV090x) diff --git a/drivers/media/dvb-frontends/stv090x_priv.h b/drivers/media/dvb-frontends/stv090x_priv.h index b22c58968c93..f8ece898c153 100644 --- a/drivers/media/dvb-frontends/stv090x_priv.h +++ b/drivers/media/dvb-frontends/stv090x_priv.h @@ -237,7 +237,7 @@ struct stv090x_state { struct stv090x_internal *internal; struct i2c_adapter *i2c; - const struct stv090x_config *config; + struct stv090x_config *config; struct dvb_frontend frontend; u32 *verbose; /* Cached module verbosity */ diff --git a/drivers/media/dvb-frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c index 0126cfae2e03..5012d0231652 100644 --- a/drivers/media/dvb-frontends/stv6110x.c +++ b/drivers/media/dvb-frontends/stv6110x.c @@ -333,6 +333,41 @@ static void stv6110x_release(struct dvb_frontend *fe) kfree(stv6110x); } +static void st6110x_init_regs(struct stv6110x_state *stv6110x) +{ + u8 default_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e}; + + memcpy(stv6110x->regs, default_regs, 8); +} + +static void stv6110x_setup_divider(struct stv6110x_state *stv6110x) +{ + switch (stv6110x->config->clk_div) { + default: + case 1: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], + CTRL2_CO_DIV, + 0); + break; + case 2: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], + CTRL2_CO_DIV, + 1); + break; + case 4: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], + CTRL2_CO_DIV, + 2); + break; + case 8: + case 0: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], + CTRL2_CO_DIV, + 3); + break; + } +} + static const struct dvb_tuner_ops stv6110x_ops = { .info = { .name = "STV6110(A) Silicon Tuner", @@ -342,7 +377,7 @@ static const struct dvb_tuner_ops stv6110x_ops = { .release = stv6110x_release }; -static const struct stv6110x_devctl stv6110x_ctl = { +static struct stv6110x_devctl stv6110x_ctl = { .tuner_init = stv6110x_init, .tuner_sleep = stv6110x_sleep, .tuner_set_mode = stv6110x_set_mode, @@ -356,48 +391,104 @@ static const struct stv6110x_devctl stv6110x_ctl = { .tuner_get_status = stv6110x_get_status, }; +static void stv6110x_set_frontend_opts(struct stv6110x_state *stv6110x) +{ + stv6110x->frontend->tuner_priv = stv6110x; + stv6110x->frontend->ops.tuner_ops = stv6110x_ops; +} + +static struct stv6110x_devctl *stv6110x_get_devctl(struct i2c_client *client) +{ + struct stv6110x_state *stv6110x = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + return stv6110x->devctl; +} + +static int stv6110x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct stv6110x_config *config = client->dev.platform_data; + + struct stv6110x_state *stv6110x; + + stv6110x = kzalloc(sizeof(*stv6110x), GFP_KERNEL); + if (!stv6110x) + return -ENOMEM; + + stv6110x->frontend = config->frontend; + stv6110x->i2c = client->adapter; + stv6110x->config = config; + stv6110x->devctl = &stv6110x_ctl; + + st6110x_init_regs(stv6110x); + stv6110x_setup_divider(stv6110x); + stv6110x_set_frontend_opts(stv6110x); + + dev_info(&stv6110x->i2c->dev, "Probed STV6110x\n"); + + i2c_set_clientdata(client, stv6110x); + + /* setup callbacks */ + config->get_devctl = stv6110x_get_devctl; + + return 0; +} + +static int stv6110x_remove(struct i2c_client *client) +{ + struct stv6110x_state *stv6110x = i2c_get_clientdata(client); + + stv6110x_release(stv6110x->frontend); + return 0; +} + const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, const struct stv6110x_config *config, struct i2c_adapter *i2c) { struct stv6110x_state *stv6110x; - u8 default_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e}; - stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL); + stv6110x = kzalloc(sizeof(*stv6110x), GFP_KERNEL); if (!stv6110x) return NULL; + stv6110x->frontend = fe; stv6110x->i2c = i2c; stv6110x->config = config; stv6110x->devctl = &stv6110x_ctl; - memcpy(stv6110x->regs, default_regs, 8); - /* setup divider */ - switch (stv6110x->config->clk_div) { - default: - case 1: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0); - break; - case 2: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1); - break; - case 4: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2); - break; - case 8: - case 0: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3); - break; - } + st6110x_init_regs(stv6110x); + stv6110x_setup_divider(stv6110x); + stv6110x_set_frontend_opts(stv6110x); fe->tuner_priv = stv6110x; fe->ops.tuner_ops = stv6110x_ops; - printk(KERN_INFO "%s: Attaching STV6110x\n", __func__); + dev_info(&stv6110x->i2c->dev, "Attaching STV6110x\n"); return stv6110x->devctl; } EXPORT_SYMBOL(stv6110x_attach); +static const struct i2c_device_id stv6110x_id_table[] = { + {"stv6110x", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, stv6110x_id_table); + +static struct i2c_driver stv6110x_driver = { + .driver = { + .name = "stv6110x", + .suppress_bind_attrs = true, + }, + .probe = stv6110x_probe, + .remove = stv6110x_remove, + .id_table = stv6110x_id_table, +}; + +module_i2c_driver(stv6110x_driver); + MODULE_AUTHOR("Manu Abraham"); MODULE_DESCRIPTION("STV6110x Silicon tuner"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/stv6110x.h b/drivers/media/dvb-frontends/stv6110x.h index 1630e55255fd..1feade3158c2 100644 --- a/drivers/media/dvb-frontends/stv6110x.h +++ b/drivers/media/dvb-frontends/stv6110x.h @@ -15,6 +15,9 @@ struct stv6110x_config { u8 addr; u32 refclk; u8 clk_div; /* divisor value for the output clock */ + struct dvb_frontend *frontend; + + struct stv6110x_devctl* (*get_devctl)(struct i2c_client *i2c); }; enum tuner_mode { diff --git a/drivers/media/dvb-frontends/stv6110x_priv.h b/drivers/media/dvb-frontends/stv6110x_priv.h index 909094df28df..b27769558f78 100644 --- a/drivers/media/dvb-frontends/stv6110x_priv.h +++ b/drivers/media/dvb-frontends/stv6110x_priv.h @@ -54,11 +54,12 @@ #define REFCLOCK_MHz (stv6110x->config->refclk / 1000000) struct stv6110x_state { + struct dvb_frontend *frontend; struct i2c_adapter *i2c; const struct stv6110x_config *config; u8 regs[8]; - const struct stv6110x_devctl *devctl; + struct stv6110x_devctl *devctl; }; #endif /* __STV6110x_PRIV_H */ diff --git a/drivers/media/dvb-frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c index e064e2b22d9d..43312bba1aec 100644 --- a/drivers/media/dvb-frontends/tda18271c2dd.c +++ b/drivers/media/dvb-frontends/tda18271c2dd.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tda18271c2dd: Driver for the TDA18271C2 tuner * * Copyright (C) 2010 Digital Devices GmbH - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ #include <linux/kernel.h> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index cb8db944aa41..79ce9ec6fc1b 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -6,7 +6,7 @@ if VIDEO_V4L2 config VIDEO_IR_I2C - tristate "I2C module for IR" if !MEDIA_SUBDRV_AUTOSELECT + tristate "I2C module for IR" if !MEDIA_SUBDRV_AUTOSELECT || EXPERT depends on I2C && RC_CORE default y help @@ -23,7 +23,7 @@ config VIDEO_IR_I2C # menu "I2C Encoders, decoders, sensors and other helper chips" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST + visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT comment "Audio decoders, processors and mixers" @@ -511,6 +511,7 @@ config VIDEO_ADV7393 config VIDEO_ADV7511 tristate "Analog Devices ADV7511 encoder" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on DRM_I2C_ADV7511=n || COMPILE_TEST select HDMI help Support for the Analog Devices ADV7511 video encoder. diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index d8ad9dad495d..fd4ea86dedd5 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -35,7 +35,7 @@ obj-$(CONFIG_VIDEO_ADV748X) += adv748x/ obj-$(CONFIG_VIDEO_ADV7604) += adv7604.o obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o -obj-$(CONFIG_VIDEO_ADV7511) += adv7511.o +obj-$(CONFIG_VIDEO_ADV7511) += adv7511-v4l2.o obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o obj-$(CONFIG_VIDEO_VS6624) += vs6624.o obj-$(CONFIG_VIDEO_BT819) += bt819.o diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511-v4l2.c index cec5ebb1c9e6..2ad6bdf1a9fc 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511-v4l2.c @@ -5,6 +5,11 @@ * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. */ +/* + * This file is named adv7511-v4l2.c so it doesn't conflict with the Analog + * Device ADV7511 (config fragment CONFIG_DRM_I2C_ADV7511). + */ + #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c index 30f9db1351b9..1adaf470c75a 100644 --- a/drivers/media/i2c/ak881x.c +++ b/drivers/media/i2c/ak881x.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for AK8813 / AK8814 TV-ecoders from Asahi Kasei Microsystems Co., Ltd. (AKM) * * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/i2c.h> @@ -232,7 +229,7 @@ static const struct v4l2_subdev_ops ak881x_subdev_ops = { static int ak881x_probe(struct i2c_client *client, const struct i2c_device_id *did) { - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; struct ak881x *ak881x; u8 ifmode, data; diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 3ecf79d242f2..0de946fe2109 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -21,9 +21,11 @@ * * CX23888 DIF support for the HVR1850 * Copyright (C) 2011 Steven Toth <stoth@kernellabs.com> + * + * CX2584x pin to pad mapping and output format configuration support are + * Copyright (C) 2011 Maciej S. Szmigiero <mail@maciej.szmigiero.name> */ - #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> @@ -64,17 +66,17 @@ MODULE_LICENSE("GPL"); static int cx25840_debug; -module_param_named(debug,cx25840_debug, int, 0644); +module_param_named(debug, cx25840_debug, int, 0644); MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]"); - /* ----------------------------------------------------------------------- */ static void cx23888_std_setup(struct i2c_client *client); int cx25840_write(struct i2c_client *client, u16 addr, u8 value) { u8 buffer[3]; + buffer[0] = addr >> 8; buffer[1] = addr & 0xff; buffer[2] = value; @@ -84,6 +86,7 @@ int cx25840_write(struct i2c_client *client, u16 addr, u8 value) int cx25840_write4(struct i2c_client *client, u16 addr, u32 value) { u8 buffer[6]; + buffer[0] = addr >> 8; buffer[1] = addr & 0xff; buffer[2] = value & 0xff; @@ -93,7 +96,7 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value) return i2c_master_send(client, buffer, 6); } -u8 cx25840_read(struct i2c_client * client, u16 addr) +u8 cx25840_read(struct i2c_client *client, u16 addr) { struct i2c_msg msgs[2]; u8 tx_buf[2], rx_buf[1]; @@ -104,13 +107,13 @@ u8 cx25840_read(struct i2c_client * client, u16 addr) msgs[0].addr = client->addr; msgs[0].flags = 0; msgs[0].len = 2; - msgs[0].buf = (char *) tx_buf; + msgs[0].buf = (char *)tx_buf; /* Read data from register */ msgs[1].addr = client->addr; msgs[1].flags = I2C_M_RD; msgs[1].len = 1; - msgs[1].buf = (char *) rx_buf; + msgs[1].buf = (char *)rx_buf; if (i2c_transfer(client->adapter, msgs, 2) < 2) return 0; @@ -118,7 +121,7 @@ u8 cx25840_read(struct i2c_client * client, u16 addr) return rx_buf[0]; } -u32 cx25840_read4(struct i2c_client * client, u16 addr) +u32 cx25840_read4(struct i2c_client *client, u16 addr) { struct i2c_msg msgs[2]; u8 tx_buf[2], rx_buf[4]; @@ -129,13 +132,13 @@ u32 cx25840_read4(struct i2c_client * client, u16 addr) msgs[0].addr = client->addr; msgs[0].flags = 0; msgs[0].len = 2; - msgs[0].buf = (char *) tx_buf; + msgs[0].buf = (char *)tx_buf; /* Read data from registers */ msgs[1].addr = client->addr; msgs[1].flags = I2C_M_RD; msgs[1].len = 4; - msgs[1].buf = (char *) rx_buf; + msgs[1].buf = (char *)rx_buf; if (i2c_transfer(client->adapter, msgs, 2) < 2) return 0; @@ -144,7 +147,7 @@ u32 cx25840_read4(struct i2c_client * client, u16 addr) rx_buf[0]; } -int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask, +int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned int and_mask, u8 or_value) { return cx25840_write(client, addr, @@ -162,13 +165,14 @@ int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask, /* ----------------------------------------------------------------------- */ -static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, - enum cx25840_audio_input aud_input); +static int set_input(struct i2c_client *client, + enum cx25840_video_input vid_input, + enum cx25840_audio_input aud_input); /* ----------------------------------------------------------------------- */ static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n, - struct v4l2_subdev_io_pin_config *p) + struct v4l2_subdev_io_pin_config *p) { struct i2c_client *client = v4l2_get_subdevdata(sd); int i; @@ -307,13 +311,225 @@ static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n, return 0; } +static u8 cx25840_function_to_pad(struct i2c_client *client, u8 function) +{ + if (function > CX25840_PAD_VRESET) { + v4l_err(client, "invalid function %u, assuming default\n", + (unsigned int)function); + return 0; + } + + return function; +} + +static void cx25840_set_invert(u8 *pinctrl3, u8 *voutctrl4, u8 function, + u8 pin, bool invert) +{ + switch (function) { + case CX25840_PAD_IRQ_N: + if (invert) + *pinctrl3 &= ~2; + else + *pinctrl3 |= 2; + break; + + case CX25840_PAD_ACTIVE: + if (invert) + *voutctrl4 |= BIT(2); + else + *voutctrl4 &= ~BIT(2); + break; + + case CX25840_PAD_VACTIVE: + if (invert) + *voutctrl4 |= BIT(5); + else + *voutctrl4 &= ~BIT(5); + break; + + case CX25840_PAD_CBFLAG: + if (invert) + *voutctrl4 |= BIT(4); + else + *voutctrl4 &= ~BIT(4); + break; + + case CX25840_PAD_VRESET: + if (invert) + *voutctrl4 |= BIT(0); + else + *voutctrl4 &= ~BIT(0); + break; + } + + if (function != CX25840_PAD_DEFAULT) + return; + + switch (pin) { + case CX25840_PIN_DVALID_PRGM0: + if (invert) + *voutctrl4 |= BIT(6); + else + *voutctrl4 &= ~BIT(6); + break; + + case CX25840_PIN_HRESET_PRGM2: + if (invert) + *voutctrl4 |= BIT(1); + else + *voutctrl4 &= ~BIT(1); + break; + } +} + +static int cx25840_s_io_pin_config(struct v4l2_subdev *sd, size_t n, + struct v4l2_subdev_io_pin_config *p) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + unsigned int i; + u8 pinctrl[6], pinconf[10], voutctrl4; + + for (i = 0; i < 6; i++) + pinctrl[i] = cx25840_read(client, 0x114 + i); + + for (i = 0; i < 10; i++) + pinconf[i] = cx25840_read(client, 0x11c + i); + + voutctrl4 = cx25840_read(client, 0x407); + + for (i = 0; i < n; i++) { + u8 strength = p[i].strength; + + if (strength != CX25840_PIN_DRIVE_SLOW && + strength != CX25840_PIN_DRIVE_MEDIUM && + strength != CX25840_PIN_DRIVE_FAST) { + v4l_err(client, + "invalid drive speed for pin %u (%u), assuming fast\n", + (unsigned int)p[i].pin, + (unsigned int)strength); + + strength = CX25840_PIN_DRIVE_FAST; + } + + switch (p[i].pin) { + case CX25840_PIN_DVALID_PRGM0: + if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE)) + pinctrl[0] &= ~BIT(6); + else + pinctrl[0] |= BIT(6); + + pinconf[3] &= 0xf0; + pinconf[3] |= cx25840_function_to_pad(client, + p[i].function); + + cx25840_set_invert(&pinctrl[3], &voutctrl4, + p[i].function, + CX25840_PIN_DVALID_PRGM0, + p[i].flags & + BIT(V4L2_SUBDEV_IO_PIN_ACTIVE_LOW)); + + pinctrl[4] &= ~(3 << 2); /* CX25840_PIN_DRIVE_MEDIUM */ + switch (strength) { + case CX25840_PIN_DRIVE_SLOW: + pinctrl[4] |= 1 << 2; + break; + + case CX25840_PIN_DRIVE_FAST: + pinctrl[4] |= 2 << 2; + break; + } + + break; + + case CX25840_PIN_HRESET_PRGM2: + if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE)) + pinctrl[1] &= ~BIT(0); + else + pinctrl[1] |= BIT(0); + + pinconf[4] &= 0xf0; + pinconf[4] |= cx25840_function_to_pad(client, + p[i].function); + + cx25840_set_invert(&pinctrl[3], &voutctrl4, + p[i].function, + CX25840_PIN_HRESET_PRGM2, + p[i].flags & + BIT(V4L2_SUBDEV_IO_PIN_ACTIVE_LOW)); + + pinctrl[4] &= ~(3 << 2); /* CX25840_PIN_DRIVE_MEDIUM */ + switch (strength) { + case CX25840_PIN_DRIVE_SLOW: + pinctrl[4] |= 1 << 2; + break; + + case CX25840_PIN_DRIVE_FAST: + pinctrl[4] |= 2 << 2; + break; + } + + break; + + case CX25840_PIN_PLL_CLK_PRGM7: + if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE)) + pinctrl[2] &= ~BIT(2); + else + pinctrl[2] |= BIT(2); + + switch (p[i].function) { + case CX25840_PAD_XTI_X5_DLL: + pinconf[6] = 0; + break; + + case CX25840_PAD_AUX_PLL: + pinconf[6] = 1; + break; + + case CX25840_PAD_VID_PLL: + pinconf[6] = 5; + break; + + case CX25840_PAD_XTI: + pinconf[6] = 2; + break; + + default: + pinconf[6] = 3; + pinconf[6] |= + cx25840_function_to_pad(client, + p[i].function) + << 4; + } + + break; + + default: + v4l_err(client, "invalid or unsupported pin %u\n", + (unsigned int)p[i].pin); + break; + } + } + + cx25840_write(client, 0x407, voutctrl4); + + for (i = 0; i < 6; i++) + cx25840_write(client, 0x114 + i, pinctrl[i]); + + for (i = 0; i < 10; i++) + cx25840_write(client, 0x11c + i, pinconf[i]); + + return 0; +} + static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n, - struct v4l2_subdev_io_pin_config *pincfg) + struct v4l2_subdev_io_pin_config *pincfg) { struct cx25840_state *state = to_state(sd); if (is_cx2388x(state)) return cx23885_s_io_pin_config(sd, n, pincfg); + else if (is_cx2584x(state)) + return cx25840_s_io_pin_config(sd, n, pincfg); return 0; } @@ -321,8 +537,10 @@ static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n, static void init_dll1(struct i2c_client *client) { - /* This is the Hauppauge sequence used to - * initialize the Delay Lock Loop 1 (ADC DLL). */ + /* + * This is the Hauppauge sequence used to + * initialize the Delay Lock Loop 1 (ADC DLL). + */ cx25840_write(client, 0x159, 0x23); cx25840_write(client, 0x15a, 0x87); cx25840_write(client, 0x15b, 0x06); @@ -337,8 +555,10 @@ static void init_dll1(struct i2c_client *client) static void init_dll2(struct i2c_client *client) { - /* This is the Hauppauge sequence used to - * initialize the Delay Lock Loop 2 (ADC DLL). */ + /* + * This is the Hauppauge sequence used to + * initialize the Delay Lock Loop 2 (ADC DLL). + */ cx25840_write(client, 0x15d, 0xe3); cx25840_write(client, 0x15e, 0x86); cx25840_write(client, 0x15f, 0x06); @@ -350,7 +570,11 @@ static void init_dll2(struct i2c_client *client) static void cx25836_initialize(struct i2c_client *client) { - /* reset configuration is described on page 3-77 of the CX25836 datasheet */ + /* + *reset configuration is described on page 3-77 + * of the CX25836 datasheet + */ + /* 2. */ cx25840_and_or(client, 0x000, ~0x01, 0x01); cx25840_and_or(client, 0x000, ~0x01, 0x00); @@ -376,10 +600,96 @@ static void cx25836_initialize(struct i2c_client *client) static void cx25840_work_handler(struct work_struct *work) { struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work); + cx25840_loadfw(state->c); wake_up(&state->fw_wait); } +#define CX25840_VCONFIG_SET_BIT(state, opt_msk, voc, idx, bit, oneval) \ + do { \ + if ((state)->vid_config & (opt_msk)) { \ + if (((state)->vid_config & (opt_msk)) == \ + (oneval)) \ + (voc)[idx] |= BIT(bit); \ + else \ + (voc)[idx] &= ~BIT(bit); \ + } \ + } while (0) + +/* apply current vconfig to hardware regs */ +static void cx25840_vconfig_apply(struct i2c_client *client) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u8 voutctrl[3]; + unsigned int i; + + for (i = 0; i < 3; i++) + voutctrl[i] = cx25840_read(client, 0x404 + i); + + if (state->vid_config & CX25840_VCONFIG_FMT_MASK) + voutctrl[0] &= ~3; + switch (state->vid_config & CX25840_VCONFIG_FMT_MASK) { + case CX25840_VCONFIG_FMT_BT656: + voutctrl[0] |= 1; + break; + + case CX25840_VCONFIG_FMT_VIP11: + voutctrl[0] |= 2; + break; + + case CX25840_VCONFIG_FMT_VIP2: + voutctrl[0] |= 3; + break; + + case CX25840_VCONFIG_FMT_BT601: + /* zero */ + default: + break; + } + + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_RES_MASK, voutctrl, + 0, 2, CX25840_VCONFIG_RES_10BIT); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VBIRAW_MASK, voutctrl, + 0, 3, CX25840_VCONFIG_VBIRAW_ENABLED); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_ANCDATA_MASK, voutctrl, + 0, 4, CX25840_VCONFIG_ANCDATA_ENABLED); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_TASKBIT_MASK, voutctrl, + 0, 5, CX25840_VCONFIG_TASKBIT_ONE); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_ACTIVE_MASK, voutctrl, + 1, 2, CX25840_VCONFIG_ACTIVE_HORIZONTAL); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VALID_MASK, voutctrl, + 1, 3, CX25840_VCONFIG_VALID_ANDACTIVE); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_HRESETW_MASK, voutctrl, + 1, 4, CX25840_VCONFIG_HRESETW_PIXCLK); + + if (state->vid_config & CX25840_VCONFIG_CLKGATE_MASK) + voutctrl[1] &= ~(3 << 6); + switch (state->vid_config & CX25840_VCONFIG_CLKGATE_MASK) { + case CX25840_VCONFIG_CLKGATE_VALID: + voutctrl[1] |= 2; + break; + + case CX25840_VCONFIG_CLKGATE_VALIDACTIVE: + voutctrl[1] |= 3; + break; + + case CX25840_VCONFIG_CLKGATE_NONE: + /* zero */ + default: + break; + } + + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_DCMODE_MASK, voutctrl, + 2, 0, CX25840_VCONFIG_DCMODE_BYTES); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_IDID0S_MASK, voutctrl, + 2, 1, CX25840_VCONFIG_IDID0S_LINECNT); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VIPCLAMP_MASK, voutctrl, + 2, 4, CX25840_VCONFIG_VIPCLAMP_ENABLED); + + for (i = 0; i < 3; i++) + cx25840_write(client, 0x404 + i, voutctrl[i]); +} + static void cx25840_initialize(struct i2c_client *client) { DEFINE_WAIT(wait); @@ -389,8 +699,10 @@ static void cx25840_initialize(struct i2c_client *client) /* datasheet startup in numbered steps, refer to page 3-77 */ /* 2. */ cx25840_and_or(client, 0x803, ~0x10, 0x00); - /* The default of this register should be 4, but I get 0 instead. - * Set this register to 4 manually. */ + /* + * The default of this register should be 4, but I get 0 instead. + * Set this register to 4 manually. + */ cx25840_write(client, 0x000, 0x04); /* 3. */ init_dll1(client); @@ -400,10 +712,12 @@ static void cx25840_initialize(struct i2c_client *client) cx25840_write(client, 0x13c, 0x01); cx25840_write(client, 0x13c, 0x00); /* 5. */ - /* Do the firmware load in a work handler to prevent. - Otherwise the kernel is blocked waiting for the - bit-banging i2c interface to finish uploading the - firmware. */ + /* + * Do the firmware load in a work handler to prevent. + * Otherwise the kernel is blocked waiting for the + * bit-banging i2c interface to finish uploading the + * firmware. + */ INIT_WORK(&state->fw_work, cx25840_work_handler); init_waitqueue_head(&state->fw_wait); q = create_singlethread_workqueue("cx25840_fw"); @@ -446,6 +760,9 @@ static void cx25840_initialize(struct i2c_client *client) /* (re)set input */ set_input(client, state->vid_input, state->aud_input); + if (state->generic_mode) + cx25840_vconfig_apply(client); + /* start microcontroller */ cx25840_and_or(client, 0x803, ~0x10, 0x10); } @@ -632,10 +949,12 @@ static void cx23885_initialize(struct i2c_client *client) cx25840_write(client, 0x160, 0x1d); cx25840_write(client, 0x164, 0x00); - /* Do the firmware load in a work handler to prevent. - Otherwise the kernel is blocked waiting for the - bit-banging i2c interface to finish uploading the - firmware. */ + /* + * Do the firmware load in a work handler to prevent. + * Otherwise the kernel is blocked waiting for the + * bit-banging i2c interface to finish uploading the + * firmware. + */ INIT_WORK(&state->fw_work, cx25840_work_handler); init_waitqueue_head(&state->fw_wait); q = create_singlethread_workqueue("cx25840_fw"); @@ -647,7 +966,8 @@ static void cx23885_initialize(struct i2c_client *client) destroy_workqueue(q); } - /* Call the cx23888 specific std setup func, we no longer rely on + /* + * Call the cx23888 specific std setup func, we no longer rely on * the generic cx24840 func. */ if (is_cx23888(state)) @@ -669,7 +989,9 @@ static void cx23885_initialize(struct i2c_client *client) cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff); /* CC raw enable */ - /* - VIP 1.1 control codes - 10bit, blue field enable. + + /* + * - VIP 1.1 control codes - 10bit, blue field enable. * - enable raw data during vertical blanking. * - enable ancillary Data insertion for 656 or VIP. */ @@ -752,10 +1074,12 @@ static void cx231xx_initialize(struct i2c_client *client) /* White crush, Chroma AGC & Chroma Killer enabled */ cx25840_write(client, 0x401, 0xe8); - /* Do the firmware load in a work handler to prevent. - Otherwise the kernel is blocked waiting for the - bit-banging i2c interface to finish uploading the - firmware. */ + /* + * Do the firmware load in a work handler to prevent. + * Otherwise the kernel is blocked waiting for the + * bit-banging i2c interface to finish uploading the + * firmware. + */ INIT_WORK(&state->fw_work, cx25840_work_handler); init_waitqueue_head(&state->fw_wait); q = create_singlethread_workqueue("cx25840_fw"); @@ -800,13 +1124,20 @@ void cx25840_std_setup(struct i2c_client *client) else cx25840_write(client, 0x49f, 0x14); + /* generic mode uses the values that the chip autoconfig would set */ if (std & V4L2_STD_625_50) { hblank = 132; hactive = 720; burst = 93; - vblank = 36; - vactive = 580; - vblank656 = 40; + if (state->generic_mode) { + vblank = 34; + vactive = 576; + vblank656 = 38; + } else { + vblank = 36; + vactive = 580; + vblank656 = 40; + } src_decimation = 0x21f; luma_lpf = 2; @@ -815,6 +1146,10 @@ void cx25840_std_setup(struct i2c_client *client) comb = 0; sc = 0x0a425f; } else if (std == V4L2_STD_PAL_Nc) { + if (state->generic_mode) { + burst = 95; + luma_lpf = 1; + } uv_lpf = 1; comb = 0x20; sc = 556453; @@ -829,12 +1164,20 @@ void cx25840_std_setup(struct i2c_client *client) vactive = 487; luma_lpf = 1; uv_lpf = 1; + if (state->generic_mode) { + vblank = 20; + vblank656 = 24; + } src_decimation = 0x21f; if (std == V4L2_STD_PAL_60) { - vblank = 26; - vblank656 = 26; - burst = 0x5b; + if (!state->generic_mode) { + vblank = 26; + vblank656 = 26; + burst = 0x5b; + } else { + burst = 0x59; + } luma_lpf = 2; comb = 0x20; sc = 688739; @@ -845,8 +1188,10 @@ void cx25840_std_setup(struct i2c_client *client) comb = 0x20; sc = 555452; } else { - vblank = 26; - vblank656 = 26; + if (!state->generic_mode) { + vblank = 26; + vblank656 = 26; + } burst = 0x5b; comb = 0x66; sc = 556063; @@ -867,24 +1212,28 @@ void cx25840_std_setup(struct i2c_client *client) int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L; pll /= pll_post; - v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n", - pll / 1000000, pll % 1000000); - v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n", - pll / 8000000, (pll / 8) % 1000000); + v4l_dbg(1, cx25840_debug, client, + "PLL = %d.%06d MHz\n", + pll / 1000000, pll % 1000000); + v4l_dbg(1, cx25840_debug, client, + "PLL/8 = %d.%06d MHz\n", + pll / 8000000, (pll / 8) % 1000000); fin = ((u64)src_decimation * pll) >> 12; v4l_dbg(1, cx25840_debug, client, - "ADC Sampling freq = %d.%06d MHz\n", - fin / 1000000, fin % 1000000); + "ADC Sampling freq = %d.%06d MHz\n", + fin / 1000000, fin % 1000000); fsc = (((u64)sc) * pll) >> 24L; v4l_dbg(1, cx25840_debug, client, - "Chroma sub-carrier freq = %d.%06d MHz\n", - fsc / 1000000, fsc % 1000000); + "Chroma sub-carrier freq = %d.%06d MHz\n", + fsc / 1000000, fsc % 1000000); - v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, vblank %i, vactive %i, vblank656 %i, src_dec %i, burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, sc 0x%06x\n", + v4l_dbg(1, cx25840_debug, client, + "hblank %i, hactive %i, vblank %i, vactive %i, vblank656 %i, src_dec %i, burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, sc 0x%06x\n", hblank, hactive, vblank, vactive, vblank656, - src_decimation, burst, luma_lpf, uv_lpf, comb, sc); + src_decimation, burst, luma_lpf, uv_lpf, + comb, sc); } } @@ -939,10 +1288,10 @@ static void input_change(struct i2c_client *client) /* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */ if (std & V4L2_STD_SECAM) { cx25840_write(client, 0x402, 0); - } - else { + } else { cx25840_write(client, 0x402, 0x04); - cx25840_write(client, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); + cx25840_write(client, 0x49f, + (std & V4L2_STD_NTSC) ? 0x14 : 0x11); } cx25840_and_or(client, 0x401, ~0x60, 0); cx25840_and_or(client, 0x401, ~0x60, 0x60); @@ -956,13 +1305,14 @@ static void input_change(struct i2c_client *client) if (state->radio) { cx25840_write(client, 0x808, 0xf9); cx25840_write(client, 0x80b, 0x00); - } - else if (std & V4L2_STD_525_60) { - /* Certain Hauppauge PVR150 models have a hardware bug - that causes audio to drop out. For these models the - audio standard must be set explicitly. - To be precise: it affects cards with tuner models - 85, 99 and 112 (model numbers from tveeprom). */ + } else if (std & V4L2_STD_525_60) { + /* + * Certain Hauppauge PVR150 models have a hardware bug + * that causes audio to drop out. For these models the + * audio standard must be set explicitly. + * To be precise: it affects cards with tuner models + * 85, 99 and 112 (model numbers from tveeprom). + */ int hw_fix = state->pvr150_workaround; if (std == V4L2_STD_NTSC_M_JP) { @@ -979,35 +1329,40 @@ static void input_change(struct i2c_client *client) } else if (std & V4L2_STD_PAL) { /* Autodetect audio standard and audio system */ cx25840_write(client, 0x808, 0xff); - /* Since system PAL-L is pretty much non-existent and - not used by any public broadcast network, force - 6.5 MHz carrier to be interpreted as System DK, - this avoids DK audio detection instability */ + /* + * Since system PAL-L is pretty much non-existent and + * not used by any public broadcast network, force + * 6.5 MHz carrier to be interpreted as System DK, + * this avoids DK audio detection instability + */ cx25840_write(client, 0x80b, 0x00); } else if (std & V4L2_STD_SECAM) { /* Autodetect audio standard and audio system */ cx25840_write(client, 0x808, 0xff); - /* If only one of SECAM-DK / SECAM-L is required, then force - 6.5MHz carrier, else autodetect it */ + /* + * If only one of SECAM-DK / SECAM-L is required, then force + * 6.5MHz carrier, else autodetect it + */ if ((std & V4L2_STD_SECAM_DK) && !(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { /* 6.5 MHz carrier to be interpreted as System DK */ cx25840_write(client, 0x80b, 0x00); - } else if (!(std & V4L2_STD_SECAM_DK) && - (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { + } else if (!(std & V4L2_STD_SECAM_DK) && + (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { /* 6.5 MHz carrier to be interpreted as System L */ cx25840_write(client, 0x80b, 0x08); - } else { + } else { /* 6.5 MHz carrier to be autodetected */ cx25840_write(client, 0x80b, 0x10); - } + } } cx25840_and_or(client, 0x810, ~0x01, 0); } -static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, - enum cx25840_audio_input aud_input) +static int set_input(struct i2c_client *client, + enum cx25840_video_input vid_input, + enum cx25840_audio_input aud_input) { struct cx25840_state *state = to_state(i2c_get_clientdata(client)); u8 is_composite = (vid_input >= CX25840_COMPOSITE1 && @@ -1032,7 +1387,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp vid_input); reg = vid_input & 0xff; is_composite = !is_component && - ((vid_input & CX25840_SVIDEO_ON) != CX25840_SVIDEO_ON); + ((vid_input & CX25840_SVIDEO_ON) != CX25840_SVIDEO_ON); v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n", reg, is_composite); @@ -1040,8 +1395,10 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); } else { if ((vid_input & ~0xff0) || - luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 || - chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { + luma < CX25840_SVIDEO_LUMA1 || + luma > CX25840_SVIDEO_LUMA8 || + chroma < CX25840_SVIDEO_CHROMA4 || + chroma > CX25840_SVIDEO_CHROMA8) { v4l_err(client, "0x%04x is not a valid video input!\n", vid_input); return -EINVAL; @@ -1065,12 +1422,24 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp case CX25840_AUDIO_SERIAL: /* do nothing, use serial audio input */ break; - case CX25840_AUDIO4: reg &= ~0x30; break; - case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; - case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; - case CX25840_AUDIO7: reg &= ~0xc0; break; - case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; - + case CX25840_AUDIO4: + reg &= ~0x30; + break; + case CX25840_AUDIO5: + reg &= ~0x30; + reg |= 0x10; + break; + case CX25840_AUDIO6: + reg &= ~0x30; + reg |= 0x20; + break; + case CX25840_AUDIO7: + reg &= ~0xc0; + break; + case CX25840_AUDIO8: + reg &= ~0xc0; + reg |= 0x40; + break; default: v4l_err(client, "0x%04x is not a valid audio input!\n", aud_input); @@ -1087,7 +1456,6 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); if (is_cx2388x(state)) { - /* Enable or disable the DIF for tuner use */ if (is_dif) { cx25840_and_or(client, 0x102, ~0x80, 0x80); @@ -1118,15 +1486,23 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_write4(client, 0x410, 0xffff0dbf); cx25840_write4(client, 0x414, 0x00137d03); - cx25840_write4(client, state->vbi_regs_offset + 0x42c, 0x42600000); - cx25840_write4(client, state->vbi_regs_offset + 0x430, 0x0000039b); - cx25840_write4(client, state->vbi_regs_offset + 0x438, 0x00000000); - - cx25840_write4(client, state->vbi_regs_offset + 0x440, 0xF8E3E824); - cx25840_write4(client, state->vbi_regs_offset + 0x444, 0x401040dc); - cx25840_write4(client, state->vbi_regs_offset + 0x448, 0xcd3f02a0); - cx25840_write4(client, state->vbi_regs_offset + 0x44c, 0x161f1000); - cx25840_write4(client, state->vbi_regs_offset + 0x450, 0x00000802); + cx25840_write4(client, state->vbi_regs_offset + 0x42c, + 0x42600000); + cx25840_write4(client, state->vbi_regs_offset + 0x430, + 0x0000039b); + cx25840_write4(client, state->vbi_regs_offset + 0x438, + 0x00000000); + + cx25840_write4(client, state->vbi_regs_offset + 0x440, + 0xF8E3E824); + cx25840_write4(client, state->vbi_regs_offset + 0x444, + 0x401040dc); + cx25840_write4(client, state->vbi_regs_offset + 0x448, + 0xcd3f02a0); + cx25840_write4(client, state->vbi_regs_offset + 0x44c, + 0x161f1000); + cx25840_write4(client, state->vbi_regs_offset + 0x450, + 0x00000802); cx25840_write4(client, 0x91c, 0x01000000); cx25840_write4(client, 0x8e0, 0x03063870); @@ -1193,8 +1569,9 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp * Only one of the two will be in use. */ cx25840_write4(client, AFE_CTRL, val); - } else + } else { cx25840_and_or(client, 0x102, ~0x2, 0); + } } state->vid_input = vid_input; @@ -1233,29 +1610,32 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_write(client, 0x919, 0x01); } - if (is_cx2388x(state) && ((aud_input == CX25840_AUDIO7) || - (aud_input == CX25840_AUDIO6))) { + if (is_cx2388x(state) && + ((aud_input == CX25840_AUDIO7) || (aud_input == CX25840_AUDIO6))) { /* Configure audio from LR1 or LR2 input */ cx25840_write4(client, 0x910, 0); cx25840_write4(client, 0x8d0, 0x63073); - } else - if (is_cx2388x(state) && (aud_input == CX25840_AUDIO8)) { + } else if (is_cx2388x(state) && (aud_input == CX25840_AUDIO8)) { /* Configure audio from tuner/sif input */ cx25840_write4(client, 0x910, 0x12b000c9); cx25840_write4(client, 0x8d0, 0x1f063870); } if (is_cx23888(state)) { - /* HVR1850 */ - /* AUD_IO_CTRL - I2S Input, Parallel1*/ - /* - Channel 1 src - Parallel1 (Merlin out) */ - /* - Channel 2 src - Parallel2 (Merlin out) */ - /* - Channel 3 src - Parallel3 (Merlin AC97 out) */ - /* - I2S source and dir - Merlin, output */ + /* + * HVR1850 + * + * AUD_IO_CTRL - I2S Input, Parallel1 + * - Channel 1 src - Parallel1 (Merlin out) + * - Channel 2 src - Parallel2 (Merlin out) + * - Channel 3 src - Parallel3 (Merlin AC97 out) + * - I2S source and dir - Merlin, output + */ cx25840_write4(client, 0x124, 0x100); if (!is_dif) { - /* Stop microcontroller if we don't need it + /* + * Stop microcontroller if we don't need it * to avoid audio popping on svideo/composite use. */ cx25840_and_or(client, 0x803, ~0x10, 0x00); @@ -1297,11 +1677,14 @@ static int set_v4lstd(struct i2c_client *client) fmt = 0xc; } - v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt); + v4l_dbg(1, cx25840_debug, client, + "changing video std to fmt %i\n", fmt); - /* Follow step 9 of section 3.16 in the cx25840 datasheet. - Without this PAL may display a vertical ghosting effect. - This happens for example with the Yuan MPC622. */ + /* + * Follow step 9 of section 3.16 in the cx25840 datasheet. + * Without this PAL may display a vertical ghosting effect. + * This happens for example with the Yuan MPC622. + */ if (fmt >= 4 && fmt < 8) { /* Set format to NTSC-M */ cx25840_and_or(client, 0x400, ~0xf, 1); @@ -1363,14 +1746,15 @@ static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl) /* ----------------------------------------------------------------------- */ static int cx25840_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - int HSC, VSC, Vsrc, Hsrc, filter, Vlines; - int is_50Hz = !(state->std & V4L2_STD_525_60); + u32 hsc, vsc, v_src, h_src, v_add; + int filter; + int is_50hz = !(state->std & V4L2_STD_525_60); if (format->pad || fmt->code != MEDIA_BUS_FMT_FIXED) return -EINVAL; @@ -1379,42 +1763,63 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd, fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; if (is_cx23888(state)) { - Vsrc = (cx25840_read(client, 0x42a) & 0x3f) << 4; - Vsrc |= (cx25840_read(client, 0x429) & 0xf0) >> 4; + v_src = (cx25840_read(client, 0x42a) & 0x3f) << 4; + v_src |= (cx25840_read(client, 0x429) & 0xf0) >> 4; } else { - Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4; - Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4; + v_src = (cx25840_read(client, 0x476) & 0x3f) << 4; + v_src |= (cx25840_read(client, 0x475) & 0xf0) >> 4; } if (is_cx23888(state)) { - Hsrc = (cx25840_read(client, 0x426) & 0x3f) << 4; - Hsrc |= (cx25840_read(client, 0x425) & 0xf0) >> 4; + h_src = (cx25840_read(client, 0x426) & 0x3f) << 4; + h_src |= (cx25840_read(client, 0x425) & 0xf0) >> 4; } else { - Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4; - Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; + h_src = (cx25840_read(client, 0x472) & 0x3f) << 4; + h_src |= (cx25840_read(client, 0x471) & 0xf0) >> 4; } - Vlines = fmt->height + (is_50Hz ? 4 : 7); + if (!state->generic_mode) { + v_add = is_50hz ? 4 : 7; - /* - * We keep 1 margin for the Vsrc < Vlines check since the - * cx23888 reports a Vsrc of 486 instead of 487 for the NTSC - * height. Without that margin the cx23885 fails in this - * check. - */ - if ((fmt->width == 0) || (Vlines == 0) || - (fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || - (Vlines * 8 < Vsrc) || (Vsrc + 1 < Vlines)) { - v4l_err(client, "%dx%d is not a valid size!\n", - fmt->width, fmt->height); - return -ERANGE; + /* + * cx23888 in 525-line mode is programmed for 486 active lines + * while other chips use 487 active lines. + * + * See reg 0x428 bits [21:12] in cx23888_std_setup() vs + * vactive in cx25840_std_setup(). + */ + if (is_cx23888(state) && !is_50hz) + v_add--; + } else { + v_add = 0; } + + if (h_src == 0 || + v_src <= v_add) { + v4l_err(client, + "chip reported picture size (%u x %u) is far too small\n", + (unsigned int)h_src, (unsigned int)v_src); + /* + * that's the best we can do since the output picture + * size is completely unknown in this case + */ + return -EINVAL; + } + + fmt->width = clamp(fmt->width, (h_src + 15) / 16, h_src); + + if (v_add * 8 >= v_src) + fmt->height = clamp(fmt->height, (u32)1, v_src - v_add); + else + fmt->height = clamp(fmt->height, (v_src - v_add * 8 + 7) / 8, + v_src - v_add); + if (format->which == V4L2_SUBDEV_FORMAT_TRY) return 0; - HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); - VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); - VSC &= 0x1fff; + hsc = (h_src * (1 << 20)) / fmt->width - (1 << 20); + vsc = (1 << 16) - (v_src * (1 << 9) / (fmt->height + v_add) - (1 << 9)); + vsc &= 0x1fff; if (fmt->width >= 385) filter = 0; @@ -1425,21 +1830,23 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd, else filter = 3; - v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n", - fmt->width, fmt->height, HSC, VSC); + v4l_dbg(1, cx25840_debug, client, + "decoder set size %u x %u with scale %x x %x\n", + (unsigned int)fmt->width, (unsigned int)fmt->height, + (unsigned int)hsc, (unsigned int)vsc); - /* HSCALE=HSC */ + /* HSCALE=hsc */ if (is_cx23888(state)) { - cx25840_write4(client, 0x434, HSC | (1 << 24)); - /* VSCALE=VSC VS_INTRLACE=1 VFILT=filter */ - cx25840_write4(client, 0x438, VSC | (1 << 19) | (filter << 16)); + cx25840_write4(client, 0x434, hsc | (1 << 24)); + /* VSCALE=vsc VS_INTRLACE=1 VFILT=filter */ + cx25840_write4(client, 0x438, vsc | (1 << 19) | (filter << 16)); } else { - cx25840_write(client, 0x418, HSC & 0xff); - cx25840_write(client, 0x419, (HSC >> 8) & 0xff); - cx25840_write(client, 0x41a, HSC >> 16); - /* VSCALE=VSC */ - cx25840_write(client, 0x41c, VSC & 0xff); - cx25840_write(client, 0x41d, VSC >> 8); + cx25840_write(client, 0x418, hsc & 0xff); + cx25840_write(client, 0x419, (hsc >> 8) & 0xff); + cx25840_write(client, 0x41a, hsc >> 16); + /* VSCALE=vsc */ + cx25840_write(client, 0x41c, vsc & 0xff); + cx25840_write(client, 0x41d, vsc >> 8); /* VS_INTRLACE=1 VFILT=filter */ cx25840_write(client, 0x41e, 0x8 | filter); } @@ -1466,23 +1873,25 @@ static void log_video_status(struct i2c_client *client) int vid_input = state->vid_input; v4l_info(client, "Video signal: %spresent\n", - (gen_stat2 & 0x20) ? "" : "not "); + (gen_stat2 & 0x20) ? "" : "not "); v4l_info(client, "Detected format: %s\n", - fmt_strs[gen_stat1 & 0xf]); + fmt_strs[gen_stat1 & 0xf]); v4l_info(client, "Specified standard: %s\n", - vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); + vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); if (vid_input >= CX25840_COMPOSITE1 && vid_input <= CX25840_COMPOSITE8) { v4l_info(client, "Specified video input: Composite %d\n", - vid_input - CX25840_COMPOSITE1 + 1); + vid_input - CX25840_COMPOSITE1 + 1); } else { - v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", - (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); + v4l_info(client, + "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", + (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); } - v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); + v4l_info(client, "Specified audioclock freq: %d Hz\n", + state->audclk_freq); } /* ----------------------------------------------------------------------- */ @@ -1501,177 +1910,434 @@ static void log_audio_status(struct i2c_client *client) char *p; switch (mod_det_stat0) { - case 0x00: p = "mono"; break; - case 0x01: p = "stereo"; break; - case 0x02: p = "dual"; break; - case 0x04: p = "tri"; break; - case 0x10: p = "mono with SAP"; break; - case 0x11: p = "stereo with SAP"; break; - case 0x12: p = "dual with SAP"; break; - case 0x14: p = "tri with SAP"; break; - case 0xfe: p = "forced mode"; break; - default: p = "not defined"; + case 0x00: + p = "mono"; + break; + case 0x01: + p = "stereo"; + break; + case 0x02: + p = "dual"; + break; + case 0x04: + p = "tri"; + break; + case 0x10: + p = "mono with SAP"; + break; + case 0x11: + p = "stereo with SAP"; + break; + case 0x12: + p = "dual with SAP"; + break; + case 0x14: + p = "tri with SAP"; + break; + case 0xfe: + p = "forced mode"; + break; + default: + p = "not defined"; } v4l_info(client, "Detected audio mode: %s\n", p); switch (mod_det_stat1) { - case 0x00: p = "not defined"; break; - case 0x01: p = "EIAJ"; break; - case 0x02: p = "A2-M"; break; - case 0x03: p = "A2-BG"; break; - case 0x04: p = "A2-DK1"; break; - case 0x05: p = "A2-DK2"; break; - case 0x06: p = "A2-DK3"; break; - case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x08: p = "AM-L"; break; - case 0x09: p = "NICAM-BG"; break; - case 0x0a: p = "NICAM-DK"; break; - case 0x0b: p = "NICAM-I"; break; - case 0x0c: p = "NICAM-L"; break; - case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; - case 0x0e: p = "IF FM Radio"; break; - case 0x0f: p = "BTSC"; break; - case 0x10: p = "high-deviation FM"; break; - case 0x11: p = "very high-deviation FM"; break; - case 0xfd: p = "unknown audio standard"; break; - case 0xfe: p = "forced audio standard"; break; - case 0xff: p = "no detected audio standard"; break; - default: p = "not defined"; + case 0x00: + p = "not defined"; + break; + case 0x01: + p = "EIAJ"; + break; + case 0x02: + p = "A2-M"; + break; + case 0x03: + p = "A2-BG"; + break; + case 0x04: + p = "A2-DK1"; + break; + case 0x05: + p = "A2-DK2"; + break; + case 0x06: + p = "A2-DK3"; + break; + case 0x07: + p = "A1 (6.0 MHz FM Mono)"; + break; + case 0x08: + p = "AM-L"; + break; + case 0x09: + p = "NICAM-BG"; + break; + case 0x0a: + p = "NICAM-DK"; + break; + case 0x0b: + p = "NICAM-I"; + break; + case 0x0c: + p = "NICAM-L"; + break; + case 0x0d: + p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; + break; + case 0x0e: + p = "IF FM Radio"; + break; + case 0x0f: + p = "BTSC"; + break; + case 0x10: + p = "high-deviation FM"; + break; + case 0x11: + p = "very high-deviation FM"; + break; + case 0xfd: + p = "unknown audio standard"; + break; + case 0xfe: + p = "forced audio standard"; + break; + case 0xff: + p = "no detected audio standard"; + break; + default: + p = "not defined"; } v4l_info(client, "Detected audio standard: %s\n", p); v4l_info(client, "Audio microcontroller: %s\n", - (download_ctl & 0x10) ? - ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); + (download_ctl & 0x10) ? + ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); switch (audio_config >> 4) { - case 0x00: p = "undefined"; break; - case 0x01: p = "BTSC"; break; - case 0x02: p = "EIAJ"; break; - case 0x03: p = "A2-M"; break; - case 0x04: p = "A2-BG"; break; - case 0x05: p = "A2-DK1"; break; - case 0x06: p = "A2-DK2"; break; - case 0x07: p = "A2-DK3"; break; - case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x09: p = "AM-L"; break; - case 0x0a: p = "NICAM-BG"; break; - case 0x0b: p = "NICAM-DK"; break; - case 0x0c: p = "NICAM-I"; break; - case 0x0d: p = "NICAM-L"; break; - case 0x0e: p = "FM radio"; break; - case 0x0f: p = "automatic detection"; break; - default: p = "undefined"; + case 0x00: + p = "undefined"; + break; + case 0x01: + p = "BTSC"; + break; + case 0x02: + p = "EIAJ"; + break; + case 0x03: + p = "A2-M"; + break; + case 0x04: + p = "A2-BG"; + break; + case 0x05: + p = "A2-DK1"; + break; + case 0x06: + p = "A2-DK2"; + break; + case 0x07: + p = "A2-DK3"; + break; + case 0x08: + p = "A1 (6.0 MHz FM Mono)"; + break; + case 0x09: + p = "AM-L"; + break; + case 0x0a: + p = "NICAM-BG"; + break; + case 0x0b: + p = "NICAM-DK"; + break; + case 0x0c: + p = "NICAM-I"; + break; + case 0x0d: + p = "NICAM-L"; + break; + case 0x0e: + p = "FM radio"; + break; + case 0x0f: + p = "automatic detection"; + break; + default: + p = "undefined"; } v4l_info(client, "Configured audio standard: %s\n", p); if ((audio_config >> 4) < 0xF) { switch (audio_config & 0xF) { - case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; - case 0x01: p = "MONO2 (LANGUAGE B)"; break; - case 0x02: p = "MONO3 (STEREO forced MONO)"; break; - case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; - case 0x04: p = "STEREO"; break; - case 0x05: p = "DUAL1 (AB)"; break; - case 0x06: p = "DUAL2 (AC) (FM)"; break; - case 0x07: p = "DUAL3 (BC) (FM)"; break; - case 0x08: p = "DUAL4 (AC) (AM)"; break; - case 0x09: p = "DUAL5 (BC) (AM)"; break; - case 0x0a: p = "SAP"; break; - default: p = "undefined"; + case 0x00: + p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; + break; + case 0x01: + p = "MONO2 (LANGUAGE B)"; + break; + case 0x02: + p = "MONO3 (STEREO forced MONO)"; + break; + case 0x03: + p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; + break; + case 0x04: + p = "STEREO"; + break; + case 0x05: + p = "DUAL1 (AB)"; + break; + case 0x06: + p = "DUAL2 (AC) (FM)"; + break; + case 0x07: + p = "DUAL3 (BC) (FM)"; + break; + case 0x08: + p = "DUAL4 (AC) (AM)"; + break; + case 0x09: + p = "DUAL5 (BC) (AM)"; + break; + case 0x0a: + p = "SAP"; + break; + default: + p = "undefined"; } v4l_info(client, "Configured audio mode: %s\n", p); } else { switch (audio_config & 0xF) { - case 0x00: p = "BG"; break; - case 0x01: p = "DK1"; break; - case 0x02: p = "DK2"; break; - case 0x03: p = "DK3"; break; - case 0x04: p = "I"; break; - case 0x05: p = "L"; break; - case 0x06: p = "BTSC"; break; - case 0x07: p = "EIAJ"; break; - case 0x08: p = "A2-M"; break; - case 0x09: p = "FM Radio"; break; - case 0x0f: p = "automatic standard and mode detection"; break; - default: p = "undefined"; + case 0x00: + p = "BG"; + break; + case 0x01: + p = "DK1"; + break; + case 0x02: + p = "DK2"; + break; + case 0x03: + p = "DK3"; + break; + case 0x04: + p = "I"; + break; + case 0x05: + p = "L"; + break; + case 0x06: + p = "BTSC"; + break; + case 0x07: + p = "EIAJ"; + break; + case 0x08: + p = "A2-M"; + break; + case 0x09: + p = "FM Radio"; + break; + case 0x0f: + p = "automatic standard and mode detection"; + break; + default: + p = "undefined"; } v4l_info(client, "Configured audio system: %s\n", p); } if (aud_input) { - v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); + v4l_info(client, "Specified audio input: Tuner (In%d)\n", + aud_input); } else { v4l_info(client, "Specified audio input: External\n"); } switch (pref_mode & 0xf) { - case 0: p = "mono/language A"; break; - case 1: p = "language B"; break; - case 2: p = "language C"; break; - case 3: p = "analog fallback"; break; - case 4: p = "stereo"; break; - case 5: p = "language AC"; break; - case 6: p = "language BC"; break; - case 7: p = "language AB"; break; - default: p = "undefined"; + case 0: + p = "mono/language A"; + break; + case 1: + p = "language B"; + break; + case 2: + p = "language C"; + break; + case 3: + p = "analog fallback"; + break; + case 4: + p = "stereo"; + break; + case 5: + p = "language AC"; + break; + case 6: + p = "language BC"; + break; + case 7: + p = "language AB"; + break; + default: + p = "undefined"; } v4l_info(client, "Preferred audio mode: %s\n", p); if ((audio_config & 0xf) == 0xf) { switch ((afc0 >> 3) & 0x3) { - case 0: p = "system DK"; break; - case 1: p = "system L"; break; - case 2: p = "autodetect"; break; - default: p = "undefined"; + case 0: + p = "system DK"; + break; + case 1: + p = "system L"; + break; + case 2: + p = "autodetect"; + break; + default: + p = "undefined"; } v4l_info(client, "Selected 65 MHz format: %s\n", p); switch (afc0 & 0x7) { - case 0: p = "chroma"; break; - case 1: p = "BTSC"; break; - case 2: p = "EIAJ"; break; - case 3: p = "A2-M"; break; - case 4: p = "autodetect"; break; - default: p = "undefined"; + case 0: + p = "chroma"; + break; + case 1: + p = "BTSC"; + break; + case 2: + p = "EIAJ"; + break; + case 3: + p = "A2-M"; + break; + case 4: + p = "autodetect"; + break; + default: + p = "undefined"; } v4l_info(client, "Selected 45 MHz format: %s\n", p); } } +#define CX25840_VCONFIG_OPTION(state, cfg_in, opt_msk) \ + do { \ + if ((cfg_in) & (opt_msk)) { \ + (state)->vid_config &= ~(opt_msk); \ + (state)->vid_config |= (cfg_in) & (opt_msk); \ + } \ + } while (0) + +/* apply incoming options to the current vconfig */ +static void cx25840_vconfig_add(struct cx25840_state *state, u32 cfg_in) +{ + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_FMT_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_RES_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VBIRAW_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_ANCDATA_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_TASKBIT_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_ACTIVE_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VALID_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_HRESETW_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_CLKGATE_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_DCMODE_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_IDID0S_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VIPCLAMP_MASK); +} + /* ----------------------------------------------------------------------- */ -/* This load_fw operation must be called to load the driver's firmware. - Without this the audio standard detection will fail and you will - only get mono. +/* + * Initializes the device in the generic mode. + * For cx2584x chips also adds additional video output settings provided + * in @val parameter (CX25840_VCONFIG_*). + * + * The generic mode disables some of the ivtv-related hacks in this driver. + * For cx2584x chips it also enables setting video output configuration while + * setting it according to datasheet defaults by default. + */ +static int cx25840_init(struct v4l2_subdev *sd, u32 val) +{ + struct cx25840_state *state = to_state(sd); - Since loading the firmware is often problematic when the driver is - compiled into the kernel I recommend postponing calling this function - until the first open of the video device. Another reason for - postponing it is that loading this firmware takes a long time (seconds) - due to the slow i2c bus speed. So it will speed up the boot process if - you can avoid loading the fw as long as the video device isn't used. */ -static int cx25840_load_fw(struct v4l2_subdev *sd) + state->generic_mode = true; + + if (is_cx2584x(state)) { + /* set datasheet video output defaults */ + state->vid_config = CX25840_VCONFIG_FMT_BT656 | + CX25840_VCONFIG_RES_8BIT | + CX25840_VCONFIG_VBIRAW_DISABLED | + CX25840_VCONFIG_ANCDATA_ENABLED | + CX25840_VCONFIG_TASKBIT_ONE | + CX25840_VCONFIG_ACTIVE_HORIZONTAL | + CX25840_VCONFIG_VALID_NORMAL | + CX25840_VCONFIG_HRESETW_NORMAL | + CX25840_VCONFIG_CLKGATE_NONE | + CX25840_VCONFIG_DCMODE_DWORDS | + CX25840_VCONFIG_IDID0S_NORMAL | + CX25840_VCONFIG_VIPCLAMP_DISABLED; + + /* add additional settings */ + cx25840_vconfig_add(state, val); + } else { + /* TODO: generic mode needs to be developed for other chips */ + WARN_ON(1); + } + + return 0; +} + +static int cx25840_reset(struct v4l2_subdev *sd, u32 val) { struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); + if (is_cx2583x(state)) + cx25836_initialize(client); + else if (is_cx2388x(state)) + cx23885_initialize(client); + else if (is_cx231xx(state)) + cx231xx_initialize(client); + else + cx25840_initialize(client); + + state->is_initialized = 1; + + return 0; +} + +/* + * This load_fw operation must be called to load the driver's firmware. + * This will load the firmware on the first invocation (further ones are NOP). + * Without this the audio standard detection will fail and you will + * only get mono. + * Alternatively, you can call the reset operation instead of this one. + * + * Since loading the firmware is often problematic when the driver is + * compiled into the kernel I recommend postponing calling this function + * until the first open of the video device. Another reason for + * postponing it is that loading this firmware takes a long time (seconds) + * due to the slow i2c bus speed. So it will speed up the boot process if + * you can avoid loading the fw as long as the video device isn't used. + */ +static int cx25840_load_fw(struct v4l2_subdev *sd) +{ + struct cx25840_state *state = to_state(sd); + if (!state->is_initialized) { /* initialize and load firmware */ - state->is_initialized = 1; - if (is_cx2583x(state)) - cx25836_initialize(client); - else if (is_cx2388x(state)) - cx23885_initialize(client); - else if (is_cx231xx(state)) - cx231xx_initialize(client); - else - cx25840_initialize(client); + cx25840_reset(sd, 0); } return 0; } #ifdef CONFIG_VIDEO_ADV_DEBUG -static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int cx25840_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -1680,7 +2346,8 @@ static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int cx25840_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) +static int cx25840_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -1699,7 +2366,7 @@ static int cx25840_s_audio_stream(struct v4l2_subdev *sd, int enable) return 0; v4l_dbg(1, cx25840_debug, client, "%s audio output\n", - enable ? "enable" : "disable"); + enable ? "enable" : "disable"); if (enable) { v = cx25840_read(client, 0x115) | 0x80; @@ -1722,7 +2389,7 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) u8 v; v4l_dbg(1, cx25840_debug, client, "%s video output\n", - enable ? "enable" : "disable"); + enable ? "enable" : "disable"); /* * It's not clear what should be done for these devices. @@ -1749,7 +2416,7 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) } /* Query the current detected video format */ -static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) +static int cx25840_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -1775,10 +2442,11 @@ static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) }; u32 fmt = (cx25840_read4(client, 0x40c) >> 8) & 0xf; - *std = stds[ fmt ]; + *std = stds[fmt]; - v4l_dbg(1, cx25840_debug, client, "g_std fmt = %x, v4l2_std_id = 0x%x\n", - fmt, (unsigned int)stds[ fmt ]); + v4l_dbg(1, cx25840_debug, client, + "querystd fmt = %x, v4l2_std_id = 0x%x\n", + fmt, (unsigned int)stds[fmt]); return 0; } @@ -1787,7 +2455,8 @@ static int cx25840_g_input_status(struct v4l2_subdev *sd, u32 *status) { struct i2c_client *client = v4l2_get_subdevdata(sd); - /* A limited function that checks for signal status and returns + /* + * A limited function that checks for signal status and returns * the state. */ @@ -1798,6 +2467,15 @@ static int cx25840_g_input_status(struct v4l2_subdev *sd, u32 *status) return 0; } +static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) +{ + struct cx25840_state *state = to_state(sd); + + *std = state->std; + + return 0; +} + static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct cx25840_state *state = to_state(sd); @@ -1827,6 +2505,11 @@ static int cx25840_s_video_routing(struct v4l2_subdev *sd, if (is_cx23888(state)) cx23888_std_setup(client); + if (is_cx2584x(state) && state->generic_mode && config) { + cx25840_vconfig_add(state, config); + cx25840_vconfig_apply(client); + } + return set_input(client, input, state->aud_input); } @@ -1841,7 +2524,8 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd, return set_input(client, state->vid_input, input); } -static int cx25840_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq) +static int cx25840_s_frequency(struct v4l2_subdev *sd, + const struct v4l2_frequency *freq) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -1864,9 +2548,8 @@ static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) if (is_cx2583x(state)) return 0; - vt->capability |= - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | - V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + vt->capability |= V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; mode = cx25840_read(client, 0x804); @@ -1896,54 +2579,46 @@ static int cx25840_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) return 0; switch (vt->audmode) { - case V4L2_TUNER_MODE_MONO: - /* mono -> mono - stereo -> mono - bilingual -> lang1 */ - cx25840_and_or(client, 0x809, ~0xf, 0x00); - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1: - /* mono -> mono - stereo -> stereo - bilingual -> lang1 */ - cx25840_and_or(client, 0x809, ~0xf, 0x04); - break; - case V4L2_TUNER_MODE_LANG1_LANG2: - /* mono -> mono - stereo -> stereo - bilingual -> lang1/lang2 */ - cx25840_and_or(client, 0x809, ~0xf, 0x07); - break; - case V4L2_TUNER_MODE_LANG2: - /* mono -> mono - stereo -> stereo - bilingual -> lang2 */ - cx25840_and_or(client, 0x809, ~0xf, 0x01); - break; - default: - return -EINVAL; + case V4L2_TUNER_MODE_MONO: + /* + * mono -> mono + * stereo -> mono + * bilingual -> lang1 + */ + cx25840_and_or(client, 0x809, ~0xf, 0x00); + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1: + /* + * mono -> mono + * stereo -> stereo + * bilingual -> lang1 + */ + cx25840_and_or(client, 0x809, ~0xf, 0x04); + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + /* + * mono -> mono + * stereo -> stereo + * bilingual -> lang1/lang2 + */ + cx25840_and_or(client, 0x809, ~0xf, 0x07); + break; + case V4L2_TUNER_MODE_LANG2: + /* + * mono -> mono + * stereo -> stereo + * bilingual -> lang2 + */ + cx25840_and_or(client, 0x809, ~0xf, 0x01); + break; + default: + return -EINVAL; } state->audmode = vt->audmode; return 0; } -static int cx25840_reset(struct v4l2_subdev *sd, u32 val) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (is_cx2583x(state)) - cx25836_initialize(client); - else if (is_cx2388x(state)) - cx23885_initialize(client); - else if (is_cx231xx(state)) - cx231xx_initialize(client); - else - cx25840_initialize(client); - return 0; -} - static int cx25840_log_status(struct v4l2_subdev *sd) { struct cx25840_state *state = to_state(sd); @@ -5050,6 +5725,8 @@ static const struct v4l2_ctrl_ops cx25840_ctrl_ops = { static const struct v4l2_subdev_core_ops cx25840_core_ops = { .log_status = cx25840_log_status, .reset = cx25840_reset, + /* calling the (optional) init op will turn on the generic mode */ + .init = cx25840_init, .load_fw = cx25840_load_fw, .s_io_pin_config = common_s_io_pin_config, #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -5073,8 +5750,9 @@ static const struct v4l2_subdev_audio_ops cx25840_audio_ops = { }; static const struct v4l2_subdev_video_ops cx25840_video_ops = { - .s_std = cx25840_s_std, .g_std = cx25840_g_std, + .s_std = cx25840_s_std, + .querystd = cx25840_querystd, .s_routing = cx25840_s_video_routing, .s_stream = cx25840_s_stream, .g_input_status = cx25840_g_input_status, @@ -5110,22 +5788,28 @@ static u32 get_cx2388x_ident(struct i2c_client *client) /* Come out of digital power down */ cx25840_write(client, 0x000, 0); - /* Detecting whether the part is cx23885/7/8 is more + /* + * Detecting whether the part is cx23885/7/8 is more * difficult than it needs to be. No ID register. Instead we * probe certain registers indicated in the datasheets to look - * for specific defaults that differ between the silicon designs. */ + * for specific defaults that differ between the silicon designs. + */ /* It's either 885/7 if the IR Tx Clk Divider register exists */ if (cx25840_read4(client, 0x204) & 0xffff) { - /* CX23885 returns bogus repetitive byte values for the DIF, - * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131) */ + /* + * CX23885 returns bogus repetitive byte values for the DIF, + * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131) + */ ret = cx25840_read4(client, 0x300); if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) { /* No DIF */ ret = CX23885_AV; } else { - /* CX23887 has a broken DIF, but the registers - * appear valid (but unused), good enough to detect. */ + /* + * CX23887 has a broken DIF, but the registers + * appear valid (but unused), good enough to detect. + */ ret = CX23887_AV; } } else if (cx25840_read4(client, 0x300) & 0x0fffffff) { @@ -5157,14 +5841,18 @@ static int cx25840_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); + v4l_dbg(1, cx25840_debug, client, + "detecting cx25840 client on address 0x%x\n", + client->addr << 1); device_id = cx25840_read(client, 0x101) << 8; device_id |= cx25840_read(client, 0x100); v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id); - /* The high byte of the device ID should be - * 0x83 for the cx2583x and 0x84 for the cx2584x */ + /* + * The high byte of the device ID should be + * 0x83 for the cx2583x and 0x84 for the cx2584x + */ if ((device_id & 0xff00) == 0x8300) { id = CX25836 + ((device_id >> 4) & 0xf) - 6; } else if ((device_id & 0xff00) == 0x8400) { @@ -5178,7 +5866,8 @@ static int cx25840_probe(struct i2c_client *client, v4l_err(client, "likely a confused/unresponsive cx2388[578] A/V decoder found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - v4l_err(client, "A method to reset it from the cx25840 driver software is not known at this time\n"); + v4l_err(client, + "A method to reset it from the cx25840 driver software is not known at this time\n"); return -ENODEV; } else { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); @@ -5186,7 +5875,7 @@ static int cx25840_probe(struct i2c_client *client, } state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); - if (state == NULL) + if (!state) return -ENOMEM; sd = &state->sd; @@ -5213,7 +5902,7 @@ static int cx25840_probe(struct i2c_client *client, sd->entity.function = MEDIA_ENT_F_ATV_DECODER; ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads), - state->pads); + state->pads); if (ret < 0) { v4l_info(client, "failed to initialize media entity!\n"); return ret; @@ -5241,8 +5930,10 @@ static int cx25840_probe(struct i2c_client *client, case CX25841: case CX25842: case CX25843: - /* Note: revision '(device_id & 0x0f) == 2' was never built. The - marking skips from 0x1 == 22 to 0x3 == 23. */ + /* + * Note: revision '(device_id & 0x0f) == 2' was never built. + * The marking skips from 0x1 == 22 to 0x3 == 23. + */ v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", (device_id & 0xfff0) >> 4, (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 @@ -5270,13 +5961,13 @@ static int cx25840_probe(struct i2c_client *client, state->std = V4L2_STD_NTSC_M; v4l2_ctrl_handler_init(&state->hdl, 9); v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, - V4L2_CID_CONTRAST, 0, 127, 1, 64); + V4L2_CID_CONTRAST, 0, 127, 1, 64); v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, - V4L2_CID_SATURATION, 0, 127, 1, 64); + V4L2_CID_SATURATION, 0, 127, 1, 64); v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); + V4L2_CID_HUE, -128, 127, 1, 0); if (!is_cx2583x(state)) { default_volume = cx25840_read(client, 0x8d4); /* @@ -5288,8 +5979,7 @@ static int cx25840_probe(struct i2c_client *client, /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */ default_volume = 228; cx25840_write(client, 0x8d4, 228); - } - else if (default_volume < 20) { + } else if (default_volume < 20) { /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */ default_volume = 20; cx25840_write(client, 0x8d4, 20); @@ -5297,20 +5987,23 @@ static int cx25840_probe(struct i2c_client *client, default_volume = (((228 - default_volume) >> 1) + 23) << 9; state->volume = v4l2_ctrl_new_std(&state->hdl, - &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME, - 0, 65535, 65535 / 100, default_volume); + &cx25840_audio_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, + 0, 65535, 65535 / 100, + default_volume); state->mute = v4l2_ctrl_new_std(&state->hdl, - &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE, - 0, 1, 1, 0); + &cx25840_audio_ctrl_ops, + V4L2_CID_AUDIO_MUTE, + 0, 1, 1, 0); v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, - V4L2_CID_AUDIO_BALANCE, - 0, 65535, 65535 / 100, 32768); + V4L2_CID_AUDIO_BALANCE, + 0, 65535, 65535 / 100, 32768); v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, - V4L2_CID_AUDIO_BASS, - 0, 65535, 65535 / 100, 32768); + V4L2_CID_AUDIO_BASS, + 0, 65535, 65535 / 100, 32768); v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, - V4L2_CID_AUDIO_TREBLE, - 0, 65535, 65535 / 100, 32768); + V4L2_CID_AUDIO_TREBLE, + 0, 65535, 65535 / 100, 32768); } sd->ctrl_handler = &state->hdl; if (state->hdl.error) { diff --git a/drivers/media/i2c/cx25840/cx25840-core.h b/drivers/media/i2c/cx25840/cx25840-core.h index 7fa5787635ea..8b89e90687a1 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.h +++ b/drivers/media/i2c/cx25840/cx25840-core.h @@ -7,7 +7,6 @@ #ifndef _CX25840_CORE_H_ #define _CX25840_CORE_H_ - #include <linux/videodev2.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> @@ -44,10 +43,15 @@ enum cx25840_media_pads { * @mute: audio mute V4L2 control (non-cx2583x devices only) * @pvr150_workaround: whether we enable workaround for Hauppauge PVR150 * hardware bug (audio dropping out) + * @generic_mode: whether we disable ivtv-specific hacks + * this mode gets turned on when the bridge driver calls + * cx25840 subdevice init core op * @radio: set if we are currently in the radio mode, otherwise * the current mode is non-radio (that is, video) * @std: currently set video standard * @vid_input: currently set video input + * @vid_config: currently set video output configuration + * only used in the generic mode * @aud_input: currently set audio input * @audclk_freq: currently set audio sample rate * @audmode: currently set audio mode (when in non-radio mode) @@ -74,9 +78,11 @@ struct cx25840_state { struct v4l2_ctrl *mute; }; int pvr150_workaround; + bool generic_mode; int radio; v4l2_std_id std; enum cx25840_video_input vid_input; + u32 vid_config; enum cx25840_audio_input aud_input; u32 audclk_freq; int audmode; @@ -84,7 +90,7 @@ struct cx25840_state { enum cx25840_model id; u32 rev; int is_initialized; - unsigned vbi_regs_offset; + unsigned int vbi_regs_offset; wait_queue_head_t fw_wait; struct work_struct fw_work; struct cx25840_ir_state *ir_state; @@ -109,6 +115,14 @@ static inline bool is_cx2583x(struct cx25840_state *state) state->id == CX25837; } +static inline bool is_cx2584x(struct cx25840_state *state) +{ + return state->id == CX25840 || + state->id == CX25841 || + state->id == CX25842 || + state->id == CX25843; +} + static inline bool is_cx231xx(struct cx25840_state *state) { return state->id == CX2310X_AV; @@ -142,7 +156,8 @@ int cx25840_write(struct i2c_client *client, u16 addr, u8 value); int cx25840_write4(struct i2c_client *client, u16 addr, u32 value); u8 cx25840_read(struct i2c_client *client, u16 addr); u32 cx25840_read4(struct i2c_client *client, u16 addr); -int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value); +int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned int mask, + u8 value); int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask, u32 or_value); void cx25840_std_setup(struct i2c_client *client); @@ -161,9 +176,12 @@ extern const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops; /* ----------------------------------------------------------------------- */ /* cx25850-vbi.c */ int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt); -int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); -int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); -int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi); +int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, + struct v4l2_sliced_vbi_format *fmt); +int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, + struct v4l2_sliced_vbi_format *fmt); +int cx25840_decode_vbi_line(struct v4l2_subdev *sd, + struct v4l2_decode_vbi_line *vbi); /* ----------------------------------------------------------------------- */ /* cx25850-ir.c */ diff --git a/drivers/media/i2c/cx25840/cx25840-vbi.c b/drivers/media/i2c/cx25840/cx25840-vbi.c index 643335f0f827..a066d5f0fec9 100644 --- a/drivers/media/i2c/cx25840/cx25840-vbi.c +++ b/drivers/media/i2c/cx25840/cx25840-vbi.c @@ -86,6 +86,7 @@ int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format * memset(svbi->service_lines, 0, sizeof(svbi->service_lines)); svbi->service_set = 0; /* we're done if raw VBI is active */ + /* TODO: this will have to be changed for generic_mode VBI */ if ((cx25840_read(client, 0x404) & 0x10) == 0) return 0; @@ -128,6 +129,7 @@ int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) cx25840_write(client, 0x54f, vbi_offset); else cx25840_write(client, 0x47f, vbi_offset); + /* TODO: this will have to be changed for generic_mode VBI */ cx25840_write(client, 0x404, 0x2e); return 0; } @@ -148,6 +150,7 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format * cx25840_std_setup(client); /* Sliced VBI */ + /* TODO: this will have to be changed for generic_mode VBI */ cx25840_write(client, 0x404, 0x32); /* Ancillary data */ cx25840_write(client, 0x406, 0x13); if (is_cx23888(state)) @@ -202,6 +205,7 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format * } cx25840_write(client, state->vbi_regs_offset + 0x43c, 0x16); + /* TODO: this will have to be changed for generic_mode VBI */ if (is_cx23888(state)) cx25840_write(client, 0x428, is_pal ? 0x2a : 0x22); else diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index 83e9961b0505..159a3a604f0e 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -1111,6 +1111,6 @@ static struct i2c_driver imx214_i2c_driver = { module_i2c_driver(imx214_i2c_driver); -MODULE_DESCRIPTION("Sony IMX214 Camera drier"); +MODULE_DESCRIPTION("Sony IMX214 Camera driver"); MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/lm3646.c b/drivers/media/i2c/lm3646.c index 73fbe3c37fc9..d8a8853f9a2b 100644 --- a/drivers/media/i2c/lm3646.c +++ b/drivers/media/i2c/lm3646.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/media/i2c/lm3646.c * General device driver for TI lm3646, Dual FLASH LED Driver @@ -6,10 +7,6 @@ * * Contact: Daniel Jeong <gshark.jeong@gmail.com> * Ldd-Mlp <ldd-mlp@list.ti.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c index 4b23fde937b3..2df743cbe09d 100644 --- a/drivers/media/i2c/mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -730,7 +730,7 @@ static int mt9m001_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9m001 *mt9m001; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; int ret; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index 5168bb5880c4..12cb012d91f7 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for MT9M111/MT9M112/MT9M131 CMOS Image Sensor from Micron/Aptina * * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/videodev2.h> #include <linux/slab.h> @@ -13,6 +10,7 @@ #include <linux/log2.h> #include <linux/gpio.h> #include <linux/delay.h> +#include <linux/regulator/consumer.h> #include <linux/v4l2-mediabus.h> #include <linux/module.h> #include <linux/property.h> @@ -243,6 +241,7 @@ struct mt9m111 { int power_count; const struct mt9m111_datafmt *fmt; int lastpage; /* PageMap cache value */ + struct regulator *regulator; bool is_streaming; /* user point of view - 0: falling 1: rising edge */ unsigned int pclk_sample:1; @@ -982,11 +981,23 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111) if (ret < 0) return ret; + ret = regulator_enable(mt9m111->regulator); + if (ret < 0) + goto out_clk_disable; + ret = mt9m111_resume(mt9m111); - if (ret < 0) { - dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret); - v4l2_clk_disable(mt9m111->clk); - } + if (ret < 0) + goto out_regulator_disable; + + return 0; + +out_regulator_disable: + regulator_disable(mt9m111->regulator); + +out_clk_disable: + v4l2_clk_disable(mt9m111->clk); + + dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret); return ret; } @@ -994,6 +1005,7 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111) static void mt9m111_power_off(struct mt9m111 *mt9m111) { mt9m111_suspend(mt9m111); + regulator_disable(mt9m111->regulator); v4l2_clk_disable(mt9m111->clk); } @@ -1235,7 +1247,7 @@ static int mt9m111_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9m111 *mt9m111; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; int ret; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { @@ -1248,14 +1260,23 @@ static int mt9m111_probe(struct i2c_client *client, if (!mt9m111) return -ENOMEM; - ret = mt9m111_probe_fw(client, mt9m111); - if (ret) - return ret; + if (dev_fwnode(&client->dev)) { + ret = mt9m111_probe_fw(client, mt9m111); + if (ret) + return ret; + } mt9m111->clk = v4l2_clk_get(&client->dev, "mclk"); if (IS_ERR(mt9m111->clk)) return PTR_ERR(mt9m111->clk); + mt9m111->regulator = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(mt9m111->regulator)) { + dev_err(&client->dev, "regulator not found: %ld\n", + PTR_ERR(mt9m111->regulator)); + return PTR_ERR(mt9m111->regulator); + } + /* Default HIGHPOWER context */ mt9m111->ctx = &context_b; diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 715be3632b01..dc23b9ed510a 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for MT9P031 CMOS Image Sensor from Aptina * @@ -6,10 +7,6 @@ * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de> * * Based on the MT9V032 driver and Bastian Hecht's code. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> @@ -1034,7 +1031,7 @@ static int mt9p031_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9p031_platform_data *pdata = mt9p031_get_pdata(client); - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; struct mt9p031 *mt9p031; unsigned int i; int ret; diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c index f683d2cb0486..2e96ff5234b4 100644 --- a/drivers/media/i2c/mt9t001.c +++ b/drivers/media/i2c/mt9t001.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for MT9T001 CMOS Image Sensor from Aptina (Micron) * @@ -6,10 +7,6 @@ * Based on the MT9M001 driver, * * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 67f69ad6ecf4..4b9b98cf6674 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for MT9V022, MT9V024, MT9V032, and MT9V034 CMOS Image Sensors * @@ -6,10 +7,6 @@ * Based on the MT9M001 driver, * * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 45bb872db3c5..aac6f77afa0f 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -1224,7 +1224,7 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl) ov13858->exposure->minimum, max, ov13858->exposure->step, max); break; - }; + } /* * Applying V4L2 control value only happens @@ -1262,7 +1262,7 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl) "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ctrl->val); break; - }; + } pm_runtime_put(&client->dev); diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index 83031cfc7914..ecd167d7c4d2 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ov2640 Camera Driver * @@ -7,10 +8,6 @@ * * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright (C) 2006, OmniVision - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> @@ -1197,7 +1194,7 @@ static int ov2640_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov2640_priv *priv; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; int ret; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c index 98a1f2e312b5..6814583d9606 100644 --- a/drivers/media/i2c/ov2685.c +++ b/drivers/media/i2c/ov2685.c @@ -576,7 +576,7 @@ static int ov2685_set_ctrl(struct v4l2_ctrl *ctrl) __func__, ctrl->id, ctrl->val); ret = -EINVAL; break; - }; + } pm_runtime_put(&client->dev); diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index 5d107c53364d..e65a94353175 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -1143,7 +1143,7 @@ static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl) dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", __func__, ctrl->id, ctrl->val); break; - }; + } pm_runtime_put(&client->dev); diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 1b972e591b48..5b9af5e5b7f1 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * V4L2 subdevice driver for OmniVision OV6650 Camera Sensor * @@ -18,10 +19,6 @@ * Hardware specific bits initially based on former work by Matt Callow * drivers/media/video/omap/sensor_ov6650.c * Copyright (C) 2006 Matt Callow - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> @@ -1009,7 +1006,6 @@ static int ov6650_probe(struct i2c_client *client, priv->colorspace = V4L2_COLORSPACE_JPEG; priv->subdev.internal_ops = &ov6650_internal_ops; - priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ret = v4l2_async_register_subdev(&priv->subdev); if (ret) diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 54e80a60aa57..70bb870b1d08 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -532,7 +532,7 @@ static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl) struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev); struct regmap *regmap = ov7740->regmap; int ret; - u8 val = 0; + u8 val; if (!pm_runtime_get_if_in_use(&client->dev)) return 0; @@ -551,6 +551,7 @@ static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl) ret = ov7740_set_contrast(regmap, ctrl->val); break; case V4L2_CID_VFLIP: + val = ctrl->val ? REG0C_IMG_FLIP : 0x00; ret = regmap_update_bits(regmap, REG_REG0C, REG0C_IMG_FLIP, val); break; @@ -561,16 +562,16 @@ static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_AUTOGAIN: if (!ctrl->val) - return ov7740_set_gain(regmap, ov7740->gain->val); - - ret = ov7740_set_autogain(regmap, ctrl->val); + ret = ov7740_set_gain(regmap, ov7740->gain->val); + else + ret = ov7740_set_autogain(regmap, ctrl->val); break; case V4L2_CID_EXPOSURE_AUTO: if (ctrl->val == V4L2_EXPOSURE_MANUAL) - return ov7740_set_exp(regmap, ov7740->exposure->val); - - ret = ov7740_set_autoexp(regmap, ctrl->val); + ret = ov7740_set_exp(regmap, ov7740->exposure->val); + else + ret = ov7740_set_autoexp(regmap, ctrl->val); break; default: ret = -EINVAL; @@ -785,7 +786,11 @@ static int ov7740_try_fmt_internal(struct v4l2_subdev *sd, fsize++; } - + if (i >= ARRAY_SIZE(ov7740_framesizes)) { + fsize = &ov7740_framesizes[0]; + fmt->width = fsize->width; + fmt->height = fsize->height; + } if (ret_frmsize != NULL) *ret_frmsize = fsize; @@ -1007,8 +1012,6 @@ static int ov7740_init_controls(struct ov7740 *ov7740) ov7740->gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, V4L2_CID_GAIN, 0, 1023, 1, 500); - if (ov7740->gain) - ov7740->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; ov7740->auto_gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, V4L2_CID_AUTOGAIN, 0, 1, 1, 1); @@ -1026,7 +1029,6 @@ static int ov7740_init_controls(struct ov7740 *ov7740) v4l2_ctrl_auto_cluster(2, &ov7740->auto_gain, 0, true); v4l2_ctrl_auto_cluster(2, &ov7740->auto_exposure, V4L2_EXPOSURE_MANUAL, true); - v4l2_ctrl_cluster(2, &ov7740->hflip); if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index dbf1095b9440..cd347d6b7b9d 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -195,11 +195,11 @@ static const struct ov8856_reg mode_3280x2464_regs[] = { {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, - {0x3803, 0x07}, + {0x3803, 0x06}, {0x3804, 0x0c}, {0x3805, 0xdf}, {0x3806, 0x09}, - {0x3807, 0xa6}, + {0x3807, 0xa7}, {0x3808, 0x0c}, {0x3809, 0xd0}, {0x380a, 0x09}, @@ -211,7 +211,7 @@ static const struct ov8856_reg mode_3280x2464_regs[] = { {0x3810, 0x00}, {0x3811, 0x00}, {0x3812, 0x00}, - {0x3813, 0x00}, + {0x3813, 0x01}, {0x3814, 0x01}, {0x3815, 0x01}, {0x3816, 0x00}, @@ -385,11 +385,11 @@ static const struct ov8856_reg mode_1640x1232_regs[] = { {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, - {0x3803, 0x07}, + {0x3803, 0x06}, {0x3804, 0x0c}, {0x3805, 0xdf}, {0x3806, 0x09}, - {0x3807, 0xa6}, + {0x3807, 0xa7}, {0x3808, 0x06}, {0x3809, 0x68}, {0x380a, 0x04}, @@ -401,7 +401,7 @@ static const struct ov8856_reg mode_1640x1232_regs[] = { {0x3810, 0x00}, {0x3811, 0x00}, {0x3812, 0x00}, - {0x3813, 0x00}, + {0x3813, 0x01}, {0x3814, 0x03}, {0x3815, 0x01}, {0x3816, 0x00}, diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index d6831f28378b..482609665305 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -691,14 +691,14 @@ static int ov9640_probe(struct i2c_client *client, priv->gpio_power = devm_gpiod_get(&client->dev, "Camera power", GPIOD_OUT_LOW); - if (IS_ERR_OR_NULL(priv->gpio_power)) { + if (IS_ERR(priv->gpio_power)) { ret = PTR_ERR(priv->gpio_power); return ret; } priv->gpio_reset = devm_gpiod_get(&client->dev, "Camera reset", GPIOD_OUT_HIGH); - if (IS_ERR_OR_NULL(priv->gpio_reset)) { + if (IS_ERR(priv->gpio_reset)) { ret = PTR_ERR(priv->gpio_reset); return ret; } diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index eefd57ec2a73..30ab2225fbd0 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Omnivision OV9650/OV9652 CMOS Image Sensor driver * @@ -6,10 +7,6 @@ * Register definitions and initial settings based on a driver written * by Vladimir Fonov. * Copyright (c) 2010, Vladimir Fonov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> #include <linux/delay.h> diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 727db7c0670a..8e6de06b3e72 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Samsung S5K5BAF UXGA 1/5" 2M CMOS Image Sensor * with embedded SoC ISP. @@ -7,10 +8,6 @@ * * Based on S5K6AA driver authored by Sylwester Nawrocki * Copyright (C) 2013, Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c index 2e140272794b..3b7721f81be2 100644 --- a/drivers/media/i2c/s5k6a3.c +++ b/drivers/media/i2c/s5k6a3.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung S5K6A3 image sensor driver * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c index e46d72cee566..ab96d6067fc3 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.c +++ b/drivers/media/i2c/smiapp/smiapp-quirk.c @@ -194,7 +194,7 @@ static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor) return rval; /* Wait for 1 ms + one line => 2 ms is likely enough */ - usleep_range(2000, 2000); + usleep_range(2000, 2050); /* Restore it */ rval = smiapp_write_8(sensor, 0x3205, 0x00); diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index 9369f38dbf3d..81285b8d5cfb 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -61,7 +61,10 @@ static const u32 mipid02_supported_fmt_codes[] = { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, - MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_BGR888_1X24 + MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_BGR888_1X24, + MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE, + MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_JPEG_1X8 }; /* regulator supplies */ @@ -99,6 +102,7 @@ struct mipid02_dev { u8 data_lane1_reg1; u8 mode_reg1; u8 mode_reg2; + u8 data_selection_ctrl; u8 data_id_rreg; u8 pix_width_ctrl; u8 pix_width_ctrl_emb; @@ -128,6 +132,10 @@ static int bpp_from_code(__u32 code) case MEDIA_BUS_FMT_SRGGB12_1X12: return 12; case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_RGB565_2X8_LE: + case MEDIA_BUS_FMT_RGB565_2X8_BE: return 16; case MEDIA_BUS_FMT_BGR888_1X24: return 24; @@ -155,9 +163,14 @@ static u8 data_type_from_code(__u32 code) case MEDIA_BUS_FMT_SRGGB12_1X12: return 0x2c; case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: return 0x1e; case MEDIA_BUS_FMT_BGR888_1X24: return 0x24; + case MEDIA_BUS_FMT_RGB565_2X8_LE: + case MEDIA_BUS_FMT_RGB565_2X8_BE: + return 0x22; default: return 0; } @@ -331,6 +344,25 @@ static int mipid02_detect(struct mipid02_dev *bridge) return mipid02_read_reg(bridge, MIPID02_CLK_LANE_WR_REG1, ®); } +static u32 mipid02_get_link_freq_from_cid_link_freq(struct mipid02_dev *bridge, + struct v4l2_subdev *subdev) +{ + struct v4l2_querymenu qm = {.id = V4L2_CID_LINK_FREQ, }; + struct v4l2_ctrl *ctrl; + int ret; + + ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_LINK_FREQ); + if (!ctrl) + return 0; + qm.index = v4l2_ctrl_g_ctrl(ctrl); + + ret = v4l2_querymenu(subdev->ctrl_handler, &qm); + if (ret) + return 0; + + return qm.value; +} + static u32 mipid02_get_link_freq_from_cid_pixel_rate(struct mipid02_dev *bridge, struct v4l2_subdev *subdev) { @@ -358,10 +390,14 @@ static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge) struct v4l2_subdev *subdev = bridge->s_subdev; u32 link_freq; - link_freq = mipid02_get_link_freq_from_cid_pixel_rate(bridge, subdev); + link_freq = mipid02_get_link_freq_from_cid_link_freq(bridge, subdev); if (!link_freq) { - dev_err(&client->dev, "Failed to detect link frequency"); - return -EINVAL; + link_freq = mipid02_get_link_freq_from_cid_pixel_rate(bridge, + subdev); + if (!link_freq) { + dev_err(&client->dev, "Failed to get link frequency"); + return -EINVAL; + } } dev_dbg(&client->dev, "detect link_freq = %d Hz", link_freq); @@ -452,6 +488,7 @@ static int mipid02_configure_from_tx(struct mipid02_dev *bridge) { struct v4l2_fwnode_endpoint *ep = &bridge->tx; + bridge->r.data_selection_ctrl = SELECTION_MANUAL_WIDTH; bridge->r.pix_width_ctrl = ep->bus.parallel.bus_width; bridge->r.pix_width_ctrl_emb = ep->bus.parallel.bus_width; if (ep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) @@ -467,10 +504,15 @@ static int mipid02_configure_from_code(struct mipid02_dev *bridge) u8 data_type; bridge->r.data_id_rreg = 0; - data_type = data_type_from_code(bridge->fmt.code); - if (!data_type) - return -EINVAL; - bridge->r.data_id_rreg = data_type; + + if (bridge->fmt.code != MEDIA_BUS_FMT_JPEG_1X8) { + bridge->r.data_selection_ctrl |= SELECTION_MANUAL_DATA; + + data_type = data_type_from_code(bridge->fmt.code); + if (!data_type) + return -EINVAL; + bridge->r.data_id_rreg = data_type; + } return 0; } @@ -554,7 +596,7 @@ static int mipid02_stream_enable(struct mipid02_dev *bridge) if (ret) goto error; ret = mipid02_write_reg(bridge, MIPID02_DATA_SELECTION_CTRL, - SELECTION_MANUAL_DATA | SELECTION_MANUAL_WIDTH); + bridge->r.data_selection_ctrl); if (ret) goto error; ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL, diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c index 06a78c2cdaab..cbdc9be0a597 100644 --- a/drivers/media/i2c/tda7432.c +++ b/drivers/media/i2c/tda7432.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * For the STS-Thompson TDA7432 audio processor chip * @@ -9,7 +10,7 @@ * * Copyright (c) 2000 Eric Sandeen <eric_sandeen@bigfoot.com> * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@kernel.org> - * This code is placed under the terms of the GNU General Public License + * * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) * Which was based on tda8425.c by Greg Alexander (c) 1998 * diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 3ada3bb27402..a7fbe5b400c2 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/media/i2c/tvp514x.c * @@ -13,16 +14,6 @@ * Manjunath Hadli <mrh@ti.com> * Karicheri Muralidharan <m-karicheri2@ti.com> * Prabhakar Lad <prabhakar.lad@ti.com> - * - * This package is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/i2c.h> diff --git a/drivers/media/i2c/tvp514x_regs.h b/drivers/media/i2c/tvp514x_regs.h index 1e6c0857590e..cc236c968f67 100644 --- a/drivers/media/i2c/tvp514x_regs.h +++ b/drivers/media/i2c/tvp514x_regs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * drivers/media/i2c/tvp514x_regs.h * @@ -10,16 +11,6 @@ * Hardik Shah <hardik.shah@ti.com> * Manjunath Hadli <mrh@ti.com> * Karicheri Muralidharan <m-karicheri2@ti.com> - * - * This package is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef _TVP514X_REGS_H diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index 4d7cd736b930..a25a350b0ddc 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -934,8 +934,7 @@ static int tw9910_probe(struct i2c_client *client, { struct tw9910_priv *priv; struct tw9910_video_info *info; - struct i2c_adapter *adapter = - to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; int ret; if (!client->dev.platform_data) { diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index abd3152df7d0..078141712c88 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -190,12 +190,8 @@ static int mlx90640_setup(struct video_i2c_data *data) unsigned int n, idx; for (n = 0; n < data->chip->num_frame_intervals - 1; n++) { - if (data->frame_interval.numerator - != data->chip->frame_intervals[n].numerator) - continue; - - if (data->frame_interval.denominator - == data->chip->frame_intervals[n].denominator) + if (V4L2_FRACT_COMPARE(data->frame_interval, ==, + data->chip->frame_intervals[n])) break; } diff --git a/drivers/media/mc/Kconfig b/drivers/media/mc/Kconfig new file mode 100644 index 000000000000..3b9795cfcb36 --- /dev/null +++ b/drivers/media/mc/Kconfig @@ -0,0 +1,33 @@ +# +# Media controller +# Selectable only for webcam/grabbers, as other drivers don't use it +# + +config MEDIA_CONTROLLER + bool "Media Controller API" + depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT + help + Enable the media controller API used to query media devices internal + topology and configure it dynamically. + + This API is mostly used by camera interfaces in embedded platforms. + +config MEDIA_CONTROLLER_DVB + bool "Enable Media controller for DVB (EXPERIMENTAL)" + depends on MEDIA_CONTROLLER && DVB_CORE + help + Enable the media controller API support for DVB. + + This is currently experimental. + +config MEDIA_CONTROLLER_REQUEST_API + bool "Enable Media controller Request API (EXPERIMENTAL)" + depends on MEDIA_CONTROLLER && STAGING_MEDIA + help + DO NOT ENABLE THIS OPTION UNLESS YOU KNOW WHAT YOU'RE DOING. + + This option enables the Request API for the Media controller and V4L2 + interfaces. It is currently needed by a few stateless codec drivers. + + There is currently no intention to provide API or ABI stability for + this new API as of yet. diff --git a/drivers/media/mc/Makefile b/drivers/media/mc/Makefile new file mode 100644 index 000000000000..119037f0e686 --- /dev/null +++ b/drivers/media/mc/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 + +mc-objs := mc-device.o mc-devnode.o mc-entity.o \ + mc-request.o + +ifeq ($(CONFIG_USB),y) + mc-objs += mc-dev-allocator.o +endif + +obj-$(CONFIG_MEDIA_SUPPORT) += mc.o diff --git a/drivers/media/media-dev-allocator.c b/drivers/media/mc/mc-dev-allocator.c index ae17887dec59..ae17887dec59 100644 --- a/drivers/media/media-dev-allocator.c +++ b/drivers/media/mc/mc-dev-allocator.c diff --git a/drivers/media/media-device.c b/drivers/media/mc/mc-device.c index 9ae481ddd975..e19df5165e78 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/mc/mc-device.c @@ -494,6 +494,7 @@ static long media_device_enum_links32(struct media_device *mdev, { struct media_links_enum links; compat_uptr_t pads_ptr, links_ptr; + int ret; memset(&links, 0, sizeof(links)); @@ -505,7 +506,14 @@ static long media_device_enum_links32(struct media_device *mdev, links.pads = compat_ptr(pads_ptr); links.links = compat_ptr(links_ptr); - return media_device_enum_links(mdev, &links); + ret = media_device_enum_links(mdev, &links); + if (ret) + return ret; + + if (copy_to_user(ulinks->reserved, links.reserved, + sizeof(ulinks->reserved))) + return -EFAULT; + return 0; } #define MEDIA_IOC_ENUM_LINKS32 _IOWR('|', 0x02, struct media_links_enum32) diff --git a/drivers/media/media-devnode.c b/drivers/media/mc/mc-devnode.c index f11382afe23b..f11382afe23b 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/mc/mc-devnode.c diff --git a/drivers/media/media-entity.c b/drivers/media/mc/mc-entity.c index 7c429ce98bae..7c429ce98bae 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/mc/mc-entity.c diff --git a/drivers/media/media-request.c b/drivers/media/mc/mc-request.c index e3fca436c75b..e3fca436c75b 100644 --- a/drivers/media/media-request.c +++ b/drivers/media/mc/mc-request.c diff --git a/drivers/media/pci/bt8xx/bttv-audio-hook.c b/drivers/media/pci/bt8xx/bttv-audio-hook.c index 8febe7358a8f..da1914a20b81 100644 --- a/drivers/media/pci/bt8xx/bttv-audio-hook.c +++ b/drivers/media/pci/bt8xx/bttv-audio-hook.c @@ -1,8 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Handlers for board audio hooks, split from bttv-cards * * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@kernel.org> - * This code is placed under the terms of the GNU General Public License */ #include "bttv-audio-hook.h" diff --git a/drivers/media/pci/bt8xx/bttv-audio-hook.h b/drivers/media/pci/bt8xx/bttv-audio-hook.h index c61b9ac4f4e3..d6a1a5a60a56 100644 --- a/drivers/media/pci/bt8xx/bttv-audio-hook.h +++ b/drivers/media/pci/bt8xx/bttv-audio-hook.h @@ -1,4 +1,6 @@ /* + * SPDX-License-Identifier: GPL-2.0 + * * Handlers for board audio hooks, split from bttv-cards * * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@kernel.org> diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 636e6a2549a9..612d1c0010c1 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2453,7 +2453,6 @@ static int bttv_s_fmt_vid_overlay(struct file *file, void *priv, static int bttv_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; @@ -2464,17 +2463,17 @@ static int bttv_querycap(struct file *file, void *priv, strscpy(cap->card, btv->video_dev.name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(btv->c.pci)); - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_DEVICE_CAPS; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; if (no_overlay <= 0) cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; if (video_is_registered(&btv->vbi_dev)) cap->capabilities |= V4L2_CAP_VBI_CAPTURE; - if (video_is_registered(&btv->radio_dev)) + if (video_is_registered(&btv->radio_dev)) { cap->capabilities |= V4L2_CAP_RADIO; + if (btv->has_tea575x) + cap->capabilities |= V4L2_CAP_HW_FREQ_SEEK; + } /* * No need to lock here: those vars are initialized during board @@ -2484,27 +2483,6 @@ static int bttv_querycap(struct file *file, void *priv, cap->capabilities |= V4L2_CAP_RDS_CAPTURE; if (btv->tuner_type != TUNER_ABSENT) cap->capabilities |= V4L2_CAP_TUNER; - if (vdev->vfl_type == VFL_TYPE_GRABBER) - cap->device_caps = cap->capabilities & - (V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_OVERLAY | - V4L2_CAP_TUNER); - else if (vdev->vfl_type == VFL_TYPE_VBI) - cap->device_caps = cap->capabilities & - (V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_TUNER); - else { - cap->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; - if (btv->has_saa6588) - cap->device_caps |= V4L2_CAP_READWRITE | - V4L2_CAP_RDS_CAPTURE; - if (btv->has_tea575x) - cap->device_caps |= V4L2_CAP_HW_FREQ_SEEK; - } return 0; } @@ -3939,6 +3917,12 @@ static int bttv_register_video(struct bttv *btv) /* video */ vdev_init(btv, &btv->video_dev, &bttv_video_template, "video"); + btv->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + if (btv->tuner_type != TUNER_ABSENT) + btv->video_dev.device_caps |= V4L2_CAP_TUNER; + if (no_overlay <= 0) + btv->video_dev.device_caps |= V4L2_CAP_VIDEO_OVERLAY; if (video_register_device(&btv->video_dev, VFL_TYPE_GRABBER, video_nr[btv->c.nr]) < 0) @@ -3953,6 +3937,10 @@ static int bttv_register_video(struct bttv *btv) /* vbi */ vdev_init(btv, &btv->vbi_dev, &bttv_video_template, "vbi"); + btv->vbi_dev.device_caps = V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | V4L2_CAP_TUNER; + if (btv->tuner_type != TUNER_ABSENT) + btv->vbi_dev.device_caps |= V4L2_CAP_TUNER; if (video_register_device(&btv->vbi_dev, VFL_TYPE_VBI, vbi_nr[btv->c.nr]) < 0) @@ -3964,6 +3952,12 @@ static int bttv_register_video(struct bttv *btv) return 0; /* radio */ vdev_init(btv, &btv->radio_dev, &radio_template, "radio"); + btv->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; + if (btv->has_saa6588) + btv->radio_dev.device_caps |= V4L2_CAP_READWRITE | + V4L2_CAP_RDS_CAPTURE; + if (btv->has_tea575x) + btv->radio_dev.device_caps |= V4L2_CAP_HW_FREQ_SEEK; btv->radio_dev.ctrl_handler = &btv->radio_ctrl_handler; if (video_register_device(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr[btv->c.nr]) < 0) diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig index 6c6c60abe9b1..e0e7df460a92 100644 --- a/drivers/media/pci/cobalt/Kconfig +++ b/drivers/media/pci/cobalt/Kconfig @@ -3,7 +3,7 @@ config VIDEO_COBALT tristate "Cisco Cobalt support" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API depends on PCI_MSI && MTD_COMPLEX_MAPPINGS - depends on GPIOLIB || COMPILE_TEST + depends on (GPIOLIB && DRM_I2C_ADV7511=n) || COMPILE_TEST depends on SND depends on MTD select I2C_ALGOBIT diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index f9fa3a7c3b8f..39dabd4da60f 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -483,13 +483,8 @@ static int cobalt_querycap(struct file *file, void *priv_fh, strscpy(vcap->card, "cobalt", sizeof(vcap->card)); snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCIe:%s", pci_name(cobalt->pci_dev)); - vcap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - if (s->is_output) - vcap->device_caps |= V4L2_CAP_VIDEO_OUTPUT; - else - vcap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; - vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS | - V4L2_CAP_VIDEO_CAPTURE; + vcap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS; if (cobalt->have_hsma_tx) vcap->capabilities |= V4L2_CAP_VIDEO_OUTPUT; return 0; @@ -1274,6 +1269,11 @@ static int cobalt_node_register(struct cobalt *cobalt, int node) q->lock = &s->lock; q->dev = &cobalt->pci_dev->dev; vdev->queue = q; + vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (s->is_output) + vdev->device_caps |= V4L2_CAP_VIDEO_OUTPUT; + else + vdev->device_caps |= V4L2_CAP_VIDEO_CAPTURE; video_set_drvdata(vdev, s); ret = vb2_queue_init(q); diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 9f5972f6d3a6..d9ffc9c359ca 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -385,16 +385,13 @@ static int cx18_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) { struct cx18_open_id *id = fh2id(fh); - struct cx18_stream *s = video_drvdata(file); struct cx18 *cx = id->cx; strscpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); strscpy(vcap->card, cx->card_name, sizeof(vcap->card)); snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(cx->pci_dev)); - vcap->capabilities = cx->v4l2_cap; /* capabilities */ - vcap->device_caps = s->v4l2_dev_caps; /* device capabilities */ - vcap->capabilities |= V4L2_CAP_DEVICE_CAPS; + vcap->capabilities = cx->v4l2_cap | V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index 9805e50c2477..b79718519b9b 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -411,6 +411,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type) return 0; num = s->video_dev.num; + s->video_dev.device_caps = s->v4l2_dev_caps; /* device capabilities */ /* card number + user defined offset + device offset */ if (type != CX18_ENC_STREAM_TYPE_MPG) { struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 8aa5f9b1498a..82f96a4091ac 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1324,12 +1324,11 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, cx23885_boards[tsport->dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_AUDIO | V4L2_CAP_DEVICE_CAPS; if (dev->tuner_type != TUNER_ABSENT) - cap->device_caps |= V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_AUDIO | V4L2_CAP_DEVICE_CAPS; + cap->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -1542,6 +1541,10 @@ int cx23885_417_register(struct cx23885_dev *dev) video_set_drvdata(dev->v4l_device, dev); dev->v4l_device->lock = &dev->lock; dev->v4l_device->queue = q; + dev->v4l_device->device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + if (dev->tuner_type != TUNER_ABSENT) + dev->v4l_device->device_caps |= V4L2_CAP_TUNER; err = video_register_device(dev->v4l_device, VFL_TYPE_GRABBER, -1); if (err < 0) { diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index c9ef9ff7b0bd..4f386db33a11 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -2647,8 +2647,6 @@ int cx23885_dvb_register(struct cx23885_tsport *port) dev->pci_bus, dev->pci_slot); - err = -ENODEV; - /* dvb stuff */ /* We have to init the queue for each frontend on a port. */ pr_info("%s: cx23885 based dvb card\n", dev->name); diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 0c59ecccc38a..b254473db9a3 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -627,21 +627,17 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct cx23885_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); strscpy(cap->driver, "cx23885", sizeof(cap->driver)); strscpy(cap->card, cx23885_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_AUDIO; + cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_AUDIO | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_DEVICE_CAPS; if (dev->tuner_type != TUNER_ABSENT) - cap->device_caps |= V4L2_CAP_TUNER; - if (vdev->vfl_type == VFL_TYPE_VBI) - cap->device_caps |= V4L2_CAP_VBI_CAPTURE; - else - cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; - cap->capabilities = cap->device_caps | V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS; + cap->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -1306,6 +1302,10 @@ int cx23885_video_register(struct cx23885_dev *dev) dev->video_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_video_template, "video"); dev->video_dev->queue = &dev->vb2_vidq; + dev->video_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_AUDIO | V4L2_CAP_VIDEO_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT) + dev->video_dev->device_caps |= V4L2_CAP_TUNER; err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, video_nr[dev->nr]); if (err < 0) { @@ -1320,6 +1320,10 @@ int cx23885_video_register(struct cx23885_dev *dev) dev->vbi_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_vbi_template, "vbi"); dev->vbi_dev->queue = &dev->vb2_vbiq; + dev->vbi_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_AUDIO | V4L2_CAP_VBI_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT) + dev->vbi_dev->device_caps |= V4L2_CAP_TUNER; err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->nr]); if (err < 0) { diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 1bb5dfc74e27..de7641170478 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -426,18 +426,13 @@ static int cx25821_vidioc_querycap(struct file *file, void *priv, { struct cx25821_channel *chan = video_drvdata(file); struct cx25821_dev *dev = chan->dev; - const u32 cap_input = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE; strscpy(cap->driver, "cx25821", sizeof(cap->driver)); strscpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - if (chan->id >= VID_CHANNEL_NUM) - cap->device_caps = cap_output; - else - cap->device_caps = cap_input; - cap->capabilities = cap_input | cap_output | V4L2_CAP_DEVICE_CAPS; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_DEVICE_CAPS; return 0; } @@ -624,6 +619,8 @@ static const struct video_device cx25821_video_device = { .minor = -1, .ioctl_ops = &video_ioctl_ops, .tvnorms = CX25821_NORMS, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; static const struct v4l2_file_operations video_out_fops = { @@ -657,6 +654,7 @@ static const struct video_device cx25821_video_out_device = { .minor = -1, .ioctl_ops = &video_out_ioctl_ops, .tvnorms = CX25821_NORMS, + .device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE, }; void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index b4ad5d12054e..e1e71ae293ed 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -95,7 +95,7 @@ MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s)."); MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards"); MODULE_AUTHOR("Ricardo Cerqueira"); MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(CX88_VERSION); MODULE_SUPPORTED_DEVICE("{{Conexant,23881},{{Conexant,23882},{{Conexant,23883}"); diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index 0a10c9d192f3..200d68827073 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -28,7 +28,7 @@ MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards"); MODULE_AUTHOR("Jelle Foks <jelle@foks.us>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(CX88_VERSION); static unsigned int debug; @@ -1136,6 +1136,10 @@ static int blackbird_register_video(struct cx8802_dev *dev) dev->mpeg_dev.ctrl_handler = &dev->cxhdl.hdl; video_set_drvdata(&dev->mpeg_dev, dev); dev->mpeg_dev.queue = &dev->vb2_mpegq; + dev->mpeg_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE; + if (dev->core->board.tuner_type != UNSET) + dev->mpeg_dev.device_caps |= V4L2_CAP_TUNER; err = video_register_device(&dev->mpeg_dev, VFL_TYPE_GRABBER, -1); if (err < 0) { pr_info("can't register mpeg device\n"); diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index 8597cb8274ab..dcadf78657d6 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -31,7 +31,7 @@ MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); /* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/cx88/cx88-i2c.c b/drivers/media/pci/cx88/cx88-i2c.c index 50a9ae3fa596..7fc64aef1ef7 100644 --- a/drivers/media/pci/cx88/cx88-i2c.c +++ b/drivers/media/pci/cx88/cx88-i2c.c @@ -8,7 +8,6 @@ * & Marcus Metzler (mocm@thp.uni-koeln.de) * (c) 2002 Yurij Sysoev <yurij@naturesoft.net> * (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org> - * * (c) 2005 Mauro Carvalho Chehab <mchehab@kernel.org> * - Multituner support and i2c address binding */ diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c index 27f690b54e0c..589f52d961eb 100644 --- a/drivers/media/pci/cx88/cx88-input.c +++ b/drivers/media/pci/cx88/cx88-input.c @@ -167,14 +167,14 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer) { - unsigned long missed; + u64 missed; struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer); cx88_ir_handle_key(ir); missed = hrtimer_forward_now(&ir->timer, ktime_set(0, ir->polling * 1000000)); if (missed > 1) - ir_dprintk("Missed ticks %ld\n", missed - 1); + ir_dprintk("Missed ticks %llu\n", missed - 1); return HRTIMER_RESTART; } diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index 3b49ebb21b13..e59a74514c7c 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -33,7 +33,7 @@ MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(CX88_VERSION); /* ------------------------------------------------------------------ */ @@ -800,27 +800,12 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, int cx88_querycap(struct file *file, struct cx88_core *core, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); - strscpy(cap->card, core->board.name, sizeof(cap->card)); - cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_DEVICE_CAPS; if (core->board.tuner_type != UNSET) - cap->device_caps |= V4L2_CAP_TUNER; - switch (vdev->vfl_type) { - case VFL_TYPE_RADIO: - cap->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; - break; - case VFL_TYPE_GRABBER: - cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - cap->device_caps |= V4L2_CAP_VBI_CAPTURE; - break; - default: - return -EINVAL; - } - cap->capabilities = cap->device_caps | V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS; + cap->capabilities |= V4L2_CAP_TUNER; if (core->board.radio.type == CX88_RADIO) cap->capabilities |= V4L2_CAP_RADIO; return 0; @@ -1473,6 +1458,10 @@ static int cx8800_initdev(struct pci_dev *pci_dev, video_set_drvdata(&dev->video_dev, dev); dev->video_dev.ctrl_handler = &core->video_hdl; dev->video_dev.queue = &dev->vb2_vidq; + dev->video_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE; + if (core->board.tuner_type != UNSET) + dev->video_dev.device_caps |= V4L2_CAP_TUNER; err = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER, video_nr[core->nr]); if (err < 0) { @@ -1486,6 +1475,10 @@ static int cx8800_initdev(struct pci_dev *pci_dev, &cx8800_vbi_template, "vbi"); video_set_drvdata(&dev->vbi_dev, dev); dev->vbi_dev.queue = &dev->vb2_vbiq; + dev->vbi_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VBI_CAPTURE; + if (core->board.tuner_type != UNSET) + dev->vbi_dev.device_caps |= V4L2_CAP_TUNER; err = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[core->nr]); if (err < 0) { @@ -1500,6 +1493,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, &cx8800_radio_template, "radio"); video_set_drvdata(&dev->radio_dev, dev); dev->radio_dev.ctrl_handler = &core->audio_hdl; + dev->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; err = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO, radio_nr[core->nr]); if (err < 0) { diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig index eaac91d14654..dab34fb85c09 100644 --- a/drivers/media/pci/ddbridge/Kconfig +++ b/drivers/media/pci/ddbridge/Kconfig @@ -36,7 +36,6 @@ config DVB_DDBRIDGE_MSIENABLE bool "Enable Message Signaled Interrupts (MSI) per default (EXPERIMENTAL)" depends on DVB_DDBRIDGE depends on PCI_MSI - default n help Use PCI MSI (Message Signaled Interrupts) per default. Enabling this might lead to I2C errors originating from the bridge in conjunction diff --git a/drivers/media/pci/dt3155/Kconfig b/drivers/media/pci/dt3155/Kconfig index d678ced93f17..a3d24b8a719b 100644 --- a/drivers/media/pci/dt3155/Kconfig +++ b/drivers/media/pci/dt3155/Kconfig @@ -3,7 +3,6 @@ config VIDEO_DT3155 tristate "DT3155 frame grabber" depends on PCI && VIDEO_DEV && VIDEO_V4L2 select VIDEOBUF2_DMA_CONTIG - default n help Enables dt3155 device driver for the DataTranslation DT3155 frame grabber. Say Y here if you have this hardware. diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c index d6d29e61aae9..b4cdda50e742 100644 --- a/drivers/media/pci/dt3155/dt3155.c +++ b/drivers/media/pci/dt3155/dt3155.c @@ -297,9 +297,6 @@ static int dt3155_querycap(struct file *filp, void *p, strscpy(cap->driver, DT3155_NAME, sizeof(cap->driver)); strscpy(cap->card, DT3155_NAME " frame grabber", sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -490,6 +487,8 @@ static const struct video_device dt3155_vdev = { .minor = -1, .release = video_device_release_empty, .tvnorms = V4L2_STD_ALL, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE, }; static int dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 2a52a393fe74..c1d133e17e4b 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1174,7 +1174,7 @@ static const struct v4l2_file_operations cio2_v4l2_fops = { static const struct v4l2_ioctl_ops cio2_v4l2_ioctl_ops = { .vidioc_querycap = cio2_v4l2_querycap, - .vidioc_enum_fmt_vid_cap_mplane = cio2_v4l2_enum_fmt, + .vidioc_enum_fmt_vid_cap = cio2_v4l2_enum_fmt, .vidioc_g_fmt_vid_cap_mplane = cio2_v4l2_g_fmt, .vidioc_s_fmt_vid_cap_mplane = cio2_v4l2_s_fmt, .vidioc_try_fmt_vid_cap_mplane = cio2_v4l2_try_fmt, diff --git a/drivers/media/pci/ivtv/Kconfig b/drivers/media/pci/ivtv/Kconfig index 079569955fb4..36c089103cf9 100644 --- a/drivers/media/pci/ivtv/Kconfig +++ b/drivers/media/pci/ivtv/Kconfig @@ -32,7 +32,6 @@ config VIDEO_IVTV config VIDEO_IVTV_DEPRECATED_IOCTLS bool "enable the DVB ioctls abuse on ivtv driver" depends on VIDEO_IVTV - default n help Enable the usage of the a DVB set of ioctls that were abused by IVTV driver for a while. @@ -77,7 +76,6 @@ config VIDEO_FB_IVTV config VIDEO_FB_IVTV_FORCE_PAT bool "force cx23415 framebuffer init with x86 PAT enabled" depends on VIDEO_FB_IVTV && X86_PAT - default n help With PAT enabled, the cx23415 framebuffer driver does not utilize write-combined caching on the framebuffer memory. diff --git a/drivers/media/pci/ivtv/ivtv-cards.h b/drivers/media/pci/ivtv/ivtv-cards.h index 965def0cbfaa..f3e2c5634962 100644 --- a/drivers/media/pci/ivtv/ivtv-cards.h +++ b/drivers/media/pci/ivtv/ivtv-cards.h @@ -156,8 +156,7 @@ #define IVTV_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | \ V4L2_CAP_SLICED_VBI_CAPTURE) -#define IVTV_CAP_DECODER (V4L2_CAP_VIDEO_OUTPUT | \ - V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_OVERLAY) +#define IVTV_CAP_DECODER (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_SLICED_VBI_OUTPUT) struct ivtv_card_video_input { u8 video_type; /* video input type */ diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index d1e358a2273e..5595f6a274e7 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -734,18 +734,11 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc { struct ivtv_open_id *id = fh2id(file->private_data); struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; strscpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); strscpy(vcap->card, itv->card_name, sizeof(vcap->card)); snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev)); vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS; - vcap->device_caps = s->caps; - if ((s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY) && - !itv->osd_video_pbase) { - vcap->capabilities &= ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY; - vcap->device_caps &= ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY; - } return 0; } diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c index a641f20e3f86..f7de9118f609 100644 --- a/drivers/media/pci/ivtv/ivtv-streams.c +++ b/drivers/media/pci/ivtv/ivtv-streams.c @@ -139,8 +139,7 @@ static struct { "decoder MPG", VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, PCI_DMA_TODEVICE, 0, - V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | - V4L2_CAP_VIDEO_OUTPUT_OVERLAY, + V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, &ivtv_v4l2_dec_fops }, { /* IVTV_DEC_STREAM_TYPE_VBI */ @@ -161,8 +160,7 @@ static struct { "decoder YUV", VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET, PCI_DMA_TODEVICE, 0, - V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | - V4L2_CAP_VIDEO_OUTPUT_OVERLAY, + V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, &ivtv_v4l2_dec_fops } }; @@ -301,6 +299,14 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) if (s_mpg->vdev.v4l2_dev) num = s_mpg->vdev.num + ivtv_stream_info[type].num_offset; } + s->vdev.device_caps = s->caps; + if (itv->osd_video_pbase) { + itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps |= + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps |= + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + itv->v4l2_cap |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + } video_set_drvdata(&s->vdev, s); /* Register device. First try the desired minor, then any free one. */ diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c index 66be490ec563..95a56cce9b65 100644 --- a/drivers/media/pci/ivtv/ivtvfb.c +++ b/drivers/media/pci/ivtv/ivtvfb.c @@ -1220,6 +1220,11 @@ static int ivtvfb_init_card(struct ivtv *itv) /* Allocate DMA */ ivtv_udma_alloc(itv); + itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps |= + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps |= + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + itv->v4l2_cap |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY; return 0; } @@ -1246,11 +1251,12 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p) struct osd_info *oi = itv->osd_info; if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { - if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) { - IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n", - itv->instance); - return 0; - } + itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps &= + ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps &= + ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + itv->v4l2_cap &= ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + unregister_framebuffer(&itv->osd_info->ivtvfb_info); IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance); itv->ivtvfb_restore = NULL; ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info); diff --git a/drivers/media/pci/meye/Kconfig b/drivers/media/pci/meye/Kconfig index b0ba78abbdbb..b37da612dd0c 100644 --- a/drivers/media/pci/meye/Kconfig +++ b/drivers/media/pci/meye/Kconfig @@ -2,7 +2,8 @@ config VIDEO_MEYE tristate "Sony Vaio Picturebook Motion Eye Video For Linux" depends on PCI && VIDEO_V4L2 - depends on SONY_LAPTOP || COMPILE_TEST + depends on SONY_LAPTOP + depends on X86 || COMPILE_TEST help This is the video4linux driver for the Motion Eye camera found in the Vaio Picturebook laptops. Please read the material in diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index bbe91b0f2565..8218810c899e 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1013,11 +1013,6 @@ static int vidioc_querycap(struct file *file, void *fh, strscpy(cap->driver, "meye", sizeof(cap->driver)); strscpy(cap->card, "meye", sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev)); - - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -1529,6 +1524,7 @@ static const struct video_device meye_template = { .fops = &meye_fops, .ioctl_ops = &meye_ioctl_ops, .release = video_device_release_empty, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING, }; static const struct v4l2_ctrl_ops meye_ctrl_ops = { diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 7a106bc11a2b..6185806a00e0 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ngene-cards.c: nGene PCIe bridge driver - card specific info * @@ -7,20 +8,6 @@ * Modifications for new nGene firmware, * support for EEPROM-copying, * support for new dual DVB-S2 card prototype - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 27953b3610a3..b75ab7d29226 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ngene.c: nGene PCIe bridge driver * @@ -7,20 +8,6 @@ * Modifications for new nGene firmware, * support for EEPROM-copying, * support for new dual DVB-S2 card prototype - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ #include <linux/module.h> diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index 5147e83397a1..fda24ba3dc3c 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ngene-dvb.c: nGene PCIe bridge driver - DVB functions * @@ -7,20 +8,6 @@ * Modifications for new nGene firmware, * support for EEPROM-copying, * support for new dual DVB-S2 card prototype - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ #include <linux/module.h> diff --git a/drivers/media/pci/ngene/ngene-i2c.c b/drivers/media/pci/ngene/ngene-i2c.c index 02a06f6c97f8..2e9e9774dc6f 100644 --- a/drivers/media/pci/ngene/ngene-i2c.c +++ b/drivers/media/pci/ngene/ngene-i2c.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ngene-i2c.c: nGene PCIe bridge driver i2c functions * @@ -7,20 +8,6 @@ * Modifications for new nGene firmware, * support for EEPROM-copying, * support for new dual DVB-S2 card prototype - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ /* FIXME - some of these can probably be removed */ diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 01d9f1b58fcb..84f04e0e0cb9 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ngene.h: nGene PCIe bridge driver * * Copyright (C) 2005-2007 Micronas - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ #ifndef _NGENE_H_ diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index fa9a0ead46d5..2d582c02adbf 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -1206,6 +1206,14 @@ static int saa7134_initdev(struct pci_dev *pci_dev, dev->video_dev->ctrl_handler = &dev->ctrl_handler; dev->video_dev->lock = &dev->lock; dev->video_dev->queue = &dev->video_vbq; + dev->video_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET) + dev->video_dev->device_caps |= V4L2_CAP_TUNER; + + if (saa7134_no_overlay <= 0) + dev->video_dev->device_caps |= V4L2_CAP_VIDEO_OVERLAY; + err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, video_nr[dev->nr]); if (err < 0) { @@ -1220,6 +1228,10 @@ static int saa7134_initdev(struct pci_dev *pci_dev, dev->vbi_dev->ctrl_handler = &dev->ctrl_handler; dev->vbi_dev->lock = &dev->lock; dev->vbi_dev->queue = &dev->vbi_vbq; + dev->vbi_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VBI_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET) + dev->vbi_dev->device_caps |= V4L2_CAP_TUNER; err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, vbi_nr[dev->nr]); @@ -1232,6 +1244,9 @@ static int saa7134_initdev(struct pci_dev *pci_dev, dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio"); dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler; dev->radio_dev->lock = &dev->lock; + dev->radio_dev->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; + if (dev->has_rds) + dev->radio_dev->device_caps |= V4L2_CAP_RDS_CAPTURE; err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, radio_nr[dev->nr]); if (err < 0) diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index 17eafaa5bf02..1a41a56afec6 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -287,6 +287,10 @@ static int empress_init(struct saa7134_dev *dev) if (err) return err; dev->empress_dev->queue = q; + dev->empress_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET) + dev->empress_dev->device_caps |= V4L2_CAP_TUNER; video_set_drvdata(dev->empress_dev, dev); err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER, diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 89c1271476c7..606df51bb636 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1489,50 +1489,20 @@ int saa7134_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct saa7134_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - u32 radio_caps, video_caps, vbi_caps; - - unsigned int tuner_type = dev->tuner_type; strscpy(cap->driver, "saa7134", sizeof(cap->driver)); strscpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - - cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if ((tuner_type != TUNER_ABSENT) && (tuner_type != UNSET)) - cap->device_caps |= V4L2_CAP_TUNER; - - radio_caps = V4L2_CAP_RADIO; + cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_RADIO | V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS; + if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET) + cap->capabilities |= V4L2_CAP_TUNER; if (dev->has_rds) - radio_caps |= V4L2_CAP_RDS_CAPTURE; - - video_caps = V4L2_CAP_VIDEO_CAPTURE; - if (saa7134_no_overlay <= 0 && !is_empress(file)) - video_caps |= V4L2_CAP_VIDEO_OVERLAY; - - vbi_caps = V4L2_CAP_VBI_CAPTURE; - - switch (vdev->vfl_type) { - case VFL_TYPE_RADIO: - cap->device_caps |= radio_caps; - break; - case VFL_TYPE_GRABBER: - cap->device_caps |= video_caps; - break; - case VFL_TYPE_VBI: - cap->device_caps |= vbi_caps; - break; - default: - return -EINVAL; - } - cap->capabilities = radio_caps | video_caps | vbi_caps | - cap->device_caps | V4L2_CAP_DEVICE_CAPS; - if (vdev->vfl_type == VFL_TYPE_RADIO) { - cap->device_caps &= ~V4L2_CAP_STREAMING; - if (!dev->has_rds) - cap->device_caps &= ~V4L2_CAP_READWRITE; - } + cap->capabilities |= V4L2_CAP_RDS_CAPTURE; + if (saa7134_no_overlay <= 0) + cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; return 0; } diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index c594aff92e70..9ae04e18e6c6 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -1112,16 +1112,25 @@ static int saa7164_proc_show(struct seq_file *m, void *v) return 0; } +static struct proc_dir_entry *saa7164_pe; + static int saa7164_proc_create(void) { - struct proc_dir_entry *pe; - - pe = proc_create_single("saa7164", S_IRUGO, NULL, saa7164_proc_show); - if (!pe) + saa7164_pe = proc_create_single("saa7164", 0444, NULL, saa7164_proc_show); + if (!saa7164_pe) return -ENOMEM; return 0; } + +static void saa7164_proc_destroy(void) +{ + if (saa7164_pe) + remove_proc_entry("saa7164", NULL); +} +#else +static int saa7164_proc_create(void) { return 0; } +static void saa7164_proc_destroy(void) {} #endif static int saa7164_thread_function(void *data) @@ -1493,19 +1502,21 @@ static struct pci_driver saa7164_pci_driver = { static int __init saa7164_init(void) { - printk(KERN_INFO "saa7164 driver loaded\n"); + int ret = pci_register_driver(&saa7164_pci_driver); + + if (ret) + return ret; -#ifdef CONFIG_PROC_FS saa7164_proc_create(); -#endif - return pci_register_driver(&saa7164_pci_driver); + + pr_info("saa7164 driver loaded\n"); + + return 0; } static void __exit saa7164_fini(void) { -#ifdef CONFIG_PROC_FS - remove_proc_entry("saa7164", NULL); -#endif + saa7164_proc_destroy(); pci_unregister_driver(&saa7164_pci_driver); } diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index dcfabad8b284..43fdaa2d32bd 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -491,16 +491,9 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, saa7164_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - - cap->device_caps = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_TUNER; - - cap->capabilities = cap->device_caps | - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_DEVICE_CAPS; - + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_DEVICE_CAPS; return 0; } @@ -973,6 +966,8 @@ static struct video_device saa7164_mpeg_template = { .ioctl_ops = &mpeg_ioctl_ops, .minor = -1, .tvnorms = SAA7164_NORMS, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_TUNER, }; static struct video_device *saa7164_encoder_alloc( diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index 154a04d17ce5..49d61a64c8cb 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -202,16 +202,9 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, saa7164_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - - cap->device_caps = - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_TUNER; - - cap->capabilities = cap->device_caps | - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_DEVICE_CAPS; - + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_DEVICE_CAPS; return 0; } @@ -675,6 +668,8 @@ static struct video_device saa7164_vbi_template = { .ioctl_ops = &vbi_ioctl_ops, .minor = -1, .tvnorms = SAA7164_NORMS, + .device_caps = V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_TUNER, }; static struct video_device *saa7164_vbi_alloc( diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 73698cc26dd5..609100a46ff8 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -771,9 +771,6 @@ static int solo_enc_querycap(struct file *file, void *priv, solo_enc->ch); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(solo_dev->pdev)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1191,6 +1188,8 @@ static const struct video_device solo_enc_template = { .minor = -1, .release = video_device_release, .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; static const struct v4l2_ctrl_ops solo_ctrl_ops = { diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c index 1ce431af8fc6..a968f75920b5 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c @@ -378,9 +378,6 @@ static int solo_querycap(struct file *file, void *priv, strscpy(cap->card, "Softlogic 6x10", sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(solo_dev->pdev)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -628,6 +625,8 @@ static const struct video_device solo_v4l2_template = { .minor = -1, .release = video_device_release, .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; static const struct v4l2_ctrl_ops solo_ctrl_ops = { diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 9de5b2a35519..e52e29814378 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -407,10 +407,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(vip->pdev)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -759,6 +755,8 @@ static const struct video_device video_dev_template = { .fops = &vip_fops, .ioctl_ops = &vip_ioctl_ops, .tvnorms = V4L2_STD_ALL, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; /** diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig index d96d4fa20457..8a362ee9105f 100644 --- a/drivers/media/pci/ttpci/Kconfig +++ b/drivers/media/pci/ttpci/Kconfig @@ -1,13 +1,14 @@ # SPDX-License-Identifier: GPL-2.0-only config DVB_AV7110_IR bool + depends on RC_CORE=y || RC_CORE = DVB_AV7110 + default DVB_AV7110 config DVB_AV7110 tristate "AV7110 cards" depends on DVB_CORE && PCI && I2C select TTPCI_EEPROM select VIDEO_SAA7146_VV - select DVB_AV7110_IR if INPUT_EVDEV=y || INPUT_EVDEV=DVB_AV7110 depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index e6ee23544a6e..d0cdee1c6eb0 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -218,7 +218,7 @@ static void recover_arm(struct av7110 *av7110) restart_feeds(av7110); #if IS_ENABLED(CONFIG_DVB_AV7110_IR) - av7110_check_ir_config(av7110, true); + av7110_set_ir_config(av7110); #endif } @@ -250,10 +250,6 @@ static int arm_thread(void *data) if (!av7110->arm_ready) continue; -#if IS_ENABLED(CONFIG_DVB_AV7110_IR) - av7110_check_ir_config(av7110, false); -#endif - if (mutex_lock_interruptible(&av7110->dcomlock)) break; newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); @@ -659,9 +655,11 @@ static void gpioirq(unsigned long cookie) return; case DATA_IRCOMMAND: - if (av7110->ir.ir_handler) - av7110->ir.ir_handler(av7110, - swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) + av7110_ir_handler(av7110, + swahw32(irdebi(av7110, DEBINOSWAP, Reserved, + 0, 4))); +#endif iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); break; diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h index 8606ef5ebbe2..809d938ae166 100644 --- a/drivers/media/pci/ttpci/av7110.h +++ b/drivers/media/pci/ttpci/av7110.h @@ -81,23 +81,11 @@ struct av7110; /* infrared remote control */ struct infrared { - u16 key_map[256]; - struct input_dev *input_dev; + struct rc_dev *rcdev; char input_phys[32]; - struct timer_list keyup_timer; - struct tasklet_struct ir_tasklet; - void (*ir_handler)(struct av7110 *av7110, u32 ircom); - u32 ir_command; u32 ir_config; - u32 device_mask; - u8 protocol; - u8 inversion; - u16 last_key; - u16 last_toggle; - bool keypressed; }; - /* place to store all the necessary device information */ struct av7110 { @@ -304,9 +292,10 @@ struct av7110 { extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, u16 subpid, u16 pcrpid); -extern int av7110_check_ir_config(struct av7110 *av7110, int force); -extern int av7110_ir_init(struct av7110 *av7110); -extern void av7110_ir_exit(struct av7110 *av7110); +void av7110_ir_handler(struct av7110 *av7110, u32 ircom); +int av7110_set_ir_config(struct av7110 *av7110); +int av7110_ir_init(struct av7110 *av7110); +void av7110_ir_exit(struct av7110 *av7110); /* msp3400 i2c subaddresses */ #define MSP_WR_DEM 0x10 diff --git a/drivers/media/pci/ttpci/av7110_ir.c b/drivers/media/pci/ttpci/av7110_ir.c index dfa18878e5f0..432789a3c312 100644 --- a/drivers/media/pci/ttpci/av7110_ir.c +++ b/drivers/media/pci/ttpci/av7110_ir.c @@ -4,379 +4,156 @@ * * Copyright (C) 1999-2003 Holger Waechtler <holger@convergence.de> * Copyright (C) 2003-2007 Oliver Endriss <o.endriss@gmx.de> + * Copyright (C) 2019 Sean Young <sean@mess.org> */ - -#include <linux/types.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/proc_fs.h> #include <linux/kernel.h> -#include <linux/bitops.h> +#include <media/rc-core.h> #include "av7110.h" #include "av7110_hw.h" - -#define AV_CNT 4 - #define IR_RC5 0 #define IR_RCMM 1 #define IR_RC5_EXT 2 /* internal only */ -#define IR_ALL 0xffffffff - -#define UP_TIMEOUT (HZ*7/25) - - -/* Note: enable ir debugging by or'ing debug with 16 */ - -static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM}; -module_param_array(ir_protocol, int, NULL, 0644); -MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)"); - -static int ir_inversion[AV_CNT]; -module_param_array(ir_inversion, int, NULL, 0644); -MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted"); - -static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL }; -module_param_array(ir_device_mask, uint, NULL, 0644); -MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)"); - - -static int av_cnt; -static struct av7110 *av_list[AV_CNT]; - -static u16 default_key_map [256] = { - KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, - KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, - KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - KEY_CHANNELUP, KEY_CHANNELDOWN, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, KEY_TEXT, 0, 0, KEY_TV, 0, 0, 0, 0, 0, KEY_SETUP, 0, 0, - 0, 0, 0, KEY_SUBTITLE, 0, 0, KEY_LANGUAGE, 0, - KEY_RADIO, 0, 0, 0, 0, KEY_EXIT, 0, 0, - KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_OK, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RED, KEY_GREEN, KEY_YELLOW, - KEY_BLUE, 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_LIST, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, KEY_UP, KEY_UP, KEY_DOWN, KEY_DOWN, - 0, 0, 0, 0, KEY_EPG, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_VCR -}; - - -/* key-up timer */ -static void av7110_emit_keyup(struct timer_list *t) -{ - struct infrared *ir = from_timer(ir, t, keyup_timer); - - if (!ir || !ir->keypressed) - return; - - input_report_key(ir->input_dev, ir->last_key, 0); - input_sync(ir->input_dev); - ir->keypressed = false; -} - - -/* tasklet */ -static void av7110_emit_key(unsigned long parm) +/* interrupt handler */ +void av7110_ir_handler(struct av7110 *av7110, u32 ircom) { - struct infrared *ir = (struct infrared *) parm; - u32 ircom = ir->ir_command; - u8 data; - u8 addr; - u16 toggle; - u16 keycode; - - /* extract device address and data */ - switch (ir->protocol) { - case IR_RC5: /* RC5: 5 bits device address, 6 bits data */ - data = ircom & 0x3f; - addr = (ircom >> 6) & 0x1f; - toggle = ircom & 0x0800; - break; + struct rc_dev *rcdev = av7110->ir.rcdev; + enum rc_proto proto; + u32 command, addr, scancode; + u32 toggle; - case IR_RCMM: /* RCMM: ? bits device address, ? bits data */ - data = ircom & 0xff; - addr = (ircom >> 8) & 0x1f; - toggle = ircom & 0x8000; - break; - - case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */ - data = ircom & 0x3f; - addr = (ircom >> 6) & 0x1f; - /* invert 7th data bit for backward compatibility with RC5 keymaps */ - if (!(ircom & 0x1000)) - data |= 0x40; - toggle = ircom & 0x0800; - break; - - default: - printk("%s invalid protocol %x\n", __func__, ir->protocol); - return; - } - - input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data); - input_event(ir->input_dev, EV_MSC, MSC_SCAN, data); - - keycode = ir->key_map[data]; - - dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n", - __func__, ircom, addr, data, keycode); - - /* check device address */ - if (!(ir->device_mask & (1 << addr))) - return; - - if (!keycode) { - printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n", - __func__, ircom, addr, data); - return; - } - - if (ir->keypressed && - (ir->last_key != keycode || toggle != ir->last_toggle)) - input_event(ir->input_dev, EV_KEY, ir->last_key, 0); - - input_event(ir->input_dev, EV_KEY, keycode, 1); - input_sync(ir->input_dev); - - ir->keypressed = true; - ir->last_key = keycode; - ir->last_toggle = toggle; - - mod_timer(&ir->keyup_timer, jiffies + UP_TIMEOUT); -} - - -/* register with input layer */ -static void input_register_keys(struct infrared *ir) -{ - int i; + dprintk(4, "ir command = %08x\n", ircom); - set_bit(EV_KEY, ir->input_dev->evbit); - set_bit(EV_REP, ir->input_dev->evbit); - set_bit(EV_MSC, ir->input_dev->evbit); + if (rcdev) { + switch (av7110->ir.ir_config) { + case IR_RC5: /* RC5: 5 bits device address, 6 bits command */ + command = ircom & 0x3f; + addr = (ircom >> 6) & 0x1f; + scancode = RC_SCANCODE_RC5(addr, command); + toggle = ircom & 0x0800; + proto = RC_PROTO_RC5; + break; - set_bit(MSC_RAW, ir->input_dev->mscbit); - set_bit(MSC_SCAN, ir->input_dev->mscbit); + case IR_RCMM: /* RCMM: ? bits device address, ? bits command */ + command = ircom & 0xff; + addr = (ircom >> 8) & 0x1f; + scancode = ircom; + toggle = ircom & 0x8000; + proto = RC_PROTO_UNKNOWN; + break; - memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit)); + case IR_RC5_EXT: + /* + * extended RC5: 5 bits device address, 7 bits command + * + * Extended RC5 uses only one start bit. The second + * start bit is re-assigned bit 6 of the command bit. + */ + command = ircom & 0x3f; + addr = (ircom >> 6) & 0x1f; + if (!(ircom & 0x1000)) + command |= 0x40; + scancode = RC_SCANCODE_RC5(addr, command); + toggle = ircom & 0x0800; + proto = RC_PROTO_RC5; + break; + default: + dprintk(2, "unknown ir config %d\n", + av7110->ir.ir_config); + return; + } - for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) { - if (ir->key_map[i] > KEY_MAX) - ir->key_map[i] = 0; - else if (ir->key_map[i] > KEY_RESERVED) - set_bit(ir->key_map[i], ir->input_dev->keybit); + rc_keydown(rcdev, proto, scancode, toggle != 0); } - - ir->input_dev->keycode = ir->key_map; - ir->input_dev->keycodesize = sizeof(ir->key_map[0]); - ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map); } -/* check for configuration changes */ -int av7110_check_ir_config(struct av7110 *av7110, int force) +int av7110_set_ir_config(struct av7110 *av7110) { - int i; - int modified = force; - int ret = -ENODEV; - - for (i = 0; i < av_cnt; i++) - if (av7110 == av_list[i]) - break; - - if (i < av_cnt && av7110) { - if ((av7110->ir.protocol & 1) != ir_protocol[i] || - av7110->ir.inversion != ir_inversion[i]) - modified = true; - - if (modified) { - /* protocol */ - if (ir_protocol[i]) { - ir_protocol[i] = 1; - av7110->ir.protocol = IR_RCMM; - av7110->ir.ir_config = 0x0001; - } else if (FW_VERSION(av7110->arm_app) >= 0x2620) { - av7110->ir.protocol = IR_RC5_EXT; - av7110->ir.ir_config = 0x0002; - } else { - av7110->ir.protocol = IR_RC5; - av7110->ir.ir_config = 0x0000; - } - /* inversion */ - if (ir_inversion[i]) { - ir_inversion[i] = 1; - av7110->ir.ir_config |= 0x8000; - } - av7110->ir.inversion = ir_inversion[i]; - /* update ARM */ - ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, - av7110->ir.ir_config); - } else - ret = 0; + dprintk(4, "ir config = %08x\n", av7110->ir.ir_config); - /* address */ - if (av7110->ir.device_mask != ir_device_mask[i]) - av7110->ir.device_mask = ir_device_mask[i]; - } - - return ret; + return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, + av7110->ir.ir_config); } - -/* /proc/av7110_ir interface */ -static ssize_t av7110_ir_proc_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) +static int change_protocol(struct rc_dev *rcdev, u64 *rc_type) { - char *page; + struct av7110 *av7110 = rcdev->priv; u32 ir_config; - int size = sizeof ir_config + sizeof av_list[0]->ir.key_map; - int i; - if (count < size) + if (*rc_type & RC_PROTO_BIT_UNKNOWN) { + ir_config = IR_RCMM; + *rc_type = RC_PROTO_UNKNOWN; + } else if (*rc_type & RC_PROTO_BIT_RC5) { + if (FW_VERSION(av7110->arm_app) >= 0x2620) + ir_config = IR_RC5_EXT; + else + ir_config = IR_RC5; + *rc_type = RC_PROTO_BIT_RC5; + } else { return -EINVAL; - - page = vmalloc(size); - if (!page) - return -ENOMEM; - - if (copy_from_user(page, buffer, size)) { - vfree(page); - return -EFAULT; } - memcpy(&ir_config, page, sizeof ir_config); - - for (i = 0; i < av_cnt; i++) { - /* keymap */ - memcpy(av_list[i]->ir.key_map, page + sizeof ir_config, - sizeof(av_list[i]->ir.key_map)); - /* protocol, inversion, address */ - ir_protocol[i] = ir_config & 0x0001; - ir_inversion[i] = ir_config & 0x8000 ? 1 : 0; - if (ir_config & 0x4000) - ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f); - else - ir_device_mask[i] = IR_ALL; - /* update configuration */ - av7110_check_ir_config(av_list[i], false); - input_register_keys(&av_list[i]->ir); - } - vfree(page); - return count; -} + if (ir_config == av7110->ir.ir_config) + return 0; -static const struct file_operations av7110_ir_proc_fops = { - .owner = THIS_MODULE, - .write = av7110_ir_proc_write, - .llseek = noop_llseek, -}; + av7110->ir.ir_config = ir_config; -/* interrupt handler */ -static void ir_handler(struct av7110 *av7110, u32 ircom) -{ - dprintk(4, "ir command = %08x\n", ircom); - av7110->ir.ir_command = ircom; - tasklet_schedule(&av7110->ir.ir_tasklet); + return av7110_set_ir_config(av7110); } - int av7110_ir_init(struct av7110 *av7110) { - struct input_dev *input_dev; - static struct proc_dir_entry *e; - int err; - - if (av_cnt >= ARRAY_SIZE(av_list)) - return -ENOSPC; + struct rc_dev *rcdev; + struct pci_dev *pci; + int ret; - av_list[av_cnt++] = av7110; - av7110_check_ir_config(av7110, true); - - timer_setup(&av7110->ir.keyup_timer, av7110_emit_keyup, 0); - - input_dev = input_allocate_device(); - if (!input_dev) + rcdev = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!rcdev) return -ENOMEM; - av7110->ir.input_dev = input_dev; - snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys), - "pci-%s/ir0", pci_name(av7110->dev->pci)); + pci = av7110->dev->pci; - input_dev->name = "DVB on-card IR receiver"; - - input_dev->phys = av7110->ir.input_phys; - input_dev->id.bustype = BUS_PCI; - input_dev->id.version = 2; - if (av7110->dev->pci->subsystem_vendor) { - input_dev->id.vendor = av7110->dev->pci->subsystem_vendor; - input_dev->id.product = av7110->dev->pci->subsystem_device; + snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys), + "pci-%s/ir0", pci_name(pci)); + + rcdev->device_name = av7110->card_name; + rcdev->driver_name = KBUILD_MODNAME; + rcdev->input_phys = av7110->ir.input_phys; + rcdev->input_id.bustype = BUS_PCI; + rcdev->input_id.version = 2; + if (pci->subsystem_vendor) { + rcdev->input_id.vendor = pci->subsystem_vendor; + rcdev->input_id.product = pci->subsystem_device; } else { - input_dev->id.vendor = av7110->dev->pci->vendor; - input_dev->id.product = av7110->dev->pci->device; - } - input_dev->dev.parent = &av7110->dev->pci->dev; - /* initial keymap */ - memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map); - input_register_keys(&av7110->ir); - err = input_register_device(input_dev); - if (err) { - input_free_device(input_dev); - return err; + rcdev->input_id.vendor = pci->vendor; + rcdev->input_id.product = pci->device; } - /* - * Input core's default autorepeat is 33 cps with 250 msec - * delay, let's adjust to numbers more suitable for remote - * control. - */ - input_enable_softrepeat(input_dev, 250, 125); + rcdev->dev.parent = &pci->dev; + rcdev->allowed_protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_UNKNOWN; + rcdev->change_protocol = change_protocol; + rcdev->map_name = RC_MAP_HAUPPAUGE; + rcdev->priv = av7110; - if (av_cnt == 1) { - e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops); - if (e) - proc_set_size(e, 4 + 256 * sizeof(u16)); - } + av7110->ir.rcdev = rcdev; + av7110->ir.ir_config = IR_RC5; + av7110_set_ir_config(av7110); - tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir); - av7110->ir.ir_handler = ir_handler; + ret = rc_register_device(rcdev); + if (ret) { + av7110->ir.rcdev = NULL; + rc_free_device(rcdev); + } - return 0; + return ret; } - void av7110_ir_exit(struct av7110 *av7110) { - int i; - - if (av_cnt == 0) - return; - - del_timer_sync(&av7110->ir.keyup_timer); - av7110->ir.ir_handler = NULL; - tasklet_kill(&av7110->ir.ir_tasklet); - - for (i = 0; i < av_cnt; i++) - if (av_list[i] == av7110) { - av_list[i] = av_list[av_cnt-1]; - av_list[av_cnt-1] = NULL; - break; - } - - if (av_cnt == 1) - remove_proc_entry("av7110_ir", NULL); - - input_unregister_device(av7110->ir.input_dev); - - av_cnt--; + rc_unregister_device(av7110->ir.rcdev); } //MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>, Oliver Endriss <o.endriss@gmx.de>"); diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 5b469cf578f5..8e0952d65ad4 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -729,12 +729,6 @@ static int tw68_querycap(struct file *file, void *priv, strscpy(cap->card, "Techwell Capture Card", sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->device_caps = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -913,6 +907,8 @@ static const struct video_device tw68_video_template = { .ioctl_ops = &video_ioctl_ops, .release = video_device_release_empty, .tvnorms = TW68_NORMS, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; /* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c index 377fb1e453fa..9be8c6e4fb69 100644 --- a/drivers/media/pci/tw686x/tw686x-video.c +++ b/drivers/media/pci/tw686x/tw686x-video.c @@ -765,9 +765,6 @@ static int tw686x_querycap(struct file *file, void *priv, strscpy(cap->card, dev->name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(dev->pci_dev)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1280,6 +1277,8 @@ int tw686x_video_init(struct tw686x_dev *dev) vdev->minor = -1; vdev->lock = &vc->vb_mutex; vdev->ctrl_handler = &vc->ctrl_handler; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; vc->device = vdev; video_set_drvdata(vdev, vc); diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index f2b5f27ebacb..8a19654b393a 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -6,7 +6,6 @@ menuconfig V4L_PLATFORM_DRIVERS bool "V4L platform devices" depends on MEDIA_CAMERA_SUPPORT - default n help Say Y here to enable support for platform-specific V4L drivers. @@ -155,7 +154,6 @@ config VIDEO_TI_CAL depends on SOC_DRA7XX || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE - default n help Support for the TI CAL (Camera Adaptation Layer) block found on DRA72X SoC. @@ -168,7 +166,6 @@ menuconfig V4L_MEM2MEM_DRIVERS bool "Memory-to-memory multimedia devices" depends on VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - default n help Say Y here to enable selecting drivers for V4L devices that use system memory for both source and destination buffers, as opposed @@ -236,7 +233,6 @@ config VIDEO_MEDIATEK_MDP select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV select VIDEO_MEDIATEK_VPU - default n help It is a v4l2 driver and present in Mediatek MT8173 SoCs. The driver supports for scaling and color space conversion. @@ -252,7 +248,6 @@ config VIDEO_MEDIATEK_VCODEC select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV select VIDEO_MEDIATEK_VPU - default n help Mediatek video codec driver provides HW capability to encode and decode in a range of video formats @@ -276,7 +271,6 @@ config VIDEO_SAMSUNG_S5P_G2D depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV - default n help This is a v4l2 driver for Samsung S5P and EXYNOS4 G2D 2d graphics accelerator. @@ -296,7 +290,6 @@ config VIDEO_SAMSUNG_S5P_MFC depends on VIDEO_DEV && VIDEO_V4L2 depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG - default n help MFC 5.1 and 6.x driver for V4L2 @@ -459,7 +452,6 @@ config VIDEO_ROCKCHIP_RGA depends on ARCH_ROCKCHIP || COMPILE_TEST select VIDEOBUF2_DMA_SG select V4L2_MEM2MEM_DEV - default n help This is a v4l2 driver for Rockchip SOC RGA 2d graphics accelerator. Rockchip RGA is a separate 2D raster graphic acceleration unit. @@ -477,7 +469,6 @@ config VIDEO_TI_VPE select VIDEO_TI_VPDMA select VIDEO_TI_SC select VIDEO_TI_CSC - default n help Support for the TI VPE(Video Processing Engine) block found on DRA7XX SoC. @@ -530,7 +521,6 @@ config VIDEO_VIM2M depends on VIDEO_DEV && VIDEO_V4L2 select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV - default n help This is a virtual test device for the memory-to-memory driver framework. @@ -542,7 +532,6 @@ endif #V4L_TEST_DRIVERS menuconfig DVB_PLATFORM_DRIVERS bool "DVB platform devices" depends on MEDIA_DIGITAL_TV_SUPPORT - default n help Say Y here to enable support for platform-specific Digital TV drivers. @@ -678,7 +667,6 @@ endif #CEC_PLATFORM_DRIVERS menuconfig SDR_PLATFORM_DRIVERS bool "SDR platform devices" depends on MEDIA_SDR_SUPPORT - default n help Say Y here to enable support for platform-specific SDR Drivers. diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index 8144fe36ad48..f899ac3b4a61 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -187,6 +187,7 @@ enum { VIDEO_STREAMING, VIDEO_FRAME_INPRG, VIDEO_STOPPED, + VIDEO_CLOCKS_ON, }; struct aspeed_video_addr { @@ -440,7 +441,7 @@ static int aspeed_video_start_frame(struct aspeed_video *video) if (!(seq_ctrl & VE_SEQ_CTRL_COMP_BUSY) || !(seq_ctrl & VE_SEQ_CTRL_CAP_BUSY)) { - dev_err(video->dev, "Engine busy; don't start frame\n"); + dev_dbg(video->dev, "Engine busy; don't start frame\n"); return -EBUSY; } @@ -462,8 +463,7 @@ static int aspeed_video_start_frame(struct aspeed_video *video) aspeed_video_write(video, VE_COMP_ADDR, addr); aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, - VE_INTERRUPT_COMP_COMPLETE | - VE_INTERRUPT_CAPTURE_COMPLETE); + VE_INTERRUPT_COMP_COMPLETE); aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP); @@ -483,19 +483,30 @@ static void aspeed_video_enable_mode_detect(struct aspeed_video *video) static void aspeed_video_off(struct aspeed_video *video) { + if (!test_bit(VIDEO_CLOCKS_ON, &video->flags)) + return; + /* Disable interrupts */ aspeed_video_write(video, VE_INTERRUPT_CTRL, 0); + aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff); /* Turn off the relevant clocks */ - clk_disable_unprepare(video->vclk); - clk_disable_unprepare(video->eclk); + clk_disable(video->vclk); + clk_disable(video->eclk); + + clear_bit(VIDEO_CLOCKS_ON, &video->flags); } static void aspeed_video_on(struct aspeed_video *video) { + if (test_bit(VIDEO_CLOCKS_ON, &video->flags)) + return; + /* Turn on the relevant clocks */ - clk_prepare_enable(video->eclk); - clk_prepare_enable(video->vclk); + clk_enable(video->eclk); + clk_enable(video->vclk); + + set_bit(VIDEO_CLOCKS_ON, &video->flags); } static void aspeed_video_bufs_done(struct aspeed_video *video, @@ -511,7 +522,7 @@ static void aspeed_video_bufs_done(struct aspeed_video *video, spin_unlock_irqrestore(&video->lock, flags); } -static void aspeed_video_irq_res_change(struct aspeed_video *video) +static void aspeed_video_irq_res_change(struct aspeed_video *video, ulong delay) { dev_dbg(video->dev, "Resolution changed; resetting\n"); @@ -521,7 +532,7 @@ static void aspeed_video_irq_res_change(struct aspeed_video *video) aspeed_video_off(video); aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR); - schedule_delayed_work(&video->res_work, RESOLUTION_CHANGE_DELAY); + schedule_delayed_work(&video->res_work, delay); } static irqreturn_t aspeed_video_irq(int irq, void *arg) @@ -534,7 +545,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) * re-initialize */ if (sts & VE_INTERRUPT_MODE_DETECT_WD) { - aspeed_video_irq_res_change(video); + aspeed_video_irq_res_change(video, 0); return IRQ_HANDLED; } @@ -544,7 +555,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) VE_INTERRUPT_MODE_DETECT, 0); aspeed_video_write(video, VE_INTERRUPT_STATUS, VE_INTERRUPT_MODE_DETECT); - + sts &= ~VE_INTERRUPT_MODE_DETECT; set_bit(VIDEO_MODE_DETECT_DONE, &video->flags); wake_up_interruptible_all(&video->wait); } else { @@ -552,13 +563,13 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) * Signal acquired while NOT doing resolution * detection; reset the engine and re-initialize */ - aspeed_video_irq_res_change(video); + aspeed_video_irq_res_change(video, + RESOLUTION_CHANGE_DELAY); return IRQ_HANDLED; } } - if ((sts & VE_INTERRUPT_COMP_COMPLETE) && - (sts & VE_INTERRUPT_CAPTURE_COMPLETE)) { + if (sts & VE_INTERRUPT_COMP_COMPLETE) { struct aspeed_video_buffer *buf; u32 frame_size = aspeed_video_read(video, VE_OFFSET_COMP_STREAM); @@ -587,17 +598,15 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) VE_SEQ_CTRL_FORCE_IDLE | VE_SEQ_CTRL_TRIG_COMP, 0); aspeed_video_update(video, VE_INTERRUPT_CTRL, - VE_INTERRUPT_COMP_COMPLETE | - VE_INTERRUPT_CAPTURE_COMPLETE, 0); + VE_INTERRUPT_COMP_COMPLETE, 0); aspeed_video_write(video, VE_INTERRUPT_STATUS, - VE_INTERRUPT_COMP_COMPLETE | - VE_INTERRUPT_CAPTURE_COMPLETE); - + VE_INTERRUPT_COMP_COMPLETE); + sts &= ~VE_INTERRUPT_COMP_COMPLETE; if (test_bit(VIDEO_STREAMING, &video->flags) && buf) aspeed_video_start_frame(video); } - return IRQ_HANDLED; + return sts ? IRQ_NONE : IRQ_HANDLED; } static void aspeed_video_check_and_set_polarity(struct aspeed_video *video) @@ -723,27 +732,6 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) det->height = MIN_HEIGHT; video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; - /* - * Since we need max buffer size for detection, free the second source - * buffer first. - */ - if (video->srcs[1].size) - aspeed_video_free_buf(video, &video->srcs[1]); - - if (video->srcs[0].size < VE_MAX_SRC_BUFFER_SIZE) { - if (video->srcs[0].size) - aspeed_video_free_buf(video, &video->srcs[0]); - - if (!aspeed_video_alloc_buf(video, &video->srcs[0], - VE_MAX_SRC_BUFFER_SIZE)) { - dev_err(video->dev, - "Failed to allocate source buffers\n"); - return; - } - } - - aspeed_video_write(video, VE_SRC0_ADDR, video->srcs[0].dma); - do { if (tries) { set_current_state(TASK_INTERRUPTIBLE); @@ -758,7 +746,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) res_check(video), MODE_DETECT_TIMEOUT); if (!rc) { - dev_err(video->dev, "Timed out; first mode detect\n"); + dev_dbg(video->dev, "Timed out; first mode detect\n"); clear_bit(VIDEO_RES_DETECT, &video->flags); return; } @@ -776,7 +764,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) MODE_DETECT_TIMEOUT); clear_bit(VIDEO_RES_DETECT, &video->flags); if (!rc) { - dev_err(video->dev, "Timed out; second mode detect\n"); + dev_dbg(video->dev, "Timed out; second mode detect\n"); return; } @@ -810,7 +798,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) } while (invalid_resolution && (tries++ < INVALID_RESOLUTION_RETRIES)); if (invalid_resolution) { - dev_err(video->dev, "Invalid resolution detected\n"); + dev_dbg(video->dev, "Invalid resolution detected\n"); return; } @@ -836,8 +824,29 @@ static void aspeed_video_set_resolution(struct aspeed_video *video) struct v4l2_bt_timings *act = &video->active_timings; unsigned int size = act->width * act->height; + /* Set capture/compression frame sizes */ aspeed_video_calc_compressed_size(video, size); + if (video->active_timings.width == 1680) { + /* + * This is a workaround to fix a silicon bug on A1 and A2 + * revisions. Since it doesn't break capturing operation of + * other revisions, use it for all revisions without checking + * the revision ID. It picked 1728 which is a very next + * 64-pixels aligned value to 1680 to minimize memory bandwidth + * and to get better access speed from video engine. + */ + aspeed_video_write(video, VE_CAP_WINDOW, + 1728 << 16 | act->height); + size += (1728 - 1680) * video->active_timings.height; + } else { + aspeed_video_write(video, VE_CAP_WINDOW, + act->width << 16 | act->height); + } + aspeed_video_write(video, VE_COMP_WINDOW, + act->width << 16 | act->height); + aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4); + /* Don't use direct mode below 1024 x 768 (irqs don't fire) */ if (size < DIRECT_FETCH_THRESHOLD) { aspeed_video_write(video, VE_TGS_0, @@ -854,29 +863,16 @@ static void aspeed_video_set_resolution(struct aspeed_video *video) aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_DIRECT_FETCH); } - /* Set capture/compression frame sizes */ - aspeed_video_write(video, VE_CAP_WINDOW, - act->width << 16 | act->height); - aspeed_video_write(video, VE_COMP_WINDOW, - act->width << 16 | act->height); - aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4); - size *= 4; - if (size == video->srcs[0].size / 2) { - aspeed_video_write(video, VE_SRC1_ADDR, - video->srcs[0].dma + size); - } else if (size == video->srcs[0].size) { - if (!aspeed_video_alloc_buf(video, &video->srcs[1], size)) - goto err_mem; - - aspeed_video_write(video, VE_SRC1_ADDR, video->srcs[1].dma); - } else { - aspeed_video_free_buf(video, &video->srcs[0]); + if (size != video->srcs[0].size) { + if (video->srcs[0].size) + aspeed_video_free_buf(video, &video->srcs[0]); + if (video->srcs[1].size) + aspeed_video_free_buf(video, &video->srcs[1]); if (!aspeed_video_alloc_buf(video, &video->srcs[0], size)) goto err_mem; - if (!aspeed_video_alloc_buf(video, &video->srcs[1], size)) goto err_mem; @@ -1445,7 +1441,7 @@ static void aspeed_video_stop_streaming(struct vb2_queue *q) !test_bit(VIDEO_FRAME_INPRG, &video->flags), STOP_TIMEOUT); if (!rc) { - dev_err(video->dev, "Timed out when stopping streaming\n"); + dev_dbg(video->dev, "Timed out when stopping streaming\n"); /* * Need to force stop any DMA and try and get HW into a good @@ -1589,8 +1585,8 @@ static int aspeed_video_init(struct aspeed_video *video) return -ENODEV; } - rc = devm_request_irq(dev, irq, aspeed_video_irq, IRQF_SHARED, - DEVICE_NAME, video); + rc = devm_request_threaded_irq(dev, irq, NULL, aspeed_video_irq, + IRQF_ONESHOT, DEVICE_NAME, video); if (rc < 0) { dev_err(dev, "Unable to request IRQ %d\n", irq); return rc; @@ -1602,31 +1598,46 @@ static int aspeed_video_init(struct aspeed_video *video) return PTR_ERR(video->eclk); } + rc = clk_prepare(video->eclk); + if (rc) + return rc; + video->vclk = devm_clk_get(dev, "vclk"); if (IS_ERR(video->vclk)) { dev_err(dev, "Unable to get VCLK\n"); - return PTR_ERR(video->vclk); + rc = PTR_ERR(video->vclk); + goto err_unprepare_eclk; } + rc = clk_prepare(video->vclk); + if (rc) + goto err_unprepare_eclk; + of_reserved_mem_device_init(dev); rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); if (rc) { dev_err(dev, "Failed to set DMA mask\n"); - of_reserved_mem_device_release(dev); - return rc; + goto err_release_reserved_mem; } if (!aspeed_video_alloc_buf(video, &video->jpeg, VE_JPEG_HEADER_SIZE)) { dev_err(dev, "Failed to allocate DMA for JPEG header\n"); - of_reserved_mem_device_release(dev); - return rc; + goto err_release_reserved_mem; } aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420); return 0; + +err_release_reserved_mem: + of_reserved_mem_device_release(dev); + clk_unprepare(video->vclk); +err_unprepare_eclk: + clk_unprepare(video->eclk); + + return rc; } static int aspeed_video_probe(struct platform_device *pdev) @@ -1670,6 +1681,11 @@ static int aspeed_video_remove(struct platform_device *pdev) struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); struct aspeed_video *video = to_aspeed_video(v4l2_dev); + aspeed_video_off(video); + + clk_unprepare(video->vclk); + clk_unprepare(video->eclk); + video_unregister_device(&video->vdev); vb2_queue_release(&video->queue); diff --git a/drivers/media/platform/atmel/Makefile b/drivers/media/platform/atmel/Makefile index 484936604ccb..2dba38994a70 100644 --- a/drivers/media/platform/atmel/Makefile +++ b/drivers/media/platform/atmel/Makefile @@ -1,3 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o +atmel-isc-objs = atmel-sama5d2-isc.o atmel-isc-base.o + obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o +obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc-base.c index 05b9cfb91d20..c1c776b348a9 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc-base.c @@ -1,24 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Atmel Image Sensor Controller (ISC) driver + * Microchip Image Sensor Controller (ISC) common driver base * - * Copyright (C) 2016 Atmel + * Copyright (C) 2016-2019 Microchip Technology, Inc. * - * Author: Songjun Wu <songjun.wu@microchip.com> + * Author: Songjun Wu + * Author: Eugen Hristev <eugen.hristev@microchip.com> * - * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA - * - * ISC video pipeline integrates the following submodules: - * PFE: Parallel Front End to sample the camera sensor input stream - * WB: Programmable white balance in the Bayer domain - * CFA: Color filter array interpolation module - * CC: Programmable color correction - * GAM: Gamma correction - * CSC: Programmable color space conversion - * CBC: Contrast and Brightness control - * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling - * RLP: This module performs rounding, range limiting - * and packing of the incoming data */ #include <linux/clk.h> @@ -45,176 +33,19 @@ #include <media/videobuf2-dma-contig.h> #include "atmel-isc-regs.h" +#include "atmel-isc.h" -#define ATMEL_ISC_NAME "atmel_isc" - -#define ISC_MAX_SUPPORT_WIDTH 2592 -#define ISC_MAX_SUPPORT_HEIGHT 1944 - -#define ISC_CLK_MAX_DIV 255 - -enum isc_clk_id { - ISC_ISPCK = 0, - ISC_MCK = 1, -}; - -struct isc_clk { - struct clk_hw hw; - struct clk *clk; - struct regmap *regmap; - spinlock_t lock; - u8 id; - u8 parent_id; - u32 div; - struct device *dev; -}; - -#define to_isc_clk(hw) container_of(hw, struct isc_clk, hw) - -struct isc_buffer { - struct vb2_v4l2_buffer vb; - struct list_head list; -}; - -struct isc_subdev_entity { - struct v4l2_subdev *sd; - struct v4l2_async_subdev *asd; - struct v4l2_async_notifier notifier; - - u32 pfe_cfg0; - - struct list_head list; -}; - -/* - * struct isc_format - ISC media bus format information - This structure represents the interface between the ISC - and the sensor. It's the input format received by - the ISC. - * @fourcc: Fourcc code for this format - * @mbus_code: V4L2 media bus format code. - * @cfa_baycfg: If this format is RAW BAYER, indicate the type of bayer. - this is either BGBG, RGRG, etc. - * @pfe_cfg0_bps: Number of hardware data lines connected to the ISC - */ - -struct isc_format { - u32 fourcc; - u32 mbus_code; - u32 cfa_baycfg; - - bool sd_support; - u32 pfe_cfg0_bps; -}; - -/* Pipeline bitmap */ -#define WB_ENABLE BIT(0) -#define CFA_ENABLE BIT(1) -#define CC_ENABLE BIT(2) -#define GAM_ENABLE BIT(3) -#define GAM_BENABLE BIT(4) -#define GAM_GENABLE BIT(5) -#define GAM_RENABLE BIT(6) -#define CSC_ENABLE BIT(7) -#define CBC_ENABLE BIT(8) -#define SUB422_ENABLE BIT(9) -#define SUB420_ENABLE BIT(10) - -#define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE) - -/* - * struct fmt_config - ISC format configuration and internal pipeline - This structure represents the internal configuration - of the ISC. - It also holds the format that ISC will present to v4l2. - * @sd_format: Pointer to an isc_format struct that holds the sensor - configuration. - * @fourcc: Fourcc code for this format. - * @bpp: Bytes per pixel in the current format. - * @rlp_cfg_mode: Configuration of the RLP (rounding, limiting packaging) - * @dcfg_imode: Configuration of the input of the DMA module - * @dctrl_dview: Configuration of the output of the DMA module - * @bits_pipeline: Configuration of the pipeline, which modules are enabled - */ -struct fmt_config { - struct isc_format *sd_format; - - u32 fourcc; - u8 bpp; - - u32 rlp_cfg_mode; - u32 dcfg_imode; - u32 dctrl_dview; - - u32 bits_pipeline; -}; - -#define HIST_ENTRIES 512 -#define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1) - -enum{ - HIST_INIT = 0, - HIST_ENABLED, - HIST_DISABLED, -}; - -struct isc_ctrls { - struct v4l2_ctrl_handler handler; - - u32 brightness; - u32 contrast; - u8 gamma_index; - u8 awb; - - u32 r_gain; - u32 b_gain; - - u32 hist_entry[HIST_ENTRIES]; - u32 hist_count[HIST_BAYER]; - u8 hist_id; - u8 hist_stat; -}; - -#define ISC_PIPE_LINE_NODE_NUM 11 - -struct isc_device { - struct regmap *regmap; - struct clk *hclock; - struct clk *ispck; - struct isc_clk isc_clks[2]; - - struct device *dev; - struct v4l2_device v4l2_dev; - struct video_device video_dev; - - struct vb2_queue vb2_vidq; - spinlock_t dma_queue_lock; - struct list_head dma_queue; - struct isc_buffer *cur_frm; - unsigned int sequence; - bool stop; - struct completion comp; - - struct v4l2_format fmt; - struct isc_format **user_formats; - unsigned int num_user_formats; - - struct fmt_config config; - struct fmt_config try_config; - - struct isc_ctrls ctrls; - struct work_struct awb_work; - - struct mutex lock; - - struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM]; +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (0-2)"); - struct isc_subdev_entity *current_subdev; - struct list_head subdev_entities; -}; +static unsigned int sensor_preferred = 1; +module_param(sensor_preferred, uint, 0644); +MODULE_PARM_DESC(sensor_preferred, + "Sensor is preferred to output the specified format (1-on 0-off), default 1"); /* This is a list of the formats that the ISC can *output* */ -static struct isc_format controller_formats[] = { +const struct isc_format controller_formats[] = { { .fourcc = V4L2_PIX_FMT_ARGB444, }, @@ -245,7 +76,7 @@ static struct isc_format controller_formats[] = { }; /* This is a list of formats that the ISC can receive as *input* */ -static struct isc_format formats_list[] = { +struct isc_format formats_list[] = { { .fourcc = V4L2_PIX_FMT_SBGGR8, .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, @@ -335,11 +166,8 @@ static struct isc_format formats_list[] = { }, }; -#define GAMMA_MAX 2 -#define GAMMA_ENTRIES 64 - /* Gamma table with gamma 1/2.2 */ -static const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { +const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { /* 0 --> gamma 1/1.8 */ { 0x65, 0x66002F, 0x950025, 0xBB0020, 0xDB001D, 0xF8001A, 0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012, @@ -383,14 +211,39 @@ static const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { #define ISC_IS_FORMAT_RAW(mbus_code) \ (((mbus_code) & 0xf000) == 0x3000) -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "debug level (0-2)"); +static inline void isc_update_awb_ctrls(struct isc_device *isc) +{ + struct isc_ctrls *ctrls = &isc->ctrls; -static unsigned int sensor_preferred = 1; -module_param(sensor_preferred, uint, 0644); -MODULE_PARM_DESC(sensor_preferred, - "Sensor is preferred to output the specified format (1-on 0-off), default 1"); + regmap_write(isc->regmap, ISC_WB_O_RGR, + (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_R])) | + ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16)); + regmap_write(isc->regmap, ISC_WB_O_BGB, + (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_B])) | + ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16)); + regmap_write(isc->regmap, ISC_WB_G_RGR, + ctrls->gain[ISC_HIS_CFG_MODE_R] | + (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16)); + regmap_write(isc->regmap, ISC_WB_G_BGB, + ctrls->gain[ISC_HIS_CFG_MODE_B] | + (ctrls->gain[ISC_HIS_CFG_MODE_GB] << 16)); +} + +static inline void isc_reset_awb_ctrls(struct isc_device *isc) +{ + unsigned int c; + + for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { + /* gains have a fixed point at 9 decimals */ + isc->ctrls.gain[c] = 1 << 9; + /* offsets are in 2's complements, the value + * will be substracted from ISC_WB_O_ZERO_VAL to obtain + * 2's complement of a value between 0 and + * ISC_WB_O_ZERO_VAL >> 1 + */ + isc->ctrls.offset[c] = ISC_WB_O_ZERO_VAL; + } +} static int isc_wait_clk_stable(struct clk_hw *hw) { @@ -646,7 +499,7 @@ static int isc_clk_register(struct isc_device *isc, unsigned int id) return 0; } -static int isc_clk_init(struct isc_device *isc) +int isc_clk_init(struct isc_device *isc) { unsigned int i; int ret; @@ -663,7 +516,7 @@ static int isc_clk_init(struct isc_device *isc) return 0; } -static void isc_clk_cleanup(struct isc_device *isc) +void isc_clk_cleanup(struct isc_device *isc) { unsigned int i; @@ -772,7 +625,9 @@ static void isc_start_dma(struct isc_device *isc) dctrl_dview = isc->config.dctrl_dview; regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS); + spin_lock(&isc->awb_lock); regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); + spin_unlock(&isc->awb_lock); } static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) @@ -794,11 +649,11 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) bay_cfg = isc->config.sd_format->cfa_baycfg; + if (ctrls->awb == ISC_WB_NONE) + isc_reset_awb_ctrls(isc); + regmap_write(regmap, ISC_WB_CFG, bay_cfg); - regmap_write(regmap, ISC_WB_O_RGR, 0x0); - regmap_write(regmap, ISC_WB_O_BGR, 0x0); - regmap_write(regmap, ISC_WB_G_RGR, ctrls->r_gain | (0x1 << 25)); - regmap_write(regmap, ISC_WB_G_BGR, ctrls->b_gain | (0x1 << 25)); + isc_update_awb_ctrls(isc); regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL); @@ -848,13 +703,13 @@ static void isc_set_histogram(struct isc_device *isc, bool enable) if (enable) { regmap_write(regmap, ISC_HIS_CFG, - ISC_HIS_CFG_MODE_R | + ISC_HIS_CFG_MODE_GR | (isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT) | ISC_HIS_CFG_RAR); regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN); regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE); - ctrls->hist_id = ISC_HIS_CFG_MODE_R; + ctrls->hist_id = ISC_HIS_CFG_MODE_GR; isc_update_profile(isc); regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); @@ -897,7 +752,7 @@ static int isc_configure(struct isc_device *isc) isc_set_pipeline(isc, pipeline); /* - * The current implemented histogram is available for RAW R, B, GB + * The current implemented histogram is available for RAW R, B, GB, GR * channels. We need to check if sensor is outputting RAW BAYER */ if (isc->ctrls.awb && @@ -949,6 +804,10 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) spin_unlock_irqrestore(&isc->dma_queue_lock, flags); + /* if we streaming from RAW, we can do one-shot white balance adj */ + if (ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) + v4l2_ctrl_activate(isc->do_wb_ctrl, true); + return 0; err_configure: @@ -973,6 +832,8 @@ static void isc_stop_streaming(struct vb2_queue *vq) struct isc_buffer *buf; int ret; + v4l2_ctrl_activate(isc->do_wb_ctrl, false); + isc->stop = true; /* Wait until the end of the current frame */ @@ -1433,7 +1294,7 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) - goto isc_try_fmt_err; + goto isc_try_fmt_subdev_err; v4l2_fill_pix_format(pixfmt, &format.format); @@ -1448,6 +1309,7 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, isc_try_fmt_err: v4l2_err(&isc->v4l2_dev, "Could not find any possible format for a working pipeline\n"); +isc_try_fmt_subdev_err: memset(&isc->try_config, 0, sizeof(isc->try_config)); return ret; @@ -1472,6 +1334,12 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) return ret; isc->fmt = *f; + + if (isc->try_config.sd_format && isc->config.sd_format && + isc->try_config.sd_format != isc->config.sd_format) { + isc->ctrls.hist_stat = HIST_INIT; + isc_reset_awb_ctrls(isc); + } /* make the try configuration active */ isc->config = isc->try_config; @@ -1588,7 +1456,7 @@ static int isc_enum_frameintervals(struct file *file, void *fh, .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; int ret = -EINVAL; - int i; + unsigned int i; for (i = 0; i < isc->num_user_formats; i++) if (isc->user_formats[i]->fourcc == fival->pixel_format) @@ -1708,7 +1576,7 @@ static const struct v4l2_file_operations isc_fops = { .poll = vb2_fop_poll, }; -static irqreturn_t isc_interrupt(int irq, void *dev_id) +irqreturn_t isc_interrupt(int irq, void *dev_id) { struct isc_device *isc = (struct isc_device *)dev_id; struct regmap *regmap = isc->regmap; @@ -1755,7 +1623,7 @@ static irqreturn_t isc_interrupt(int irq, void *dev_id) return ret; } -static void isc_hist_count(struct isc_device *isc) +static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max) { struct regmap *regmap = isc->regmap; struct isc_ctrls *ctrls = &isc->ctrls; @@ -1763,25 +1631,99 @@ static void isc_hist_count(struct isc_device *isc) u32 *hist_entry = &ctrls->hist_entry[0]; u32 i; + *min = 0; + *max = HIST_ENTRIES; + regmap_bulk_read(regmap, ISC_HIS_ENTRY, hist_entry, HIST_ENTRIES); *hist_count = 0; - for (i = 0; i < HIST_ENTRIES; i++) + /* + * we deliberately ignore the end of the histogram, + * the most white pixels + */ + for (i = 1; i < HIST_ENTRIES; i++) { + if (*hist_entry && !*min) + *min = i; + if (*hist_entry) + *max = i; *hist_count += i * (*hist_entry++); + } + + if (!*min) + *min = 1; } static void isc_wb_update(struct isc_ctrls *ctrls) { u32 *hist_count = &ctrls->hist_count[0]; - u64 g_count = (u64)hist_count[ISC_HIS_CFG_MODE_GB] << 9; - u32 hist_r = hist_count[ISC_HIS_CFG_MODE_R]; - u32 hist_b = hist_count[ISC_HIS_CFG_MODE_B]; + u32 c, offset[4]; + u64 avg = 0; + /* We compute two gains, stretch gain and grey world gain */ + u32 s_gain[4], gw_gain[4]; + + /* + * According to Grey World, we need to set gains for R/B to normalize + * them towards the green channel. + * Thus we want to keep Green as fixed and adjust only Red/Blue + * Compute the average of the both green channels first + */ + avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] + + (u64)hist_count[ISC_HIS_CFG_MODE_GB]; + avg >>= 1; - if (hist_r) - ctrls->r_gain = div_u64(g_count, hist_r); + /* Green histogram is null, nothing to do */ + if (!avg) + return; - if (hist_b) - ctrls->b_gain = div_u64(g_count, hist_b); + for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { + /* + * the color offset is the minimum value of the histogram. + * we stretch this color to the full range by substracting + * this value from the color component. + */ + offset[c] = ctrls->hist_minmax[c][HIST_MIN_INDEX]; + /* + * The offset is always at least 1. If the offset is 1, we do + * not need to adjust it, so our result must be zero. + * the offset is computed in a histogram on 9 bits (0..512) + * but the offset in register is based on + * 12 bits pipeline (0..4096). + * we need to shift with the 3 bits that the histogram is + * ignoring + */ + ctrls->offset[c] = (offset[c] - 1) << 3; + + /* the offset is then taken and converted to 2's complements */ + if (!ctrls->offset[c]) + ctrls->offset[c] = ISC_WB_O_ZERO_VAL; + + /* + * the stretch gain is the total number of histogram bins + * divided by the actual range of color component (Max - Min) + * If we compute gain like this, the actual color component + * will be stretched to the full histogram. + * We need to shift 9 bits for precision, we have 9 bits for + * decimals + */ + s_gain[c] = (HIST_ENTRIES << 9) / + (ctrls->hist_minmax[c][HIST_MAX_INDEX] - + ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1); + + /* + * Now we have to compute the gain w.r.t. the average. + * Add/lose gain to the component towards the average. + * If it happens that the component is zero, use the + * fixed point value : 1.0 gain. + */ + if (hist_count[c]) + gw_gain[c] = div_u64(avg << 9, hist_count[c]); + else + gw_gain[c] = 1 << 9; + + /* multiply both gains and adjust for decimals */ + ctrls->gain[c] = s_gain[c] * gw_gain[c]; + ctrls->gain[c] >>= 9; + } } static void isc_awb_work(struct work_struct *w) @@ -1792,27 +1734,66 @@ static void isc_awb_work(struct work_struct *w) struct isc_ctrls *ctrls = &isc->ctrls; u32 hist_id = ctrls->hist_id; u32 baysel; + unsigned long flags; + u32 min, max; + + /* streaming is not active anymore */ + if (isc->stop) + return; if (ctrls->hist_stat != HIST_ENABLED) return; - isc_hist_count(isc); + isc_hist_count(isc, &min, &max); + ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min; + ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max; if (hist_id != ISC_HIS_CFG_MODE_B) { hist_id++; } else { isc_wb_update(ctrls); - hist_id = ISC_HIS_CFG_MODE_R; + hist_id = ISC_HIS_CFG_MODE_GR; } ctrls->hist_id = hist_id; baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; + /* if no more auto white balance, reset controls. */ + if (ctrls->awb == ISC_WB_NONE) + isc_reset_awb_ctrls(isc); + pm_runtime_get_sync(isc->dev); + /* + * only update if we have all the required histograms and controls + * if awb has been disabled, we need to reset registers as well. + */ + if (hist_id == ISC_HIS_CFG_MODE_GR || ctrls->awb == ISC_WB_NONE) { + /* + * It may happen that DMA Done IRQ will trigger while we are + * updating white balance registers here. + * In that case, only parts of the controls have been updated. + * We can avoid that by locking the section. + */ + spin_lock_irqsave(&isc->awb_lock, flags); + isc_update_awb_ctrls(isc); + spin_unlock_irqrestore(&isc->awb_lock, flags); + + /* + * if we are doing just the one time white balance adjustment, + * we are basically done. + */ + if (ctrls->awb == ISC_WB_ONETIME) { + v4l2_info(&isc->v4l2_dev, + "Completed one time white-balance adjustment.\n"); + ctrls->awb = ISC_WB_NONE; + } + } regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR); isc_update_profile(isc); - regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); + /* if awb has been disabled, we don't need to start another histogram */ + if (ctrls->awb) + regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); pm_runtime_put_sync(isc->dev); } @@ -1823,6 +1804,9 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl) struct isc_device, ctrls.handler); struct isc_ctrls *ctrls = &isc->ctrls; + if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) + return 0; + switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK; @@ -1834,11 +1818,33 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl) ctrls->gamma_index = ctrl->val; break; case V4L2_CID_AUTO_WHITE_BALANCE: - ctrls->awb = ctrl->val; - if (ctrls->hist_stat != HIST_ENABLED) { - ctrls->r_gain = 0x1 << 9; - ctrls->b_gain = 0x1 << 9; - } + if (ctrl->val == 1) + ctrls->awb = ISC_WB_AUTO; + else + ctrls->awb = ISC_WB_NONE; + + /* we did not configure ISC yet */ + if (!isc->config.sd_format) + break; + + if (ctrls->hist_stat != HIST_ENABLED) + isc_reset_awb_ctrls(isc); + + if (isc->ctrls.awb == ISC_WB_AUTO && + vb2_is_streaming(&isc->vb2_vidq) && + ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) + isc_set_histogram(isc, true); + + break; + case V4L2_CID_DO_WHITE_BALANCE: + /* if AWB is enabled, do nothing */ + if (ctrls->awb == ISC_WB_AUTO) + return 0; + + ctrls->awb = ISC_WB_ONETIME; + isc_set_histogram(isc, true); + v4l2_dbg(1, debug, &isc->v4l2_dev, + "One time white-balance started.\n"); break; default: return -EINVAL; @@ -1859,16 +1865,32 @@ static int isc_ctrl_init(struct isc_device *isc) int ret; ctrls->hist_stat = HIST_INIT; + isc_reset_awb_ctrls(isc); - ret = v4l2_ctrl_handler_init(hdl, 4); + ret = v4l2_ctrl_handler_init(hdl, 5); if (ret < 0) return ret; + ctrls->brightness = 0; + ctrls->contrast = 256; + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0); v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256); v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2); v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + /* do_white_balance is a button, so min,max,step,default are ignored */ + isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DO_WHITE_BALANCE, + 0, 0, 0, 0); + + if (!isc->do_wb_ctrl) { + ret = hdl->error; + v4l2_ctrl_handler_free(hdl); + return ret; + } + + v4l2_ctrl_activate(isc->do_wb_ctrl, false); + v4l2_ctrl_handler_setup(hdl); return 0; @@ -1994,7 +2016,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) struct isc_device, v4l2_dev); struct video_device *vdev = &isc->video_dev; struct vb2_queue *q = &isc->vb2_vidq; - int ret; + int ret = 0; INIT_WORK(&isc->awb_work, isc_awb_work); @@ -2025,30 +2047,31 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) if (ret < 0) { v4l2_err(&isc->v4l2_dev, "vb2_queue_init() failed: %d\n", ret); - return ret; + goto isc_async_complete_err; } /* Init video dma queues */ INIT_LIST_HEAD(&isc->dma_queue); spin_lock_init(&isc->dma_queue_lock); + spin_lock_init(&isc->awb_lock); ret = isc_formats_init(isc); if (ret < 0) { v4l2_err(&isc->v4l2_dev, "Init format failed: %d\n", ret); - return ret; + goto isc_async_complete_err; } ret = isc_set_default_fmt(isc); if (ret) { v4l2_err(&isc->v4l2_dev, "Could not set default format\n"); - return ret; + goto isc_async_complete_err; } ret = isc_ctrl_init(isc); if (ret) { v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret); - return ret; + goto isc_async_complete_err; } /* Register video device */ @@ -2068,19 +2091,23 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) if (ret < 0) { v4l2_err(&isc->v4l2_dev, "video_register_device failed: %d\n", ret); - return ret; + goto isc_async_complete_err; } return 0; + +isc_async_complete_err: + mutex_destroy(&isc->lock); + return ret; } -static const struct v4l2_async_notifier_operations isc_async_ops = { +const struct v4l2_async_notifier_operations isc_async_ops = { .bound = isc_async_bound, .unbind = isc_async_unbind, .complete = isc_async_complete, }; -static void isc_subdev_cleanup(struct isc_device *isc) +void isc_subdev_cleanup(struct isc_device *isc) { struct isc_subdev_entity *subdev_entity; @@ -2092,7 +2119,7 @@ static void isc_subdev_cleanup(struct isc_device *isc) INIT_LIST_HEAD(&isc->subdev_entities); } -static int isc_pipeline_init(struct isc_device *isc) +int isc_pipeline_init(struct isc_device *isc) { struct device *dev = isc->dev; struct regmap *regmap = isc->regmap; @@ -2125,300 +2152,12 @@ static int isc_pipeline_init(struct isc_device *isc) return 0; } -static int isc_parse_dt(struct device *dev, struct isc_device *isc) -{ - struct device_node *np = dev->of_node; - struct device_node *epn = NULL, *rem; - struct isc_subdev_entity *subdev_entity; - unsigned int flags; - int ret; - - INIT_LIST_HEAD(&isc->subdev_entities); - - while (1) { - struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 }; - - epn = of_graph_get_next_endpoint(np, epn); - if (!epn) - return 0; - - rem = of_graph_get_remote_port_parent(epn); - if (!rem) { - dev_notice(dev, "Remote device at %pOF not found\n", - epn); - continue; - } - - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn), - &v4l2_epn); - if (ret) { - of_node_put(rem); - ret = -EINVAL; - dev_err(dev, "Could not parse the endpoint\n"); - break; - } - - subdev_entity = devm_kzalloc(dev, - sizeof(*subdev_entity), GFP_KERNEL); - if (!subdev_entity) { - of_node_put(rem); - ret = -ENOMEM; - break; - } - - /* asd will be freed by the subsystem once it's added to the - * notifier list - */ - subdev_entity->asd = kzalloc(sizeof(*subdev_entity->asd), - GFP_KERNEL); - if (!subdev_entity->asd) { - of_node_put(rem); - ret = -ENOMEM; - break; - } - - flags = v4l2_epn.bus.parallel.flags; - - if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW; - - if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW; - - if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) - subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW; - - if (v4l2_epn.bus_type == V4L2_MBUS_BT656) - subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC | - ISC_PFE_CFG0_CCIR656; - - subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_FWNODE; - subdev_entity->asd->match.fwnode = - of_fwnode_handle(rem); - list_add_tail(&subdev_entity->list, &isc->subdev_entities); - } - - of_node_put(epn); - return ret; -} - /* regmap configuration */ #define ATMEL_ISC_REG_MAX 0xbfc -static const struct regmap_config isc_regmap_config = { +const struct regmap_config isc_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, .max_register = ATMEL_ISC_REG_MAX, }; -static int atmel_isc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct isc_device *isc; - struct resource *res; - void __iomem *io_base; - struct isc_subdev_entity *subdev_entity; - int irq; - int ret; - - isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL); - if (!isc) - return -ENOMEM; - - platform_set_drvdata(pdev, isc); - isc->dev = dev; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - io_base = devm_ioremap_resource(dev, res); - if (IS_ERR(io_base)) - return PTR_ERR(io_base); - - isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config); - if (IS_ERR(isc->regmap)) { - ret = PTR_ERR(isc->regmap); - dev_err(dev, "failed to init register map: %d\n", ret); - return ret; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - dev_err(dev, "failed to get irq: %d\n", ret); - return ret; - } - - ret = devm_request_irq(dev, irq, isc_interrupt, 0, - ATMEL_ISC_NAME, isc); - if (ret < 0) { - dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n", - irq, ret); - return ret; - } - - ret = isc_pipeline_init(isc); - if (ret) - return ret; - - isc->hclock = devm_clk_get(dev, "hclock"); - if (IS_ERR(isc->hclock)) { - ret = PTR_ERR(isc->hclock); - dev_err(dev, "failed to get hclock: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(isc->hclock); - if (ret) { - dev_err(dev, "failed to enable hclock: %d\n", ret); - return ret; - } - - ret = isc_clk_init(isc); - if (ret) { - dev_err(dev, "failed to init isc clock: %d\n", ret); - goto unprepare_hclk; - } - - isc->ispck = isc->isc_clks[ISC_ISPCK].clk; - - ret = clk_prepare_enable(isc->ispck); - if (ret) { - dev_err(dev, "failed to enable ispck: %d\n", ret); - goto unprepare_hclk; - } - - /* ispck should be greater or equal to hclock */ - ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock)); - if (ret) { - dev_err(dev, "failed to set ispck rate: %d\n", ret); - goto unprepare_clk; - } - - ret = v4l2_device_register(dev, &isc->v4l2_dev); - if (ret) { - dev_err(dev, "unable to register v4l2 device.\n"); - goto unprepare_clk; - } - - ret = isc_parse_dt(dev, isc); - if (ret) { - dev_err(dev, "fail to parse device tree\n"); - goto unregister_v4l2_device; - } - - if (list_empty(&isc->subdev_entities)) { - dev_err(dev, "no subdev found\n"); - ret = -ENODEV; - goto unregister_v4l2_device; - } - - list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { - v4l2_async_notifier_init(&subdev_entity->notifier); - - ret = v4l2_async_notifier_add_subdev(&subdev_entity->notifier, - subdev_entity->asd); - if (ret) { - fwnode_handle_put(subdev_entity->asd->match.fwnode); - kfree(subdev_entity->asd); - goto cleanup_subdev; - } - - subdev_entity->notifier.ops = &isc_async_ops; - - ret = v4l2_async_notifier_register(&isc->v4l2_dev, - &subdev_entity->notifier); - if (ret) { - dev_err(dev, "fail to register async notifier\n"); - goto cleanup_subdev; - } - - if (video_is_registered(&isc->video_dev)) - break; - } - - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - pm_request_idle(dev); - - return 0; - -cleanup_subdev: - isc_subdev_cleanup(isc); - -unregister_v4l2_device: - v4l2_device_unregister(&isc->v4l2_dev); - -unprepare_clk: - clk_disable_unprepare(isc->ispck); -unprepare_hclk: - clk_disable_unprepare(isc->hclock); - - isc_clk_cleanup(isc); - - return ret; -} - -static int atmel_isc_remove(struct platform_device *pdev) -{ - struct isc_device *isc = platform_get_drvdata(pdev); - - pm_runtime_disable(&pdev->dev); - clk_disable_unprepare(isc->ispck); - clk_disable_unprepare(isc->hclock); - - isc_subdev_cleanup(isc); - - v4l2_device_unregister(&isc->v4l2_dev); - - isc_clk_cleanup(isc); - - return 0; -} - -static int __maybe_unused isc_runtime_suspend(struct device *dev) -{ - struct isc_device *isc = dev_get_drvdata(dev); - - clk_disable_unprepare(isc->ispck); - clk_disable_unprepare(isc->hclock); - - return 0; -} - -static int __maybe_unused isc_runtime_resume(struct device *dev) -{ - struct isc_device *isc = dev_get_drvdata(dev); - int ret; - - ret = clk_prepare_enable(isc->hclock); - if (ret) - return ret; - - return clk_prepare_enable(isc->ispck); -} - -static const struct dev_pm_ops atmel_isc_dev_pm_ops = { - SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL) -}; - -static const struct of_device_id atmel_isc_of_match[] = { - { .compatible = "atmel,sama5d2-isc" }, - { } -}; -MODULE_DEVICE_TABLE(of, atmel_isc_of_match); - -static struct platform_driver atmel_isc_driver = { - .probe = atmel_isc_probe, - .remove = atmel_isc_remove, - .driver = { - .name = ATMEL_ISC_NAME, - .pm = &atmel_isc_dev_pm_ops, - .of_match_table = of_match_ptr(atmel_isc_of_match), - }, -}; - -module_platform_driver(atmel_isc_driver); - -MODULE_AUTHOR("Songjun Wu <songjun.wu@microchip.com>"); -MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC"); -MODULE_LICENSE("GPL v2"); -MODULE_SUPPORTED_DEVICE("video"); diff --git a/drivers/media/platform/atmel/atmel-isc-regs.h b/drivers/media/platform/atmel/atmel-isc-regs.h index 8f7f8efc71a7..c1283fb21bf6 100644 --- a/drivers/media/platform/atmel/atmel-isc-regs.h +++ b/drivers/media/platform/atmel/atmel-isc-regs.h @@ -100,13 +100,15 @@ #define ISC_WB_O_RGR 0x00000060 /* ISC White Balance Offset for B, GB Register */ -#define ISC_WB_O_BGR 0x00000064 +#define ISC_WB_O_BGB 0x00000064 /* ISC White Balance Gain for R, GR Register */ #define ISC_WB_G_RGR 0x00000068 /* ISC White Balance Gain for B, GB Register */ -#define ISC_WB_G_BGR 0x0000006c +#define ISC_WB_G_BGB 0x0000006c + +#define ISC_WB_O_ZERO_VAL (1 << 13) /* ISC Color Filter Array Control Register */ #define ISC_CFA_CTRL 0x00000070 diff --git a/drivers/media/platform/atmel/atmel-isc.h b/drivers/media/platform/atmel/atmel-isc.h new file mode 100644 index 000000000000..bfaed2fad2b5 --- /dev/null +++ b/drivers/media/platform/atmel/atmel-isc.h @@ -0,0 +1,245 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Microchip Image Sensor Controller (ISC) driver header file + * + * Copyright (C) 2016-2019 Microchip Technology, Inc. + * + * Author: Songjun Wu + * Author: Eugen Hristev <eugen.hristev@microchip.com> + * + */ +#ifndef _ATMEL_ISC_H_ + +#define ISC_MAX_SUPPORT_WIDTH 2592 +#define ISC_MAX_SUPPORT_HEIGHT 1944 + +#define ISC_CLK_MAX_DIV 255 + +enum isc_clk_id { + ISC_ISPCK = 0, + ISC_MCK = 1, +}; + +struct isc_clk { + struct clk_hw hw; + struct clk *clk; + struct regmap *regmap; + spinlock_t lock; /* serialize access to clock registers */ + u8 id; + u8 parent_id; + u32 div; + struct device *dev; +}; + +#define to_isc_clk(v) container_of(v, struct isc_clk, hw) + +struct isc_buffer { + struct vb2_v4l2_buffer vb; + struct list_head list; +}; + +struct isc_subdev_entity { + struct v4l2_subdev *sd; + struct v4l2_async_subdev *asd; + struct v4l2_async_notifier notifier; + + u32 pfe_cfg0; + + struct list_head list; +}; + +/* + * struct isc_format - ISC media bus format information + This structure represents the interface between the ISC + and the sensor. It's the input format received by + the ISC. + * @fourcc: Fourcc code for this format + * @mbus_code: V4L2 media bus format code. + * @cfa_baycfg: If this format is RAW BAYER, indicate the type of bayer. + this is either BGBG, RGRG, etc. + * @pfe_cfg0_bps: Number of hardware data lines connected to the ISC + */ + +struct isc_format { + u32 fourcc; + u32 mbus_code; + u32 cfa_baycfg; + + bool sd_support; + u32 pfe_cfg0_bps; +}; + +/* Pipeline bitmap */ +#define WB_ENABLE BIT(0) +#define CFA_ENABLE BIT(1) +#define CC_ENABLE BIT(2) +#define GAM_ENABLE BIT(3) +#define GAM_BENABLE BIT(4) +#define GAM_GENABLE BIT(5) +#define GAM_RENABLE BIT(6) +#define CSC_ENABLE BIT(7) +#define CBC_ENABLE BIT(8) +#define SUB422_ENABLE BIT(9) +#define SUB420_ENABLE BIT(10) + +#define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE) + +/* + * struct fmt_config - ISC format configuration and internal pipeline + This structure represents the internal configuration + of the ISC. + It also holds the format that ISC will present to v4l2. + * @sd_format: Pointer to an isc_format struct that holds the sensor + configuration. + * @fourcc: Fourcc code for this format. + * @bpp: Bytes per pixel in the current format. + * @rlp_cfg_mode: Configuration of the RLP (rounding, limiting packaging) + * @dcfg_imode: Configuration of the input of the DMA module + * @dctrl_dview: Configuration of the output of the DMA module + * @bits_pipeline: Configuration of the pipeline, which modules are enabled + */ +struct fmt_config { + struct isc_format *sd_format; + + u32 fourcc; + u8 bpp; + + u32 rlp_cfg_mode; + u32 dcfg_imode; + u32 dctrl_dview; + + u32 bits_pipeline; +}; + +#define HIST_ENTRIES 512 +#define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1) + +enum{ + HIST_INIT = 0, + HIST_ENABLED, + HIST_DISABLED, +}; + +struct isc_ctrls { + struct v4l2_ctrl_handler handler; + + u32 brightness; + u32 contrast; + u8 gamma_index; +#define ISC_WB_NONE 0 +#define ISC_WB_AUTO 1 +#define ISC_WB_ONETIME 2 + u8 awb; + + /* one for each component : GR, R, GB, B */ + u32 gain[HIST_BAYER]; + u32 offset[HIST_BAYER]; + + u32 hist_entry[HIST_ENTRIES]; + u32 hist_count[HIST_BAYER]; + u8 hist_id; + u8 hist_stat; +#define HIST_MIN_INDEX 0 +#define HIST_MAX_INDEX 1 + u32 hist_minmax[HIST_BAYER][2]; +}; + +#define ISC_PIPE_LINE_NODE_NUM 11 + +/* + * struct isc_device - ISC device driver data/config struct + * @regmap: Register map + * @hclock: Hclock clock input (refer datasheet) + * @ispck: iscpck clock (refer datasheet) + * @isc_clks: ISC clocks + * + * @dev: Registered device driver + * @v4l2_dev: v4l2 registered device + * @video_dev: registered video device + * + * @vb2_vidq: video buffer 2 video queue + * @dma_queue_lock: lock to serialize the dma buffer queue + * @dma_queue: the queue for dma buffers + * @cur_frm: current isc frame/buffer + * @sequence: current frame number + * @stop: true if isc is not streaming, false if streaming + * @comp: completion reference that signals frame completion + * + * @fmt: current v42l format + * @user_formats: list of formats that are supported and agreed with sd + * @num_user_formats: how many formats are in user_formats + * + * @config: current ISC format configuration + * @try_config: the current ISC try format , not yet activated + * + * @ctrls: holds information about ISC controls + * @do_wb_ctrl: control regarding the DO_WHITE_BALANCE button + * @awb_work: workqueue reference for autowhitebalance histogram + * analysis + * + * @lock: lock for serializing userspace file operations + * with ISC operations + * @awb_lock: lock for serializing awb work queue operations + * with DMA/buffer operations + * + * @pipeline: configuration of the ISC pipeline + * + * @current_subdev: current subdevice: the sensor + * @subdev_entities: list of subdevice entitites + */ +struct isc_device { + struct regmap *regmap; + struct clk *hclock; + struct clk *ispck; + struct isc_clk isc_clks[2]; + + struct device *dev; + struct v4l2_device v4l2_dev; + struct video_device video_dev; + + struct vb2_queue vb2_vidq; + spinlock_t dma_queue_lock; /* serialize access to dma queue */ + struct list_head dma_queue; + struct isc_buffer *cur_frm; + unsigned int sequence; + bool stop; + struct completion comp; + + struct v4l2_format fmt; + struct isc_format **user_formats; + unsigned int num_user_formats; + + struct fmt_config config; + struct fmt_config try_config; + + struct isc_ctrls ctrls; + struct v4l2_ctrl *do_wb_ctrl; + struct work_struct awb_work; + + struct mutex lock; /* serialize access to file operations */ + spinlock_t awb_lock; /* serialize access to DMA buffers from awb work queue */ + + struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM]; + + struct isc_subdev_entity *current_subdev; + struct list_head subdev_entities; +}; + +#define GAMMA_MAX 2 +#define GAMMA_ENTRIES 64 + +#define ATMEL_ISC_NAME "atmel-isc" + +extern struct isc_format formats_list[]; +extern const struct isc_format controller_formats[]; +extern const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES]; +extern const struct regmap_config isc_regmap_config; +extern const struct v4l2_async_notifier_operations isc_async_ops; + +irqreturn_t isc_interrupt(int irq, void *dev_id); +int isc_pipeline_init(struct isc_device *isc); +int isc_clk_init(struct isc_device *isc); +void isc_subdev_cleanup(struct isc_device *isc); +void isc_clk_cleanup(struct isc_device *isc); + +#endif diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 08b8d5583080..d7d94c1a39d3 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011 Atmel Corporation * Josh Wu, <josh.wu@atmel.com> @@ -5,10 +6,6 @@ * Based on previous work by Lars Haring, <lars.haring@atmel.com> * and Sedji Gaouaou * Based on the bttv driver for Bt848 with respective copyright holders - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/media/platform/atmel/atmel-isi.h b/drivers/media/platform/atmel/atmel-isi.h index 0acb32a2b65c..47a9108dba55 100644 --- a/drivers/media/platform/atmel/atmel-isi.h +++ b/drivers/media/platform/atmel/atmel-isi.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Register definitions for the Atmel Image Sensor Interface. * @@ -6,10 +7,6 @@ * * Based on previous work by Lars Haring, <lars.haring@atmel.com> * and Sedji Gaouaou - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __ATMEL_ISI_H__ #define __ATMEL_ISI_H__ diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c new file mode 100644 index 000000000000..266df14da2d5 --- /dev/null +++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip Image Sensor Controller (ISC) driver + * + * Copyright (C) 2016-2019 Microchip Technology, Inc. + * + * Author: Songjun Wu + * Author: Eugen Hristev <eugen.hristev@microchip.com> + * + * + * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA + * + * ISC video pipeline integrates the following submodules: + * PFE: Parallel Front End to sample the camera sensor input stream + * WB: Programmable white balance in the Bayer domain + * CFA: Color filter array interpolation module + * CC: Programmable color correction + * GAM: Gamma correction + * CSC: Programmable color space conversion + * CBC: Contrast and Brightness control + * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling + * RLP: This module performs rounding, range limiting + * and packing of the incoming data + */ + +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/math64.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/videodev2.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-image-sizes.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> +#include <media/videobuf2-dma-contig.h> + +#include "atmel-isc-regs.h" +#include "atmel-isc.h" + +#define ISC_MAX_SUPPORT_WIDTH 2592 +#define ISC_MAX_SUPPORT_HEIGHT 1944 + +#define ISC_CLK_MAX_DIV 255 + +static int isc_parse_dt(struct device *dev, struct isc_device *isc) +{ + struct device_node *np = dev->of_node; + struct device_node *epn = NULL, *rem; + struct isc_subdev_entity *subdev_entity; + unsigned int flags; + int ret; + + INIT_LIST_HEAD(&isc->subdev_entities); + + while (1) { + struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 }; + + epn = of_graph_get_next_endpoint(np, epn); + if (!epn) + return 0; + + rem = of_graph_get_remote_port_parent(epn); + if (!rem) { + dev_notice(dev, "Remote device at %pOF not found\n", + epn); + continue; + } + + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn), + &v4l2_epn); + if (ret) { + of_node_put(rem); + ret = -EINVAL; + dev_err(dev, "Could not parse the endpoint\n"); + break; + } + + subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity), + GFP_KERNEL); + if (!subdev_entity) { + of_node_put(rem); + ret = -ENOMEM; + break; + } + + /* asd will be freed by the subsystem once it's added to the + * notifier list + */ + subdev_entity->asd = kzalloc(sizeof(*subdev_entity->asd), + GFP_KERNEL); + if (!subdev_entity->asd) { + of_node_put(rem); + ret = -ENOMEM; + break; + } + + flags = v4l2_epn.bus.parallel.flags; + + if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW; + + if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW; + + if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW; + + if (v4l2_epn.bus_type == V4L2_MBUS_BT656) + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC | + ISC_PFE_CFG0_CCIR656; + + subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_FWNODE; + subdev_entity->asd->match.fwnode = of_fwnode_handle(rem); + list_add_tail(&subdev_entity->list, &isc->subdev_entities); + } + + of_node_put(epn); + return ret; +} + +static int atmel_isc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct isc_device *isc; + struct resource *res; + void __iomem *io_base; + struct isc_subdev_entity *subdev_entity; + int irq; + int ret; + + isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL); + if (!isc) + return -ENOMEM; + + platform_set_drvdata(pdev, isc); + isc->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + io_base = devm_ioremap_resource(dev, res); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); + + isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config); + if (IS_ERR(isc->regmap)) { + ret = PTR_ERR(isc->regmap); + dev_err(dev, "failed to init register map: %d\n", ret); + return ret; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + dev_err(dev, "failed to get irq: %d\n", ret); + return ret; + } + + ret = devm_request_irq(dev, irq, isc_interrupt, 0, + ATMEL_ISC_NAME, isc); + if (ret < 0) { + dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n", + irq, ret); + return ret; + } + + ret = isc_pipeline_init(isc); + if (ret) + return ret; + + isc->hclock = devm_clk_get(dev, "hclock"); + if (IS_ERR(isc->hclock)) { + ret = PTR_ERR(isc->hclock); + dev_err(dev, "failed to get hclock: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(isc->hclock); + if (ret) { + dev_err(dev, "failed to enable hclock: %d\n", ret); + return ret; + } + + ret = isc_clk_init(isc); + if (ret) { + dev_err(dev, "failed to init isc clock: %d\n", ret); + goto unprepare_hclk; + } + + isc->ispck = isc->isc_clks[ISC_ISPCK].clk; + + ret = clk_prepare_enable(isc->ispck); + if (ret) { + dev_err(dev, "failed to enable ispck: %d\n", ret); + goto unprepare_hclk; + } + + /* ispck should be greater or equal to hclock */ + ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock)); + if (ret) { + dev_err(dev, "failed to set ispck rate: %d\n", ret); + goto unprepare_clk; + } + + ret = v4l2_device_register(dev, &isc->v4l2_dev); + if (ret) { + dev_err(dev, "unable to register v4l2 device.\n"); + goto unprepare_clk; + } + + ret = isc_parse_dt(dev, isc); + if (ret) { + dev_err(dev, "fail to parse device tree\n"); + goto unregister_v4l2_device; + } + + if (list_empty(&isc->subdev_entities)) { + dev_err(dev, "no subdev found\n"); + ret = -ENODEV; + goto unregister_v4l2_device; + } + + list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { + v4l2_async_notifier_init(&subdev_entity->notifier); + + ret = v4l2_async_notifier_add_subdev(&subdev_entity->notifier, + subdev_entity->asd); + if (ret) { + fwnode_handle_put(subdev_entity->asd->match.fwnode); + kfree(subdev_entity->asd); + goto cleanup_subdev; + } + + subdev_entity->notifier.ops = &isc_async_ops; + + ret = v4l2_async_notifier_register(&isc->v4l2_dev, + &subdev_entity->notifier); + if (ret) { + dev_err(dev, "fail to register async notifier\n"); + goto cleanup_subdev; + } + + if (video_is_registered(&isc->video_dev)) + break; + } + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_request_idle(dev); + + return 0; + +cleanup_subdev: + isc_subdev_cleanup(isc); + +unregister_v4l2_device: + v4l2_device_unregister(&isc->v4l2_dev); + +unprepare_clk: + clk_disable_unprepare(isc->ispck); +unprepare_hclk: + clk_disable_unprepare(isc->hclock); + + isc_clk_cleanup(isc); + + return ret; +} + +static int atmel_isc_remove(struct platform_device *pdev) +{ + struct isc_device *isc = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + + isc_subdev_cleanup(isc); + + v4l2_device_unregister(&isc->v4l2_dev); + + clk_disable_unprepare(isc->ispck); + clk_disable_unprepare(isc->hclock); + + isc_clk_cleanup(isc); + + return 0; +} + +static int __maybe_unused isc_runtime_suspend(struct device *dev) +{ + struct isc_device *isc = dev_get_drvdata(dev); + + clk_disable_unprepare(isc->ispck); + clk_disable_unprepare(isc->hclock); + + return 0; +} + +static int __maybe_unused isc_runtime_resume(struct device *dev) +{ + struct isc_device *isc = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(isc->hclock); + if (ret) + return ret; + + ret = clk_prepare_enable(isc->ispck); + if (ret) + clk_disable_unprepare(isc->hclock); + + return ret; +} + +static const struct dev_pm_ops atmel_isc_dev_pm_ops = { + SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL) +}; + +static const struct of_device_id atmel_isc_of_match[] = { + { .compatible = "atmel,sama5d2-isc" }, + { } +}; +MODULE_DEVICE_TABLE(of, atmel_isc_of_match); + +static struct platform_driver atmel_isc_driver = { + .probe = atmel_isc_probe, + .remove = atmel_isc_remove, + .driver = { + .name = ATMEL_ISC_NAME, + .pm = &atmel_isc_dev_pm_ops, + .of_match_table = of_match_ptr(atmel_isc_of_match), + }, +}; + +module_platform_driver(atmel_isc_driver); + +MODULE_AUTHOR("Songjun Wu"); +MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC"); +MODULE_LICENSE("GPL v2"); +MODULE_SUPPORTED_DEVICE("video"); diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c index d2861749d640..5b17d3a31896 100644 --- a/drivers/media/platform/cec-gpio/cec-gpio.c +++ b/drivers/media/platform/cec-gpio/cec-gpio.c @@ -17,7 +17,6 @@ struct cec_gpio { struct gpio_desc *cec_gpio; int cec_irq; bool cec_is_low; - bool cec_have_irq; struct gpio_desc *hpd_gpio; int hpd_irq; @@ -55,9 +54,6 @@ static void cec_gpio_low(struct cec_adapter *adap) if (cec->cec_is_low) return; - if (WARN_ON_ONCE(cec->cec_have_irq)) - free_irq(cec->cec_irq, cec); - cec->cec_have_irq = false; cec->cec_is_low = true; gpiod_set_value(cec->cec_gpio, 0); } @@ -114,14 +110,7 @@ static bool cec_gpio_enable_irq(struct cec_adapter *adap) { struct cec_gpio *cec = cec_get_drvdata(adap); - if (cec->cec_have_irq) - return true; - - if (request_irq(cec->cec_irq, cec_gpio_irq_handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - adap->name, cec)) - return false; - cec->cec_have_irq = true; + enable_irq(cec->cec_irq); return true; } @@ -129,9 +118,7 @@ static void cec_gpio_disable_irq(struct cec_adapter *adap) { struct cec_gpio *cec = cec_get_drvdata(adap); - if (cec->cec_have_irq) - free_irq(cec->cec_irq, cec); - cec->cec_have_irq = false; + disable_irq(cec->cec_irq); } static void cec_gpio_status(struct cec_adapter *adap, struct seq_file *file) @@ -139,8 +126,7 @@ static void cec_gpio_status(struct cec_adapter *adap, struct seq_file *file) struct cec_gpio *cec = cec_get_drvdata(adap); seq_printf(file, "mode: %s\n", cec->cec_is_low ? "low-drive" : "read"); - if (cec->cec_have_irq) - seq_printf(file, "using irq: %d\n", cec->cec_irq); + seq_printf(file, "using irq: %d\n", cec->cec_irq); if (cec->hpd_gpio) seq_printf(file, "hpd: %s\n", cec->hpd_is_high ? "high" : "low"); @@ -215,6 +201,14 @@ static int cec_gpio_probe(struct platform_device *pdev) if (IS_ERR(cec->adap)) return PTR_ERR(cec->adap); + ret = devm_request_irq(dev, cec->cec_irq, cec_gpio_irq_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + cec->adap->name, cec); + if (ret) + return ret; + + cec_gpio_disable_irq(cec->adap); + if (cec->hpd_gpio) { cec->hpd_irq = gpiod_to_irq(cec->hpd_gpio); ret = devm_request_threaded_irq(dev, cec->hpd_irq, diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile index f13adacd924e..bbb16425a875 100644 --- a/drivers/media/platform/coda/Makefile +++ b/drivers/media/platform/coda/Makefile @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -I$(src) -coda-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-jpeg.o +coda-vpu-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-mpeg2.o coda-mpeg4.o coda-jpeg.o -obj-$(CONFIG_VIDEO_CODA) += coda.o +obj-$(CONFIG_VIDEO_CODA) += coda-vpu.o obj-$(CONFIG_VIDEO_IMX_VDOA) += imx-vdoa.o diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 976f6aa69f41..00c7bed3dd57 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -98,6 +98,8 @@ static int coda_command_sync(struct coda_ctx *ctx, int cmd) struct coda_dev *dev = ctx->dev; int ret; + lockdep_assert_held(&dev->coda_mutex); + coda_command_async(ctx, cmd); ret = coda_wait_timeout(dev); trace_coda_bit_done(ctx); @@ -112,6 +114,8 @@ int coda_hw_reset(struct coda_ctx *ctx) unsigned int idx; int ret; + lockdep_assert_held(&dev->coda_mutex); + if (!dev->rstc) return -ENOENT; @@ -176,7 +180,7 @@ static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); } -static int coda_bitstream_pad(struct coda_ctx *ctx, u32 size) +static int coda_h264_bitstream_pad(struct coda_ctx *ctx, u32 size) { unsigned char *buf; u32 n; @@ -195,51 +199,122 @@ static int coda_bitstream_pad(struct coda_ctx *ctx, u32 size) return (n < size) ? -ENOSPC : 0; } -static int coda_bitstream_queue(struct coda_ctx *ctx, - struct vb2_v4l2_buffer *src_buf) +int coda_bitstream_flush(struct coda_ctx *ctx) { - u32 src_size = vb2_get_plane_payload(&src_buf->vb2_buf, 0); - u32 n; + int ret; - n = kfifo_in(&ctx->bitstream_fifo, - vb2_plane_vaddr(&src_buf->vb2_buf, 0), src_size); - if (n < src_size) - return -ENOSPC; + if (ctx->inst_type != CODA_INST_DECODER || !ctx->use_bit) + return 0; - src_buf->sequence = ctx->qsequence++; + ret = coda_command_sync(ctx, CODA_COMMAND_DEC_BUF_FLUSH); + if (ret < 0) { + v4l2_err(&ctx->dev->v4l2_dev, "failed to flush bitstream\n"); + return ret; + } + + kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, + ctx->bitstream.size); + coda_kfifo_sync_to_device_full(ctx); return 0; } +static int coda_bitstream_queue(struct coda_ctx *ctx, const u8 *buf, u32 size) +{ + u32 n = kfifo_in(&ctx->bitstream_fifo, buf, size); + + return (n < size) ? -ENOSPC : 0; +} + +static u32 coda_buffer_parse_headers(struct coda_ctx *ctx, + struct vb2_v4l2_buffer *src_buf, + u32 payload) +{ + u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); + u32 size = 0; + + switch (ctx->codec->src_fourcc) { + case V4L2_PIX_FMT_MPEG2: + size = coda_mpeg2_parse_headers(ctx, vaddr, payload); + break; + case V4L2_PIX_FMT_MPEG4: + size = coda_mpeg4_parse_headers(ctx, vaddr, payload); + break; + default: + break; + } + + return size; +} + static bool coda_bitstream_try_queue(struct coda_ctx *ctx, struct vb2_v4l2_buffer *src_buf) { unsigned long payload = vb2_get_plane_payload(&src_buf->vb2_buf, 0); + u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); int ret; + int i; if (coda_get_bitstream_payload(ctx) + payload + 512 >= ctx->bitstream.size) return false; - if (vb2_plane_vaddr(&src_buf->vb2_buf, 0) == NULL) { + if (!vaddr) { v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n"); return true; } - /* Add zero padding before the first H.264 buffer, if it is too small */ + if (ctx->qsequence == 0 && payload < 512) { + /* + * Add padding after the first buffer, if it is too small to be + * fetched by the CODA, by repeating the headers. Without + * repeated headers, or the first frame already queued, decoder + * sequence initialization fails with error code 0x2000 on i.MX6 + * or error code 0x1 on i.MX51. + */ + u32 header_size = coda_buffer_parse_headers(ctx, src_buf, + payload); + + if (header_size) { + coda_dbg(1, ctx, "pad with %u-byte header\n", + header_size); + for (i = payload; i < 512; i += header_size) { + ret = coda_bitstream_queue(ctx, vaddr, + header_size); + if (ret < 0) { + v4l2_err(&ctx->dev->v4l2_dev, + "bitstream buffer overflow\n"); + return false; + } + if (ctx->dev->devtype->product == CODA_960) + break; + } + } else { + coda_dbg(1, ctx, + "could not parse header, sequence initialization might fail\n"); + } + } + + /* Add padding before the first buffer, if it is too small */ if (ctx->qsequence == 0 && payload < 512 && ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) - coda_bitstream_pad(ctx, 512 - payload); + coda_h264_bitstream_pad(ctx, 512 - payload); - ret = coda_bitstream_queue(ctx, src_buf); + ret = coda_bitstream_queue(ctx, vaddr, payload); if (ret < 0) { v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); return false; } + + src_buf->sequence = ctx->qsequence++; + /* Sync read pointer to device */ if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev)) coda_kfifo_sync_to_device_write(ctx); + /* Set the stream-end flag after the last buffer is queued */ + if (src_buf->flags & V4L2_BUF_FLAG_LAST) + coda_bit_stream_end_flag(ctx); ctx->hold = false; return true; @@ -327,6 +402,9 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list) meta->timestamp = src_buf->vb2_buf.timestamp; meta->start = start; meta->end = ctx->bitstream_fifo.kfifo.in; + meta->last = src_buf->flags & V4L2_BUF_FLAG_LAST; + if (meta->last) + coda_dbg(1, ctx, "marking last meta"); spin_lock(&ctx->buffer_meta_lock); list_add_tail(&meta->list, &ctx->buffer_meta_list); @@ -391,7 +469,7 @@ static void coda_free_framebuffers(struct coda_ctx *ctx) int i; for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) - coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]); + coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i].buf); } static int coda_alloc_framebuffers(struct coda_ctx *ctx, @@ -431,7 +509,7 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, coda_free_framebuffers(ctx); return -ENOMEM; } - ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i], + ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i].buf, size, name); kfree(name); if (ret < 0) { @@ -445,7 +523,7 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, u32 y, cb, cr, mvcol; /* Start addresses of Y, Cb, Cr planes */ - y = ctx->internal_frames[i].paddr; + y = ctx->internal_frames[i].buf.paddr; cb = y + ysize; cr = y + ysize + ysize/4; mvcol = y + ysize + ysize/4 + ysize/4; @@ -597,6 +675,102 @@ static int coda_encode_header(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, return 0; } +static u32 coda_slice_mode(struct coda_ctx *ctx) +{ + int size, unit; + + switch (ctx->params.slice_mode) { + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: + default: + return 0; + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB: + size = ctx->params.slice_max_mb; + unit = 1; + break; + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES: + size = ctx->params.slice_max_bits; + unit = 0; + break; + } + + return ((size & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET) | + ((unit & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET) | + ((1 & CODA_SLICING_MODE_MASK) << CODA_SLICING_MODE_OFFSET); +} + +static int coda_enc_param_change(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + u32 change_enable = 0; + u32 success; + int ret; + + if (ctx->params.gop_size_changed) { + change_enable |= CODA_PARAM_CHANGE_RC_GOP; + coda_write(dev, ctx->params.gop_size, + CODA_CMD_ENC_PARAM_RC_GOP); + ctx->gopcounter = ctx->params.gop_size - 1; + ctx->params.gop_size_changed = false; + } + if (ctx->params.h264_intra_qp_changed) { + coda_dbg(1, ctx, "parameter change: intra Qp %u\n", + ctx->params.h264_intra_qp); + + if (ctx->params.bitrate) { + change_enable |= CODA_PARAM_CHANGE_RC_INTRA_QP; + coda_write(dev, ctx->params.h264_intra_qp, + CODA_CMD_ENC_PARAM_RC_INTRA_QP); + } + ctx->params.h264_intra_qp_changed = false; + } + if (ctx->params.bitrate_changed) { + coda_dbg(1, ctx, "parameter change: bitrate %u kbit/s\n", + ctx->params.bitrate); + change_enable |= CODA_PARAM_CHANGE_RC_BITRATE; + coda_write(dev, ctx->params.bitrate, + CODA_CMD_ENC_PARAM_RC_BITRATE); + ctx->params.bitrate_changed = false; + } + if (ctx->params.framerate_changed) { + coda_dbg(1, ctx, "parameter change: frame rate %u/%u Hz\n", + ctx->params.framerate & 0xffff, + (ctx->params.framerate >> 16) + 1); + change_enable |= CODA_PARAM_CHANGE_RC_FRAME_RATE; + coda_write(dev, ctx->params.framerate, + CODA_CMD_ENC_PARAM_RC_FRAME_RATE); + ctx->params.framerate_changed = false; + } + if (ctx->params.intra_refresh_changed) { + coda_dbg(1, ctx, "parameter change: intra refresh MBs %u\n", + ctx->params.intra_refresh); + change_enable |= CODA_PARAM_CHANGE_INTRA_MB_NUM; + coda_write(dev, ctx->params.intra_refresh, + CODA_CMD_ENC_PARAM_INTRA_MB_NUM); + ctx->params.intra_refresh_changed = false; + } + if (ctx->params.slice_mode_changed) { + change_enable |= CODA_PARAM_CHANGE_SLICE_MODE; + coda_write(dev, coda_slice_mode(ctx), + CODA_CMD_ENC_PARAM_SLICE_MODE); + ctx->params.slice_mode_changed = false; + } + + if (!change_enable) + return 0; + + coda_write(dev, change_enable, CODA_CMD_ENC_PARAM_CHANGE_ENABLE); + + ret = coda_command_sync(ctx, CODA_COMMAND_RC_CHANGE_PARAMETER); + if (ret < 0) + return ret; + + success = coda_read(dev, CODA_RET_ENC_PARAM_CHANGE_SUCCESS); + if (success != 1) + coda_dbg(1, ctx, "parameter change failed: %u\n", success); + + return 0; +} + static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) { phys_addr_t ret; @@ -1035,33 +1209,16 @@ static int coda_start_encoding(struct coda_ctx *ctx) * in JPEG mode */ if (dst_fourcc != V4L2_PIX_FMT_JPEG) { - switch (ctx->params.slice_mode) { - case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: - value = 0; - break; - case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: - value = (ctx->params.slice_max_mb & - CODA_SLICING_SIZE_MASK) - << CODA_SLICING_SIZE_OFFSET; - value |= (1 & CODA_SLICING_UNIT_MASK) - << CODA_SLICING_UNIT_OFFSET; - value |= 1 & CODA_SLICING_MODE_MASK; - break; - case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: - value = (ctx->params.slice_max_bits & - CODA_SLICING_SIZE_MASK) - << CODA_SLICING_SIZE_OFFSET; - value |= (0 & CODA_SLICING_UNIT_MASK) - << CODA_SLICING_UNIT_OFFSET; - value |= 1 & CODA_SLICING_MODE_MASK; - break; - } + value = coda_slice_mode(ctx); coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); value = ctx->params.gop_size; coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); } if (ctx->params.bitrate) { + ctx->params.bitrate_changed = false; + ctx->params.h264_intra_qp_changed = false; + /* Rate control enabled */ value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET; @@ -1198,9 +1355,9 @@ static int coda_start_encoding(struct coda_ctx *ctx) coda9_set_frame_cache(ctx, q_data_src->fourcc); /* FIXME */ - coda_write(dev, ctx->internal_frames[2].paddr, + coda_write(dev, ctx->internal_frames[2].buf.paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A); - coda_write(dev, ctx->internal_frames[3].paddr, + coda_write(dev, ctx->internal_frames[3].buf.paddr, CODA9_CMD_SET_FRAME_SUBSAMP_B); } } @@ -1316,6 +1473,13 @@ static int coda_prepare_encode(struct coda_ctx *ctx) u32 rot_mode = 0; u32 dst_fourcc; u32 reg; + int ret; + + ret = coda_enc_param_change(ctx); + if (ret < 0) { + v4l2_warn(&ctx->dev->v4l2_dev, "parameter change failed: %d\n", + ret); + } src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); @@ -1452,12 +1616,25 @@ static int coda_prepare_encode(struct coda_ctx *ctx) return 0; } +static char coda_frame_type_char(u32 flags) +{ + return (flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : + (flags & V4L2_BUF_FLAG_PFRAME) ? 'P' : + (flags & V4L2_BUF_FLAG_BFRAME) ? 'B' : '?'; +} + static void coda_finish_encode(struct coda_ctx *ctx) { struct vb2_v4l2_buffer *src_buf, *dst_buf; struct coda_dev *dev = ctx->dev; u32 wr_ptr, start_ptr; + /* + * Lock to make sure that an encoder stop command running in parallel + * will either already have marked src_buf as last, or it will wake up + * the capture queue after the buffers are returned. + */ + mutex_lock(&ctx->wakeup_mutex); src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); @@ -1483,33 +1660,30 @@ static void coda_finish_encode(struct coda_ctx *ctx) coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); coda_read(dev, CODA_RET_ENC_PIC_FLAG); - if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) { + dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | + V4L2_BUF_FLAG_PFRAME | + V4L2_BUF_FLAG_LAST); + if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; - dst_buf->flags &= ~V4L2_BUF_FLAG_PFRAME; - } else { + else dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; - dst_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME; - } + dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST; - dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; - dst_buf->field = src_buf->field; - dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - dst_buf->flags |= - src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - dst_buf->timecode = src_buf->timecode; + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); + mutex_unlock(&ctx->wakeup_mutex); ctx->gopcounter--; if (ctx->gopcounter < 0) ctx->gopcounter = ctx->params.gop_size - 1; - coda_dbg(1, ctx, "job finished: encoded %c frame (%d)\n", - (dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : 'P', - dst_buf->sequence); + coda_dbg(1, ctx, "job finished: encoded %c frame (%d)%s\n", + coda_frame_type_char(dst_buf->flags), dst_buf->sequence, + (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : ""); } static void coda_seq_end_work(struct work_struct *work) @@ -1579,8 +1753,7 @@ static int coda_alloc_bitstream_buffer(struct coda_ctx *ctx, return 0; ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2); - ctx->bitstream.vaddr = dma_alloc_wc(&ctx->dev->plat_dev->dev, - ctx->bitstream.size, + ctx->bitstream.vaddr = dma_alloc_wc(ctx->dev->dev, ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL); if (!ctx->bitstream.vaddr) { v4l2_err(&ctx->dev->v4l2_dev, @@ -1598,8 +1771,8 @@ static void coda_free_bitstream_buffer(struct coda_ctx *ctx) if (ctx->bitstream.vaddr == NULL) return; - dma_free_wc(&ctx->dev->plat_dev->dev, ctx->bitstream.size, - ctx->bitstream.vaddr, ctx->bitstream.paddr); + dma_free_wc(ctx->dev->dev, ctx->bitstream.size, ctx->bitstream.vaddr, + ctx->bitstream.paddr); ctx->bitstream.vaddr = NULL; kfifo_init(&ctx->bitstream_fifo, NULL, 0); } @@ -1656,7 +1829,7 @@ static bool coda_reorder_enable(struct coda_ctx *ctx) return profile > V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; } -static int __coda_start_decoding(struct coda_ctx *ctx) +static int __coda_decoder_seq_init(struct coda_ctx *ctx) { struct coda_q_data *q_data_src, *q_data_dst; u32 bitstream_buf, bitstream_size; @@ -1666,6 +1839,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx) u32 val; int ret; + lockdep_assert_held(&dev->coda_mutex); + coda_dbg(1, ctx, "Video Data Order Adapter: %s\n", ctx->use_vdoa ? "Enabled" : "Disabled"); @@ -1677,8 +1852,6 @@ static int __coda_start_decoding(struct coda_ctx *ctx) src_fourcc = q_data_src->fourcc; dst_fourcc = q_data_dst->fourcc; - coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); - /* Update coda bitstream read and write pointers from kfifo */ coda_kfifo_sync_to_device_full(ctx); @@ -1739,6 +1912,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx) v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); return ret; } + ctx->sequence_offset = ~0U; ctx->initialized = 1; /* Update kfifo out pointer from coda bitstream read pointer */ @@ -1804,6 +1978,64 @@ static int __coda_start_decoding(struct coda_ctx *ctx) (top_bottom & 0x3ff); } + if (dev->devtype->product != CODA_DX6) { + u8 profile, level; + + val = coda_read(dev, CODA7_RET_DEC_SEQ_HEADER_REPORT); + profile = val & 0xff; + level = (val >> 8) & 0x7f; + + if (profile || level) + coda_update_profile_level_ctrls(ctx, profile, level); + } + + return 0; +} + +static void coda_dec_seq_init_work(struct work_struct *work) +{ + struct coda_ctx *ctx = container_of(work, + struct coda_ctx, seq_init_work); + struct coda_dev *dev = ctx->dev; + int ret; + + mutex_lock(&ctx->buffer_mutex); + mutex_lock(&dev->coda_mutex); + + if (ctx->initialized == 1) + goto out; + + ret = __coda_decoder_seq_init(ctx); + if (ret < 0) + goto out; + + ctx->initialized = 1; + +out: + mutex_unlock(&dev->coda_mutex); + mutex_unlock(&ctx->buffer_mutex); +} + +static int __coda_start_decoding(struct coda_ctx *ctx) +{ + struct coda_q_data *q_data_src, *q_data_dst; + struct coda_dev *dev = ctx->dev; + u32 src_fourcc, dst_fourcc; + int ret; + + if (!ctx->initialized) { + ret = __coda_decoder_seq_init(ctx); + if (ret < 0) + return ret; + } + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + src_fourcc = q_data_src->fourcc; + dst_fourcc = q_data_dst->fourcc; + + coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); + ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); if (ret < 0) { v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n"); @@ -1812,7 +2044,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx) /* Tell the decoder how many frame buffers we allocated. */ coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); - coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE); + coda_write(dev, round_up(q_data_dst->rect.width, 16), + CODA_CMD_SET_FRAME_BUF_STRIDE); if (dev->devtype->product != CODA_DX6) { /* Set secondary AXI IRAM */ @@ -1928,7 +2161,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) ctx->display_idx < ctx->num_internal_frames) { vdoa_device_run(ctx->vdoa, vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0), - ctx->internal_frames[ctx->display_idx].paddr); + ctx->internal_frames[ctx->display_idx].buf.paddr); } else { if (dev->devtype->product == CODA_960) { /* @@ -2026,6 +2259,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) int width, height; int decoded_idx; int display_idx; + struct coda_internal_frame *decoded_frame = NULL; u32 src_fourcc; int success; u32 err_mb; @@ -2146,12 +2380,19 @@ static void coda_finish_decode(struct coda_ctx *ctx) else if (ctx->display_idx < 0) ctx->hold = true; } else if (decoded_idx == -2) { + if (ctx->display_idx >= 0 && + ctx->display_idx < ctx->num_internal_frames) + ctx->sequence_offset++; /* no frame was decoded, we still return remaining buffers */ } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { v4l2_err(&dev->v4l2_dev, "decoded frame index out of range: %d\n", decoded_idx); } else { - val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; + decoded_frame = &ctx->internal_frames[decoded_idx]; + + val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM); + if (ctx->sequence_offset == -1) + ctx->sequence_offset = val; val -= ctx->sequence_offset; spin_lock(&ctx->buffer_meta_lock); if (!list_empty(&ctx->buffer_meta_list)) { @@ -2173,28 +2414,26 @@ static void coda_finish_decode(struct coda_ctx *ctx) val, ctx->sequence_offset, meta->sequence); } - ctx->frame_metas[decoded_idx] = *meta; + decoded_frame->meta = *meta; kfree(meta); } else { spin_unlock(&ctx->buffer_meta_lock); v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n"); - memset(&ctx->frame_metas[decoded_idx], 0, + memset(&decoded_frame->meta, 0, sizeof(struct coda_buffer_meta)); - ctx->frame_metas[decoded_idx].sequence = val; + decoded_frame->meta.sequence = val; + decoded_frame->meta.last = false; ctx->sequence_offset++; } - trace_coda_dec_pic_done(ctx, &ctx->frame_metas[decoded_idx]); + trace_coda_dec_pic_done(ctx, &decoded_frame->meta); val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; - if (val == 0) - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME; - else if (val == 1) - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME; - else - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME; + decoded_frame->type = (val == 0) ? V4L2_BUF_FLAG_KEYFRAME : + (val == 1) ? V4L2_BUF_FLAG_PFRAME : + V4L2_BUF_FLAG_BFRAME; - ctx->frame_errors[decoded_idx] = err_mb; + decoded_frame->error = err_mb; } if (display_idx == -1) { @@ -2214,6 +2453,10 @@ static void coda_finish_decode(struct coda_ctx *ctx) /* If a frame was copied out, return it */ if (ctx->display_idx >= 0 && ctx->display_idx < ctx->num_internal_frames) { + struct coda_internal_frame *ready_frame; + + ready_frame = &ctx->internal_frames[ctx->display_idx]; + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); dst_buf->sequence = ctx->osequence++; @@ -2221,8 +2464,25 @@ static void coda_finish_decode(struct coda_ctx *ctx) dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME); - dst_buf->flags |= ctx->frame_types[ctx->display_idx]; - meta = &ctx->frame_metas[ctx->display_idx]; + dst_buf->flags |= ready_frame->type; + meta = &ready_frame->meta; + if (meta->last && !coda_reorder_enable(ctx)) { + /* + * If this was the last decoded frame, and reordering + * is disabled, this will be the last display frame. + */ + coda_dbg(1, ctx, "last meta, marking as last frame\n"); + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + } else if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG && + display_idx == -1) { + /* + * If there is no designated presentation frame anymore, + * this frame has to be the last one. + */ + coda_dbg(1, ctx, + "no more frames to return, marking as last frame\n"); + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + } dst_buf->timecode = meta->timecode; dst_buf->vb2_buf.timestamp = meta->timestamp; @@ -2231,18 +2491,39 @@ static void coda_finish_decode(struct coda_ctx *ctx) vb2_set_plane_payload(&dst_buf->vb2_buf, 0, q_data_dst->sizeimage); - if (ctx->frame_errors[ctx->display_idx] || err_vdoa) + if (ready_frame->error || err_vdoa) coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR); else coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); - coda_dbg(1, ctx, "job finished: decoded %c frame (%u/%u)\n", - (dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : - ((dst_buf->flags & V4L2_BUF_FLAG_PFRAME) ? 'P' : 'B'), - dst_buf->sequence, ctx->qsequence); + if (decoded_frame) { + coda_dbg(1, ctx, "job finished: decoded %c frame %u, returned %c frame %u (%u/%u)%s\n", + coda_frame_type_char(decoded_frame->type), + decoded_frame->meta.sequence, + coda_frame_type_char(dst_buf->flags), + ready_frame->meta.sequence, + dst_buf->sequence, ctx->qsequence, + (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? + " (last)" : ""); + } else { + coda_dbg(1, ctx, "job finished: no frame decoded (%d), returned %c frame %u (%u/%u)%s\n", + decoded_idx, + coda_frame_type_char(dst_buf->flags), + ready_frame->meta.sequence, + dst_buf->sequence, ctx->qsequence, + (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? + " (last)" : ""); + } } else { - coda_dbg(1, ctx, "job finished: no frame decoded (%u/%u)\n", - ctx->osequence, ctx->qsequence); + if (decoded_frame) { + coda_dbg(1, ctx, "job finished: decoded %c frame %u, no frame returned (%d)\n", + coda_frame_type_char(decoded_frame->type), + decoded_frame->meta.sequence, + ctx->display_idx); + } else { + coda_dbg(1, ctx, "job finished: no frame decoded (%d) or returned (%d)\n", + decoded_idx, ctx->display_idx); + } } /* The rotator will copy the current display frame next time */ @@ -2286,6 +2567,7 @@ const struct coda_context_ops coda_bit_decode_ops = { .prepare_run = coda_prepare_decode, .finish_run = coda_finish_decode, .run_timeout = coda_decode_timeout, + .seq_init_work = coda_dec_seq_init_work, .seq_end_work = coda_seq_end_work, .release = coda_bit_release, }; @@ -2297,6 +2579,7 @@ irqreturn_t coda_irq_handler(int irq, void *data) /* read status register to attend the IRQ */ coda_read(dev, CODA_REG_BIT_INT_STATUS); + coda_write(dev, 0, CODA_REG_BIT_INT_REASON); coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET, CODA_REG_BIT_INT_CLEAR); @@ -2304,7 +2587,6 @@ irqreturn_t coda_irq_handler(int irq, void *data) if (ctx == NULL) { v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n"); - mutex_unlock(&dev->coda_mutex); return IRQ_HANDLED; } diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 6238047273f2..01428de2596e 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -74,7 +74,7 @@ MODULE_PARM_DESC(enable_bwb, "Enable BWB unit for decoding, may crash on certain void coda_write(struct coda_dev *dev, u32 data, u32 reg) { - v4l2_dbg(2, coda_debug, &dev->v4l2_dev, + v4l2_dbg(3, coda_debug, &dev->v4l2_dev, "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); writel(data, dev->regs_base + reg); } @@ -84,7 +84,7 @@ unsigned int coda_read(struct coda_dev *dev, u32 reg) u32 data; data = readl(dev->regs_base + reg); - v4l2_dbg(2, coda_debug, &dev->v4l2_dev, + v4l2_dbg(3, coda_debug, &dev->v4l2_dev, "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); return data; } @@ -879,14 +879,25 @@ static int coda_qbuf(struct file *file, void *priv, { struct coda_ctx *ctx = fh_to_ctx(priv); + if (ctx->inst_type == CODA_INST_DECODER && + buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + buf->flags &= ~V4L2_BUF_FLAG_LAST; + return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf); } -static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx, - struct vb2_v4l2_buffer *buf) +static int coda_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) && - (buf->sequence == (ctx->qsequence - 1))); + struct coda_ctx *ctx = fh_to_ctx(priv); + int ret; + + ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf); + + if (ctx->inst_type == CODA_INST_DECODER && + buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + buf->flags &= ~V4L2_BUF_FLAG_LAST; + + return ret; } void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, @@ -896,11 +907,8 @@ void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, .type = V4L2_EVENT_EOS }; - if (coda_buf_is_end_of_stream(ctx, buf)) { - buf->flags |= V4L2_BUF_FLAG_LAST; - + if (buf->flags & V4L2_BUF_FLAG_LAST) v4l2_event_queue_fh(&ctx->fh, &eos_event); - } v4l2_m2m_buf_done(buf, state); } @@ -1001,36 +1009,52 @@ static int coda_try_encoder_cmd(struct file *file, void *fh, if (ctx->inst_type != CODA_INST_ENCODER) return -ENOTTY; - if (ec->cmd != V4L2_ENC_CMD_STOP) - return -EINVAL; + return v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); +} - if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END) - return -EINVAL; +static void coda_wake_up_capture_queue(struct coda_ctx *ctx) +{ + struct vb2_queue *dst_vq; - return 0; + coda_dbg(1, ctx, "waking up capture queue\n"); + + dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_vq->last_buffer_dequeued = true; + wake_up(&dst_vq->done_wq); } static int coda_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec) { struct coda_ctx *ctx = fh_to_ctx(fh); - struct vb2_queue *dst_vq; + struct vb2_v4l2_buffer *buf; int ret; ret = coda_try_encoder_cmd(file, fh, ec); if (ret < 0) return ret; - /* Set the stream-end flag on this context */ - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + mutex_lock(&ctx->wakeup_mutex); + buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); + if (buf) { + /* + * If the last output buffer is still on the queue, make sure + * that decoder finish_run will see the last flag and report it + * to userspace. + */ + buf->flags |= V4L2_BUF_FLAG_LAST; + } else { + /* Set the stream-end flag on this context */ + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - /* If there is no buffer in flight, wake up */ - if (!ctx->streamon_out || ctx->qsequence == ctx->osequence) { - dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_vq->last_buffer_dequeued = true; - wake_up(&dst_vq->done_wq); + /* + * If the last output buffer has already been taken from the + * queue, wake up the capture queue and signal end of stream + * via the -EPIPE mechanism. + */ + coda_wake_up_capture_queue(ctx); } + mutex_unlock(&ctx->wakeup_mutex); return 0; } @@ -1043,32 +1067,89 @@ static int coda_try_decoder_cmd(struct file *file, void *fh, if (ctx->inst_type != CODA_INST_DECODER) return -ENOTTY; - if (dc->cmd != V4L2_DEC_CMD_STOP) - return -EINVAL; - - if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK) - return -EINVAL; - - if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0)) - return -EINVAL; - - return 0; + return v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); } static int coda_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) { struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_dev *dev = ctx->dev; + struct vb2_v4l2_buffer *buf; + struct vb2_queue *dst_vq; + bool stream_end; + bool wakeup; int ret; ret = coda_try_decoder_cmd(file, fh, dc); if (ret < 0) return ret; - /* Set the stream-end flag on this context */ - coda_bit_stream_end_flag(ctx); - ctx->hold = false; - v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); + switch (dc->cmd) { + case V4L2_DEC_CMD_START: + mutex_lock(&ctx->bitstream_mutex); + mutex_lock(&dev->coda_mutex); + coda_bitstream_flush(ctx); + mutex_unlock(&dev->coda_mutex); + dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + vb2_clear_last_buffer_dequeued(dst_vq); + ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG; + coda_fill_bitstream(ctx, NULL); + mutex_unlock(&ctx->bitstream_mutex); + break; + case V4L2_DEC_CMD_STOP: + stream_end = false; + wakeup = false; + + buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); + if (buf) { + coda_dbg(1, ctx, "marking last pending buffer\n"); + + /* Mark last buffer */ + buf->flags |= V4L2_BUF_FLAG_LAST; + + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) == 0) { + coda_dbg(1, ctx, "all remaining buffers queued\n"); + stream_end = true; + } + } else { + coda_dbg(1, ctx, "marking last meta\n"); + + /* Mark last meta */ + spin_lock(&ctx->buffer_meta_lock); + if (!list_empty(&ctx->buffer_meta_list)) { + struct coda_buffer_meta *meta; + + meta = list_last_entry(&ctx->buffer_meta_list, + struct coda_buffer_meta, + list); + meta->last = true; + stream_end = true; + } else { + wakeup = true; + } + spin_unlock(&ctx->buffer_meta_lock); + } + + if (stream_end) { + coda_dbg(1, ctx, "all remaining buffers queued\n"); + + /* Set the stream-end flag on this context */ + coda_bit_stream_end_flag(ctx); + ctx->hold = false; + v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); + } + + if (wakeup) { + /* If there is no buffer in flight, wake up */ + coda_wake_up_capture_queue(ctx); + } + + break; + default: + return -EINVAL; + } return 0; } @@ -1236,6 +1317,7 @@ static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) tpf = &a->parm.output.timeperframe; coda_approximate_timeperframe(tpf); ctx->params.framerate = coda_timeperframe_to_frate(tpf); + ctx->params.framerate_changed = true; return 0; } @@ -1243,9 +1325,16 @@ static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) static int coda_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { + struct coda_ctx *ctx = fh_to_ctx(fh); + switch (sub->type) { case V4L2_EVENT_EOS: return v4l2_event_subscribe(fh, sub, 0, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + if (ctx->inst_type == CODA_INST_DECODER) + return v4l2_event_subscribe(fh, sub, 0, NULL); + else + return -EINVAL; default: return v4l2_ctrl_subscribe_event(fh, sub); } @@ -1269,7 +1358,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_qbuf = coda_qbuf, .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, - .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_dqbuf = coda_dqbuf, .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, @@ -1325,7 +1414,7 @@ static void coda_pic_run_work(struct work_struct *work) if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) { - dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n"); + dev_err(dev->dev, "CODA PIC_RUN timeout\n"); ctx->hold = true; @@ -1412,7 +1501,7 @@ static int coda_job_ready(void *m2m_priv) return 0; } - coda_dbg(1, ctx, "job ready\n"); + coda_dbg(2, ctx, "job ready\n"); return 1; } @@ -1563,42 +1652,81 @@ static void coda_update_menu_ctrl(struct v4l2_ctrl *ctrl, int value) v4l2_ctrl_unlock(ctrl); } -static void coda_update_h264_profile_ctrl(struct coda_ctx *ctx) +void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, + u8 level_idc) { const char * const *profile_names; + const char * const *level_names; + struct v4l2_ctrl *profile_ctrl; + struct v4l2_ctrl *level_ctrl; + const char *codec_name; + u32 profile_cid; + u32 level_cid; int profile; + int level; - profile = coda_h264_profile(ctx->params.h264_profile_idc); - if (profile < 0) { - v4l2_warn(&ctx->dev->v4l2_dev, "Invalid H264 Profile: %u\n", - ctx->params.h264_profile_idc); + switch (ctx->codec->src_fourcc) { + case V4L2_PIX_FMT_H264: + codec_name = "H264"; + profile_cid = V4L2_CID_MPEG_VIDEO_H264_PROFILE; + level_cid = V4L2_CID_MPEG_VIDEO_H264_LEVEL; + profile_ctrl = ctx->h264_profile_ctrl; + level_ctrl = ctx->h264_level_ctrl; + profile = coda_h264_profile(profile_idc); + level = coda_h264_level(level_idc); + break; + case V4L2_PIX_FMT_MPEG2: + codec_name = "MPEG-2"; + profile_cid = V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE; + level_cid = V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL; + profile_ctrl = ctx->mpeg2_profile_ctrl; + level_ctrl = ctx->mpeg2_level_ctrl; + profile = coda_mpeg2_profile(profile_idc); + level = coda_mpeg2_level(level_idc); + break; + case V4L2_PIX_FMT_MPEG4: + codec_name = "MPEG-4"; + profile_cid = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE; + level_cid = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL; + profile_ctrl = ctx->mpeg4_profile_ctrl; + level_ctrl = ctx->mpeg4_level_ctrl; + profile = coda_mpeg4_profile(profile_idc); + level = coda_mpeg4_level(level_idc); + break; + default: return; } - coda_update_menu_ctrl(ctx->h264_profile_ctrl, profile); - - profile_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_PROFILE); - - coda_dbg(1, ctx, "Parsed H264 Profile: %s\n", profile_names[profile]); -} + profile_names = v4l2_ctrl_get_menu(profile_cid); + level_names = v4l2_ctrl_get_menu(level_cid); -static void coda_update_h264_level_ctrl(struct coda_ctx *ctx) -{ - const char * const *level_names; - int level; + if (profile < 0) { + v4l2_warn(&ctx->dev->v4l2_dev, "Invalid %s profile: %u\n", + codec_name, profile_idc); + } else { + coda_dbg(1, ctx, "Parsed %s profile: %s\n", codec_name, + profile_names[profile]); + coda_update_menu_ctrl(profile_ctrl, profile); + } - level = coda_h264_level(ctx->params.h264_level_idc); if (level < 0) { - v4l2_warn(&ctx->dev->v4l2_dev, "Invalid H264 Level: %u\n", - ctx->params.h264_level_idc); - return; + v4l2_warn(&ctx->dev->v4l2_dev, "Invalid %s level: %u\n", + codec_name, level_idc); + } else { + coda_dbg(1, ctx, "Parsed %s level: %s\n", codec_name, + level_names[level]); + coda_update_menu_ctrl(level_ctrl, level); } +} - coda_update_menu_ctrl(ctx->h264_level_ctrl, level); - - level_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL); +static void coda_queue_source_change_event(struct coda_ctx *ctx) +{ + static const struct v4l2_event source_change_event = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; - coda_dbg(1, ctx, "Parsed H264 Level: %s\n", level_names[level]); + v4l2_event_queue_fh(&ctx->fh, &source_change_event); } static void coda_buf_queue(struct vb2_buffer *vb) @@ -1631,8 +1759,9 @@ static void coda_buf_queue(struct vb2_buffer *vb) */ if (!ctx->params.h264_profile_idc) { coda_sps_parse_profile(ctx, vb); - coda_update_h264_profile_ctrl(ctx); - coda_update_h264_level_ctrl(ctx); + coda_update_profile_level_ctrls(ctx, + ctx->params.h264_profile_idc, + ctx->params.h264_level_idc); } } @@ -1642,6 +1771,22 @@ static void coda_buf_queue(struct vb2_buffer *vb) /* This set buf->sequence = ctx->qsequence++ */ coda_fill_bitstream(ctx, NULL); mutex_unlock(&ctx->bitstream_mutex); + + if (!ctx->initialized) { + /* + * Run sequence initialization in case the queued + * buffer contained headers. + */ + if (vb2_is_streaming(vb->vb2_queue) && + ctx->ops->seq_init_work) { + queue_work(ctx->dev->workqueue, + &ctx->seq_init_work); + flush_work(&ctx->seq_init_work); + } + + if (ctx->initialized) + coda_queue_source_change_event(ctx); + } } else { if (ctx->inst_type == CODA_INST_ENCODER && vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -1653,7 +1798,7 @@ static void coda_buf_queue(struct vb2_buffer *vb) int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, size_t size, const char *name, struct dentry *parent) { - buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr, + buf->vaddr = dma_alloc_coherent(dev->dev, size, &buf->paddr, GFP_KERNEL); if (!buf->vaddr) { v4l2_err(&dev->v4l2_dev, @@ -1670,7 +1815,7 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, buf->dentry = debugfs_create_blob(name, 0644, parent, &buf->blob); if (!buf->dentry) - dev_warn(&dev->plat_dev->dev, + dev_warn(dev->dev, "failed to create debugfs entry %s\n", name); } @@ -1681,8 +1826,7 @@ void coda_free_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf) { if (buf->vaddr) { - dma_free_coherent(&dev->plat_dev->dev, buf->size, - buf->vaddr, buf->paddr); + dma_free_coherent(dev->dev, buf->size, buf->vaddr, buf->paddr); buf->vaddr = NULL; buf->size = 0; debugfs_remove(buf->dentry); @@ -1715,10 +1859,21 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) coda_fill_bitstream(ctx, &list); mutex_unlock(&ctx->bitstream_mutex); - if (coda_get_bitstream_payload(ctx) < 512) { + if (ctx->dev->devtype->product != CODA_960 && + coda_get_bitstream_payload(ctx) < 512) { + v4l2_err(v4l2_dev, "start payload < 512\n"); ret = -EINVAL; goto err; } + + if (!ctx->initialized) { + /* Run sequence initialization */ + if (ctx->ops->seq_init_work) { + queue_work(ctx->dev->workqueue, + &ctx->seq_init_work); + flush_work(&ctx->seq_init_work); + } + } } ctx->streamon_out = 1; @@ -1853,11 +2008,16 @@ static const struct vb2_ops coda_qops = { static int coda_s_ctrl(struct v4l2_ctrl *ctrl) { + const char * const *val_names = v4l2_ctrl_get_menu(ctrl->id); struct coda_ctx *ctx = container_of(ctrl->handler, struct coda_ctx, ctrls); - coda_dbg(1, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n", - ctrl->id, ctrl->name, ctrl->val); + if (val_names) + coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d (\"%s\")\n", + ctrl->id, ctrl->name, ctrl->val, val_names[ctrl->val]); + else + coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n", + ctrl->id, ctrl->name, ctrl->val); switch (ctrl->id) { case V4L2_CID_HFLIP: @@ -1874,12 +2034,14 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_MPEG_VIDEO_BITRATE: ctx->params.bitrate = ctrl->val / 1000; + ctx->params.bitrate_changed = true; break; case V4L2_CID_MPEG_VIDEO_GOP_SIZE: ctx->params.gop_size = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: ctx->params.h264_intra_qp = ctrl->val; + ctx->params.h264_intra_qp_changed = true; break; case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: ctx->params.h264_inter_qp = ctrl->val; @@ -1919,23 +2081,29 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: ctx->params.mpeg4_inter_qp = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: + case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: /* nothing to do, these are fixed */ break; case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: ctx->params.slice_mode = ctrl->val; + ctx->params.slice_mode_changed = true; break; case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: ctx->params.slice_max_mb = ctrl->val; + ctx->params.slice_mode_changed = true; break; case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: ctx->params.slice_max_bits = ctrl->val * 8; + ctx->params.slice_mode_changed = true; break; case V4L2_CID_MPEG_VIDEO_HEADER_MODE: break; case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: ctx->params.intra_refresh = ctrl->val; + ctx->params.intra_refresh_changed = true; break; case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: ctx->params.force_ipicture = true; @@ -2040,7 +2208,7 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) } v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, - V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, 0x0, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, 0x0, V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1); @@ -2098,6 +2266,34 @@ static void coda_decode_ctrls(struct coda_ctx *ctx) &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, max, 0, max); if (ctx->h264_level_ctrl) ctx->h264_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctx->mpeg2_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE, + V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH, 0, + V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH); + if (ctx->mpeg2_profile_ctrl) + ctx->mpeg2_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctx->mpeg2_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL, + V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH, 0, + V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH); + if (ctx->mpeg2_level_ctrl) + ctx->mpeg2_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctx->mpeg4_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, + V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY, 0, + V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY); + if (ctx->mpeg4_profile_ctrl) + ctx->mpeg4_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctx->mpeg4_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, + V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, 0, + V4L2_MPEG_VIDEO_MPEG4_LEVEL_5); + if (ctx->mpeg4_level_ctrl) + ctx->mpeg4_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; } static int coda_ctrls_setup(struct coda_ctx *ctx) @@ -2154,7 +2350,7 @@ static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) * queues to have at least one buffer queued. */ vq->min_buffers_needed = 1; - vq->dev = &ctx->dev->plat_dev->dev; + vq->dev = ctx->dev->dev; return vb2_queue_init(vq); } @@ -2240,6 +2436,8 @@ static int coda_open(struct file *file) ctx->use_bit = !ctx->cvd->direct; init_completion(&ctx->completion); INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); + if (ctx->ops->seq_init_work) + INIT_WORK(&ctx->seq_init_work, ctx->ops->seq_init_work); if (ctx->ops->seq_end_work) INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work); v4l2_fh_init(&ctx->fh, video_devdata(file)); @@ -2277,7 +2475,7 @@ static int coda_open(struct file *file) ctx->use_vdoa = false; /* Power up and upload firmware if necessary */ - ret = pm_runtime_get_sync(&dev->plat_dev->dev); + ret = pm_runtime_get_sync(dev->dev); if (ret < 0) { v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret); goto err_pm_get; @@ -2312,6 +2510,7 @@ static int coda_open(struct file *file) mutex_init(&ctx->bitstream_mutex); mutex_init(&ctx->buffer_mutex); + mutex_init(&ctx->wakeup_mutex); INIT_LIST_HEAD(&ctx->buffer_meta_list); spin_lock_init(&ctx->buffer_meta_lock); @@ -2324,7 +2523,7 @@ err_ctx_init: err_clk_ahb: clk_disable_unprepare(dev->clk_per); err_clk_per: - pm_runtime_put_sync(&dev->plat_dev->dev); + pm_runtime_put_sync(dev->dev); err_pm_get: v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); @@ -2363,7 +2562,7 @@ static int coda_release(struct file *file) v4l2_ctrl_handler_free(&ctx->ctrls); clk_disable_unprepare(dev->clk_ahb); clk_disable_unprepare(dev->clk_per); - pm_runtime_put_sync(&dev->plat_dev->dev); + pm_runtime_put_sync(dev->dev); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); ida_free(&dev->ida, ctx->idx); @@ -2486,9 +2685,12 @@ err_clk_per: static int coda_register_device(struct coda_dev *dev, int i) { struct video_device *vfd = &dev->vfd[i]; + enum coda_inst_type type; + int ret; if (i >= dev->devtype->num_vdevs) return -EINVAL; + type = dev->devtype->vdevs[i]->type; strscpy(vfd->name, dev->devtype->vdevs[i]->name, sizeof(vfd->name)); vfd->fops = &coda_fops; @@ -2504,7 +2706,12 @@ static int coda_register_device(struct coda_dev *dev, int i) v4l2_disable_ioctl(vfd, VIDIOC_G_CROP); v4l2_disable_ioctl(vfd, VIDIOC_S_CROP); - return video_register_device(vfd, VFL_TYPE_GRABBER, 0); + ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); + if (!ret) + v4l2_info(&dev->v4l2_dev, "%s registered as %s\n", + type == CODA_INST_ENCODER ? "encoder" : "decoder", + video_device_node_name(vfd)); + return ret; } static void coda_copy_firmware(struct coda_dev *dev, const u8 * const buf, @@ -2550,18 +2757,16 @@ static int coda_firmware_request(struct coda_dev *dev) fw = dev->devtype->firmware[dev->firmware]; - dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw, + dev_dbg(dev->dev, "requesting firmware '%s' for %s\n", fw, coda_product_name(dev->devtype->product)); - return request_firmware_nowait(THIS_MODULE, true, fw, - &dev->plat_dev->dev, GFP_KERNEL, dev, - coda_fw_callback); + return request_firmware_nowait(THIS_MODULE, true, fw, dev->dev, + GFP_KERNEL, dev, coda_fw_callback); } static void coda_fw_callback(const struct firmware *fw, void *context) { struct coda_dev *dev = context; - struct platform_device *pdev = dev->plat_dev; int i, ret; if (!fw) { @@ -2579,7 +2784,7 @@ static void coda_fw_callback(const struct firmware *fw, void *context) * firmware requests, report that the fallback firmware was * found. */ - dev_info(&pdev->dev, "Using fallback firmware %s\n", + dev_info(dev->dev, "Using fallback firmware %s\n", dev->devtype->firmware[dev->firmware]); } @@ -2618,10 +2823,7 @@ static void coda_fw_callback(const struct firmware *fw, void *context) } } - v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n", - dev->vfd[0].num, dev->vfd[i - 1].num); - - pm_runtime_put_sync(&pdev->dev); + pm_runtime_put_sync(dev->dev); return; rel_vfd: @@ -2629,7 +2831,7 @@ rel_vfd: video_unregister_device(&dev->vfd[i]); v4l2_m2m_release(dev->m2m_dev); put_pm: - pm_runtime_put_sync(&pdev->dev); + pm_runtime_put_sync(dev->dev); } enum coda_platform { @@ -2744,7 +2946,6 @@ static int coda_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct gen_pool *pool; struct coda_dev *dev; - struct resource *res; int ret, irq; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); @@ -2762,7 +2963,7 @@ static int coda_probe(struct platform_device *pdev) spin_lock_init(&dev->irqlock); - dev->plat_dev = pdev; + dev->dev = &pdev->dev; dev->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(dev->clk_per)) { dev_err(&pdev->dev, "Could not get per clock\n"); @@ -2776,8 +2977,7 @@ static int coda_probe(struct platform_device *pdev) } /* Get memory for physical registers */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->regs_base = devm_ioremap_resource(&pdev->dev, res); + dev->regs_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dev->regs_base)) return PTR_ERR(dev->regs_base); @@ -2790,8 +2990,8 @@ static int coda_probe(struct platform_device *pdev) return irq; } - ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler, - IRQF_ONESHOT, dev_name(&pdev->dev), dev); + ret = devm_request_irq(&pdev->dev, irq, coda_irq_handler, 0, + dev_name(&pdev->dev), dev); if (ret < 0) { dev_err(&pdev->dev, "failed to request irq: %d\n", ret); return ret; diff --git a/drivers/media/platform/coda/coda-h264.c b/drivers/media/platform/coda/coda-h264.c index a2fa29da1d31..8bd0aa8af114 100644 --- a/drivers/media/platform/coda/coda-h264.c +++ b/drivers/media/platform/coda/coda-h264.c @@ -10,7 +10,8 @@ #include <linux/kernel.h> #include <linux/string.h> #include <linux/videodev2.h> -#include <coda.h> + +#include "coda.h" static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; diff --git a/drivers/media/platform/coda/coda-mpeg2.c b/drivers/media/platform/coda/coda-mpeg2.c new file mode 100644 index 000000000000..6f3f6721d286 --- /dev/null +++ b/drivers/media/platform/coda/coda-mpeg2.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Coda multi-standard codec IP - MPEG-2 helper functions + * + * Copyright (C) 2019 Pengutronix, Philipp Zabel + */ + +#include <linux/kernel.h> +#include <linux/videodev2.h> +#include "coda.h" + +int coda_mpeg2_profile(int profile_idc) +{ + switch (profile_idc) { + case 5: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SIMPLE; + case 4: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN; + case 3: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SNR_SCALABLE; + case 2: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SPATIALLY_SCALABLE; + case 1: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH; + default: + return -EINVAL; + } +} + +int coda_mpeg2_level(int level_idc) +{ + switch (level_idc) { + case 10: + return V4L2_MPEG_VIDEO_MPEG2_LEVEL_LOW; + case 8: + return V4L2_MPEG_VIDEO_MPEG2_LEVEL_MAIN; + case 6: + return V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH_1440; + case 4: + return V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH; + default: + return -EINVAL; + } +} + +/* + * Check if the buffer starts with the MPEG-2 sequence header (with or without + * quantization matrix) and extension header, for example: + * + * 00 00 01 b3 2d 01 e0 34 08 8b a3 81 + * 10 11 11 12 12 12 13 13 13 13 14 14 14 14 14 15 + * 15 15 15 15 15 16 16 16 16 16 16 16 17 17 17 17 + * 17 17 17 17 18 18 18 19 18 18 18 19 1a 1a 1a 1a + * 19 1b 1b 1b 1b 1b 1c 1c 1c 1c 1e 1e 1e 1f 1f 21 + * 00 00 01 b5 14 8a 00 01 00 00 + * + * or: + * + * 00 00 01 b3 08 00 40 15 ff ff e0 28 + * 00 00 01 b5 14 8a 00 01 00 00 + * + * Returns the detected header size in bytes or 0. + */ +u32 coda_mpeg2_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size) +{ + static const u8 sequence_header_start[4] = { 0x00, 0x00, 0x01, 0xb3 }; + static const union { + u8 extension_start[4]; + u8 start_code_prefix[3]; + } u = { { 0x00, 0x00, 0x01, 0xb5 } }; + + if (size < 22 || + memcmp(buf, sequence_header_start, 4) != 0) + return 0; + + if ((size == 22 || + (size >= 25 && memcmp(buf + 22, u.start_code_prefix, 3) == 0)) && + memcmp(buf + 12, u.extension_start, 4) == 0) + return 22; + + if ((size == 86 || + (size > 89 && memcmp(buf + 86, u.start_code_prefix, 3) == 0)) && + memcmp(buf + 76, u.extension_start, 4) == 0) + return 86; + + return 0; +} diff --git a/drivers/media/platform/coda/coda-mpeg4.c b/drivers/media/platform/coda/coda-mpeg4.c new file mode 100644 index 000000000000..483a4fba1b4f --- /dev/null +++ b/drivers/media/platform/coda/coda-mpeg4.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Coda multi-standard codec IP - MPEG-4 helper functions + * + * Copyright (C) 2019 Pengutronix, Philipp Zabel + */ + +#include <linux/kernel.h> +#include <linux/videodev2.h> + +#include "coda.h" + +int coda_mpeg4_profile(int profile_idc) +{ + switch (profile_idc) { + case 0: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE; + case 15: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE; + case 2: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE; + case 1: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE; + case 11: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY; + default: + return -EINVAL; + } +} + +int coda_mpeg4_level(int level_idc) +{ + switch (level_idc) { + case 0: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_0; + case 1: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_1; + case 2: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_2; + case 3: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_3; + case 4: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_4; + case 5: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_5; + default: + return -EINVAL; + } +} + +/* + * Check if the buffer starts with the MPEG-4 visual object sequence and visual + * object headers, for example: + * + * 00 00 01 b0 f1 + * 00 00 01 b5 a9 13 00 00 01 00 00 00 01 20 08 + * d4 8d 88 00 f5 04 04 08 14 30 3f + * + * Returns the detected header size in bytes or 0. + */ +u32 coda_mpeg4_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size) +{ + static const u8 vos_start[4] = { 0x00, 0x00, 0x01, 0xb0 }; + static const union { + u8 vo_start[4]; + u8 start_code_prefix[3]; + } u = { { 0x00, 0x00, 0x01, 0xb5 } }; + + if (size < 30 || + memcmp(buf, vos_start, 4) != 0 || + memcmp(buf + 5, u.vo_start, 4) != 0) + return 0; + + if (size == 30 || + (size >= 33 && memcmp(buf + 30, u.start_code_prefix, 3) == 0)) + return 30; + + if (size == 31 || + (size >= 34 && memcmp(buf + 31, u.start_code_prefix, 3) == 0)) + return 31; + + if (size == 32 || + (size >= 35 && memcmp(buf + 32, u.start_code_prefix, 3) == 0)) + return 32; + + return 0; +} diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index cfcfff7838cd..848bf1da401e 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -70,7 +70,7 @@ struct coda_aux_buf { struct coda_dev { struct v4l2_device v4l2_dev; struct video_device vfd[5]; - struct platform_device *plat_dev; + struct device *dev; const struct coda_devtype *devtype; int firmware; struct vdoa_data *vdoa; @@ -118,6 +118,8 @@ struct coda_params { s8 h264_chroma_qp_index_offset; u8 h264_profile_idc; u8 h264_level_idc; + u8 mpeg2_profile_idc; + u8 mpeg2_level_idc; u8 mpeg4_intra_qp; u8 mpeg4_inter_qp; u8 gop_size; @@ -135,6 +137,12 @@ struct coda_params { u32 slice_max_bits; u32 slice_max_mb; bool force_ipicture; + bool gop_size_changed; + bool bitrate_changed; + bool framerate_changed; + bool h264_intra_qp_changed; + bool intra_refresh_changed; + bool slice_mode_changed; }; struct coda_buffer_meta { @@ -144,6 +152,7 @@ struct coda_buffer_meta { u64 timestamp; unsigned int start; unsigned int end; + bool last; }; /* Per-queue, driver-specific private data */ @@ -183,14 +192,23 @@ struct coda_context_ops { int (*prepare_run)(struct coda_ctx *ctx); void (*finish_run)(struct coda_ctx *ctx); void (*run_timeout)(struct coda_ctx *ctx); + void (*seq_init_work)(struct work_struct *work); void (*seq_end_work)(struct work_struct *work); void (*release)(struct coda_ctx *ctx); }; +struct coda_internal_frame { + struct coda_aux_buf buf; + struct coda_buffer_meta meta; + u32 type; + u32 error; +}; + struct coda_ctx { struct coda_dev *dev; struct mutex buffer_mutex; struct work_struct pic_run_work; + struct work_struct seq_init_work; struct work_struct seq_end_work; struct completion completion; const struct coda_video_device *cvd; @@ -213,6 +231,10 @@ struct coda_ctx { struct v4l2_ctrl_handler ctrls; struct v4l2_ctrl *h264_profile_ctrl; struct v4l2_ctrl *h264_level_ctrl; + struct v4l2_ctrl *mpeg2_profile_ctrl; + struct v4l2_ctrl *mpeg2_level_ctrl; + struct v4l2_ctrl *mpeg4_profile_ctrl; + struct v4l2_ctrl *mpeg4_level_ctrl; struct v4l2_fh fh; int gopcounter; int runcounter; @@ -225,10 +247,7 @@ struct coda_ctx { struct coda_aux_buf parabuf; struct coda_aux_buf psbuf; struct coda_aux_buf slicebuf; - struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS]; - u32 frame_types[CODA_MAX_FRAMEBUFFERS]; - struct coda_buffer_meta frame_metas[CODA_MAX_FRAMEBUFFERS]; - u32 frame_errors[CODA_MAX_FRAMEBUFFERS]; + struct coda_internal_frame internal_frames[CODA_MAX_FRAMEBUFFERS]; struct list_head buffer_meta_list; spinlock_t buffer_meta_lock; int num_metas; @@ -241,11 +260,18 @@ struct coda_ctx { u32 bit_stream_param; u32 frm_dis_flg; u32 frame_mem_ctrl; + u32 para_change; int display_idx; struct dentry *debugfs_entry; bool use_bit; bool use_vdoa; struct vdoa_ctx *vdoa; + /* + * wakeup mutex used to serialize encoder stop command and finish_run, + * ensures that finish_run always either flags the last returned buffer + * or wakes up the capture queue to signal EOS afterwards. + */ + struct mutex wakeup_mutex; }; extern int coda_debug; @@ -310,6 +336,7 @@ static inline bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx, } bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx, unsigned int pos); +int coda_bitstream_flush(struct coda_ctx *ctx); void coda_bit_stream_end_flag(struct coda_ctx *ctx); @@ -324,6 +351,16 @@ int coda_sps_parse_profile(struct coda_ctx *ctx, struct vb2_buffer *vb); int coda_h264_sps_fixup(struct coda_ctx *ctx, int width, int height, char *buf, int *size, int max_size); +int coda_mpeg2_profile(int profile_idc); +int coda_mpeg2_level(int level_idc); +u32 coda_mpeg2_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size); +int coda_mpeg4_profile(int profile_idc); +int coda_mpeg4_level(int level_idc); +u32 coda_mpeg4_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size); + +void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, + u8 level_idc); + bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb); int coda_jpeg_write_tables(struct coda_ctx *ctx); void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality); diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h index abf8e195f6c0..b17464b56d3d 100644 --- a/drivers/media/platform/coda/coda_regs.h +++ b/drivers/media/platform/coda/coda_regs.h @@ -177,7 +177,7 @@ #define CODA_RET_DEC_SEQ_FRATE_DR 0x1e8 #define CODA_RET_DEC_SEQ_JPG_PARA 0x1e4 #define CODA_RET_DEC_SEQ_JPG_THUMB_IND 0x1e8 -#define CODA9_RET_DEC_SEQ_HEADER_REPORT 0x1ec +#define CODA7_RET_DEC_SEQ_HEADER_REPORT 0x1ec /* Decoder Picture Run */ #define CODA_CMD_DEC_PIC_ROT_MODE 0x180 @@ -342,6 +342,24 @@ #define CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE 0x1a4 #define CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET 0x1a8 +/* Encoder Parameter Change */ +#define CODA_CMD_ENC_PARAM_CHANGE_ENABLE 0x180 +#define CODA_PARAM_CHANGE_RC_GOP BIT(0) +#define CODA_PARAM_CHANGE_RC_INTRA_QP BIT(1) +#define CODA_PARAM_CHANGE_RC_BITRATE BIT(2) +#define CODA_PARAM_CHANGE_RC_FRAME_RATE BIT(3) +#define CODA_PARAM_CHANGE_INTRA_MB_NUM BIT(4) +#define CODA_PARAM_CHANGE_SLICE_MODE BIT(5) +#define CODA_PARAM_CHANGE_HEC_MODE BIT(6) +#define CODA_CMD_ENC_PARAM_RC_GOP 0x184 +#define CODA_CMD_ENC_PARAM_RC_INTRA_QP 0x188 +#define CODA_CMD_ENC_PARAM_RC_BITRATE 0x18c +#define CODA_CMD_ENC_PARAM_RC_FRAME_RATE 0x190 +#define CODA_CMD_ENC_PARAM_INTRA_MB_NUM 0x194 +#define CODA_CMD_ENC_PARAM_SLICE_MODE 0x198 +#define CODA_CMD_ENC_PARAM_HEC_MODE 0x19c +#define CODA_RET_ENC_PARAM_CHANGE_SUCCESS 0x1c0 + /* Encoder Picture Run */ #define CODA9_CMD_ENC_PIC_SRC_INDEX 0x180 #define CODA9_CMD_ENC_PIC_SRC_STRIDE 0x184 diff --git a/drivers/media/platform/coda/trace.h b/drivers/media/platform/coda/trace.h index a672bfc4c6ba..6cf58237fff2 100644 --- a/drivers/media/platform/coda/trace.h +++ b/drivers/media/platform/coda/trace.h @@ -157,7 +157,7 @@ DEFINE_EVENT(coda_buf_meta_class, coda_dec_rot_done, #endif /* __CODA_TRACE_H__ */ #undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_PATH ../../drivers/media/platform/coda #undef TRACE_INCLUDE_FILE #define TRACE_INCLUDE_FILE trace diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 61809d2050fa..f0f7ef638c56 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1376,6 +1376,14 @@ vpif_init_free_channel_objects: return err; } +static inline void free_vpif_objs(void) +{ + int i; + + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) + kfree(vpif_obj.dev[i]); +} + static int vpif_async_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) @@ -1645,7 +1653,7 @@ static __init int vpif_probe(struct platform_device *pdev) err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); if (err) { v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); - goto cleanup; + goto vpif_free; } while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) { @@ -1692,7 +1700,9 @@ static __init int vpif_probe(struct platform_device *pdev) "registered sub device %s\n", subdevdata->name); } - vpif_probe_complete(); + err = vpif_probe_complete(); + if (err) + goto probe_subdev_out; } else { vpif_obj.notifier.ops = &vpif_async_ops; err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev, @@ -1711,6 +1721,8 @@ probe_subdev_out: kfree(vpif_obj.sd); vpif_unregister: v4l2_device_unregister(&vpif_obj.v4l2_dev); +vpif_free: + free_vpif_objs(); cleanup: v4l2_async_notifier_cleanup(&vpif_obj.notifier); diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c index 3f079ac1b080..d38d2bbb6f0f 100644 --- a/drivers/media/platform/davinci/vpss.c +++ b/drivers/media/platform/davinci/vpss.c @@ -498,9 +498,9 @@ static struct platform_driver vpss_driver = { static void vpss_exit(void) { + platform_driver_unregister(&vpss_driver); iounmap(oper_cfg.vpss_regs_base2); release_mem_region(VPSS_CLK_CTRL, 4); - platform_driver_unregister(&vpss_driver); } static int __init vpss_init(void) @@ -509,6 +509,11 @@ static int __init vpss_init(void) return -EBUSY; oper_cfg.vpss_regs_base2 = ioremap(VPSS_CLK_CTRL, 4); + if (unlikely(!oper_cfg.vpss_regs_base2)) { + release_mem_region(VPSS_CLK_CTRL, 4); + return -ENOMEM; + } + writel(VPSS_CLK_CTRL_VENCCLKEN | VPSS_CLK_CTRL_DACCLKEN, oper_cfg.vpss_regs_base2); diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index ea46d7387221..854869f0024e 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -327,7 +327,7 @@ void gsc_check_src_scale_info(struct gsc_variant *var, } } -int gsc_enum_fmt_mplane(struct v4l2_fmtdesc *f) +int gsc_enum_fmt(struct v4l2_fmtdesc *f) { const struct gsc_fmt *fmt; diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h index c81f0a17d286..772183b090c2 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/exynos-gsc/gsc-core.h @@ -1,12 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com * * header file for Samsung EXYNOS5 SoC series G-Scaler driver - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef GSC_CORE_H_ @@ -387,7 +385,7 @@ void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state); u32 get_plane_size(struct gsc_frame *fr, unsigned int plane); const struct gsc_fmt *get_format(int index); const struct gsc_fmt *find_fmt(u32 *pixelformat, u32 *mbus_code, u32 index); -int gsc_enum_fmt_mplane(struct v4l2_fmtdesc *f); +int gsc_enum_fmt(struct v4l2_fmtdesc *f); int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f); void gsc_set_frame_size(struct gsc_frame *frame, int width, int height); int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f); diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index 677d7cc80785..35a1d0d6dd66 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -294,15 +294,13 @@ static int gsc_m2m_querycap(struct file *file, void *fh, strscpy(cap->card, GSC_MODULE_NAME " gscaler", sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(&gsc->pdev->dev)); - cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } -static int gsc_m2m_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int gsc_m2m_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { - return gsc_enum_fmt_mplane(f); + return gsc_enum_fmt(f); } static int gsc_m2m_g_fmt_mplane(struct file *file, void *fh, @@ -558,8 +556,8 @@ static int gsc_m2m_s_selection(struct file *file, void *fh, static const struct v4l2_ioctl_ops gsc_m2m_ioctl_ops = { .vidioc_querycap = gsc_m2m_querycap, - .vidioc_enum_fmt_vid_cap_mplane = gsc_m2m_enum_fmt_mplane, - .vidioc_enum_fmt_vid_out_mplane = gsc_m2m_enum_fmt_mplane, + .vidioc_enum_fmt_vid_cap = gsc_m2m_enum_fmt, + .vidioc_enum_fmt_vid_out = gsc_m2m_enum_fmt, .vidioc_g_fmt_vid_cap_mplane = gsc_m2m_g_fmt_mplane, .vidioc_g_fmt_vid_out_mplane = gsc_m2m_g_fmt_mplane, .vidioc_try_fmt_vid_cap_mplane = gsc_m2m_try_fmt_mplane, @@ -759,6 +757,8 @@ int gsc_register_m2m_device(struct gsc_dev *gsc) gsc->vdev.lock = &gsc->lock; gsc->vdev.vfl_dir = VFL_DIR_M2M; gsc->vdev.v4l2_dev = &gsc->v4l2_dev; + gsc->vdev.device_caps = V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_M2M_MPLANE; snprintf(gsc->vdev.name, sizeof(gsc->vdev.name), "%s.%d:m2m", GSC_MODULE_NAME, gsc->id); diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.h b/drivers/media/platform/exynos-gsc/gsc-regs.h index 4678f9a6a4fd..d4f7ead6b322 100644 --- a/drivers/media/platform/exynos-gsc/gsc-regs.h +++ b/drivers/media/platform/exynos-gsc/gsc-regs.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Register definition file for Samsung G-Scaler driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef REGS_GSC_H_ diff --git a/drivers/media/platform/exynos4-is/common.c b/drivers/media/platform/exynos4-is/common.c index 76f557548dfc..944b224eb621 100644 --- a/drivers/media/platform/exynos4-is/common.c +++ b/drivers/media/platform/exynos4-is/common.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung S5P/EXYNOS4 SoC Camera Subsystem driver * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> @@ -37,15 +34,12 @@ struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity) } EXPORT_SYMBOL(fimc_find_remote_sensor); -void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap, - unsigned int caps) +void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap) { strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); strscpy(cap->card, dev->driver->name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(dev)); - cap->device_caps = caps; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; } EXPORT_SYMBOL(__fimc_vidioc_querycap); diff --git a/drivers/media/platform/exynos4-is/common.h b/drivers/media/platform/exynos4-is/common.h index 75b9c71d9419..0389b66e5144 100644 --- a/drivers/media/platform/exynos4-is/common.h +++ b/drivers/media/platform/exynos4-is/common.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> @@ -12,5 +9,4 @@ #include <media/v4l2-subdev.h> struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity); -void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap, - unsigned int caps); +void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap); diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index de4af0357a3c..66510365dd5d 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung S5P/EXYNOS4 SoC series camera interface (camera capture) driver * * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. * Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> @@ -728,13 +725,12 @@ static int fimc_cap_querycap(struct file *file, void *priv, { struct fimc_dev *fimc = video_drvdata(file); - __fimc_vidioc_querycap(&fimc->pdev->dev, cap, V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_CAPTURE_MPLANE); + __fimc_vidioc_querycap(&fimc->pdev->dev, cap); return 0; } -static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int fimc_cap_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { struct fimc_fmt *fmt; @@ -1361,7 +1357,7 @@ static int fimc_cap_s_selection(struct file *file, void *fh, static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { .vidioc_querycap = fimc_cap_querycap, - .vidioc_enum_fmt_vid_cap_mplane = fimc_cap_enum_fmt_mplane, + .vidioc_enum_fmt_vid_cap = fimc_cap_enum_fmt, .vidioc_try_fmt_vid_cap_mplane = fimc_cap_try_fmt_mplane, .vidioc_s_fmt_vid_cap_mplane = fimc_cap_s_fmt_mplane, .vidioc_g_fmt_vid_cap_mplane = fimc_cap_g_fmt_mplane, @@ -1765,6 +1761,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, vfd->release = video_device_release_empty; vfd->queue = q; vfd->lock = &fimc->lock; + vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE; video_set_drvdata(vfd, fimc); vid_cap = &fimc->vid_cap; diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h index 9f751a5efd64..d130f664a60b 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.h +++ b/drivers/media/platform/exynos4-is/fimc-core.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef FIMC_CORE_H_ diff --git a/drivers/media/platform/exynos4-is/fimc-is-command.h b/drivers/media/platform/exynos4-is/fimc-is-command.h index b06b56b890d5..87978609ad55 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-command.h +++ b/drivers/media/platform/exynos4-is/fimc-is-command.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Samsung Exynos4x12 FIMC-IS (Imaging Subsystem) driver * @@ -7,10 +8,6 @@ * * Authors: Younghwan Joo <yhwan.joo@samsung.com> * Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef FIMC_IS_CMD_H_ diff --git a/drivers/media/platform/exynos4-is/fimc-is-errno.c b/drivers/media/platform/exynos4-is/fimc-is-errno.c index bbb08576492e..5d9f4c1cdc5e 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-errno.c +++ b/drivers/media/platform/exynos4-is/fimc-is-errno.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung Exynos4 SoC series FIMC-IS slave interface driver * @@ -7,10 +8,6 @@ * * Authors: Younghwan Joo <yhwan.joo@samsung.com> * Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "fimc-is-errno.h" diff --git a/drivers/media/platform/exynos4-is/fimc-is-errno.h b/drivers/media/platform/exynos4-is/fimc-is-errno.h index 77f4fc860be5..da36b48b8f9f 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-errno.h +++ b/drivers/media/platform/exynos4-is/fimc-is-errno.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Samsung Exynos4 SoC series FIMC-IS slave interface driver * @@ -7,10 +8,6 @@ * * Authors: Younghwan Joo <yhwan.joo@samsung.com> * Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef FIMC_IS_ERR_H_ diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/exynos4-is/fimc-is-i2c.c index be937caf7645..83a28ef8e099 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-i2c.c +++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.h b/drivers/media/platform/exynos4-is/fimc-is-i2c.h index 0d38d6bb963b..a23bd20be6c8 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-i2c.h +++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define FIMC_IS_I2C_COMPATIBLE "samsung,exynos4212-i2c-isp" diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c index 72b9b436c5c0..9c816ae3b3e5 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-param.c +++ b/drivers/media/platform/exynos4-is/fimc-is-param.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * @@ -5,10 +6,6 @@ * * Authors: Younghwan Joo <yhwan.joo@samsung.com> * Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.h b/drivers/media/platform/exynos4-is/fimc-is-param.h index 22923a3d405e..206904674927 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-param.h +++ b/drivers/media/platform/exynos4-is/fimc-is-param.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * @@ -5,10 +6,6 @@ * * Authors: Younghwan Joo <yhwan.joo@samsung.com> * Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef FIMC_IS_PARAM_H_ #define FIMC_IS_PARAM_H_ diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c index e0e291066037..366e6393817d 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-regs.c +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * @@ -5,10 +6,6 @@ * * Authors: Younghwan Joo <yhwan.joo@samsung.com> * Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.h b/drivers/media/platform/exynos4-is/fimc-is-regs.h index 141e5ddadbeb..5d8b01bc84a2 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-regs.h +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * @@ -5,10 +6,6 @@ * * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com> * Younghwan Joo <yhwan.joo@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef FIMC_IS_REG_H_ #define FIMC_IS_REG_H_ diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.c b/drivers/media/platform/exynos4-is/fimc-is-sensor.c index 10e82e21b5d1..0e5b9fede4ae 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-sensor.c +++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "fimc-is-sensor.h" diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.h b/drivers/media/platform/exynos4-is/fimc-is-sensor.h index 173ccffa4bcd..9aefc63889de 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-sensor.h +++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * @@ -5,10 +6,6 @@ * * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com> * Younghwan Joo <yhwan.joo@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef FIMC_IS_SENSOR_H_ #define FIMC_IS_SENSOR_H_ diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 02da0b06e56a..e043d55133a3 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * @@ -5,10 +6,6 @@ * * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com> * Younghwan Joo <yhwan.joo@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ diff --git a/drivers/media/platform/exynos4-is/fimc-is.h b/drivers/media/platform/exynos4-is/fimc-is.h index ee05da034aa1..7ee96a058d40 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.h +++ b/drivers/media/platform/exynos4-is/fimc-is.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * @@ -5,10 +6,6 @@ * * Authors: Younghwan Joo <yhwan.joo@samsung.com> * Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef FIMC_IS_H_ #define FIMC_IS_H_ diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index bb35a2017f21..a75f932a289a 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * @@ -8,10 +9,6 @@ * * The hardware handling code derived from a driver written by * Younghwan Joo <yhwan.joo@samsung.com>. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> @@ -349,12 +346,12 @@ static int isp_video_querycap(struct file *file, void *priv, { struct fimc_isp *isp = video_drvdata(file); - __fimc_vidioc_querycap(&isp->pdev->dev, cap, V4L2_CAP_STREAMING); + __fimc_vidioc_querycap(&isp->pdev->dev, cap); return 0; } -static int isp_video_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int isp_video_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { const struct fimc_fmt *fmt; @@ -551,7 +548,7 @@ static int isp_video_reqbufs(struct file *file, void *priv, static const struct v4l2_ioctl_ops isp_video_ioctl_ops = { .vidioc_querycap = isp_video_querycap, - .vidioc_enum_fmt_vid_cap_mplane = isp_video_enum_fmt_mplane, + .vidioc_enum_fmt_vid_cap = isp_video_enum_fmt, .vidioc_try_fmt_vid_cap_mplane = isp_video_try_fmt_mplane, .vidioc_s_fmt_vid_cap_mplane = isp_video_s_fmt_mplane, .vidioc_g_fmt_vid_cap_mplane = isp_video_g_fmt_mplane, @@ -614,6 +611,7 @@ int fimc_isp_video_device_register(struct fimc_isp *isp, vdev->minor = -1; vdev->release = video_device_release_empty; vdev->lock = &isp->video_lock; + vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE; iv->pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_pads_init(&vdev->entity, 1, &iv->pad); diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.h b/drivers/media/platform/exynos4-is/fimc-isp-video.h index f79a1b348aa6..edcb3a5e3cb9 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.h +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef FIMC_ISP_VIDEO__ #define FIMC_ISP_VIDEO__ diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index 9a48c0f69320..907b83e6649d 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * @@ -5,10 +6,6 @@ * * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com> * Younghwan Joo <yhwan.joo@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ diff --git a/drivers/media/platform/exynos4-is/fimc-isp.h b/drivers/media/platform/exynos4-is/fimc-isp.h index 3cdd52491294..161fa01a8781 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.h +++ b/drivers/media/platform/exynos4-is/fimc-isp.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * @@ -5,10 +6,6 @@ * * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com> * Younghwan Joo <yhwan.joo@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef FIMC_ISP_H_ #define FIMC_ISP_H_ diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c index 16565a0b4bf1..85f765e0f4e1 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Register interface file for EXYNOS FIMC-LITE (camera interface) driver * * Copyright (C) 2012 Samsung Electronics Co., Ltd. * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.h b/drivers/media/platform/exynos4-is/fimc-lite-reg.h index 10a7d7bbcc27..48f2cf1148b8 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite-reg.h +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef FIMC_LITE_REG_H_ diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 96f0a8a0dcae..c1f0aee02e5e 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung EXYNOS FIMC-LITE (camera host interface) driver * * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ @@ -658,14 +655,11 @@ static int fimc_lite_querycap(struct file *file, void *priv, strscpy(cap->card, FIMC_LITE_DRV_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(&fimc->pdev->dev)); - - cap->device_caps = V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } -static int fimc_lite_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int fimc_lite_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { const struct fimc_fmt *fmt; @@ -954,7 +948,7 @@ static int fimc_lite_s_selection(struct file *file, void *fh, static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = { .vidioc_querycap = fimc_lite_querycap, - .vidioc_enum_fmt_vid_cap_mplane = fimc_lite_enum_fmt_mplane, + .vidioc_enum_fmt_vid_cap = fimc_lite_enum_fmt, .vidioc_try_fmt_vid_cap_mplane = fimc_lite_try_fmt_mplane, .vidioc_s_fmt_vid_cap_mplane = fimc_lite_s_fmt_mplane, .vidioc_g_fmt_vid_cap_mplane = fimc_lite_g_fmt_mplane, @@ -1282,6 +1276,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) vfd->minor = -1; vfd->release = video_device_release_empty; vfd->queue = q; + vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING; fimc->reqbufs_count = 0; INIT_LIST_HEAD(&fimc->pending_buf_q); diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index 3e238b8c834a..e6846c5fc9ac 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef FIMC_LITE_H_ diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index b950c152fa28..62e876fc3555 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -232,14 +232,13 @@ static int fimc_m2m_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { struct fimc_dev *fimc = video_drvdata(file); - unsigned int caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; - __fimc_vidioc_querycap(&fimc->pdev->dev, cap, caps); + __fimc_vidioc_querycap(&fimc->pdev->dev, cap); return 0; } -static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int fimc_m2m_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { struct fimc_fmt *fmt; @@ -529,8 +528,8 @@ static int fimc_m2m_s_selection(struct file *file, void *fh, static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { .vidioc_querycap = fimc_m2m_querycap, - .vidioc_enum_fmt_vid_cap_mplane = fimc_m2m_enum_fmt_mplane, - .vidioc_enum_fmt_vid_out_mplane = fimc_m2m_enum_fmt_mplane, + .vidioc_enum_fmt_vid_cap = fimc_m2m_enum_fmt, + .vidioc_enum_fmt_vid_out = fimc_m2m_enum_fmt, .vidioc_g_fmt_vid_cap_mplane = fimc_m2m_g_fmt_mplane, .vidioc_g_fmt_vid_out_mplane = fimc_m2m_g_fmt_mplane, .vidioc_try_fmt_vid_cap_mplane = fimc_m2m_try_fmt_mplane, @@ -732,6 +731,7 @@ int fimc_register_m2m_device(struct fimc_dev *fimc, vfd->release = video_device_release_empty; vfd->lock = &fimc->lock; vfd->vfl_dir = VFL_DIR_M2M; + vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags); snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id); diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c index 0806724553a2..5ce2bdebd424 100644 --- a/drivers/media/platform/exynos4-is/fimc-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-reg.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Register interface file for Samsung Camera Interface (FIMC) driver * * Copyright (C) 2010 - 2013 Samsung Electronics Co., Ltd. * Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/media/platform/exynos4-is/fimc-reg.h b/drivers/media/platform/exynos4-is/fimc-reg.h index 6c97798c75a5..03ba6c2bc84b 100644 --- a/drivers/media/platform/exynos4-is/fimc-reg.h +++ b/drivers/media/platform/exynos4-is/fimc-reg.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Samsung camera host interface (FIMC) registers definition * * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef FIMC_REG_H_ diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 1b83a6ec745f..d53427a8db11 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -445,6 +445,7 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, pd->fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK; else pd->fimc_bus_type = pd->sensor_bus_type; + of_node_put(np); if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor))) { of_node_put(rem); @@ -470,7 +471,8 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, static int fimc_md_register_sensor_entities(struct fimc_md *fmd) { struct device_node *parent = fmd->pdev->dev.of_node; - struct device_node *node, *ports; + struct device_node *ports = NULL; + struct device_node *node; int index = 0; int ret; @@ -519,12 +521,14 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) } index++; } + of_node_put(ports); rpm_put: pm_runtime_put(fmd->pmf); return 0; cleanup: + of_node_put(ports); v4l2_async_notifier_cleanup(&fmd->subdev_notifier); pm_runtime_put(fmd->pmf); return ret; diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h index a7c9490bbcb4..4b8f9ac52ebc 100644 --- a/drivers/media/platform/exynos4-is/media-dev.h +++ b/drivers/media/platform/exynos4-is/media-dev.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef FIMC_MDEVICE_H_ diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 234e047e3e8f..3e9ac6066cf6 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung S5P/EXYNOS SoC series MIPI-CSI receiver driver * * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/media/platform/exynos4-is/mipi-csis.h b/drivers/media/platform/exynos4-is/mipi-csis.h index 28c11c4085d8..193f253c7907 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.h +++ b/drivers/media/platform/exynos4-is/mipi-csis.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver * * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef S5P_MIPI_CSIS_H_ #define S5P_MIPI_CSIS_H_ diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig index 86b84474dd8c..3e3f86264762 100644 --- a/drivers/media/platform/marvell-ccic/Kconfig +++ b/drivers/media/platform/marvell-ccic/Kconfig @@ -2,6 +2,7 @@ config VIDEO_CAFE_CCIC tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" depends on PCI && I2C && VIDEO_V4L2 + depends on COMMON_CLK select VIDEO_OV7670 select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG @@ -15,6 +16,7 @@ config VIDEO_MMP_CAMERA tristate "Marvell Armada 610 integrated camera controller support" depends on I2C && VIDEO_V4L2 depends on ARCH_MMP || COMPILE_TEST + depends on COMMON_CLK select VIDEO_OV7670 select I2C_GPIO select VIDEOBUF2_VMALLOC diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c index cd108b14b715..37fdcc53a1c4 100644 --- a/drivers/media/platform/marvell-ccic/cafe-driver.c +++ b/drivers/media/platform/marvell-ccic/cafe-driver.c @@ -9,6 +9,7 @@ * * Copyright 2006-11 One Laptop Per Child Association, Inc. * Copyright 2006-11 Jonathan Corbet <corbet@lwn.net> + * Copyright 2018 Lubomir Rintel <lkundrak@v3.sk> * * Written by Jonathan Corbet, corbet@lwn.net. * @@ -25,10 +26,12 @@ #include <linux/slab.h> #include <linux/videodev2.h> #include <media/v4l2-device.h> +#include <media/i2c/ov7670.h> #include <linux/device.h> #include <linux/wait.h> #include <linux/delay.h> #include <linux/io.h> +#include <linux/clkdev.h> #include "mcam-core.h" @@ -50,6 +53,7 @@ struct cafe_camera { int registered; /* Fully initialized? */ struct mcam_camera mcam; struct pci_dev *pdev; + struct i2c_adapter *i2c_adapter; wait_queue_head_t smbus_wait; /* Waiting on i2c events */ }; @@ -349,15 +353,15 @@ static int cafe_smbus_setup(struct cafe_camera *cam) return ret; } - cam->mcam.i2c_adapter = adap; + cam->i2c_adapter = adap; cafe_smbus_enable_irq(cam); return 0; } static void cafe_smbus_shutdown(struct cafe_camera *cam) { - i2c_del_adapter(cam->mcam.i2c_adapter); - kfree(cam->mcam.i2c_adapter); + i2c_del_adapter(cam->i2c_adapter); + kfree(cam->i2c_adapter); } @@ -450,6 +454,29 @@ static irqreturn_t cafe_irq(int irq, void *data) return IRQ_RETVAL(handled); } +/* -------------------------------------------------------------------------- */ + +static struct ov7670_config sensor_cfg = { + /* + * Exclude QCIF mode, because it only captures a tiny portion + * of the sensor FOV + */ + .min_width = 320, + .min_height = 240, + + /* + * Set the clock speed for the XO 1; I don't believe this + * driver has ever run anywhere else. + */ + .clock_speed = 45, + .use_smbus = 1, +}; + +static struct i2c_board_info ov7670_info = { + .type = "ov7670", + .addr = 0x42 >> 1, + .platform_data = &sensor_cfg, +}; /* -------------------------------------------------------------------------- */ /* @@ -480,12 +507,6 @@ static int cafe_pci_probe(struct pci_dev *pdev, mcam->dev = &pdev->dev; snprintf(mcam->bus_info, sizeof(mcam->bus_info), "PCI:%s", pci_name(pdev)); /* - * Set the clock speed for the XO 1; I don't believe this - * driver has ever run anywhere else. - */ - mcam->clock_speed = 45; - mcam->use_smbus = 1; - /* * Vmalloc mode for buffers is traditional with this driver. * We *might* be able to run DMA_contig, especially on a system * with CMA in it. @@ -511,11 +532,10 @@ static int cafe_pci_probe(struct pci_dev *pdev, goto out_iounmap; /* - * Initialize the controller and leave it powered up. It will - * stay that way until the sensor driver shows up. + * Initialize the controller. */ cafe_ctlr_init(mcam); - cafe_ctlr_power_up(mcam); + /* * Set up I2C/SMBUS communications. We have to drop the mutex here * because the sensor could attach in this call chain, leading to @@ -525,12 +545,24 @@ static int cafe_pci_probe(struct pci_dev *pdev, if (ret) goto out_pdown; + mcam->asd.match_type = V4L2_ASYNC_MATCH_I2C; + mcam->asd.match.i2c.adapter_id = i2c_adapter_id(cam->i2c_adapter); + mcam->asd.match.i2c.address = ov7670_info.addr; + ret = mccic_register(mcam); - if (ret == 0) { + if (ret) + goto out_smbus_shutdown; + + clkdev_create(mcam->mclk, "xclk", "%d-%04x", + i2c_adapter_id(cam->i2c_adapter), ov7670_info.addr); + + if (i2c_new_device(cam->i2c_adapter, &ov7670_info)) { cam->registered = 1; return 0; } + mccic_shutdown(mcam); +out_smbus_shutdown: cafe_smbus_shutdown(cam); out_pdown: cafe_ctlr_power_down(mcam); diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index f1b301810260..dc30c48d4671 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -4,6 +4,7 @@ * so it needs platform-specific support outside of the core. * * Copyright 2011 Jonathan Corbet corbet@lwn.net + * Copyright 2018 Lubomir Rintel <lkundrak@v3.sk> */ #include <linux/kernel.h> #include <linux/module.h> @@ -21,12 +22,12 @@ #include <linux/vmalloc.h> #include <linux/io.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/videodev2.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-event.h> -#include <media/i2c/ov7670.h> #include <media/videobuf2-vmalloc.h> #include <media/videobuf2-dma-contig.h> #include <media/videobuf2-dma-sg.h> @@ -93,6 +94,9 @@ MODULE_PARM_DESC(buffer_mode, #define sensor_call(cam, o, f, args...) \ v4l2_subdev_call(cam->sensor, o, f, ##args) +#define notifier_to_mcam(notifier) \ + container_of(notifier, struct mcam_camera, notifier) + static struct mcam_format_struct { __u8 *desc; __u32 pixelformat; @@ -200,7 +204,6 @@ struct mcam_vb_buffer { struct list_head queue; struct mcam_dma_desc *dma_desc; /* Descriptor virtual address */ dma_addr_t dma_desc_pa; /* Descriptor physical address */ - int dma_desc_nent; /* Number of mapped descriptors */ }; static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_v4l2_buffer *vb) @@ -282,6 +285,8 @@ static void mcam_ctlr_stop(struct mcam_camera *cam) static void mcam_enable_mipi(struct mcam_camera *mcam) { /* Using MIPI mode and enable MIPI */ + if (mcam->calc_dphy) + mcam->calc_dphy(mcam); cam_dbg(mcam, "camera: DPHY3=0x%x, DPHY5=0x%x, DPHY6=0x%x\n", mcam->dphy[0], mcam->dphy[1], mcam->dphy[2]); mcam_reg_write(mcam, REG_CSI2_DPHY3, mcam->dphy[0]); @@ -301,9 +306,6 @@ static void mcam_enable_mipi(struct mcam_camera *mcam) */ mcam_reg_write(mcam, REG_CSI2_CTRL0, CSI2_C0_MIPI_EN | CSI2_C0_ACT_LANE(mcam->lane)); - mcam_reg_write(mcam, REG_CLKCTRL, - (mcam->mclk_src << 29) | mcam->mclk_div); - mcam->mipi_enabled = true; } } @@ -608,9 +610,11 @@ static void mcam_dma_contig_done(struct mcam_camera *cam, int frame) static void mcam_sg_next_buffer(struct mcam_camera *cam) { struct mcam_vb_buffer *buf; + struct sg_table *sg_table; buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue); list_del_init(&buf->queue); + sg_table = vb2_dma_sg_plane_desc(&buf->vb_buf.vb2_buf, 0); /* * Very Bad Not Good Things happen if you don't clear * C1_DESC_ENA before making any descriptor changes. @@ -618,7 +622,7 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam) mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA); mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa); mcam_reg_write(cam, REG_DESC_LEN_Y, - buf->dma_desc_nent*sizeof(struct mcam_dma_desc)); + sg_table->nents * sizeof(struct mcam_dma_desc)); mcam_reg_write(cam, REG_DESC_LEN_U, 0); mcam_reg_write(cam, REG_DESC_LEN_V, 0); mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); @@ -791,12 +795,6 @@ static void mcam_ctlr_image(struct mcam_camera *cam) * Make sure it knows we want to use hsync/vsync. */ mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, C0_SIFM_MASK); - /* - * This field controls the generation of EOF(DVP only) - */ - if (cam->bus_type != V4L2_MBUS_CSI2_DPHY) - mcam_reg_set_bit(cam, REG_CTRL0, - C0_EOF_VSYNC | C0_VEDGE_CTRL); } @@ -832,31 +830,6 @@ static void mcam_ctlr_irq_disable(struct mcam_camera *cam) mcam_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS); } - - -static void mcam_ctlr_init(struct mcam_camera *cam) -{ - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - /* - * Make sure it's not powered down. - */ - mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); - /* - * Turn off the enable bit. It sure should be off anyway, - * but it's good to be sure. - */ - mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); - /* - * Clock the sensor appropriately. Controller clock should - * be 48MHz, sensor "typical" value is half that. - */ - mcam_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK); - spin_unlock_irqrestore(&cam->dev_lock, flags); -} - - /* * Stop the controller, and don't return until we're really sure that no * further DMA is going on. @@ -900,14 +873,15 @@ static int mcam_ctlr_power_up(struct mcam_camera *cam) int ret; spin_lock_irqsave(&cam->dev_lock, flags); - ret = cam->plat_power_up(cam); - if (ret) { - spin_unlock_irqrestore(&cam->dev_lock, flags); - return ret; + if (cam->plat_power_up) { + ret = cam->plat_power_up(cam); + if (ret) { + spin_unlock_irqrestore(&cam->dev_lock, flags); + return ret; + } } mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); spin_unlock_irqrestore(&cam->dev_lock, flags); - msleep(5); /* Just to be sure */ return 0; } @@ -922,10 +896,101 @@ static void mcam_ctlr_power_down(struct mcam_camera *cam) * power down routine. */ mcam_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN); - cam->plat_power_down(cam); + if (cam->plat_power_down) + cam->plat_power_down(cam); spin_unlock_irqrestore(&cam->dev_lock, flags); } +/* ---------------------------------------------------------------------- */ +/* + * Controller clocks. + */ +static void mcam_clk_enable(struct mcam_camera *mcam) +{ + unsigned int i; + + for (i = 0; i < NR_MCAM_CLK; i++) { + if (!IS_ERR(mcam->clk[i])) + clk_prepare_enable(mcam->clk[i]); + } +} + +static void mcam_clk_disable(struct mcam_camera *mcam) +{ + int i; + + for (i = NR_MCAM_CLK - 1; i >= 0; i--) { + if (!IS_ERR(mcam->clk[i])) + clk_disable_unprepare(mcam->clk[i]); + } +} + +/* ---------------------------------------------------------------------- */ +/* + * Master sensor clock. + */ +static int mclk_prepare(struct clk_hw *hw) +{ + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); + + clk_prepare(cam->clk[0]); + return 0; +} + +static void mclk_unprepare(struct clk_hw *hw) +{ + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); + + clk_unprepare(cam->clk[0]); +} + +static int mclk_enable(struct clk_hw *hw) +{ + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); + int mclk_src; + int mclk_div; + + /* + * Clock the sensor appropriately. Controller clock should + * be 48MHz, sensor "typical" value is half that. + */ + if (cam->bus_type == V4L2_MBUS_CSI2_DPHY) { + mclk_src = cam->mclk_src; + mclk_div = cam->mclk_div; + } else { + mclk_src = 3; + mclk_div = 2; + } + + clk_enable(cam->clk[0]); + mcam_reg_write(cam, REG_CLKCTRL, (mclk_src << 29) | mclk_div); + mcam_ctlr_power_up(cam); + + return 0; +} + +static void mclk_disable(struct clk_hw *hw) +{ + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); + + mcam_ctlr_power_down(cam); + clk_disable(cam->clk[0]); +} + +static unsigned long mclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return 48000000; +} + +static const struct clk_ops mclk_ops = { + .prepare = mclk_prepare, + .unprepare = mclk_unprepare, + .enable = mclk_enable, + .disable = mclk_disable, + .recalc_rate = mclk_recalc_rate, +}; + /* -------------------------------------------------------------------- */ /* * Communications with the sensor. @@ -950,7 +1015,6 @@ static int mcam_cam_init(struct mcam_camera *cam) ret = __mcam_cam_reset(cam); /* Get/set parameters? */ cam->state = S_IDLE; - mcam_ctlr_power_down(cam); return ret; } @@ -1016,13 +1080,6 @@ static int mcam_read_setup(struct mcam_camera *cam) spin_lock_irqsave(&cam->dev_lock, flags); clear_bit(CF_DMA_ACTIVE, &cam->flags); mcam_reset_buffers(cam); - /* - * Update CSI2_DPHY value - */ - if (cam->calc_dphy) - cam->calc_dphy(cam); - cam_dbg(cam, "camera: DPHY sets: dphy3=0x%x, dphy5=0x%x, dphy6=0x%x\n", - cam->dphy[0], cam->dphy[1], cam->dphy[2]); if (cam->bus_type == V4L2_MBUS_CSI2_DPHY) mcam_enable_mipi(cam); else @@ -1160,12 +1217,6 @@ static void mcam_vb_stop_streaming(struct vb2_queue *vq) return; mcam_ctlr_stop_dma(cam); /* - * Reset the CCIC PHY after stopping streaming, - * otherwise, the CCIC may be unstable. - */ - if (cam->ctlr_reset) - cam->ctlr_reset(cam); - /* * VB2 reclaims the buffers, so we need to forget * about them. */ @@ -1592,9 +1643,10 @@ static int mcam_v4l_open(struct file *filp) if (ret) goto out; if (v4l2_fh_is_singular_file(filp)) { - ret = mcam_ctlr_power_up(cam); + ret = sensor_call(cam, core, s_power, 1); if (ret) goto out; + mcam_clk_enable(cam); __mcam_cam_reset(cam); mcam_set_config_needed(cam, 1); } @@ -1616,7 +1668,8 @@ static int mcam_v4l_release(struct file *filp) _vb2_fop_release(filp, NULL); if (last_open) { mcam_disable_mipi(cam); - mcam_ctlr_power_down(cam); + sensor_call(cam, core, s_power, 0); + mcam_clk_disable(cam); if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read) mcam_free_dma_bufs(cam); } @@ -1726,23 +1779,95 @@ EXPORT_SYMBOL_GPL(mccic_irq); /* * Registration and such. */ -static struct ov7670_config sensor_cfg = { + +static int mccic_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) +{ + struct mcam_camera *cam = notifier_to_mcam(notifier); + int ret; + + mutex_lock(&cam->s_mutex); + if (cam->sensor) { + cam_err(cam, "sensor already bound\n"); + ret = -EBUSY; + goto out; + } + + v4l2_set_subdev_hostdata(subdev, cam); + cam->sensor = subdev; + + ret = mcam_cam_init(cam); + if (ret) { + cam->sensor = NULL; + goto out; + } + + ret = mcam_setup_vb2(cam); + if (ret) { + cam->sensor = NULL; + goto out; + } + + cam->vdev = mcam_v4l_template; + cam->vdev.v4l2_dev = &cam->v4l2_dev; + cam->vdev.lock = &cam->s_mutex; + cam->vdev.queue = &cam->vb_queue; + video_set_drvdata(&cam->vdev, cam); + ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); + if (ret) { + cam->sensor = NULL; + goto out; + } + + cam_dbg(cam, "sensor %s bound\n", subdev->name); +out: + mutex_unlock(&cam->s_mutex); + return ret; +} + +static void mccic_notify_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) +{ + struct mcam_camera *cam = notifier_to_mcam(notifier); + + mutex_lock(&cam->s_mutex); + if (cam->sensor != subdev) { + cam_err(cam, "sensor %s not bound\n", subdev->name); + goto out; + } + + video_unregister_device(&cam->vdev); + cam->sensor = NULL; + cam_dbg(cam, "sensor %s unbound\n", subdev->name); + +out: + mutex_unlock(&cam->s_mutex); +} + +static int mccic_notify_complete(struct v4l2_async_notifier *notifier) +{ + struct mcam_camera *cam = notifier_to_mcam(notifier); + int ret; + /* - * Exclude QCIF mode, because it only captures a tiny portion - * of the sensor FOV + * Get the v4l2 setup done. */ - .min_width = 320, - .min_height = 240, -}; + ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10); + if (!ret) + cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler; + return ret; +} + +static const struct v4l2_async_notifier_operations mccic_notify_ops = { + .bound = mccic_notify_bound, + .unbind = mccic_notify_unbind, + .complete = mccic_notify_complete, +}; int mccic_register(struct mcam_camera *cam) { - struct i2c_board_info ov7670_info = { - .type = "ov7670", - .addr = 0x42 >> 1, - .platform_data = &sensor_cfg, - }; + struct clk_init_data mclk_init = { }; int ret; /* @@ -1755,64 +1880,62 @@ int mccic_register(struct mcam_camera *cam) printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, attempting vmalloc mode instead\n"); cam->buffer_mode = B_vmalloc; } + if (!mcam_buffer_mode_supported(cam->buffer_mode)) { printk(KERN_ERR "marvell-cam: buffer mode %d unsupported\n", cam->buffer_mode); - return -EINVAL; + ret = -EINVAL; + goto out; } + /* * Register with V4L */ ret = v4l2_device_register(cam->dev, &cam->v4l2_dev); if (ret) - return ret; + goto out; mutex_init(&cam->s_mutex); cam->state = S_NOTREADY; mcam_set_config_needed(cam, 1); cam->pix_format = mcam_def_pix_format; cam->mbus_code = mcam_def_mbus_code; - mcam_ctlr_init(cam); /* - * Get the v4l2 setup done. + * Register sensor notifier. */ - ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10); - if (ret) - goto out_unregister; - cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler; + v4l2_async_notifier_init(&cam->notifier); + ret = v4l2_async_notifier_add_subdev(&cam->notifier, &cam->asd); + if (ret) { + cam_warn(cam, "failed to add subdev to a notifier"); + goto out; + } + + cam->notifier.ops = &mccic_notify_ops; + ret = v4l2_async_notifier_register(&cam->v4l2_dev, &cam->notifier); + if (ret < 0) { + cam_warn(cam, "failed to register a sensor notifier"); + goto out; + } /* - * Try to find the sensor. + * Register sensor master clock. */ - sensor_cfg.clock_speed = cam->clock_speed; - sensor_cfg.use_smbus = cam->use_smbus; - cam->sensor_addr = ov7670_info.addr; - cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, - cam->i2c_adapter, &ov7670_info, NULL); - if (cam->sensor == NULL) { - ret = -ENODEV; - goto out_unregister; - } + mclk_init.parent_names = NULL; + mclk_init.num_parents = 0; + mclk_init.ops = &mclk_ops; + mclk_init.name = "mclk"; - ret = mcam_cam_init(cam); - if (ret) - goto out_unregister; + of_property_read_string(cam->dev->of_node, "clock-output-names", + &mclk_init.name); - ret = mcam_setup_vb2(cam); - if (ret) - goto out_unregister; + cam->mclk_hw.init = &mclk_init; - mutex_lock(&cam->s_mutex); - cam->vdev = mcam_v4l_template; - cam->vdev.v4l2_dev = &cam->v4l2_dev; - cam->vdev.lock = &cam->s_mutex; - cam->vdev.queue = &cam->vb_queue; - video_set_drvdata(&cam->vdev, cam); - ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); - if (ret) { - mutex_unlock(&cam->s_mutex); - goto out_unregister; + cam->mclk = devm_clk_register(cam->dev, &cam->mclk_hw); + if (IS_ERR(cam->mclk)) { + ret = PTR_ERR(cam->mclk); + dev_err(cam->dev, "can't register clock\n"); + goto out; } /* @@ -1823,11 +1946,10 @@ int mccic_register(struct mcam_camera *cam) cam_warn(cam, "Unable to alloc DMA buffers at load will try again later."); } - mutex_unlock(&cam->s_mutex); return 0; -out_unregister: - v4l2_ctrl_handler_free(&cam->ctrl_handler); +out: + v4l2_async_notifier_unregister(&cam->notifier); v4l2_device_unregister(&cam->v4l2_dev); return ret; } @@ -1843,12 +1965,12 @@ void mccic_shutdown(struct mcam_camera *cam) */ if (!list_empty(&cam->vdev.fh_list)) { cam_warn(cam, "Removing a device with users!\n"); - mcam_ctlr_power_down(cam); + sensor_call(cam, core, s_power, 0); } if (cam->buffer_mode == B_vmalloc) mcam_free_dma_bufs(cam); - video_unregister_device(&cam->vdev); v4l2_ctrl_handler_free(&cam->ctrl_handler); + v4l2_async_notifier_unregister(&cam->notifier); v4l2_device_unregister(&cam->v4l2_dev); } EXPORT_SYMBOL_GPL(mccic_shutdown); @@ -1865,7 +1987,8 @@ void mccic_suspend(struct mcam_camera *cam) enum mcam_state cstate = cam->state; mcam_ctlr_stop_dma(cam); - mcam_ctlr_power_down(cam); + sensor_call(cam, core, s_power, 0); + mcam_clk_disable(cam); cam->state = cstate; } mutex_unlock(&cam->s_mutex); @@ -1878,14 +2001,15 @@ int mccic_resume(struct mcam_camera *cam) mutex_lock(&cam->s_mutex); if (!list_empty(&cam->vdev.fh_list)) { - ret = mcam_ctlr_power_up(cam); + mcam_clk_enable(cam); + ret = sensor_call(cam, core, s_power, 1); if (ret) { mutex_unlock(&cam->s_mutex); return ret; } __mcam_cam_reset(cam); } else { - mcam_ctlr_power_down(cam); + sensor_call(cam, core, s_power, 0); } mutex_unlock(&cam->s_mutex); diff --git a/drivers/media/platform/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h index ad8955f9f0a1..2e3a7567a76a 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.h +++ b/drivers/media/platform/marvell-ccic/mcam-core.h @@ -8,6 +8,7 @@ #define _MCAM_CORE_H #include <linux/list.h> +#include <linux/clk-provider.h> #include <media/v4l2-common.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-dev.h> @@ -102,21 +103,16 @@ struct mcam_camera { * These fields should be set by the platform code prior to * calling mcam_register(). */ - struct i2c_adapter *i2c_adapter; unsigned char __iomem *regs; unsigned regs_size; /* size in bytes of the register space */ spinlock_t dev_lock; struct device *dev; /* For messages, dma alloc */ enum mcam_chip_id chip_id; - short int clock_speed; /* Sensor clock speed, default 30 */ - short int use_smbus; /* SMBUS or straight I2c? */ enum mcam_buffer_mode buffer_mode; - int mclk_min; /* The minimal value of mclk */ int mclk_src; /* which clock source the mclk derives from */ int mclk_div; /* Clock Divider Value for MCLK */ - int ccic_id; enum v4l2_mbus_type bus_type; /* MIPI support */ /* The dphy config value, allocated in board file @@ -130,6 +126,8 @@ struct mcam_camera { /* clock tree support */ struct clk *clk[NR_MCAM_CLK]; + struct clk_hw mclk_hw; + struct clk *mclk; /* * Callbacks from the core to the platform code. @@ -137,7 +135,6 @@ struct mcam_camera { int (*plat_power_up) (struct mcam_camera *cam); void (*plat_power_down) (struct mcam_camera *cam); void (*calc_dphy) (struct mcam_camera *cam); - void (*ctlr_reset) (struct mcam_camera *cam); /* * Everything below here is private to the mcam core and @@ -153,8 +150,9 @@ struct mcam_camera { * Subsystem structures. */ struct video_device vdev; + struct v4l2_async_notifier notifier; + struct v4l2_async_subdev asd; struct v4l2_subdev *sensor; - unsigned short sensor_addr; /* Videobuf2 stuff */ struct vb2_queue vb_queue; diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index bf4d4a47f1db..10559492e09e 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -4,13 +4,12 @@ * to work with the Armada 610 as used in the OLPC 1.75 system. * * Copyright 2011 Jonathan Corbet <corbet@lwn.net> + * Copyright 2018 Lubomir Rintel <lkundrak@v3.sk> */ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/i2c.h> -#include <linux/platform_data/i2c-gpio.h> #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/slab.h> @@ -18,10 +17,10 @@ #include <media/v4l2-device.h> #include <linux/platform_data/media/mmp-camera.h> #include <linux/device.h> +#include <linux/of.h> +#include <linux/of_platform.h> #include <linux/platform_device.h> -#include <linux/gpio.h> #include <linux/io.h> -#include <linux/delay.h> #include <linux/list.h> #include <linux/pm.h> #include <linux/clk.h> @@ -32,10 +31,9 @@ MODULE_ALIAS("platform:mmp-camera"); MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); MODULE_LICENSE("GPL"); -static char *mcam_clks[] = {"CCICAXICLK", "CCICFUNCLK", "CCICPHYCLK"}; +static char *mcam_clks[] = {"axi", "func", "phy"}; struct mmp_camera { - void __iomem *power_regs; struct platform_device *pdev; struct mcam_camera mcam; struct list_head devlist; @@ -91,118 +89,6 @@ static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev) return NULL; } - - - -/* - * Power-related registers; this almost certainly belongs - * somewhere else. - * - * ARMADA 610 register manual, sec 7.2.1, p1842. - */ -#define CPU_SUBSYS_PMU_BASE 0xd4282800 -#define REG_CCIC_DCGCR 0x28 /* CCIC dyn clock gate ctrl reg */ -#define REG_CCIC_CRCR 0x50 /* CCIC clk reset ctrl reg */ -#define REG_CCIC2_CRCR 0xf4 /* CCIC2 clk reset ctrl reg */ - -static void mcam_clk_enable(struct mcam_camera *mcam) -{ - unsigned int i; - - for (i = 0; i < NR_MCAM_CLK; i++) { - if (!IS_ERR(mcam->clk[i])) - clk_prepare_enable(mcam->clk[i]); - } -} - -static void mcam_clk_disable(struct mcam_camera *mcam) -{ - int i; - - for (i = NR_MCAM_CLK - 1; i >= 0; i--) { - if (!IS_ERR(mcam->clk[i])) - clk_disable_unprepare(mcam->clk[i]); - } -} - -/* - * Power control. - */ -static void mmpcam_power_up_ctlr(struct mmp_camera *cam) -{ - iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR); - iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR); - mdelay(1); -} - -static int mmpcam_power_up(struct mcam_camera *mcam) -{ - struct mmp_camera *cam = mcam_to_cam(mcam); - struct mmp_camera_platform_data *pdata; - -/* - * Turn on power and clocks to the controller. - */ - mmpcam_power_up_ctlr(cam); -/* - * Provide power to the sensor. - */ - mcam_reg_write(mcam, REG_CLKCTRL, 0x60000002); - pdata = cam->pdev->dev.platform_data; - gpio_set_value(pdata->sensor_power_gpio, 1); - mdelay(5); - mcam_reg_clear_bit(mcam, REG_CTRL1, 0x10000000); - gpio_set_value(pdata->sensor_reset_gpio, 0); /* reset is active low */ - mdelay(5); - gpio_set_value(pdata->sensor_reset_gpio, 1); /* reset is active low */ - mdelay(5); - - mcam_clk_enable(mcam); - - return 0; -} - -static void mmpcam_power_down(struct mcam_camera *mcam) -{ - struct mmp_camera *cam = mcam_to_cam(mcam); - struct mmp_camera_platform_data *pdata; -/* - * Turn off clocks and set reset lines - */ - iowrite32(0, cam->power_regs + REG_CCIC_DCGCR); - iowrite32(0, cam->power_regs + REG_CCIC_CRCR); -/* - * Shut down the sensor. - */ - pdata = cam->pdev->dev.platform_data; - gpio_set_value(pdata->sensor_power_gpio, 0); - gpio_set_value(pdata->sensor_reset_gpio, 0); - - mcam_clk_disable(mcam); -} - -static void mcam_ctlr_reset(struct mcam_camera *mcam) -{ - unsigned long val; - struct mmp_camera *cam = mcam_to_cam(mcam); - - if (mcam->ccic_id) { - /* - * Using CCIC2 - */ - val = ioread32(cam->power_regs + REG_CCIC2_CRCR); - iowrite32(val & ~0x2, cam->power_regs + REG_CCIC2_CRCR); - iowrite32(val | 0x2, cam->power_regs + REG_CCIC2_CRCR); - } else { - /* - * Using CCIC1 - */ - val = ioread32(cam->power_regs + REG_CCIC_CRCR); - iowrite32(val & ~0x2, cam->power_regs + REG_CCIC_CRCR); - iowrite32(val | 0x2, cam->power_regs + REG_CCIC_CRCR); - } -} - /* * calc the dphy register values * There are three dphy registers being used. @@ -334,13 +220,10 @@ static int mmpcam_probe(struct platform_device *pdev) struct mmp_camera *cam; struct mcam_camera *mcam; struct resource *res; + struct fwnode_handle *ep; struct mmp_camera_platform_data *pdata; int ret; - pdata = pdev->dev.platform_data; - if (!pdata) - return -ENODEV; - cam = devm_kzalloc(&pdev->dev, sizeof(*cam), GFP_KERNEL); if (cam == NULL) return -ENOMEM; @@ -348,25 +231,31 @@ static int mmpcam_probe(struct platform_device *pdev) INIT_LIST_HEAD(&cam->devlist); mcam = &cam->mcam; - mcam->plat_power_up = mmpcam_power_up; - mcam->plat_power_down = mmpcam_power_down; - mcam->ctlr_reset = mcam_ctlr_reset; mcam->calc_dphy = mmpcam_calc_dphy; mcam->dev = &pdev->dev; - mcam->use_smbus = 0; - mcam->ccic_id = pdev->id; - mcam->mclk_min = pdata->mclk_min; - mcam->mclk_src = pdata->mclk_src; - mcam->mclk_div = pdata->mclk_div; - mcam->bus_type = pdata->bus_type; - mcam->dphy = pdata->dphy; + pdata = pdev->dev.platform_data; + if (pdata) { + mcam->mclk_src = pdata->mclk_src; + mcam->mclk_div = pdata->mclk_div; + mcam->bus_type = pdata->bus_type; + mcam->dphy = pdata->dphy; + mcam->lane = pdata->lane; + } else { + /* + * These are values that used to be hardcoded in mcam-core and + * work well on a OLPC XO 1.75 with a parallel bus sensor. + * If it turns out other setups make sense, the values should + * be obtained from the device tree. + */ + mcam->mclk_src = 3; + mcam->mclk_div = 2; + } if (mcam->bus_type == V4L2_MBUS_CSI2_DPHY) { cam->mipi_clk = devm_clk_get(mcam->dev, "mipi"); if ((IS_ERR(cam->mipi_clk) && mcam->dphy[2] == 0)) return PTR_ERR(cam->mipi_clk); } mcam->mipi_enabled = false; - mcam->lane = pdata->lane; mcam->chip_id = MCAM_ARMADA610; mcam->buffer_mode = B_DMA_sg; strscpy(mcam->bus_info, "platform:mmp-camera", sizeof(mcam->bus_info)); @@ -379,54 +268,39 @@ static int mmpcam_probe(struct platform_device *pdev) if (IS_ERR(mcam->regs)) return PTR_ERR(mcam->regs); mcam->regs_size = resource_size(res); + + mcam_init_clk(mcam); + /* - * Power/clock memory is elsewhere; get it too. Perhaps this - * should really be managed outside of this driver? - */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - cam->power_regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(cam->power_regs)) - return PTR_ERR(cam->power_regs); - /* - * Find the i2c adapter. This assumes, of course, that the - * i2c bus is already up and functioning. + * Create a match of the sensor against its OF node. */ - mcam->i2c_adapter = platform_get_drvdata(pdata->i2c_device); - if (mcam->i2c_adapter == NULL) { - dev_err(&pdev->dev, "No i2c adapter\n"); + ep = fwnode_graph_get_next_endpoint(of_fwnode_handle(pdev->dev.of_node), + NULL); + if (!ep) return -ENODEV; - } - /* - * Sensor GPIO pins. - */ - ret = devm_gpio_request(&pdev->dev, pdata->sensor_power_gpio, - "cam-power"); - if (ret) { - dev_err(&pdev->dev, "Can't get sensor power gpio %d", - pdata->sensor_power_gpio); - return ret; - } - gpio_direction_output(pdata->sensor_power_gpio, 0); - ret = devm_gpio_request(&pdev->dev, pdata->sensor_reset_gpio, - "cam-reset"); - if (ret) { - dev_err(&pdev->dev, "Can't get sensor reset gpio %d", - pdata->sensor_reset_gpio); - return ret; - } - gpio_direction_output(pdata->sensor_reset_gpio, 0); - mcam_init_clk(mcam); + mcam->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; + mcam->asd.match.fwnode = fwnode_graph_get_remote_port_parent(ep); + + fwnode_handle_put(ep); /* - * Power the device up and hand it off to the core. + * Register the device with the core. */ - ret = mmpcam_power_up(mcam); - if (ret) - return ret; ret = mccic_register(mcam); if (ret) - goto out_power_down; + return ret; + + /* + * Add OF clock provider. + */ + ret = of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, + mcam->mclk); + if (ret) { + dev_err(&pdev->dev, "can't add DT clock provider\n"); + goto out; + } + /* * Finally, set up our IRQ now that the core is ready to * deal with it. @@ -434,7 +308,7 @@ static int mmpcam_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { ret = -ENODEV; - goto out_unregister; + goto out; } cam->irq = res->start; ret = devm_request_irq(&pdev->dev, cam->irq, mmpcam_irq, IRQF_SHARED, @@ -444,10 +318,10 @@ static int mmpcam_probe(struct platform_device *pdev) return 0; } -out_unregister: +out: + fwnode_handle_put(mcam->asd.match.fwnode); mccic_shutdown(mcam); -out_power_down: - mmpcam_power_down(mcam); + return ret; } @@ -458,7 +332,6 @@ static int mmpcam_remove(struct mmp_camera *cam) mmpcam_remove_device(cam); mccic_shutdown(mcam); - mmpcam_power_down(mcam); return 0; } @@ -490,17 +363,15 @@ static int mmpcam_resume(struct platform_device *pdev) { struct mmp_camera *cam = mmpcam_find_device(pdev); - /* - * Power up unconditionally just in case the core tries to - * touch a register even if nothing was active before; trust - * me, it's better this way. - */ - mmpcam_power_up_ctlr(cam); return mccic_resume(&cam->mcam); } #endif +static const struct of_device_id mmpcam_of_match[] = { + { .compatible = "marvell,mmp2-ccic", }, + {}, +}; static struct platform_driver mmpcam_driver = { .probe = mmpcam_probe, @@ -511,6 +382,7 @@ static struct platform_driver mmpcam_driver = { #endif .driver = { .name = "mmp-camera", + .of_match_table = of_match_ptr(mmpcam_of_match), } }; diff --git a/drivers/media/platform/meson/ao-cec-g12a.c b/drivers/media/platform/meson/ao-cec-g12a.c index 3620a1e310f5..fb52e5dd044a 100644 --- a/drivers/media/platform/meson/ao-cec-g12a.c +++ b/drivers/media/platform/meson/ao-cec-g12a.c @@ -365,28 +365,22 @@ static int meson_ao_cec_g12a_read(void *context, unsigned int addr, { struct meson_ao_cec_g12a_device *ao_cec = context; u32 reg = FIELD_PREP(CECB_RW_ADDR, addr); - unsigned long flags; int ret = 0; - spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); - ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); if (ret) - goto read_out; + return ret; ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg, !(reg & CECB_RW_BUS_BUSY), 5, 1000); if (ret) - goto read_out; + return ret; ret = regmap_read(ao_cec->regmap, CECB_RW_REG, ®); *data = FIELD_GET(CECB_RW_RD_DATA, reg); -read_out: - spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); - return ret; } @@ -394,19 +388,11 @@ static int meson_ao_cec_g12a_write(void *context, unsigned int addr, unsigned int data) { struct meson_ao_cec_g12a_device *ao_cec = context; - unsigned long flags; u32 reg = FIELD_PREP(CECB_RW_ADDR, addr) | FIELD_PREP(CECB_RW_WR_DATA, data) | CECB_RW_WRITE_EN; - int ret = 0; - spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); - - ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); - - spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); - - return ret; + return regmap_write(ao_cec->regmap, CECB_RW_REG, reg); } static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = { @@ -415,7 +401,6 @@ static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = { .reg_read = meson_ao_cec_g12a_read, .reg_write = meson_ao_cec_g12a_write, .max_register = 0xffff, - .fast_io = true, }; static inline void diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c index 656444e7ca2b..ee802fc3bcdf 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c @@ -518,7 +518,7 @@ static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) return -EINVAL; } - vb = vq->bufs[buf->index]; + vb = vb2_get_buffer(vq, buf->index); jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb); jpeg_src_buf->flags = (buf->m.planes[0].bytesused == 0) ? MTK_JPEG_BUF_FLAGS_LAST_FRAME : MTK_JPEG_BUF_FLAGS_INIT; @@ -528,8 +528,8 @@ end: static const struct v4l2_ioctl_ops mtk_jpeg_ioctl_ops = { .vidioc_querycap = mtk_jpeg_querycap, - .vidioc_enum_fmt_vid_cap_mplane = mtk_jpeg_enum_fmt_vid_cap, - .vidioc_enum_fmt_vid_out_mplane = mtk_jpeg_enum_fmt_vid_out, + .vidioc_enum_fmt_vid_cap = mtk_jpeg_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = mtk_jpeg_enum_fmt_vid_out, .vidioc_try_fmt_vid_cap_mplane = mtk_jpeg_try_fmt_vid_cap_mplane, .vidioc_try_fmt_vid_out_mplane = mtk_jpeg_try_fmt_vid_out_mplane, .vidioc_g_fmt_vid_cap_mplane = mtk_jpeg_g_fmt_vid_mplane, diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c index b28e3dd4885c..7c9e2d69e21a 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c @@ -612,7 +612,7 @@ static int mtk_mdp_m2m_querycap(struct file *file, void *fh, return 0; } -static int mtk_mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f, u32 type) +static int mtk_mdp_enum_fmt(struct v4l2_fmtdesc *f, u32 type) { const struct mtk_mdp_fmt *fmt; @@ -625,16 +625,16 @@ static int mtk_mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f, u32 type) return 0; } -static int mtk_mdp_m2m_enum_fmt_mplane_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int mtk_mdp_m2m_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { - return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + return mtk_mdp_enum_fmt(f, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); } -static int mtk_mdp_m2m_enum_fmt_mplane_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int mtk_mdp_m2m_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { - return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + return mtk_mdp_enum_fmt(f, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); } static int mtk_mdp_m2m_g_fmt_mplane(struct file *file, void *fh, @@ -927,8 +927,8 @@ static int mtk_mdp_m2m_s_selection(struct file *file, void *fh, static const struct v4l2_ioctl_ops mtk_mdp_m2m_ioctl_ops = { .vidioc_querycap = mtk_mdp_m2m_querycap, - .vidioc_enum_fmt_vid_cap_mplane = mtk_mdp_m2m_enum_fmt_mplane_vid_cap, - .vidioc_enum_fmt_vid_out_mplane = mtk_mdp_m2m_enum_fmt_mplane_vid_out, + .vidioc_enum_fmt_vid_cap = mtk_mdp_m2m_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = mtk_mdp_m2m_enum_fmt_vid_out, .vidioc_g_fmt_vid_cap_mplane = mtk_mdp_m2m_g_fmt_mplane, .vidioc_g_fmt_vid_out_mplane = mtk_mdp_m2m_g_fmt_mplane, .vidioc_try_fmt_vid_cap_mplane = mtk_mdp_m2m_try_fmt_mplane, diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 7ae588e62ed8..90d1a67db7e5 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> @@ -24,7 +24,7 @@ #define DFT_CFG_WIDTH MTK_VDEC_MIN_W #define DFT_CFG_HEIGHT MTK_VDEC_MIN_H -static struct mtk_video_fmt mtk_video_formats[] = { +static const struct mtk_video_fmt mtk_video_formats[] = { { .fourcc = V4L2_PIX_FMT_H264, .type = MTK_FMT_DEC, @@ -68,9 +68,9 @@ static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { #define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) #define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) -static struct mtk_video_fmt *mtk_vdec_find_format(struct v4l2_format *f) +static const struct mtk_video_fmt *mtk_vdec_find_format(struct v4l2_format *f) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; unsigned int k; for (k = 0; k < NUM_FORMATS; k++) { @@ -122,8 +122,9 @@ static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx) if (dstbuf->used) { vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, ctx->picinfo.fb_sz[0]); - vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1, - ctx->picinfo.fb_sz[1]); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1, + ctx->picinfo.fb_sz[1]); mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to done_list %d", @@ -271,7 +272,7 @@ static void mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx) static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx, unsigned int pixelformat) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; struct mtk_q_data *dst_q_data; unsigned int k; @@ -394,7 +395,8 @@ static void mtk_vdec_worker(struct work_struct *work) vdec_if_decode(ctx, NULL, NULL, &res_chg); clean_display_buffer(ctx); vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 0, 0); - vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 1, 0); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 1, 0); dst_buf->flags |= V4L2_BUF_FLAG_LAST; v4l2_m2m_buf_done(&dst_buf_info->vb, VB2_BUF_STATE_DONE); clean_free_buffer(ctx); @@ -644,7 +646,8 @@ static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh, } } -static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt) +static int vidioc_try_fmt(struct v4l2_format *f, + const struct mtk_video_fmt *fmt) { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; int i; @@ -717,7 +720,7 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt) static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; fmt = mtk_vdec_find_format(f); if (!fmt) { @@ -732,7 +735,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; fmt = mtk_vdec_find_format(f); if (!fmt) { @@ -826,7 +829,7 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, struct v4l2_pix_format_mplane *pix_mp; struct mtk_q_data *q_data; int ret = 0; - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; mtk_v4l2_debug(3, "[%d]", ctx->id); @@ -925,7 +928,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; int i, j = 0; for (i = 0; i < NUM_FORMATS; i++) { @@ -949,14 +952,14 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) return 0; } -static int vidioc_vdec_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, - struct v4l2_fmtdesc *f) +static int vidioc_vdec_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(f, false); } -static int vidioc_vdec_enum_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int vidioc_vdec_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(f, true); } @@ -1324,7 +1327,8 @@ static void vb2ops_vdec_stop_streaming(struct vb2_queue *q) while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) { vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); - vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0); v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); } @@ -1453,8 +1457,8 @@ const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops = { .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_vdec_enum_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out_mplane = vidioc_vdec_enum_fmt_vid_out_mplane, + .vidioc_enum_fmt_vid_cap = vidioc_vdec_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = vidioc_vdec_enum_fmt_vid_out, .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_querycap = vidioc_vdec_querycap, diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h index 3861d4433be9..e0c5338bde3d 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c index 372d37824377..00d090df11bb 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c index 273f78f129da..5a6ec8fb52da 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: Tiffany Lin <tiffany.lin@mediatek.com> @@ -34,8 +34,8 @@ int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev) } pdev = of_find_device_by_node(node); + of_node_put(node); if (WARN_ON(!pdev)) { - of_node_put(node); return -1; } pm->larbvdec = &pdev->dev; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h index 74555cc5a893..872d8bf8cfaf 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: Tiffany Lin <tiffany.lin@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 1044176d8e6f..c95de5d08dda 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> @@ -129,7 +129,7 @@ struct mtk_q_data { enum v4l2_field field; unsigned int bytesperline[MTK_VCODEC_MAX_PLANES]; unsigned int sizeimage[MTK_VCODEC_MAX_PLANES]; - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; }; /** @@ -273,7 +273,7 @@ struct mtk_vcodec_ctx { const struct vdec_common_if *dec_if; const struct venc_common_if *enc_if; - unsigned long drv_handle; + void *drv_handle; struct vdec_pic_info picinfo; int dpb_size; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c index 0cf5744b4c28..fd8de027e83e 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> @@ -29,7 +29,7 @@ static void mtk_venc_worker(struct work_struct *work); -static struct mtk_video_fmt mtk_video_formats[] = { +static const struct mtk_video_fmt mtk_video_formats[] = { { .fourcc = V4L2_PIX_FMT_NV12M, .type = MTK_FMT_FRAME, @@ -158,7 +158,7 @@ static const struct v4l2_ctrl_ops mtk_vcodec_enc_ctrl_ops = { static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; int i, j = 0; for (i = 0; i < NUM_FORMATS; ++i) { @@ -199,14 +199,14 @@ static int vidioc_enum_framesizes(struct file *file, void *fh, return -EINVAL; } -static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, - struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(f, false); } -static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov, - struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(f, true); } @@ -266,9 +266,9 @@ static struct mtk_q_data *mtk_venc_get_q_data(struct mtk_vcodec_ctx *ctx, return &ctx->q_data[MTK_Q_DATA_DST]; } -static struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f) +static const struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; unsigned int k; for (k = 0; k < NUM_FORMATS; k++) { @@ -283,7 +283,8 @@ static struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f) /* V4L2 specification suggests the driver corrects the format struct if any of * the dimensions is unsupported */ -static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt) +static int vidioc_try_fmt(struct v4l2_format *f, + const struct mtk_video_fmt *fmt) { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; int i; @@ -419,7 +420,7 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv, struct vb2_queue *vq; struct mtk_q_data *q_data; int i, ret; - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); if (!vq) { @@ -481,7 +482,7 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv, struct vb2_queue *vq; struct mtk_q_data *q_data; int ret, i; - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); @@ -580,7 +581,7 @@ static int vidioc_venc_g_fmt(struct file *file, void *priv, static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); fmt = mtk_venc_find_format(f); @@ -599,7 +600,7 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; fmt = mtk_venc_find_format(f); if (!fmt) { @@ -717,8 +718,8 @@ const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = { .vidioc_dqbuf = vidioc_venc_dqbuf, .vidioc_querycap = vidioc_venc_querycap, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane, @@ -864,12 +865,18 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) err_set_param: for (i = 0; i < q->num_buffers; ++i) { - if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) { + struct vb2_buffer *buf = vb2_get_buffer(q, i); + + /* + * FIXME: This check is not needed as only active buffers + * can be marked as done. + */ + if (buf->state == VB2_BUF_STATE_ACTIVE) { mtk_v4l2_debug(0, "[%d] id=%d, type=%d, %d -> VB2_BUF_STATE_QUEUED", ctx->id, i, q->type, - (int)q->bufs[i]->state); - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(q->bufs[i]), - VB2_BUF_STATE_QUEUED); + (int)buf->state); + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(buf), + VB2_BUF_STATE_QUEUED); } } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h index 8248cb628882..a9c9f86b9c83 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c index b15e9d2ef6a9..1d82aa2b6017 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c index 4740ae5e9a8e..3e2bfded79a6 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: Tiffany Lin <tiffany.lin@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h index 63165fc1b84a..b7ecdfd74823 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: Tiffany Lin <tiffany.lin@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c index f8aae7cc5f57..a3c7a380c930 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: Tiffany Lin <tiffany.lin@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h index ba632528fa72..638cd1f3526a 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: Tiffany Lin <tiffany.lin@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c index 13f7061bfb50..d48f542db1a9 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h index 677adb990e28..b999d7b84ed1 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c index 455dbe4887c1..c5f8f1fca44c 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> @@ -266,7 +266,7 @@ static void get_dpb_size(struct vdec_h264_inst *inst, unsigned int *dpb_sz) mtk_vcodec_debug(inst, "sz=%d", *dpb_sz); } -static int vdec_h264_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) +static int vdec_h264_init(struct mtk_vcodec_ctx *ctx) { struct vdec_h264_inst *inst = NULL; int err; @@ -295,7 +295,7 @@ static int vdec_h264_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) mtk_vcodec_debug(inst, "H264 Instance >> %p", inst); - *h_vdec = (unsigned long)inst; + ctx->drv_handle = inst; return 0; error_deinit: @@ -306,7 +306,7 @@ error_free_inst: return err; } -static void vdec_h264_deinit(unsigned long h_vdec) +static void vdec_h264_deinit(void *h_vdec) { struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; @@ -331,7 +331,7 @@ static int find_start_code(unsigned char *data, unsigned int data_sz) return -1; } -static int vdec_h264_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, +static int vdec_h264_decode(void *h_vdec, struct mtk_vcodec_mem *bs, struct vdec_fb *fb, bool *res_chg) { struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; @@ -451,8 +451,8 @@ static void vdec_h264_get_fb(struct vdec_h264_inst *inst, list->count--; } -static int vdec_h264_get_param(unsigned long h_vdec, - enum vdec_get_param_type type, void *out) +static int vdec_h264_get_param(void *h_vdec, enum vdec_get_param_type type, + void *out) { struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; @@ -485,16 +485,9 @@ static int vdec_h264_get_param(unsigned long h_vdec, return 0; } -static struct vdec_common_if vdec_h264_if = { +const struct vdec_common_if vdec_h264_if = { .init = vdec_h264_init, .decode = vdec_h264_decode, .get_param = vdec_h264_get_param, .deinit = vdec_h264_deinit, }; - -struct vdec_common_if *get_h264_dec_comm_if(void); - -struct vdec_common_if *get_h264_dec_comm_if(void) -{ - return &vdec_h264_if; -} diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c index 91139cef6283..63a8708ce682 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: Jungchang Tsao <jungchang.tsao@mediatek.com> @@ -388,7 +388,7 @@ static void free_working_buf(struct vdec_vp8_inst *inst) inst->vsi->dec.working_buf_dma = 0; } -static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) +static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx) { struct vdec_vp8_inst *inst; int err; @@ -419,7 +419,7 @@ static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) get_hw_reg_base(inst); mtk_vcodec_debug(inst, "VP8 Instance >> %p", inst); - *h_vdec = (unsigned long)inst; + ctx->drv_handle = inst; return 0; error_deinit: @@ -429,7 +429,7 @@ error_free_inst: return err; } -static int vdec_vp8_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, +static int vdec_vp8_decode(void *h_vdec, struct mtk_vcodec_mem *bs, struct vdec_fb *fb, bool *res_chg) { struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec; @@ -565,8 +565,8 @@ static void get_crop_info(struct vdec_vp8_inst *inst, struct v4l2_rect *cr) cr->left, cr->top, cr->width, cr->height); } -static int vdec_vp8_get_param(unsigned long h_vdec, - enum vdec_get_param_type type, void *out) +static int vdec_vp8_get_param(void *h_vdec, enum vdec_get_param_type type, + void *out) { struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec; @@ -599,7 +599,7 @@ static int vdec_vp8_get_param(unsigned long h_vdec, return 0; } -static void vdec_vp8_deinit(unsigned long h_vdec) +static void vdec_vp8_deinit(void *h_vdec) { struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec; @@ -610,16 +610,9 @@ static void vdec_vp8_deinit(unsigned long h_vdec) kfree(inst); } -static struct vdec_common_if vdec_vp8_if = { +const struct vdec_common_if vdec_vp8_if = { .init = vdec_vp8_init, .decode = vdec_vp8_decode, .get_param = vdec_vp8_get_param, .deinit = vdec_vp8_deinit, }; - -struct vdec_common_if *get_vp8_dec_comm_if(void); - -struct vdec_common_if *get_vp8_dec_comm_if(void) -{ - return &vdec_vp8_if; -} diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c index c1904ad5e69b..5066c283d86d 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: Daniel Hsiao <daniel.hsiao@mediatek.com> @@ -757,7 +757,7 @@ static int validate_vsi_array_indexes(struct vdec_vp9_inst *inst, return 0; } -static void vdec_vp9_deinit(unsigned long h_vdec) +static void vdec_vp9_deinit(void *h_vdec) { struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; struct mtk_vcodec_mem *mem; @@ -779,7 +779,7 @@ static void vdec_vp9_deinit(unsigned long h_vdec) vp9_free_inst(inst); } -static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) +static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx) { struct vdec_vp9_inst *inst; @@ -803,7 +803,7 @@ static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) inst->vsi = (struct vdec_vp9_vsi *)inst->vpu.vsi; init_all_fb_lists(inst); - (*h_vdec) = (unsigned long)inst; + ctx->drv_handle = inst; return 0; err_deinit_inst: @@ -812,8 +812,8 @@ err_deinit_inst: return -EINVAL; } -static int vdec_vp9_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, - struct vdec_fb *fb, bool *res_chg) +static int vdec_vp9_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) { int ret = 0; struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; @@ -969,8 +969,8 @@ static void get_crop_info(struct vdec_vp9_inst *inst, struct v4l2_rect *cr) cr->left, cr->top, cr->width, cr->height); } -static int vdec_vp9_get_param(unsigned long h_vdec, - enum vdec_get_param_type type, void *out) +static int vdec_vp9_get_param(void *h_vdec, enum vdec_get_param_type type, + void *out) { struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; int ret = 0; @@ -1000,16 +1000,9 @@ static int vdec_vp9_get_param(unsigned long h_vdec, return ret; } -static struct vdec_common_if vdec_vp9_if = { +const struct vdec_common_if vdec_vp9_if = { .init = vdec_vp9_init, .decode = vdec_vp9_decode, .get_param = vdec_vp9_get_param, .deinit = vdec_vp9_deinit, }; - -struct vdec_common_if *get_vp9_dec_comm_if(void); - -struct vdec_common_if *get_vp9_dec_comm_if(void) -{ - return &vdec_vp9_if; -} diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h index b6cb922fc400..ceb4db4cb3be 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> @@ -17,7 +17,7 @@ struct vdec_common_if { * @ctx : [in] mtk v4l2 context * @h_vdec : [out] driver handle */ - int (*init)(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec); + int (*init)(struct mtk_vcodec_ctx *ctx); /** * (*decode)() - trigger decode @@ -26,7 +26,7 @@ struct vdec_common_if { * @fb : [in] frame buffer to store decoded frame * @res_chg : [out] resolution change happen */ - int (*decode)(unsigned long h_vdec, struct mtk_vcodec_mem *bs, + int (*decode)(void *h_vdec, struct mtk_vcodec_mem *bs, struct vdec_fb *fb, bool *res_chg); /** @@ -35,14 +35,14 @@ struct vdec_common_if { * @type : [in] input parameter type * @out : [out] buffer to store query result */ - int (*get_param)(unsigned long h_vdec, enum vdec_get_param_type type, + int (*get_param)(void *h_vdec, enum vdec_get_param_type type, void *out); /** * (*deinit)() - deinitialize driver. * @h_vdec : [in] driver handle to be deinit */ - void (*deinit)(unsigned long h_vdec); + void (*deinit)(void *h_vdec); }; #endif diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c index 5c98a76a77b7..2e43dd4486e0 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> @@ -15,23 +15,19 @@ #include "mtk_vcodec_dec_pm.h" #include "mtk_vpu.h" -const struct vdec_common_if *get_h264_dec_comm_if(void); -const struct vdec_common_if *get_vp8_dec_comm_if(void); -const struct vdec_common_if *get_vp9_dec_comm_if(void); - int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) { int ret = 0; switch (fourcc) { case V4L2_PIX_FMT_H264: - ctx->dec_if = get_h264_dec_comm_if(); + ctx->dec_if = &vdec_h264_if; break; case V4L2_PIX_FMT_VP8: - ctx->dec_if = get_vp8_dec_comm_if(); + ctx->dec_if = &vdec_vp8_if; break; case V4L2_PIX_FMT_VP9: - ctx->dec_if = get_vp9_dec_comm_if(); + ctx->dec_if = &vdec_vp9_if; break; default: return -EINVAL; @@ -39,7 +35,7 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) mtk_vdec_lock(ctx); mtk_vcodec_dec_clock_on(&ctx->dev->pm); - ret = ctx->dec_if->init(ctx, &ctx->drv_handle); + ret = ctx->dec_if->init(ctx); mtk_vcodec_dec_clock_off(&ctx->dev->pm); mtk_vdec_unlock(ctx); @@ -66,7 +62,7 @@ int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs, } } - if (ctx->drv_handle == 0) + if (!ctx->drv_handle) return -EIO; mtk_vdec_lock(ctx); @@ -89,7 +85,7 @@ int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type, { int ret = 0; - if (ctx->drv_handle == 0) + if (!ctx->drv_handle) return -EIO; mtk_vdec_lock(ctx); @@ -101,7 +97,7 @@ int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type, void vdec_if_deinit(struct mtk_vcodec_ctx *ctx) { - if (ctx->drv_handle == 0) + if (!ctx->drv_handle) return; mtk_vdec_lock(ctx); @@ -110,5 +106,5 @@ void vdec_if_deinit(struct mtk_vcodec_ctx *ctx) mtk_vcodec_dec_clock_off(&ctx->dev->pm); mtk_vdec_unlock(ctx); - ctx->drv_handle = 0; + ctx->drv_handle = NULL; } diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h index 409623574145..270d8dc9984b 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> @@ -54,6 +54,10 @@ struct vdec_fb_node { struct vdec_fb *fb; }; +extern const struct vdec_common_if vdec_h264_if; +extern const struct vdec_common_if vdec_vp8_if; +extern const struct vdec_common_if vdec_vp9_if; + /** * vdec_if_init() - initialize decode driver * @ctx : [in] v4l2 context diff --git a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h index b05dcdeb7734..47a1c1c0fd04 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h +++ b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c index 035ba917ed0e..3f38cc4509ef 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h index 6701778ea5d9..b76f717e4fd7 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: PC Chen <pc.chen@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c index 3125eaf2a326..b9624f8df0e9 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: Jungchang Tsao <jungchang.tsao@mediatek.com> @@ -458,7 +458,7 @@ static void h264_encode_filler(struct venc_h264_inst *inst, void *buf, memset(p, 0xff, size); } -static int h264_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle) +static int h264_enc_init(struct mtk_vcodec_ctx *ctx) { int ret = 0; struct venc_h264_inst *inst; @@ -484,12 +484,12 @@ static int h264_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle) if (ret) kfree(inst); else - (*handle) = (unsigned long)inst; + ctx->drv_handle = inst; return ret; } -static int h264_enc_encode(unsigned long handle, +static int h264_enc_encode(void *handle, enum venc_start_opt opt, struct venc_frm_buf *frm_buf, struct mtk_vcodec_mem *bs_buf, @@ -584,7 +584,7 @@ encode_err: return ret; } -static int h264_enc_set_param(unsigned long handle, +static int h264_enc_set_param(void *handle, enum venc_set_param_type type, struct venc_enc_param *enc_prm) { @@ -637,7 +637,7 @@ static int h264_enc_set_param(unsigned long handle, return ret; } -static int h264_enc_deinit(unsigned long handle) +static int h264_enc_deinit(void *handle) { int ret = 0; struct venc_h264_inst *inst = (struct venc_h264_inst *)handle; @@ -655,16 +655,9 @@ static int h264_enc_deinit(unsigned long handle) return ret; } -static const struct venc_common_if venc_h264_if = { +const struct venc_common_if venc_h264_if = { .init = h264_enc_init, .encode = h264_enc_encode, .set_param = h264_enc_set_param, .deinit = h264_enc_deinit, }; - -const struct venc_common_if *get_h264_enc_comm_if(void); - -const struct venc_common_if *get_h264_enc_comm_if(void) -{ - return &venc_h264_if; -} diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c index ba19cdc4e4f1..8d36f0362efe 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: Daniel Hsiao <daniel.hsiao@mediatek.com> @@ -323,7 +323,7 @@ static int vp8_enc_encode_frame(struct venc_vp8_inst *inst, return ret; } -static int vp8_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle) +static int vp8_enc_init(struct mtk_vcodec_ctx *ctx) { int ret = 0; struct venc_vp8_inst *inst; @@ -349,12 +349,12 @@ static int vp8_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle) if (ret) kfree(inst); else - (*handle) = (unsigned long)inst; + ctx->drv_handle = inst; return ret; } -static int vp8_enc_encode(unsigned long handle, +static int vp8_enc_encode(void *handle, enum venc_start_opt opt, struct venc_frm_buf *frm_buf, struct mtk_vcodec_mem *bs_buf, @@ -391,7 +391,7 @@ encode_err: return ret; } -static int vp8_enc_set_param(unsigned long handle, +static int vp8_enc_set_param(void *handle, enum venc_set_param_type type, struct venc_enc_param *enc_prm) { @@ -442,7 +442,7 @@ static int vp8_enc_set_param(unsigned long handle, return ret; } -static int vp8_enc_deinit(unsigned long handle) +static int vp8_enc_deinit(void *handle) { int ret = 0; struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle; @@ -460,16 +460,9 @@ static int vp8_enc_deinit(unsigned long handle) return ret; } -static const struct venc_common_if venc_vp8_if = { +const struct venc_common_if venc_vp8_if = { .init = vp8_enc_init, .encode = vp8_enc_encode, .set_param = vp8_enc_set_param, .deinit = vp8_enc_deinit, }; - -const struct venc_common_if *get_vp8_enc_comm_if(void); - -const struct venc_common_if *get_vp8_enc_comm_if(void) -{ - return &venc_vp8_if; -} diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_base.h b/drivers/media/platform/mtk-vcodec/venc_drv_base.h index 81620683b94f..3d718411dc73 100644 --- a/drivers/media/platform/mtk-vcodec/venc_drv_base.h +++ b/drivers/media/platform/mtk-vcodec/venc_drv_base.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: Daniel Hsiao <daniel.hsiao@mediatek.com> @@ -19,7 +19,7 @@ struct venc_common_if { * @ctx: [in] mtk v4l2 context * @handle: [out] driver handle */ - int (*init)(struct mtk_vcodec_ctx *ctx, unsigned long *handle); + int (*init)(struct mtk_vcodec_ctx *ctx); /** * (*encode)() - trigger encode @@ -29,7 +29,7 @@ struct venc_common_if { * @bs_buf: [in] bitstream buffer to store output bitstream * @result: [out] encode result */ - int (*encode)(unsigned long handle, enum venc_start_opt opt, + int (*encode)(void *handle, enum venc_start_opt opt, struct venc_frm_buf *frm_buf, struct mtk_vcodec_mem *bs_buf, struct venc_done_result *result); @@ -40,14 +40,14 @@ struct venc_common_if { * @type: [in] parameter type * @in: [in] buffer to store the parameter */ - int (*set_param)(unsigned long handle, enum venc_set_param_type type, + int (*set_param)(void *handle, enum venc_set_param_type type, struct venc_enc_param *in); /** * (*deinit)() - deinitialize driver. * @handle: [in] driver handle */ - int (*deinit)(unsigned long handle); + int (*deinit)(void *handle); }; #endif diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.c b/drivers/media/platform/mtk-vcodec/venc_drv_if.c index 608c08b2ab8f..c6bb82ac2dcd 100644 --- a/drivers/media/platform/mtk-vcodec/venc_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/venc_drv_if.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: Daniel Hsiao <daniel.hsiao@mediatek.com> @@ -17,19 +17,16 @@ #include "mtk_vcodec_enc_pm.h" #include "mtk_vpu.h" -const struct venc_common_if *get_h264_enc_comm_if(void); -const struct venc_common_if *get_vp8_enc_comm_if(void); - int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) { int ret = 0; switch (fourcc) { case V4L2_PIX_FMT_VP8: - ctx->enc_if = get_vp8_enc_comm_if(); + ctx->enc_if = &venc_vp8_if; break; case V4L2_PIX_FMT_H264: - ctx->enc_if = get_h264_enc_comm_if(); + ctx->enc_if = &venc_h264_if; break; default: return -EINVAL; @@ -37,7 +34,7 @@ int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) mtk_venc_lock(ctx); mtk_vcodec_enc_clock_on(&ctx->dev->pm); - ret = ctx->enc_if->init(ctx, (unsigned long *)&ctx->drv_handle); + ret = ctx->enc_if->init(ctx); mtk_vcodec_enc_clock_off(&ctx->dev->pm); mtk_venc_unlock(ctx); @@ -89,7 +86,7 @@ int venc_if_deinit(struct mtk_vcodec_ctx *ctx) { int ret = 0; - if (ctx->drv_handle == 0) + if (!ctx->drv_handle) return 0; mtk_venc_lock(ctx); @@ -98,7 +95,7 @@ int venc_if_deinit(struct mtk_vcodec_ctx *ctx) mtk_vcodec_enc_clock_off(&ctx->dev->pm); mtk_venc_unlock(ctx); - ctx->drv_handle = 0; + ctx->drv_handle = NULL; return ret; } diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.h b/drivers/media/platform/mtk-vcodec/venc_drv_if.h index bbba1cec7be4..52fc9cc812fc 100644 --- a/drivers/media/platform/mtk-vcodec/venc_drv_if.h +++ b/drivers/media/platform/mtk-vcodec/venc_drv_if.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: Daniel Hsiao <daniel.hsiao@mediatek.com> @@ -110,6 +110,9 @@ struct venc_done_result { bool is_key_frm; }; +extern const struct venc_common_if venc_h264_if; +extern const struct venc_common_if venc_vp8_if; + /* * venc_if_init - Create the driver handle * @ctx: device context diff --git a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h index be34780760f4..28ee04ca6241 100644 --- a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h +++ b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: Jungchang Tsao <jungchang.tsao@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c index 7daf8694c62e..3e931b0ed096 100644 --- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c +++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 MediaTek Inc. * Author: PoChun Lin <pochun.lin@mediatek.com> diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.h b/drivers/media/platform/mtk-vcodec/venc_vpu_if.h index a6b6d0eafb50..ba301a138a5a 100644 --- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.h +++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016 MediaTek Inc. * Author: PoChun Lin <pochun.lin@mediatek.com> diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index da655d166d52..cc2ff40d060d 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -460,9 +460,9 @@ struct platform_device *vpu_get_plat_device(struct platform_device *pdev) } vpu_pdev = of_find_device_by_node(vpu_node); + of_node_put(vpu_node); if (WARN_ON(!vpu_pdev)) { dev_err(dev, "vpu pdev failed\n"); - of_node_put(vpu_node); return NULL; } diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig index 08a606a5adff..1a99dff21ca0 100644 --- a/drivers/media/platform/omap/Kconfig +++ b/drivers/media/platform/omap/Kconfig @@ -14,6 +14,5 @@ config VIDEO_OMAP2_VOUT select VIDEOBUF_DMA_CONTIG select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 select FRAME_VECTOR - default n help V4L2 Display driver support for OMAP2/3 based boards. diff --git a/drivers/media/platform/omap3isp/cfa_coef_table.h b/drivers/media/platform/omap3isp/cfa_coef_table.h index e75b0eb2519b..786200c5e4fa 100644 --- a/drivers/media/platform/omap3isp/cfa_coef_table.h +++ b/drivers/media/platform/omap3isp/cfa_coef_table.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cfa_coef_table.h * @@ -7,10 +8,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ { 244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244, diff --git a/drivers/media/platform/omap3isp/gamma_table.h b/drivers/media/platform/omap3isp/gamma_table.h index 3b507078016d..442c82c2eb22 100644 --- a/drivers/media/platform/omap3isp/gamma_table.h +++ b/drivers/media/platform/omap3isp/gamma_table.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * gamma_table.h * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ 0, 0, 1, 2, 3, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20, diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index bd57174d81a7..83216fc7156b 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * isp.c * @@ -36,10 +37,6 @@ * Thara Gopinath <thara@ti.com> * Toni Leinonen <toni.leinonen@nokia.com> * Troy Laramy <t-laramy@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <asm/cacheflush.h> @@ -2006,6 +2003,8 @@ static int isp_remove(struct platform_device *pdev) media_entity_enum_cleanup(&isp->crashed); v4l2_async_notifier_cleanup(&isp->notifier); + kfree(isp); + return 0; } @@ -2196,7 +2195,7 @@ static int isp_probe(struct platform_device *pdev) int ret; int i, m; - isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); + isp = kzalloc(sizeof(*isp), GFP_KERNEL); if (!isp) { dev_err(&pdev->dev, "could not allocate memory\n"); return -ENOMEM; @@ -2205,17 +2204,19 @@ static int isp_probe(struct platform_device *pdev) ret = fwnode_property_read_u32(of_fwnode_handle(pdev->dev.of_node), "ti,phy-type", &isp->phy_type); if (ret) - return ret; + goto error_release_isp; isp->syscon = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "syscon"); - if (IS_ERR(isp->syscon)) - return PTR_ERR(isp->syscon); + if (IS_ERR(isp->syscon)) { + ret = PTR_ERR(isp->syscon); + goto error_release_isp; + } ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 1, &isp->syscon_offset); if (ret) - return ret; + goto error_release_isp; isp->autoidle = autoidle; @@ -2372,6 +2373,8 @@ error_isp: error: v4l2_async_notifier_cleanup(&isp->notifier); mutex_destroy(&isp->isp_mutex); +error_release_isp: + kfree(isp); return ret; } @@ -2383,7 +2386,7 @@ static const struct dev_pm_ops omap3isp_pm_ops = { .complete = isp_pm_complete, }; -static struct platform_device_id omap3isp_id_table[] = { +static const struct platform_device_id omap3isp_id_table[] = { { "omap3isp", 0 }, { }, }; diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index 8b9043db94b3..a9d760fbf349 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * isp.h * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef OMAP3_ISP_CORE_H diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 261ad1175f98..1ba8a5ba343f 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ispccdc.c * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h index 3440a7097940..7883365d7203 100644 --- a/drivers/media/platform/omap3isp/ispccdc.h +++ b/drivers/media/platform/omap3isp/ispccdc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ispccdc.h * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef OMAP3_ISP_CCDC_H diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index 2dea423ffc0e..efca45bb02c8 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ispccp2.c * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/media/platform/omap3isp/ispccp2.h b/drivers/media/platform/omap3isp/ispccp2.h index 4662bffa79e3..03e6af3de1d9 100644 --- a/drivers/media/platform/omap3isp/ispccp2.h +++ b/drivers/media/platform/omap3isp/ispccp2.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ispccp2.h * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef OMAP3_ISP_CCP2_H diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index da66ea65be5d..e85917f4a50c 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ispcsi2.c * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> #include <media/v4l2-common.h> diff --git a/drivers/media/platform/omap3isp/ispcsi2.h b/drivers/media/platform/omap3isp/ispcsi2.h index 453ed62fe394..036b97f8470e 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.h +++ b/drivers/media/platform/omap3isp/ispcsi2.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ispcsi2.h * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef OMAP3_ISP_CSI2_H diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c index a28fb79abaac..6dc7359c5131 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.c +++ b/drivers/media/platform/omap3isp/ispcsiphy.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ispcsiphy.c * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/media/platform/omap3isp/ispcsiphy.h b/drivers/media/platform/omap3isp/ispcsiphy.h index 91543a09b28a..ed9b8d221e3f 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.h +++ b/drivers/media/platform/omap3isp/ispcsiphy.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ispcsiphy.h * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef OMAP3_ISP_CSI_PHY_H diff --git a/drivers/media/platform/omap3isp/isph3a.h b/drivers/media/platform/omap3isp/isph3a.h index e5b28d0f3b0f..5144f7689dda 100644 --- a/drivers/media/platform/omap3isp/isph3a.h +++ b/drivers/media/platform/omap3isp/isph3a.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * isph3a.h * @@ -9,10 +10,6 @@ * Contacts: David Cohen <dacohen@gmail.com> * Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef OMAP3_ISP_H3A_H diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c index 3c82dea4d375..e6c54c4bbfca 100644 --- a/drivers/media/platform/omap3isp/isph3a_aewb.c +++ b/drivers/media/platform/omap3isp/isph3a_aewb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * isph3a.c * @@ -9,10 +10,6 @@ * Contacts: David Cohen <dacohen@gmail.com> * Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/slab.h> @@ -291,9 +288,10 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp) { struct ispstat *aewb = &isp->isp_aewb; struct omap3isp_h3a_aewb_config *aewb_cfg; - struct omap3isp_h3a_aewb_config *aewb_recover_cfg; + struct omap3isp_h3a_aewb_config *aewb_recover_cfg = NULL; + int ret; - aewb_cfg = devm_kzalloc(isp->dev, sizeof(*aewb_cfg), GFP_KERNEL); + aewb_cfg = kzalloc(sizeof(*aewb_cfg), GFP_KERNEL); if (!aewb_cfg) return -ENOMEM; @@ -303,12 +301,12 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp) aewb->isp = isp; /* Set recover state configuration */ - aewb_recover_cfg = devm_kzalloc(isp->dev, sizeof(*aewb_recover_cfg), - GFP_KERNEL); + aewb_recover_cfg = kzalloc(sizeof(*aewb_recover_cfg), GFP_KERNEL); if (!aewb_recover_cfg) { dev_err(aewb->isp->dev, "AEWB: cannot allocate memory for recover configuration.\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err; } aewb_recover_cfg->saturation_limit = OMAP3ISP_AEWB_MAX_SATURATION_LIM; @@ -325,13 +323,22 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp) if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) { dev_err(aewb->isp->dev, "AEWB: recover configuration is invalid.\n"); - return -EINVAL; + ret = -EINVAL; + goto err; } aewb_recover_cfg->buf_size = h3a_aewb_get_buf_size(aewb_recover_cfg); aewb->recover_priv = aewb_recover_cfg; - return omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops); + ret = omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops); + +err: + if (ret) { + kfree(aewb_cfg); + kfree(aewb_recover_cfg); + } + + return ret; } /* diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c index 4da25c84f0c6..a65cfdfa9637 100644 --- a/drivers/media/platform/omap3isp/isph3a_af.c +++ b/drivers/media/platform/omap3isp/isph3a_af.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * isph3a_af.c * @@ -9,10 +10,6 @@ * Contacts: David Cohen <dacohen@gmail.com> * Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /* Linux specific include files */ @@ -354,9 +351,10 @@ int omap3isp_h3a_af_init(struct isp_device *isp) { struct ispstat *af = &isp->isp_af; struct omap3isp_h3a_af_config *af_cfg; - struct omap3isp_h3a_af_config *af_recover_cfg; + struct omap3isp_h3a_af_config *af_recover_cfg = NULL; + int ret; - af_cfg = devm_kzalloc(isp->dev, sizeof(*af_cfg), GFP_KERNEL); + af_cfg = kzalloc(sizeof(*af_cfg), GFP_KERNEL); if (af_cfg == NULL) return -ENOMEM; @@ -366,12 +364,12 @@ int omap3isp_h3a_af_init(struct isp_device *isp) af->isp = isp; /* Set recover state configuration */ - af_recover_cfg = devm_kzalloc(isp->dev, sizeof(*af_recover_cfg), - GFP_KERNEL); + af_recover_cfg = kzalloc(sizeof(*af_recover_cfg), GFP_KERNEL); if (!af_recover_cfg) { dev_err(af->isp->dev, "AF: cannot allocate memory for recover configuration.\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err; } af_recover_cfg->paxel.h_start = OMAP3ISP_AF_PAXEL_HZSTART_MIN; @@ -383,13 +381,22 @@ int omap3isp_h3a_af_init(struct isp_device *isp) if (h3a_af_validate_params(af, af_recover_cfg)) { dev_err(af->isp->dev, "AF: recover configuration is invalid.\n"); - return -EINVAL; + ret = -EINVAL; + goto err; } af_recover_cfg->buf_size = h3a_af_get_buf_size(af_recover_cfg); af->recover_priv = af_recover_cfg; - return omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops); + ret = omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops); + +err: + if (ret) { + kfree(af_cfg); + kfree(af_recover_cfg); + } + + return ret; } void omap3isp_h3a_af_cleanup(struct isp_device *isp) diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c index d4be3d0e06f9..0ef78aace6da 100644 --- a/drivers/media/platform/omap3isp/isphist.c +++ b/drivers/media/platform/omap3isp/isphist.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * isphist.c * @@ -9,10 +10,6 @@ * Contacts: David Cohen <dacohen@gmail.com> * Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> @@ -478,9 +475,9 @@ int omap3isp_hist_init(struct isp_device *isp) { struct ispstat *hist = &isp->isp_hist; struct omap3isp_hist_config *hist_cfg; - int ret = -1; + int ret; - hist_cfg = devm_kzalloc(isp->dev, sizeof(*hist_cfg), GFP_KERNEL); + hist_cfg = kzalloc(sizeof(*hist_cfg), GFP_KERNEL); if (hist_cfg == NULL) return -ENOMEM; @@ -502,7 +499,7 @@ int omap3isp_hist_init(struct isp_device *isp) if (IS_ERR(hist->dma_ch)) { ret = PTR_ERR(hist->dma_ch); if (ret == -EPROBE_DEFER) - return ret; + goto err; hist->dma_ch = NULL; dev_warn(isp->dev, @@ -518,9 +515,12 @@ int omap3isp_hist_init(struct isp_device *isp) hist->event_type = V4L2_EVENT_OMAP3ISP_HIST; ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops); + +err: if (ret) { - if (hist->dma_ch) + if (!IS_ERR_OR_NULL(hist->dma_ch)) dma_release_channel(hist->dma_ch); + kfree(hist_cfg); } return ret; diff --git a/drivers/media/platform/omap3isp/isphist.h b/drivers/media/platform/omap3isp/isphist.h index 3b5415517dcd..93cd27a3b617 100644 --- a/drivers/media/platform/omap3isp/isphist.h +++ b/drivers/media/platform/omap3isp/isphist.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * isphist.h * @@ -9,10 +10,6 @@ * Contacts: David Cohen <dacohen@gmail.com> * Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef OMAP3_ISP_HIST_H diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index 6ea6aeafd751..40e22400cf5e 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * isppreview.c * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/media/platform/omap3isp/isppreview.h b/drivers/media/platform/omap3isp/isppreview.h index 16fdc03a3d43..5fff1ec3624f 100644 --- a/drivers/media/platform/omap3isp/isppreview.h +++ b/drivers/media/platform/omap3isp/isppreview.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * isppreview.h * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef OMAP3_ISP_PREVIEW_H diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h index d08483919a77..38e2b99b3f10 100644 --- a/drivers/media/platform/omap3isp/ispreg.h +++ b/drivers/media/platform/omap3isp/ispreg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ispreg.h * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef OMAP3_ISP_REG_H diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index b281cae036b3..21ca6954df72 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ispresizer.c * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/media/platform/omap3isp/ispresizer.h b/drivers/media/platform/omap3isp/ispresizer.h index 5414542912e2..28cc89940ead 100644 --- a/drivers/media/platform/omap3isp/ispresizer.h +++ b/drivers/media/platform/omap3isp/ispresizer.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ispresizer.h * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef OMAP3_ISP_RESIZER_H diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index 47353fee26c3..62b2eacb96fd 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ispstat.c * @@ -9,10 +10,6 @@ * Contacts: David Cohen <dacohen@gmail.com> * Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/dma-mapping.h> @@ -1040,7 +1037,7 @@ static int isp_stat_init_entities(struct ispstat *stat, const char *name, v4l2_subdev_init(subdev, sd_ops); snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); - subdev->grp_id = 1 << 16; /* group ID for isp subdevs */ + subdev->grp_id = BIT(16); /* group ID for isp subdevs */ subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; v4l2_set_subdevdata(subdev, stat); @@ -1078,4 +1075,6 @@ void omap3isp_stat_cleanup(struct ispstat *stat) mutex_destroy(&stat->ioctl_lock); isp_stat_bufs_free(stat); kfree(stat->buf); + kfree(stat->priv); + kfree(stat->recover_priv); } diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h index 923b38cfc682..b548e617cf62 100644 --- a/drivers/media/platform/omap3isp/ispstat.h +++ b/drivers/media/platform/omap3isp/ispstat.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ispstat.h * @@ -9,10 +10,6 @@ * Contacts: David Cohen <dacohen@gmail.com> * Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef OMAP3_ISP_STAT_H diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 078d64114b24..499a7284c5a8 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ispvideo.c * @@ -7,10 +8,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <asm/cacheflush.h> @@ -1495,6 +1492,5 @@ int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) void omap3isp_video_unregister(struct isp_video *video) { - if (video_is_registered(&video->video)) - video_unregister_device(&video->video); + video_unregister_device(&video->video); } diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h index f6a2082b4a0a..a0908670c0cf 100644 --- a/drivers/media/platform/omap3isp/ispvideo.h +++ b/drivers/media/platform/omap3isp/ispvideo.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ispvideo.h * @@ -7,10 +8,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef OMAP3_ISP_VIDEO_H diff --git a/drivers/media/platform/omap3isp/luma_enhance_table.h b/drivers/media/platform/omap3isp/luma_enhance_table.h index 81c5b1566469..d5fbf9241f48 100644 --- a/drivers/media/platform/omap3isp/luma_enhance_table.h +++ b/drivers/media/platform/omap3isp/luma_enhance_table.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * luma_enhance_table.h * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, diff --git a/drivers/media/platform/omap3isp/noise_filter_table.h b/drivers/media/platform/omap3isp/noise_filter_table.h index 5073f9847937..da66bd0a3b9f 100644 --- a/drivers/media/platform/omap3isp/noise_filter_table.h +++ b/drivers/media/platform/omap3isp/noise_filter_table.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * noise_filter_table.h * @@ -8,10 +9,6 @@ * * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Sakari Ailus <sakari.ailus@iki.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index 6addc5ea8494..1c9bfaabc54c 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -1388,7 +1388,7 @@ static int pxa_buffer_init(struct pxa_camera_dev *pcdev, break; default: return -EINVAL; - }; + } buf->nb_planes = nb_channels; ret = sg_split(sgt->sgl, sgt->nents, 0, nb_channels, diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 58aebe7114cd..1d50dfbbb762 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -703,7 +703,7 @@ static int video_s_input(struct file *file, void *fh, unsigned int input) static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = { .vidioc_querycap = video_querycap, - .vidioc_enum_fmt_vid_cap_mplane = video_enum_fmt, + .vidioc_enum_fmt_vid_cap = video_enum_fmt, .vidioc_g_fmt_vid_cap_mplane = video_g_fmt, .vidioc_s_fmt_vid_cap_mplane = video_s_fmt, .vidioc_try_fmt_vid_cap_mplane = video_try_fmt, diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index db8e40b55d72..0acc7576cc58 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -446,7 +446,7 @@ static const struct venus_resources msm8996_res = { .reg_tbl_size = ARRAY_SIZE(msm8996_reg_preset), .clks = {"core", "iface", "bus", "mbus" }, .clks_num = 4, - .max_load = 3110400, /* 4096x2160@90 */ + .max_load = 2563200, .hfi_version = HFI_VERSION_3XX, .vmem_id = VIDC_RESOURCE_NONE, .vmem_size = 0, @@ -469,7 +469,7 @@ static const struct venus_resources sdm845_res = { .freq_tbl_size = ARRAY_SIZE(sdm845_freq_table), .clks = {"core", "iface", "bus" }, .clks_num = 3, - .max_load = 2563200, + .max_load = 3110400, /* 4096x2160@90 */ .hfi_version = HFI_VERSION_4XX, .vmem_id = VIDC_RESOURCE_NONE, .vmem_size = 0, diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 1eba23409ff3..d3d1748a7ef6 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -78,11 +78,11 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, ret = of_address_to_resource(node, 0, &r); if (ret) - return ret; + goto err_put_node; ret = request_firmware(&mdt, fwname, dev); if (ret < 0) - return ret; + goto err_put_node; fw_size = qcom_mdt_get_size(mdt); if (fw_size < 0) { @@ -116,6 +116,8 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, memunmap(mem_va); err_release_fw: release_firmware(mdt); +err_put_node: + of_node_put(node); return ret; } diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 7d0017613113..71b06dfc6dc4 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -458,6 +458,13 @@ static bool is_dynamic_bufmode(struct venus_inst *inst) struct venus_core *core = inst->core; struct venus_caps *caps; + /* + * v4 doesn't send BUFFER_ALLOC_MODE_SUPPORTED property and supports + * dynamic buffer mode by default for HFI_BUFFER_OUTPUT/OUTPUT2. + */ + if (IS_V4(core)) + return true; + caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type); if (!caps) return false; diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c index 8efd55a2ad70..4f645076abfb 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.c +++ b/drivers/media/platform/qcom/venus/hfi_cmds.c @@ -1205,6 +1205,8 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt, break; } case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE: + case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER: + case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE: /* not implemented on Venus 4xx */ return -ENOTSUPP; default: diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 6205ad8b3201..e1f998656c07 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -482,8 +482,8 @@ unlock: static const struct v4l2_ioctl_ops vdec_ioctl_ops = { .vidioc_querycap = vdec_querycap, - .vidioc_enum_fmt_vid_cap_mplane = vdec_enum_fmt, - .vidioc_enum_fmt_vid_out_mplane = vdec_enum_fmt, + .vidioc_enum_fmt_vid_cap = vdec_enum_fmt, + .vidioc_enum_fmt_vid_out = vdec_enum_fmt, .vidioc_s_fmt_vid_cap_mplane = vdec_s_fmt, .vidioc_s_fmt_vid_out_mplane = vdec_s_fmt, .vidioc_g_fmt_vid_cap_mplane = vdec_g_fmt, diff --git a/drivers/media/platform/qcom/venus/vdec_ctrls.c b/drivers/media/platform/qcom/venus/vdec_ctrls.c index 68e0f7d0b8fc..300350bfe8bd 100644 --- a/drivers/media/platform/qcom/venus/vdec_ctrls.c +++ b/drivers/media/platform/qcom/venus/vdec_ctrls.c @@ -66,7 +66,7 @@ static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; default: return -EINVAL; - }; + } return 0; } diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 7a4815d52c12..a5f3d2c46bea 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -607,8 +607,8 @@ static int venc_enum_frameintervals(struct file *file, void *fh, static const struct v4l2_ioctl_ops venc_ioctl_ops = { .vidioc_querycap = venc_querycap, - .vidioc_enum_fmt_vid_cap_mplane = venc_enum_fmt, - .vidioc_enum_fmt_vid_out_mplane = venc_enum_fmt, + .vidioc_enum_fmt_vid_cap = venc_enum_fmt, + .vidioc_enum_fmt_vid_out = venc_enum_fmt, .vidioc_s_fmt_vid_cap_mplane = venc_s_fmt, .vidioc_s_fmt_vid_out_mplane = venc_s_fmt, .vidioc_g_fmt_vid_cap_mplane = venc_g_fmt, diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index 8832285d8c15..877c0b3299e9 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -108,6 +108,9 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_H264_PROFILE: ctr->profile.h264 = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + ctr->profile.hevc = ctrl->val; + break; case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: ctr->profile.vpx = ctrl->val; break; @@ -117,6 +120,9 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_H264_LEVEL: ctr->level.h264 = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + ctr->level.hevc = ctrl->val; + break; case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: ctr->h264_i_qp = ctrl->val; break; @@ -208,7 +214,7 @@ int venc_ctrl_init(struct venus_inst *inst) { int ret; - ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 28); + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 30); if (ret) return ret; @@ -237,6 +243,19 @@ int venc_ctrl_init(struct venus_inst *inst) 0, V4L2_MPEG_VIDEO_MPEG4_LEVEL_0); v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + ~((1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + (1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + (1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10)), + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN); + + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + 0, V4L2_MPEG_VIDEO_HEVC_LEVEL_1); + + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH, ~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | @@ -265,7 +284,7 @@ int venc_ctrl_init(struct venus_inst *inst) v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, - V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, 0, V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE); v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index 8f097e514900..c14af1b929df 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -1019,10 +1019,8 @@ static int rcsi2_probe_resources(struct rcar_csi2 *priv, return ret; priv->rstc = devm_reset_control_get(&pdev->dev, NULL); - if (IS_ERR(priv->rstc)) - return PTR_ERR(priv->rstc); - return 0; + return PTR_ERR_OR_ZERO(priv->rstc); } static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = { diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index 7cbdcbf9b090..0936bcd98df1 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -749,103 +749,65 @@ static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = { * File Operations */ -static int rvin_power_on(struct rvin_dev *vin) +static int rvin_power_parallel(struct rvin_dev *vin, bool on) { - int ret; struct v4l2_subdev *sd = vin_to_source(vin); - - pm_runtime_get_sync(vin->v4l2_dev.dev); - - ret = v4l2_subdev_call(sd, core, s_power, 1); - if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) - return ret; - return 0; -} - -static int rvin_power_off(struct rvin_dev *vin) -{ + int power = on ? 1 : 0; int ret; - struct v4l2_subdev *sd = vin_to_source(vin); - - ret = v4l2_subdev_call(sd, core, s_power, 0); - - pm_runtime_put(vin->v4l2_dev.dev); + ret = v4l2_subdev_call(sd, core, s_power, power); if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) return ret; return 0; } -static int rvin_initialize_device(struct file *file) +static int rvin_open(struct file *file) { struct rvin_dev *vin = video_drvdata(file); int ret; - struct v4l2_format f = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .fmt.pix = { - .width = vin->format.width, - .height = vin->format.height, - .field = vin->format.field, - .colorspace = vin->format.colorspace, - .pixelformat = vin->format.pixelformat, - }, - }; - - ret = rvin_power_on(vin); + ret = pm_runtime_get_sync(vin->dev); if (ret < 0) return ret; - pm_runtime_enable(&vin->vdev.dev); - ret = pm_runtime_resume(&vin->vdev.dev); - if (ret < 0 && ret != -ENOSYS) - goto eresume; - - /* - * Try to configure with default parameters. Notice: this is the - * very first open, so, we cannot race against other calls, - * apart from someone else calling open() simultaneously, but - * .host_lock is protecting us against it. - */ - ret = rvin_s_fmt_vid_cap(file, NULL, &f); - if (ret < 0) - goto esfmt; - - v4l2_ctrl_handler_setup(&vin->ctrl_handler); - - return 0; -esfmt: - pm_runtime_disable(&vin->vdev.dev); -eresume: - rvin_power_off(vin); - - return ret; -} - -static int rvin_open(struct file *file) -{ - struct rvin_dev *vin = video_drvdata(file); - int ret; - - mutex_lock(&vin->lock); + ret = mutex_lock_interruptible(&vin->lock); + if (ret) + goto err_pm; file->private_data = vin; ret = v4l2_fh_open(file); if (ret) - goto unlock; - - if (!v4l2_fh_is_singular_file(file)) - goto unlock; + goto err_unlock; - if (rvin_initialize_device(file)) { - v4l2_fh_release(file); - ret = -ENODEV; + if (vin->info->use_mc) { + ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1); + if (ret < 0) + goto err_open; + } else { + if (v4l2_fh_is_singular_file(file)) { + ret = rvin_power_parallel(vin, true); + if (ret < 0) + goto err_open; + + ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler); + if (ret) + goto err_parallel; + } } + mutex_unlock(&vin->lock); -unlock: + return 0; +err_parallel: + rvin_power_parallel(vin, false); +err_open: + v4l2_fh_release(file); +err_unlock: mutex_unlock(&vin->lock); +err_pm: + pm_runtime_put(vin->dev); + return ret; } @@ -863,18 +825,17 @@ static int rvin_release(struct file *file) /* the release helper will cleanup any on-going streaming */ ret = _vb2_fop_release(file, NULL); - /* - * If this was the last open file. - * Then de-initialize hw module. - */ - if (fh_singular) { - pm_runtime_suspend(&vin->vdev.dev); - pm_runtime_disable(&vin->vdev.dev); - rvin_power_off(vin); + if (vin->info->use_mc) { + v4l2_pipeline_pm_use(&vin->vdev.entity, 0); + } else { + if (fh_singular) + rvin_power_parallel(vin, false); } mutex_unlock(&vin->lock); + pm_runtime_put(vin->dev); + return ret; } @@ -888,74 +849,6 @@ static const struct v4l2_file_operations rvin_fops = { .read = vb2_fop_read, }; -/* ----------------------------------------------------------------------------- - * Media controller file operations - */ - -static int rvin_mc_open(struct file *file) -{ - struct rvin_dev *vin = video_drvdata(file); - int ret; - - ret = mutex_lock_interruptible(&vin->lock); - if (ret) - return ret; - - ret = pm_runtime_get_sync(vin->dev); - if (ret < 0) - goto err_unlock; - - ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1); - if (ret < 0) - goto err_pm; - - file->private_data = vin; - - ret = v4l2_fh_open(file); - if (ret) - goto err_v4l2pm; - - mutex_unlock(&vin->lock); - - return 0; -err_v4l2pm: - v4l2_pipeline_pm_use(&vin->vdev.entity, 0); -err_pm: - pm_runtime_put(vin->dev); -err_unlock: - mutex_unlock(&vin->lock); - - return ret; -} - -static int rvin_mc_release(struct file *file) -{ - struct rvin_dev *vin = video_drvdata(file); - int ret; - - mutex_lock(&vin->lock); - - /* the release helper will cleanup any on-going streaming. */ - ret = _vb2_fop_release(file, NULL); - - v4l2_pipeline_pm_use(&vin->vdev.entity, 0); - pm_runtime_put(vin->dev); - - mutex_unlock(&vin->lock); - - return ret; -} - -static const struct v4l2_file_operations rvin_mc_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, - .open = rvin_mc_open, - .release = rvin_mc_release, - .poll = vb2_fop_poll, - .mmap = vb2_fop_mmap, - .read = vb2_fop_read, -}; - void rvin_v4l2_unregister(struct rvin_dev *vin) { if (!video_is_registered(&vin->vdev)) @@ -996,6 +889,7 @@ int rvin_v4l2_register(struct rvin_dev *vin) snprintf(vdev->name, sizeof(vdev->name), "VIN%u output", vin->id); vdev->release = video_device_release_empty; vdev->lock = &vin->lock; + vdev->fops = &rvin_fops; vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; @@ -1007,10 +901,8 @@ int rvin_v4l2_register(struct rvin_dev *vin) vin->format.colorspace = RVIN_DEFAULT_COLORSPACE; if (vin->info->use_mc) { - vdev->fops = &rvin_mc_fops; vdev->ioctl_ops = &rvin_mc_ioctl_ops; } else { - vdev->fops = &rvin_fops; vdev->ioctl_ops = &rvin_ioctl_ops; rvin_reset_format(vin); } diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c index 6a90bc4c476e..43aae9b6bb20 100644 --- a/drivers/media/platform/rcar_fdp1.c +++ b/drivers/media/platform/rcar_fdp1.c @@ -257,6 +257,8 @@ MODULE_PARM_DESC(debug, "activate debug info"); #define FD1_IP_H3_ES1 0x02010101 #define FD1_IP_M3W 0x02010202 #define FD1_IP_H3 0x02010203 +#define FD1_IP_M3N 0x02010204 +#define FD1_IP_E3 0x02010205 /* LUTs */ #define FD1_LUT_DIF_ADJ 0x1000 @@ -1730,8 +1732,8 @@ static const char * const fdp1_ctrl_deint_menu[] = { static const struct v4l2_ioctl_ops fdp1_ioctl_ops = { .vidioc_querycap = fdp1_vidioc_querycap, - .vidioc_enum_fmt_vid_cap_mplane = fdp1_enum_fmt_vid_cap, - .vidioc_enum_fmt_vid_out_mplane = fdp1_enum_fmt_vid_out, + .vidioc_enum_fmt_vid_cap = fdp1_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = fdp1_enum_fmt_vid_out, .vidioc_g_fmt_vid_cap_mplane = fdp1_g_fmt, .vidioc_g_fmt_vid_out_mplane = fdp1_g_fmt, .vidioc_try_fmt_vid_cap_mplane = fdp1_try_fmt, @@ -2365,6 +2367,12 @@ static int fdp1_probe(struct platform_device *pdev) case FD1_IP_H3: dprintk(fdp1, "FDP1 Version R-Car H3\n"); break; + case FD1_IP_M3N: + dprintk(fdp1, "FDP1 Version R-Car M3N\n"); + break; + case FD1_IP_E3: + dprintk(fdp1, "FDP1 Version R-Car E3\n"); + break; default: dev_err(fdp1->dev, "FDP1 Unidentifiable (0x%08x)\n", hw_version); diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c index 1dfd2eb65920..1c3f507acfc9 100644 --- a/drivers/media/platform/rcar_jpu.c +++ b/drivers/media/platform/rcar_jpu.c @@ -671,8 +671,6 @@ static int jpu_querycap(struct file *file, void *priv, strscpy(cap->driver, DRV_NAME, sizeof(cap->driver)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(ctx->jpu->dev)); - cap->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; - cap->capabilities = V4L2_CAP_DEVICE_CAPS | cap->device_caps; memset(cap->reserved, 0, sizeof(cap->reserved)); return 0; @@ -948,8 +946,8 @@ static int jpu_streamon(struct file *file, void *priv, enum v4l2_buf_type type) static const struct v4l2_ioctl_ops jpu_ioctl_ops = { .vidioc_querycap = jpu_querycap, - .vidioc_enum_fmt_vid_cap_mplane = jpu_enum_fmt_cap, - .vidioc_enum_fmt_vid_out_mplane = jpu_enum_fmt_out, + .vidioc_enum_fmt_vid_cap = jpu_enum_fmt_cap, + .vidioc_enum_fmt_vid_out = jpu_enum_fmt_out, .vidioc_g_fmt_vid_cap_mplane = jpu_g_fmt, .vidioc_g_fmt_vid_out_mplane = jpu_g_fmt, .vidioc_try_fmt_vid_cap_mplane = jpu_try_fmt, @@ -1662,6 +1660,8 @@ static int jpu_probe(struct platform_device *pdev) jpu->vfd_encoder.lock = &jpu->mutex; jpu->vfd_encoder.v4l2_dev = &jpu->v4l2_dev; jpu->vfd_encoder.vfl_dir = VFL_DIR_M2M; + jpu->vfd_encoder.device_caps = V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_M2M_MPLANE; ret = video_register_device(&jpu->vfd_encoder, VFL_TYPE_GRABBER, -1); if (ret) { @@ -1679,6 +1679,8 @@ static int jpu_probe(struct platform_device *pdev) jpu->vfd_decoder.lock = &jpu->mutex; jpu->vfd_decoder.v4l2_dev = &jpu->v4l2_dev; jpu->vfd_decoder.vfl_dir = VFL_DIR_M2M; + jpu->vfd_decoder.device_caps = V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_M2M_MPLANE; ret = video_register_device(&jpu->vfd_decoder, VFL_TYPE_GRABBER, -1); if (ret) { diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c index 150196f7cf96..57d0c0f9fa4b 100644 --- a/drivers/media/platform/renesas-ceu.c +++ b/drivers/media/platform/renesas-ceu.c @@ -1339,7 +1339,7 @@ static int ceu_enum_frameintervals(struct file *file, void *fh, static const struct v4l2_ioctl_ops ceu_ioctl_ops = { .vidioc_querycap = ceu_querycap, - .vidioc_enum_fmt_vid_cap_mplane = ceu_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = ceu_enum_fmt_vid_cap, .vidioc_try_fmt_vid_cap_mplane = ceu_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap_mplane = ceu_s_fmt_vid_cap, .vidioc_g_fmt_vid_cap_mplane = ceu_g_fmt_vid_cap, diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index c3fc94ef251e..a876d0873ebc 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver * @@ -6,10 +7,6 @@ * * Based on drivers/media/platform/s5p-fimc, * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ diff --git a/drivers/media/platform/s3c-camif/camif-core.h b/drivers/media/platform/s3c-camif/camif-core.h index be5e7357dffc..efdc00b4ec6f 100644 --- a/drivers/media/platform/s3c-camif/camif-core.h +++ b/drivers/media/platform/s3c-camif/camif-core.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver * * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com> * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef CAMIF_CORE_H_ diff --git a/drivers/media/platform/s3c-camif/camif-regs.c b/drivers/media/platform/s3c-camif/camif-regs.c index 812fb3a7c4e3..1a65532dc36d 100644 --- a/drivers/media/platform/s3c-camif/camif-regs.c +++ b/drivers/media/platform/s3c-camif/camif-regs.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung s3c24xx/s3c64xx SoC CAMIF driver * * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com> * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ diff --git a/drivers/media/platform/s3c-camif/camif-regs.h b/drivers/media/platform/s3c-camif/camif-regs.h index 5ad36c1c2a5d..29f839cdb486 100644 --- a/drivers/media/platform/s3c-camif/camif-regs.h +++ b/drivers/media/platform/s3c-camif/camif-regs.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Register definition file for s3c24xx/s3c64xx SoC CAMIF driver * * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com> * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef CAMIF_REGS_H_ diff --git a/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h b/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h index 7d9453505dce..325db8c432bd 100644 --- a/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h +++ b/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* drivers/media/platform/s5p-cec/exynos_hdmi_cec.h * * Copyright (c) 2010, 2014 Samsung Electronics * http://www.samsung.com/ * * Header file for interface of Samsung Exynos hdmi cec hardware - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _EXYNOS_HDMI_CEC_H_ diff --git a/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c b/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c index 146ae6f25cdb..eb981ebce362 100644 --- a/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c +++ b/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c * * Copyright (c) 2009, 2014 Samsung Electronics * http://www.samsung.com/ * * cec ftn file for Samsung TVOUT driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/io.h> diff --git a/drivers/media/platform/s5p-cec/regs-cec.h b/drivers/media/platform/s5p-cec/regs-cec.h index b2e7e129920e..447f717028a2 100644 --- a/drivers/media/platform/s5p-cec/regs-cec.h +++ b/drivers/media/platform/s5p-cec/regs-cec.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* drivers/media/platform/s5p-cec/regs-cec.h * * Copyright (c) 2010 Samsung Electronics * http://www.samsung.com/ * * register header file for Samsung TVOUT driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __EXYNOS_REGS__H diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 8cc730eccb6c..a3bc884b7df1 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* linux/drivers/media/platform/s5p-jpeg/jpeg-core.c * * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. @@ -5,10 +6,6 @@ * * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> * Author: Jacek Anaszewski <j.anaszewski@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h index 144c102ff05f..34f87f6c02f2 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* linux/drivers/media/platform/s5p-jpeg/jpeg-core.h * * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef JPEG_CORE_H_ diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c index 0861842b2dfc..637a5104d948 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* linux/drivers/media/platform/exynos3250-jpeg/jpeg-hw.h * * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Jacek Anaszewski <j.anaszewski@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/io.h> diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h index b6e3be8b5008..68160befce39 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* linux/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h * * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Jacek Anaszewski <j.anaszewski@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef JPEG_HW_EXYNOS3250_H_ #define JPEG_HW_EXYNOS3250_H_ diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c index c72789bae6ed..0828cfa783fe 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * Author: Jacek Anaszewski <j.anaszewski@samsung.com> * * Register interface file for JPEG driver on Exynos4x12. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/io.h> #include <linux/delay.h> diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h index cf6ec055d63a..3e2887526960 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * Author: Jacek Anaszewski <j.anaszewski@samsung.com> * * Header file of the register interface for JPEG driver on Exynos4x12. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef JPEG_HW_EXYNOS4_H_ diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c index 59c6263a71bf..491e9248286c 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* linux/drivers/media/platform/s5p-jpeg/jpeg-hw.h * * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/io.h> diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h index bfe746f8f750..98ddf7097562 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* linux/drivers/media/platform/s5p-jpeg/jpeg-hw.h * * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef JPEG_HW_S5P_H_ #define JPEG_HW_S5P_H_ diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs.h b/drivers/media/platform/s5p-jpeg/jpeg-regs.h index 574f0e8021e5..bab7fa46b89a 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-regs.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-regs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* linux/drivers/media/platform/s5p-jpeg/jpeg-regs.h * * Register definition file for Samsung JPEG codec driver @@ -7,10 +8,6 @@ * * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> * Author: Jacek Anaszewski <j.anaszewski@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef JPEG_REGS_H_ diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h index c0166ee9a455..fa49fe580e1a 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Register definition file for Samsung MFC V6.x Interface (FIMV) driver * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _REGS_FIMV_V6_H diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v7.h b/drivers/media/platform/s5p-mfc/regs-mfc-v7.h index 9f220769d970..4a7adfdaa359 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v7.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v7.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Register definition file for Samsung MFC V7.x Interface (FIMV) driver * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _REGS_MFC_V7_H diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h index bd639ae71023..162e3c7e920f 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Register definition file for Samsung MFC V8.x Interface (FIMV) driver * * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _REGS_MFC_V8_H diff --git a/drivers/media/platform/s5p-mfc/regs-mfc.h b/drivers/media/platform/s5p-mfc/regs-mfc.h index 57b7e0be0596..9171e8181c18 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Register definition file for Samsung MFC V5.1 Interface (FIMV) driver * * Kamil Debski, Copyright (c) 2010 Samsung Electronics * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _REGS_FIMV_H diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 4e936b95018a..b776f83e395e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -523,7 +523,8 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, dev); ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count, dev); - ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, + if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) + ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, get_min_scratch_buf_size, dev); if (ctx->img_width == 0 || ctx->img_height == 0) ctx->state = MFCINST_ERROR; @@ -1344,6 +1345,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) vfd->lock = &dev->mfc_mutex; vfd->v4l2_dev = &dev->v4l2_dev; vfd->vfl_dir = VFL_DIR_M2M; + vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags); snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME); dev->vfd_dec = vfd; @@ -1362,6 +1364,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) vfd->lock = &dev->mfc_mutex; vfd->v4l2_dev = &dev->v4l2_dev; vfd->vfl_dir = VFL_DIR_M2M; + vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME); dev->vfd_enc = vfd; video_set_drvdata(vfd, dev); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h index 1936a5b868f5..752bbe4fe48e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * drivers/media/platform/s5p-mfc/s5p_mfc_debug.h * @@ -6,10 +7,6 @@ * * Kamil Debski, Copyright (c) 2011 Samsung Electronics * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef S5P_MFC_DEBUG_H_ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index d12fc4f397b6..4017c8b471f4 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -271,13 +271,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, dev->vfd_dec->name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(&dev->plat_dev->dev)); - /* - * This is only a mem-to-mem video device. The capture and output - * device capability flags are left only for backward compatibility - * and are scheduled for removal. - */ - cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -309,14 +302,14 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, return 0; } -static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, - struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(file, f, false); } -static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(file, f, true); } @@ -883,8 +876,8 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh, /* v4l2_ioctl_ops */ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 74090a68f807..97e76480e942 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -130,7 +130,7 @@ static struct mfc_control controls[] = { .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, .type = V4L2_CTRL_TYPE_MENU, .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, - .maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, + .maximum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, .menu_skip_mask = 0, }, @@ -1313,13 +1313,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, dev->vfd_enc->name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(&dev->plat_dev->dev)); - /* - * This is only a mem-to-mem video device. The capture and output - * device capability flags are left only for backward compatibility - * and are scheduled for removal. - */ - cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1350,14 +1343,14 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, return -EINVAL; } -static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, - struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(file, f, false); } -static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov, - struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(file, f, true); } @@ -2339,8 +2332,8 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh, static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = { .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c index 5b8f0e085e6d..0a38f6d70ee9 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/media/platform/samsung/mfc5/s5p_mfc_intr.c * @@ -6,10 +7,6 @@ * * Kamil Debski, Copyright (C) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h index 18341a88514e..d32860db17d2 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * drivers/media/platform/samsung/mfc5/s5p_mfc_intr.h * @@ -6,10 +7,6 @@ * * Kamil Debski, Copyright (C) 2011 Samsung Electronics * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef S5P_MFC_INTR_H_ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c index 7f33cf23947f..bb65671eea91 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/media/platform/s5p-mfc/s5p_mfc_opr.c * @@ -6,10 +7,6 @@ * * Kamil Debski, Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "s5p_mfc_debug.h" diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h index 8c295f0f9740..1c5d2d4c0543 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * drivers/media/platform/s5p-mfc/s5p_mfc_opr.h * @@ -6,10 +7,6 @@ * * Kamil Debski, Copyright (C) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef S5P_MFC_OPR_H_ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index 6144e95f6425..f76a07400966 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/media/platform/samsung/mfc5/s5p_mfc_opr_v5.c * @@ -6,10 +7,6 @@ * * Kamil Debski, Copyright (c) 2011 Samsung Electronics * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "s5p_mfc_common.h" @@ -695,9 +692,9 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) /* multi-slice control */ /* multi-slice MB number or bit size */ mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL); - if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) { mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB); - } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT); } else { mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h index ffee39a127d5..b53d376ead60 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * drivers/media/platform/samsung/mfc5/s5p_mfc_opr_v5.h * @@ -6,10 +7,6 @@ * * Kamil Debski, Copyright (C) 2011 Samsung Electronics * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef S5P_MFC_OPR_V5_H_ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 281699ab7fe1..f7621a9051cb 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c * @@ -6,10 +7,6 @@ * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #undef DEBUG @@ -736,10 +733,10 @@ static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx) /* multi-slice control */ /* multi-slice MB number or bit size */ writel(ctx->slice_mode, mfc_regs->e_mslice_mode); - if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) { writel(ctx->slice_size.mb, mfc_regs->e_mslice_size_mb); } else if (ctx->slice_mode == - V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { writel(ctx->slice_size.bits, mfc_regs->e_mslice_size_bits); } else { writel(0x0, mfc_regs->e_mslice_size_mb); @@ -779,11 +776,11 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) /* multi-slice MB number or bit size */ ctx->slice_mode = p->slice_mode; reg = 0; - if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) { reg |= (0x1 << 3); writel(reg, mfc_regs->e_enc_options); ctx->slice_size.mb = p->slice_mb; - } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { reg |= (0x1 << 3); writel(reg, mfc_regs->e_enc_options); ctx->slice_size.bits = p->slice_bit; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h index f013b291ae5b..8ca514bf5e37 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h * @@ -6,10 +7,6 @@ * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef S5P_MFC_OPR_V6_H_ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 2e62f8721fa5..7d52431c2c83 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -34,6 +34,11 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) for (i = 0; i < pm->num_clocks; i++) { pm->clocks[i] = devm_clk_get(pm->device, pm->clk_names[i]); if (IS_ERR(pm->clocks[i])) { + /* additional clocks are optional */ + if (i && PTR_ERR(pm->clocks[i]) == -ENOENT) { + pm->clocks[i] = NULL; + continue; + } mfc_err("Failed to get clock: %s\n", pm->clk_names[i]); return PTR_ERR(pm->clocks[i]); diff --git a/drivers/media/platform/seco-cec/seco-cec.c b/drivers/media/platform/seco-cec/seco-cec.c index e5080d6f5b2d..1d0133f01e00 100644 --- a/drivers/media/platform/seco-cec/seco-cec.c +++ b/drivers/media/platform/seco-cec/seco-cec.c @@ -18,7 +18,7 @@ #include <linux/platform_device.h> /* CEC Framework */ -#include <media/cec.h> +#include <media/cec-notifier.h> #include "seco-cec.h" diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c index 075d4695ee4d..a79250a7f812 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c @@ -143,7 +143,7 @@ int c8sectpfe_frontend_attach(struct dvb_frontend **fe, "%s: stv0367ter_attach failed for NIM card %s\n" , __func__, dvb_card_str(tsin->dvb_card)); return -ENODEV; - }; + } /* * init the demod so that i2c gate_ctrl @@ -203,7 +203,7 @@ int c8sectpfe_frontend_attach(struct dvb_frontend **fe, "%s: stv6110x_attach failed for NIM card %s\n" , __func__, dvb_card_str(tsin->dvb_card)); return -ENODEV; - }; + } stv090x_config.tuner_init = fe2->tuner_init; stv090x_config.tuner_set_mode = fe2->tuner_set_mode; diff --git a/drivers/media/platform/sti/hva/hva-v4l2.c b/drivers/media/platform/sti/hva/hva-v4l2.c index c42623dccfd6..64004d15a9c9 100644 --- a/drivers/media/platform/sti/hva/hva-v4l2.c +++ b/drivers/media/platform/sti/hva/hva-v4l2.c @@ -566,6 +566,7 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) */ struct vb2_queue *vq; struct hva_stream *stream; + struct vb2_buffer *vb2_buf; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, buf->type); @@ -575,7 +576,8 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) return -EINVAL; } - stream = (struct hva_stream *)vq->bufs[buf->index]; + vb2_buf = vb2_get_buffer(vq, buf->index); + stream = to_hva_stream(to_vb2_v4l2_buffer(vb2_buf)); stream->bytesused = buf->bytesused; } diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index b9dad0accd1b..d855e9c09c08 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -1702,7 +1702,7 @@ static int dcmi_probe(struct platform_device *pdev) if (irq <= 0) { if (irq != -EPROBE_DEFER) dev_err(&pdev->dev, "Could not get irq\n"); - return irq; + return irq ? irq : -ENXIO; } dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 4c79eb64a7a7..6e0e894154f4 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -924,6 +924,7 @@ static int sun6i_csi_remove(struct platform_device *pdev) static const struct of_device_id sun6i_csi_of_match[] = { { .compatible = "allwinner,sun6i-a31-csi", }, + { .compatible = "allwinner,sun8i-a83t-csi", }, { .compatible = "allwinner,sun8i-h3-csi", }, { .compatible = "allwinner,sun8i-v3s-csi", }, { .compatible = "allwinner,sun50i-a64-csi", }, diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 8d075683e448..9e86d761546b 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI CAL camera interface driver * * Copyright (c) 2015 Texas Instruments Inc. * Benoit Parrot, <bparrot@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation */ #include <linux/interrupt.h> diff --git a/drivers/media/platform/ti-vpe/cal_regs.h b/drivers/media/platform/ti-vpe/cal_regs.h index 82b3dcf87128..68cfc922b422 100644 --- a/drivers/media/platform/ti-vpe/cal_regs.h +++ b/drivers/media/platform/ti-vpe/cal_regs.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * TI CAL camera interface driver * * Copyright (c) 2015 Texas Instruments Inc. * * Benoit Parrot, <bparrot@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef __TI_CAL_REGS_H diff --git a/drivers/media/platform/ti-vpe/csc.c b/drivers/media/platform/ti-vpe/csc.c index 44b8465cf101..eda2a5985da7 100644 --- a/drivers/media/platform/ti-vpe/csc.c +++ b/drivers/media/platform/ti-vpe/csc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Color space converter library * @@ -6,10 +7,6 @@ * David Griego, <dagriego@biglakesoftware.com> * Dale Farnsworth, <dale@farnsworth.org> * Archit Taneja, <archit@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/media/platform/ti-vpe/csc.h b/drivers/media/platform/ti-vpe/csc.h index 024700b15152..de9a58af2ca8 100644 --- a/drivers/media/platform/ti-vpe/csc.h +++ b/drivers/media/platform/ti-vpe/csc.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2013 Texas Instruments Inc. * * David Griego, <dagriego@biglakesoftware.com> * Dale Farnsworth, <dale@farnsworth.org> * Archit Taneja, <archit@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef TI_CSC_H #define TI_CSC_H diff --git a/drivers/media/platform/ti-vpe/sc.c b/drivers/media/platform/ti-vpe/sc.c index e9273b713782..98f95082a6fd 100644 --- a/drivers/media/platform/ti-vpe/sc.c +++ b/drivers/media/platform/ti-vpe/sc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Scaler library * @@ -6,10 +7,6 @@ * David Griego, <dagriego@biglakesoftware.com> * Dale Farnsworth, <dale@farnsworth.org> * Archit Taneja, <archit@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/media/platform/ti-vpe/sc.h b/drivers/media/platform/ti-vpe/sc.h index f1fe80b38c9f..d55de44d5257 100644 --- a/drivers/media/platform/ti-vpe/sc.h +++ b/drivers/media/platform/ti-vpe/sc.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2013 Texas Instruments Inc. * * David Griego, <dagriego@biglakesoftware.com> * Dale Farnsworth, <dale@farnsworth.org> * Archit Taneja, <archit@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef TI_SC_H #define TI_SC_H diff --git a/drivers/media/platform/ti-vpe/sc_coeff.h b/drivers/media/platform/ti-vpe/sc_coeff.h index 5bfa5c03aec6..c525d1764099 100644 --- a/drivers/media/platform/ti-vpe/sc_coeff.h +++ b/drivers/media/platform/ti-vpe/sc_coeff.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * VPE SC coefs * @@ -6,10 +7,6 @@ * David Griego, <dagriego@biglakesoftware.com> * Dale Farnsworth, <dale@farnsworth.org> * Archit Taneja, <archit@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef __TI_SC_COEFF_H diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 78d716c93649..fd37d79e1619 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * VPDMA helper library * @@ -6,10 +7,6 @@ * David Griego, <dagriego@biglakesoftware.com> * Dale Farnsworth, <dale@farnsworth.org> * Archit Taneja, <archit@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h index 7e611501c291..28bc94129348 100644 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ b/drivers/media/platform/ti-vpe/vpdma.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2013 Texas Instruments Inc. * * David Griego, <dagriego@biglakesoftware.com> * Dale Farnsworth, <dale@farnsworth.org> * Archit Taneja, <archit@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef __TI_VPDMA_H_ diff --git a/drivers/media/platform/ti-vpe/vpdma_priv.h b/drivers/media/platform/ti-vpe/vpdma_priv.h index 72c7f13b4a9d..c488609bc162 100644 --- a/drivers/media/platform/ti-vpe/vpdma_priv.h +++ b/drivers/media/platform/ti-vpe/vpdma_priv.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2013 Texas Instruments Inc. * * David Griego, <dagriego@biglakesoftware.com> * Dale Farnsworth, <dale@farnsworth.org> * Archit Taneja, <archit@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef _TI_VPDMA_PRIV_H_ diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 1e40eafec284..dda04498ac56 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI VPE mem2mem driver, based on the virtual v4l2-mem2mem example driver * @@ -11,10 +12,6 @@ * Marek Szyprowski, <m.szyprowski@samsung.com> * * Based on the virtual v4l2-mem2mem example device - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation */ #include <linux/delay.h> @@ -1495,8 +1492,6 @@ static int vpe_querycap(struct file *file, void *priv, strscpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", VPE_MODULE_NAME); - cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1973,12 +1968,12 @@ static const struct v4l2_ctrl_ops vpe_ctrl_ops = { static const struct v4l2_ioctl_ops vpe_ioctl_ops = { .vidioc_querycap = vpe_querycap, - .vidioc_enum_fmt_vid_cap_mplane = vpe_enum_fmt, + .vidioc_enum_fmt_vid_cap = vpe_enum_fmt, .vidioc_g_fmt_vid_cap_mplane = vpe_g_fmt, .vidioc_try_fmt_vid_cap_mplane = vpe_try_fmt, .vidioc_s_fmt_vid_cap_mplane = vpe_s_fmt, - .vidioc_enum_fmt_vid_out_mplane = vpe_enum_fmt, + .vidioc_enum_fmt_vid_out = vpe_enum_fmt, .vidioc_g_fmt_vid_out_mplane = vpe_g_fmt, .vidioc_try_fmt_vid_out_mplane = vpe_try_fmt, .vidioc_s_fmt_vid_out_mplane = vpe_s_fmt, @@ -2411,6 +2406,7 @@ static const struct video_device vpe_videodev = { .minor = -1, .release = video_device_release_empty, .vfl_dir = VFL_DIR_M2M, + .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, }; static const struct v4l2_m2m_ops m2m_ops = { diff --git a/drivers/media/platform/ti-vpe/vpe_regs.h b/drivers/media/platform/ti-vpe/vpe_regs.h index 74283d79eae1..9969bea0dded 100644 --- a/drivers/media/platform/ti-vpe/vpe_regs.h +++ b/drivers/media/platform/ti-vpe/vpe_regs.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2013 Texas Instruments Inc. * * David Griego, <dagriego@biglakesoftware.com> * Dale Farnsworth, <dale@farnsworth.org> * Archit Taneja, <archit@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef __TI_VPE_REGS_H diff --git a/drivers/media/platform/vicodec/Kconfig b/drivers/media/platform/vicodec/Kconfig index 36bb0e934252..89456665cb16 100644 --- a/drivers/media/platform/vicodec/Kconfig +++ b/drivers/media/platform/vicodec/Kconfig @@ -4,7 +4,6 @@ config VIDEO_VICODEC depends on VIDEO_DEV && VIDEO_V4L2 select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV - default n help Driver for a Virtual Codec diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index bd01a9206aa6..7e7c1e80f29f 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -84,6 +84,7 @@ struct vicodec_q_data { unsigned int visible_width; unsigned int visible_height; unsigned int sizeimage; + unsigned int vb2_sizeimage; unsigned int sequence; const struct v4l2_fwht_pixfmt_info *info; }; @@ -116,12 +117,14 @@ struct vicodec_ctx { struct vicodec_dev *dev; bool is_enc; bool is_stateless; + bool is_draining; + bool next_is_last; + bool has_stopped; spinlock_t *lock; struct v4l2_ctrl_handler hdl; struct vb2_v4l2_buffer *last_src_buf; - struct vb2_v4l2_buffer *last_dst_buf; /* Source and destination queue data */ struct vicodec_q_data q_data[2]; @@ -138,6 +141,10 @@ struct vicodec_ctx { bool source_changed; }; +static const struct v4l2_event vicodec_eos_event = { + .type = V4L2_EVENT_EOS +}; + static inline struct vicodec_ctx *file2ctx(struct file *file) { return container_of(file->private_data, struct vicodec_ctx, fh); @@ -329,6 +336,10 @@ static int device_process(struct vicodec_ctx *ctx, copy_cap_to_ref(p_dst, ctx->state.info, &ctx->state); vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage); + if (ntohl(ctx->state.header.flags) & FWHT_FL_I_FRAME) + dst_vb->flags |= V4L2_BUF_FLAG_KEYFRAME; + else + dst_vb->flags |= V4L2_BUF_FLAG_PFRAME; } return ret; } @@ -397,9 +408,6 @@ static enum vb2_buffer_state get_next_header(struct vicodec_ctx *ctx, /* device_run() - prepares and starts the device */ static void device_run(void *priv) { - static const struct v4l2_event eos_event = { - .type = V4L2_EVENT_EOS - }; struct vicodec_ctx *ctx = priv; struct vicodec_dev *dev = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; @@ -407,7 +415,6 @@ static void device_run(void *priv) u32 state; struct media_request *src_req; - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); src_req = src_buf->vb2_buf.req_obj.req; @@ -421,14 +428,14 @@ static void device_run(void *priv) else dst_buf->sequence = q_dst->sequence++; dst_buf->flags &= ~V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, !ctx->is_enc); - - ctx->last_dst_buf = dst_buf; + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); spin_lock(ctx->lock); if (!ctx->comp_has_next_frame && src_buf == ctx->last_src_buf) { dst_buf->flags |= V4L2_BUF_FLAG_LAST; - v4l2_event_queue_fh(&ctx->fh, &eos_event); + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); + ctx->is_draining = false; + ctx->has_stopped = true; } if (ctx->is_enc || ctx->is_stateless) { src_buf->sequence = q_src->sequence++; @@ -442,14 +449,14 @@ static void device_run(void *priv) ctx->comp_has_next_frame = false; } v4l2_m2m_buf_done(dst_buf, state); - if (ctx->is_stateless && src_req) - v4l2_ctrl_request_complete(src_req, &ctx->hdl); ctx->comp_size = 0; ctx->header_size = 0; ctx->comp_magic_cnt = 0; ctx->comp_has_frame = false; spin_unlock(ctx->lock); + if (ctx->is_stateless && src_req) + v4l2_ctrl_request_complete(src_req, &ctx->hdl); if (ctx->is_enc) v4l2_m2m_job_finish(dev->stateful_enc.m2m_dev, ctx->fh.m2m_ctx); @@ -579,6 +586,8 @@ static int job_ready(void *priv) unsigned int max_to_copy; unsigned int comp_frame_size; + if (ctx->has_stopped) + return 0; if (ctx->source_changed) return 0; if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame) @@ -598,6 +607,8 @@ restart: if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { state = get_next_header(ctx, &p, p_src + sz - p); if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { + if (ctx->is_draining && src_buf == ctx->last_src_buf) + return 1; job_remove_src_buf(ctx, state); goto restart; } @@ -625,6 +636,8 @@ restart: p += copy; ctx->comp_size += copy; if (ctx->comp_size < max_to_copy) { + if (ctx->is_draining && src_buf == ctx->last_src_buf) + return 1; job_remove_src_buf(ctx, state); goto restart; } @@ -666,7 +679,6 @@ restart: v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); update_capture_data_from_header(ctx); - ctx->first_source_change_sent = true; v4l2_event_queue_fh(&ctx->fh, &rs_event); set_last_buffer(dst_buf, src_buf, ctx); ctx->source_changed = true; @@ -713,7 +725,8 @@ static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx, const struct v4l2_fwht_pixfmt_info *info = get_q_data(ctx, f->type)->info; - if (!info || ctx->is_enc) + if (ctx->is_enc || + !vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)) info = v4l2_fwht_get_pixfmt(f->index); else info = v4l2_fwht_find_nth_fmt(info->width_div, @@ -764,9 +777,6 @@ static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) q_data = get_q_data(ctx, f->type); info = q_data->info; - if (!info) - info = v4l2_fwht_get_pixfmt(0); - switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: @@ -1032,16 +1042,10 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) default: return -EINVAL; } - if (q_data->visible_width > q_data->coded_width) - q_data->visible_width = q_data->coded_width; - if (q_data->visible_height > q_data->coded_height) - q_data->visible_height = q_data->coded_height; - dprintk(ctx->dev, - "Setting format for type %d, coded wxh: %dx%d, visible wxh: %dx%d, fourcc: %08x\n", + "Setting format for type %d, coded wxh: %dx%d, fourcc: 0x%08x\n", f->type, q_data->coded_width, q_data->coded_height, - q_data->visible_width, q_data->visible_height, q_data->info->id); return 0; @@ -1063,18 +1067,58 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct vicodec_ctx *ctx = file2ctx(file); - struct v4l2_pix_format_mplane *pix_mp; + struct vicodec_q_data *q_data; + struct vicodec_q_data *q_data_cap; struct v4l2_pix_format *pix; + struct v4l2_pix_format_mplane *pix_mp; + u32 coded_w = 0, coded_h = 0; + unsigned int size = 0; int ret; + q_data = get_q_data(ctx, f->type); + q_data_cap = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + ret = vidioc_try_fmt_vid_out(file, priv, f); if (ret) return ret; + if (ctx->is_enc) { + struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ? + &pixfmt_stateless_fwht : &pixfmt_fwht; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + coded_w = f->fmt.pix.width; + coded_h = f->fmt.pix.height; + } else { + coded_w = f->fmt.pix_mp.width; + coded_h = f->fmt.pix_mp.height; + } + if (vb2_is_busy(vq) && (coded_w != q_data->coded_width || + coded_h != q_data->coded_height)) + return -EBUSY; + size = coded_w * coded_h * + info->sizeimage_mult / info->sizeimage_div; + if (!ctx->is_stateless) + size += sizeof(struct fwht_cframe_hdr); + + if (vb2_is_busy(vq_cap) && size > q_data_cap->sizeimage) + return -EBUSY; + } + ret = vidioc_s_fmt(file2ctx(file), f); if (!ret) { + if (ctx->is_enc) { + q_data->visible_width = coded_w; + q_data->visible_height = coded_h; + q_data_cap->coded_width = coded_w; + q_data_cap->coded_height = coded_h; + q_data_cap->sizeimage = size; + } + switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: pix = &f->fmt.pix; ctx->state.colorspace = pix->colorspace; @@ -1082,7 +1126,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, ctx->state.ycbcr_enc = pix->ycbcr_enc; ctx->state.quantization = pix->quantization; break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: pix_mp = &f->fmt.pix_mp; ctx->state.colorspace = pix_mp->colorspace; @@ -1173,31 +1216,39 @@ static int vidioc_s_selection(struct file *file, void *priv, return 0; } -static void vicodec_mark_last_buf(struct vicodec_ctx *ctx) +static int vicodec_mark_last_buf(struct vicodec_ctx *ctx) { - static const struct v4l2_event eos_event = { - .type = V4L2_EVENT_EOS - }; + struct vb2_v4l2_buffer *next_dst_buf; + int ret = 0; spin_lock(ctx->lock); - ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); - if (!ctx->last_src_buf && ctx->last_dst_buf) { - ctx->last_dst_buf->flags |= V4L2_BUF_FLAG_LAST; - v4l2_event_queue_fh(&ctx->fh, &eos_event); + if (ctx->is_draining) { + ret = -EBUSY; + goto unlock; } - spin_unlock(ctx->lock); -} + if (ctx->has_stopped) + goto unlock; -static int vicodec_try_encoder_cmd(struct file *file, void *fh, - struct v4l2_encoder_cmd *ec) -{ - if (ec->cmd != V4L2_ENC_CMD_STOP) - return -EINVAL; + ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); + ctx->is_draining = true; + if (ctx->last_src_buf) + goto unlock; + + next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!next_dst_buf) { + ctx->next_is_last = true; + goto unlock; + } - if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END) - return -EINVAL; + next_dst_buf->flags |= V4L2_BUF_FLAG_LAST; + vb2_buffer_done(&next_dst_buf->vb2_buf, VB2_BUF_STATE_DONE); + ctx->is_draining = false; + ctx->has_stopped = true; + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); - return 0; +unlock: + spin_unlock(ctx->lock); + return ret; } static int vicodec_encoder_cmd(struct file *file, void *fh, @@ -1206,27 +1257,26 @@ static int vicodec_encoder_cmd(struct file *file, void *fh, struct vicodec_ctx *ctx = file2ctx(file); int ret; - ret = vicodec_try_encoder_cmd(file, fh, ec); + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); if (ret < 0) return ret; - vicodec_mark_last_buf(ctx); - return 0; -} - -static int vicodec_try_decoder_cmd(struct file *file, void *fh, - struct v4l2_decoder_cmd *dc) -{ - if (dc->cmd != V4L2_DEC_CMD_STOP) - return -EINVAL; - - if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK) - return -EINVAL; - - if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0)) - return -EINVAL; + if (!vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q) || + !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) + return 0; - return 0; + if (ec->cmd == V4L2_ENC_CMD_STOP) + return vicodec_mark_last_buf(ctx); + ret = 0; + spin_lock(ctx->lock); + if (ctx->is_draining) { + ret = -EBUSY; + } else if (ctx->has_stopped) { + ctx->has_stopped = false; + vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q); + } + spin_unlock(ctx->lock); + return ret; } static int vicodec_decoder_cmd(struct file *file, void *fh, @@ -1235,12 +1285,26 @@ static int vicodec_decoder_cmd(struct file *file, void *fh, struct vicodec_ctx *ctx = file2ctx(file); int ret; - ret = vicodec_try_decoder_cmd(file, fh, dc); + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); if (ret < 0) return ret; - vicodec_mark_last_buf(ctx); - return 0; + if (!vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q) || + !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) + return 0; + + if (dc->cmd == V4L2_DEC_CMD_STOP) + return vicodec_mark_last_buf(ctx); + ret = 0; + spin_lock(ctx->lock); + if (ctx->is_draining) { + ret = -EBUSY; + } else if (ctx->has_stopped) { + ctx->has_stopped = false; + vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q); + } + spin_unlock(ctx->lock); + return ret; } static int vicodec_enum_framesizes(struct file *file, void *fh, @@ -1283,6 +1347,8 @@ static int vicodec_subscribe_event(struct v4l2_fh *fh, return -EINVAL; /* fall through */ case V4L2_EVENT_EOS: + if (ctx->is_stateless) + return -EINVAL; return v4l2_event_subscribe(fh, sub, 0, NULL); default: return v4l2_ctrl_subscribe_event(fh, sub); @@ -1297,7 +1363,6 @@ static const struct v4l2_ioctl_ops vicodec_ioctl_ops = { .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap, @@ -1307,7 +1372,6 @@ static const struct v4l2_ioctl_ops vicodec_ioctl_ops = { .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out, .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out, .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out, .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out, @@ -1326,9 +1390,9 @@ static const struct v4l2_ioctl_ops vicodec_ioctl_ops = { .vidioc_g_selection = vidioc_g_selection, .vidioc_s_selection = vidioc_s_selection, - .vidioc_try_encoder_cmd = vicodec_try_encoder_cmd, + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, .vidioc_encoder_cmd = vicodec_encoder_cmd, - .vidioc_try_decoder_cmd = vicodec_try_decoder_cmd, + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, .vidioc_decoder_cmd = vicodec_decoder_cmd, .vidioc_enum_framesizes = vicodec_enum_framesizes, @@ -1354,6 +1418,7 @@ static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, *nplanes = 1; sizes[0] = size; + q_data->vb2_sizeimage = size; return 0; } @@ -1384,11 +1449,11 @@ static int vicodec_buf_prepare(struct vb2_buffer *vb) } } - if (vb2_plane_size(vb, 0) < q_data->sizeimage) { + if (vb2_plane_size(vb, 0) < q_data->vb2_sizeimage) { dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n", __func__, vb2_plane_size(vb, 0), - (long)q_data->sizeimage); + (long)q_data->vb2_sizeimage); return -EINVAL; } @@ -1412,6 +1477,25 @@ static void vicodec_buf_queue(struct vb2_buffer *vb) .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, }; + if (vb2_is_streaming(vq_cap)) { + if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) && + ctx->next_is_last) { + unsigned int i; + + for (i = 0; i < vb->num_planes; i++) + vb->planes[i].bytesused = 0; + vbuf->flags = V4L2_BUF_FLAG_LAST; + vbuf->field = V4L2_FIELD_NONE; + vbuf->sequence = get_q_data(ctx, vb->vb2_queue->type)->sequence++; + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + ctx->is_draining = false; + ctx->has_stopped = true; + ctx->next_is_last = false; + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); + return; + } + } + /* buf_queue handles only the first source change event */ if (ctx->first_source_change_sent) { v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); @@ -1519,16 +1603,11 @@ static int vicodec_start_streaming(struct vb2_queue *q, unsigned int total_planes_size; u8 *new_comp_frame = NULL; - if (!info) - return -EINVAL; - chroma_div = info->width_div * info->height_div; q_data->sequence = 0; if (V4L2_TYPE_IS_OUTPUT(q->type)) ctx->last_src_buf = NULL; - else - ctx->last_dst_buf = NULL; state->gop_cnt = 0; @@ -1604,6 +1683,32 @@ static void vicodec_stop_streaming(struct vb2_queue *q) vicodec_return_bufs(q, VB2_BUF_STATE_ERROR); + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + if (ctx->is_draining) { + struct vb2_v4l2_buffer *next_dst_buf; + + spin_lock(ctx->lock); + ctx->last_src_buf = NULL; + next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!next_dst_buf) { + ctx->next_is_last = true; + } else { + next_dst_buf->flags |= V4L2_BUF_FLAG_LAST; + vb2_buffer_done(&next_dst_buf->vb2_buf, VB2_BUF_STATE_DONE); + ctx->is_draining = false; + ctx->has_stopped = true; + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); + } + spin_unlock(ctx->lock); + } + } else { + ctx->is_draining = false; + ctx->has_stopped = false; + ctx->next_is_last = false; + } + if (!ctx->is_enc && V4L2_TYPE_IS_OUTPUT(q->type)) + ctx->first_source_change_sent = false; + if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) { if (!ctx->is_stateless) @@ -1771,11 +1876,13 @@ static const struct v4l2_ctrl_config vicodec_ctrl_stateless_state = { */ static int vicodec_open(struct file *file) { + const struct v4l2_fwht_pixfmt_info *info = v4l2_fwht_get_pixfmt(0); struct video_device *vfd = video_devdata(file); struct vicodec_dev *dev = video_drvdata(file); struct vicodec_ctx *ctx = NULL; struct v4l2_ctrl_handler *hdl; - unsigned int size; + unsigned int raw_size; + unsigned int comp_size; int rc = 0; if (mutex_lock_interruptible(vfd->lock)) @@ -1795,13 +1902,16 @@ static int vicodec_open(struct file *file) file->private_data = &ctx->fh; ctx->dev = dev; hdl = &ctx->hdl; - v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_handler_init(hdl, 5); v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 16, 1, 10); v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_I_FRAME_QP, 1, 31, 1, 20); v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_P_FRAME_QP, 1, 31, 1, 20); + if (ctx->is_enc) + v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 1, 1, 1); if (ctx->is_stateless) v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_stateless_state, NULL); if (hdl->error) { @@ -1814,7 +1924,7 @@ static int vicodec_open(struct file *file) v4l2_ctrl_handler_setup(hdl); if (ctx->is_enc) - ctx->q_data[V4L2_M2M_SRC].info = v4l2_fwht_get_pixfmt(0); + ctx->q_data[V4L2_M2M_SRC].info = info; else if (ctx->is_stateless) ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_stateless_fwht; else @@ -1823,22 +1933,24 @@ static int vicodec_open(struct file *file) ctx->q_data[V4L2_M2M_SRC].coded_height = 720; ctx->q_data[V4L2_M2M_SRC].visible_width = 1280; ctx->q_data[V4L2_M2M_SRC].visible_height = 720; - size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult / - ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div; - if (ctx->is_enc || ctx->is_stateless) - ctx->q_data[V4L2_M2M_SRC].sizeimage = size; + raw_size = 1280 * 720 * info->sizeimage_mult / info->sizeimage_div; + comp_size = 1280 * 720 * pixfmt_fwht.sizeimage_mult / + pixfmt_fwht.sizeimage_div; + if (ctx->is_enc) + ctx->q_data[V4L2_M2M_SRC].sizeimage = raw_size; + else if (ctx->is_stateless) + ctx->q_data[V4L2_M2M_SRC].sizeimage = comp_size; else ctx->q_data[V4L2_M2M_SRC].sizeimage = - size + sizeof(struct fwht_cframe_hdr); + comp_size + sizeof(struct fwht_cframe_hdr); + ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC]; if (ctx->is_enc) { - ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC]; ctx->q_data[V4L2_M2M_DST].info = &pixfmt_fwht; - ctx->q_data[V4L2_M2M_DST].sizeimage = 1280 * 720 * - ctx->q_data[V4L2_M2M_DST].info->sizeimage_mult / - ctx->q_data[V4L2_M2M_DST].info->sizeimage_div + - sizeof(struct fwht_cframe_hdr); + ctx->q_data[V4L2_M2M_DST].sizeimage = + comp_size + sizeof(struct fwht_cframe_hdr); } else { - ctx->q_data[V4L2_M2M_DST].info = NULL; + ctx->q_data[V4L2_M2M_DST].info = info; + ctx->q_data[V4L2_M2M_DST].sizeimage = raw_size; } ctx->state.colorspace = V4L2_COLORSPACE_REC709; @@ -2013,18 +2125,31 @@ static int register_instance(struct vicodec_dev *dev, return 0; } +static void vicodec_v4l2_dev_release(struct v4l2_device *v4l2_dev) +{ + struct vicodec_dev *dev = container_of(v4l2_dev, struct vicodec_dev, v4l2_dev); + + v4l2_device_unregister(&dev->v4l2_dev); + v4l2_m2m_release(dev->stateful_enc.m2m_dev); + v4l2_m2m_release(dev->stateful_dec.m2m_dev); + v4l2_m2m_release(dev->stateless_dec.m2m_dev); + kfree(dev); +} + static int vicodec_probe(struct platform_device *pdev) { struct vicodec_dev *dev; int ret; - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) - return ret; + goto free_dev; + + dev->v4l2_dev.release = vicodec_v4l2_dev_release; #ifdef CONFIG_MEDIA_CONTROLLER dev->mdev.dev = &pdev->dev; @@ -2102,6 +2227,8 @@ unreg_sf_enc: v4l2_m2m_release(dev->stateful_enc.m2m_dev); unreg_dev: v4l2_device_unregister(&dev->v4l2_dev); +free_dev: + kfree(dev); return ret; } @@ -2120,12 +2247,10 @@ static int vicodec_remove(struct platform_device *pdev) media_device_cleanup(&dev->mdev); #endif - v4l2_m2m_release(dev->stateful_enc.m2m_dev); - v4l2_m2m_release(dev->stateful_dec.m2m_dev); video_unregister_device(&dev->stateful_enc.vfd); video_unregister_device(&dev->stateful_dec.vfd); video_unregister_device(&dev->stateless_dec.vfd); - v4l2_device_unregister(&dev->v4l2_dev); + v4l2_device_put(&dev->v4l2_dev); return 0; } diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index 243c82b5d537..acd3bd48c7e2 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c @@ -1359,7 +1359,7 @@ static int vim2m_probe(struct platform_device *pdev) MEDIA_ENT_F_PROC_VIDEO_SCALER); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n"); - goto error_m2m; + goto error_dev; } ret = media_device_register(&dev->mdev); @@ -1373,11 +1373,11 @@ static int vim2m_probe(struct platform_device *pdev) #ifdef CONFIG_MEDIA_CONTROLLER error_m2m_mc: v4l2_m2m_unregister_media_controller(dev->m2m_dev); -error_m2m: - v4l2_m2m_release(dev->m2m_dev); #endif error_dev: video_unregister_device(&dev->vfd); + /* vim2m_device_release called by video_unregister_device to release various objects */ + return ret; error_v4l2: v4l2_device_unregister(&dev->v4l2_dev); error_free: diff --git a/drivers/media/platform/vimc/Kconfig b/drivers/media/platform/vimc/Kconfig index beba6acce593..bd221d3e1a4a 100644 --- a/drivers/media/platform/vimc/Kconfig +++ b/drivers/media/platform/vimc/Kconfig @@ -4,7 +4,6 @@ config VIDEO_VIMC depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_VMALLOC select VIDEO_V4L2_TPG - default n help Skeleton driver for Virtual Media Controller diff --git a/drivers/media/platform/vimc/Makefile b/drivers/media/platform/vimc/Makefile index c4fc8e7d365a..96d06f030c31 100644 --- a/drivers/media/platform/vimc/Makefile +++ b/drivers/media/platform/vimc/Makefile @@ -1,11 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -vimc-objs := vimc-core.o -vimc_capture-objs := vimc-capture.o -vimc_common-objs := vimc-common.o -vimc_debayer-objs := vimc-debayer.o -vimc_scaler-objs := vimc-scaler.o -vimc_sensor-objs := vimc-sensor.o -vimc_streamer-objs := vimc-streamer.o +vimc-y := vimc-core.o vimc-common.o vimc-streamer.o -obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.o vimc-debayer.o \ - vimc_scaler.o vimc_sensor.o vimc_streamer.o +obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc-capture.o vimc-debayer.o \ + vimc-scaler.o vimc-sensor.o diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c index 946dc0908566..664855708fdf 100644 --- a/drivers/media/platform/vimc/vimc-capture.c +++ b/drivers/media/platform/vimc/vimc-capture.c @@ -142,12 +142,15 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct vimc_cap_device *vcap = video_drvdata(file); + int ret; /* Do not change the format while stream is on */ if (vb2_is_busy(&vcap->queue)) return -EBUSY; - vimc_cap_try_fmt_vid_cap(file, priv, f); + ret = vimc_cap_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; dev_dbg(vcap->dev, "%s: format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c index f4d2073076ed..03016f204d05 100644 --- a/drivers/media/platform/vimc/vimc-common.c +++ b/drivers/media/platform/vimc/vimc-common.c @@ -377,7 +377,3 @@ void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd) v4l2_device_unregister_subdev(sd); } EXPORT_SYMBOL_GPL(vimc_ent_sd_unregister); - -MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Common"); -MODULE_AUTHOR("Helen Koike <helen.fornazier@gmail.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c index 03707bdcbfa8..571c55aa0e16 100644 --- a/drivers/media/platform/vimc/vimc-core.c +++ b/drivers/media/platform/vimc/vimc-core.c @@ -234,10 +234,7 @@ static void vimc_comp_unbind(struct device *master) static int vimc_comp_compare(struct device *comp, void *data) { - const struct platform_device *pdev = to_platform_device(comp); - const char *name = data; - - return !strcmp(pdev->dev.platform_data, name); + return comp == data; } static struct component_match *vimc_add_subdevs(struct vimc_device *vimc) @@ -267,7 +264,7 @@ static struct component_match *vimc_add_subdevs(struct vimc_device *vimc) } component_match_add(&vimc->pdev.dev, &match, vimc_comp_compare, - (void *)vimc->pipe_cfg->ents[i].name); + &vimc->subdevs[i]->dev); } return match; diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c index 3ae8c12f5fa3..00598fbf3cba 100644 --- a/drivers/media/platform/vimc/vimc-debayer.c +++ b/drivers/media/platform/vimc/vimc-debayer.c @@ -16,14 +16,16 @@ #include "vimc-common.h" #define VIMC_DEB_DRV_NAME "vimc-debayer" -/* This module only supports tranforming a bayer format to V4L2_PIX_FMT_RGB24 */ +/* This module only supports transforming a bayer format + * to V4L2_PIX_FMT_RGB24 + */ #define VIMC_DEB_SRC_PIXFMT V4L2_PIX_FMT_RGB24 #define VIMC_DEB_SRC_MBUS_FMT_DEFAULT MEDIA_BUS_FMT_RGB888_1X24 static unsigned int deb_mean_win_size = 3; module_param(deb_mean_win_size, uint, 0000); MODULE_PARM_DESC(deb_mean_win_size, " the window size to calculate the mean.\n" - "NOTE: the window size need to be an odd number, as the main pixel " + "NOTE: the window size needs to be an odd number, as the main pixel " "stays in the center of the window, otherwise the next odd number " "is considered"); @@ -260,7 +262,7 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ - if (vdeb->src_frame) + if (vdeb->ved.stream) return -EBUSY; sink_fmt = &vdeb->sink_fmt; @@ -327,9 +329,6 @@ static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable) const struct v4l2_format_info *pix_info; unsigned int frame_size; - if (vdeb->src_frame) - return 0; - /* We only support translating bayer to RGB24 */ if (src_pixelformat != V4L2_PIX_FMT_RGB24) { dev_err(vdeb->dev, diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c index 5f31c1e351a3..c7123a45c55b 100644 --- a/drivers/media/platform/vimc/vimc-scaler.c +++ b/drivers/media/platform/vimc/vimc-scaler.c @@ -148,7 +148,7 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ - if (vsca->src_frame) + if (vsca->ved.stream) return -EBUSY; sink_fmt = &vsca->sink_fmt; @@ -203,9 +203,6 @@ static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable) const struct v4l2_format_info *pix_info; unsigned int frame_size; - if (vsca->src_frame) - return 0; - if (!vimc_sca_is_pixfmt_supported(pixelformat)) { dev_err(vsca->dev, "pixfmt (0x%08x) is not supported\n", pixelformat); @@ -327,7 +324,7 @@ static void *vimc_sca_process_frame(struct vimc_ent_device *ved, ved); /* If the stream in this node is not active, just return */ - if (!vsca->src_frame) + if (!ved->stream) return ERR_PTR(-EINVAL); vimc_sca_fill_src_frame(vsca, sink_frame); diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index 46a25f705456..51359472eef2 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c @@ -131,7 +131,7 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ - if (vsen->frame) + if (vsen->ved.stream) return -EBUSY; mf = &vsen->mbus_format; @@ -187,10 +187,6 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) const struct v4l2_format_info *pix_info; unsigned int frame_size; - if (vsen->kthread_sen) - /* tpg is already executing */ - return 0; - /* Calculate the frame size */ pix_info = v4l2_format_info(pixelformat); frame_size = vsen->mbus_format.width * pix_info->bpp[0] * @@ -211,7 +207,6 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) vfree(vsen->frame); vsen->frame = NULL; - return 0; } return 0; diff --git a/drivers/media/platform/vimc/vimc-streamer.c b/drivers/media/platform/vimc/vimc-streamer.c index 26b674259489..3b3f36357a0e 100644 --- a/drivers/media/platform/vimc/vimc-streamer.c +++ b/drivers/media/platform/vimc/vimc-streamer.c @@ -122,6 +122,14 @@ static int vimc_streamer_pipeline_init(struct vimc_stream *stream, return -EINVAL; } +/* + * vimc_streamer_thread - process frames through the pipeline + * + * @data: vimc_stream struct of the current stream + * + * From the source to the sink, gets a frame from each subdevice and send to + * the next one of the pipeline at a fixed framerate. + */ static int vimc_streamer_thread(void *data) { struct vimc_stream *stream = data; @@ -149,6 +157,20 @@ static int vimc_streamer_thread(void *data) return 0; } +/* + * vimc_streamer_s_stream - start/stop the streaming on the media pipeline + * + * @stream: the pointer to the stream structure of the current stream + * @ved: pointer to the vimc entity of the entity of the stream + * @enable: flag to determine if stream should start/stop + * + * When starting, check if there is no stream->kthread allocated. This should + * indicate that a stream is already running. Then, it initializes + * the pipeline, creates and runs a kthread to consume buffers through the + * pipeline. + * When stopping, analogously check if there is a stream running, stop + * the thread and terminates the pipeline. + */ int vimc_streamer_s_stream(struct vimc_stream *stream, struct vimc_ent_device *ved, int enable) @@ -188,7 +210,3 @@ int vimc_streamer_s_stream(struct vimc_stream *stream, return 0; } EXPORT_SYMBOL_GPL(vimc_streamer_s_stream); - -MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Streamer"); -MODULE_AUTHOR("Lucas A. M. Magalhães <lucmaga@gmail.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig index b172bcc11758..e2ff06edfa93 100644 --- a/drivers/media/platform/vivid/Kconfig +++ b/drivers/media/platform/vivid/Kconfig @@ -11,7 +11,6 @@ config VIDEO_VIVID select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG select VIDEO_V4L2_TPG - default n help Enables a virtual video driver. This driver emulates a webcam, TV, S-Video and HDMI capture hardware, including VBI support for diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 7047df6f0e0e..bc2a176937a4 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -500,20 +500,18 @@ static const struct v4l2_file_operations vivid_radio_fops = { static const struct v4l2_ioctl_ops vivid_ioctl_ops = { .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid, + .vidioc_enum_fmt_vid_cap = vivid_enum_fmt_vid, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_mplane, .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap_mplane, .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane, .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid, + .vidioc_enum_fmt_vid_out = vivid_enum_fmt_vid, .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_mplane, .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out_mplane, .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane, .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out_mplane, @@ -669,6 +667,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0; int ret; int i; +#ifdef CONFIG_VIDEO_VIVID_CEC + unsigned int cec_tx_bus_cnt = 0; +#endif /* allocate main vivid state structure */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -722,6 +723,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) in_type_counter[HDMI]--; dev->num_inputs--; } + dev->num_hdmi_inputs = in_type_counter[HDMI]; /* how many outputs do we have and of what type? */ dev->num_outputs = num_outputs[inst]; @@ -732,6 +734,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) for (i = 0; i < dev->num_outputs; i++) { dev->output_type[i] = ((output_types[inst] >> i) & 1) ? HDMI : SVID; dev->output_name_counter[i] = out_type_counter[dev->output_type[i]]++; + dev->display_present[i] = true; } dev->has_audio_outputs = out_type_counter[SVID]; if (out_type_counter[HDMI] == 16) { @@ -743,6 +746,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) out_type_counter[HDMI]--; dev->num_outputs--; } + dev->num_hdmi_outputs = out_type_counter[HDMI]; /* do we create a video capture device? */ dev->has_vid_cap = node_type & 0x0001; @@ -1001,13 +1005,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->webcam_size_idx = 1; dev->webcam_ival_idx = 3; tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); - dev->std_cap = V4L2_STD_PAL; dev->std_out = V4L2_STD_PAL; if (dev->input_type[0] == TV || dev->input_type[0] == SVID) tvnorms_cap = V4L2_STD_ALL; if (dev->output_type[0] == SVID) tvnorms_out = V4L2_STD_ALL; - dev->dv_timings_cap = def_dv_timings; + for (i = 0; i < MAX_INPUTS; i++) { + dev->dv_timings_cap[i] = def_dv_timings; + dev->std_cap[i] = V4L2_STD_PAL; + } dev->dv_timings_out = def_dv_timings; dev->tv_freq = 2804 /* 175.25 * 16 */; dev->tv_audmode = V4L2_TUNER_MODE_STEREO; @@ -1037,6 +1043,17 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) if (ret) goto unreg_dev; + /* enable/disable interface specific controls */ + if (dev->num_outputs && dev->output_type[0] != HDMI) + v4l2_ctrl_activate(dev->ctrl_display_present, false); + if (dev->num_inputs && dev->input_type[0] != HDMI) { + v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, false); + v4l2_ctrl_activate(dev->ctrl_dv_timings, false); + } else if (dev->num_inputs && dev->input_type[0] == HDMI) { + v4l2_ctrl_activate(dev->ctrl_std_signal_mode, false); + v4l2_ctrl_activate(dev->ctrl_standard, false); + } + /* * update the capture and output formats to do a proper initial * configuration. @@ -1044,14 +1061,6 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) vivid_update_format_cap(dev, false); vivid_update_format_out(dev); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap); - /* initialize overlay */ dev->fb_cap.fmt.width = dev->src_rect.width; dev->fb_cap.fmt.height = dev->src_rect.height; @@ -1212,6 +1221,47 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->fb_info.node); } +#ifdef CONFIG_VIDEO_VIVID_CEC + if (dev->has_vid_cap && in_type_counter[HDMI]) { + struct cec_adapter *adap; + + adap = vivid_cec_alloc_adap(dev, 0, false); + ret = PTR_ERR_OR_ZERO(adap); + if (ret < 0) + goto unreg_dev; + dev->cec_rx_adap = adap; + } + + if (dev->has_vid_out) { + for (i = 0; i < dev->num_outputs; i++) { + struct cec_adapter *adap; + + if (dev->output_type[i] != HDMI) + continue; + + dev->cec_output2bus_map[i] = cec_tx_bus_cnt; + adap = vivid_cec_alloc_adap(dev, cec_tx_bus_cnt, true); + ret = PTR_ERR_OR_ZERO(adap); + if (ret < 0) { + for (i = 0; i < dev->num_outputs; i++) + cec_delete_adapter(dev->cec_tx_adap[i]); + goto unreg_dev; + } + + dev->cec_tx_adap[cec_tx_bus_cnt] = adap; + cec_tx_bus_cnt++; + } + } +#endif + + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap); + /* finally start creating the device nodes */ if (dev->has_vid_cap) { vfd = &dev->vid_cap_dev; @@ -1241,22 +1291,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) #ifdef CONFIG_VIDEO_VIVID_CEC if (in_type_counter[HDMI]) { - struct cec_adapter *adap; - - adap = vivid_cec_alloc_adap(dev, 0, false); - ret = PTR_ERR_OR_ZERO(adap); - if (ret < 0) - goto unreg_dev; - dev->cec_rx_adap = adap; - ret = cec_register_adapter(adap, &pdev->dev); + ret = cec_register_adapter(dev->cec_rx_adap, &pdev->dev); if (ret < 0) { - cec_delete_adapter(adap); + cec_delete_adapter(dev->cec_rx_adap); dev->cec_rx_adap = NULL; goto unreg_dev; } - cec_s_phys_addr(adap, 0, false); + cec_s_phys_addr(dev->cec_rx_adap, 0, false); v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI input 0\n", - dev_name(&adap->devnode.dev)); + dev_name(&dev->cec_rx_adap->devnode.dev)); } #endif @@ -1268,10 +1311,6 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) } if (dev->has_vid_out) { -#ifdef CONFIG_VIDEO_VIVID_CEC - unsigned int bus_cnt = 0; -#endif - vfd = &dev->vid_out_dev; snprintf(vfd->name, sizeof(vfd->name), "vivid-%03d-vid-out", inst); @@ -1299,30 +1338,21 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) #endif #ifdef CONFIG_VIDEO_VIVID_CEC - for (i = 0; i < dev->num_outputs; i++) { - struct cec_adapter *adap; - - if (dev->output_type[i] != HDMI) - continue; - dev->cec_output2bus_map[i] = bus_cnt; - adap = vivid_cec_alloc_adap(dev, bus_cnt, true); - ret = PTR_ERR_OR_ZERO(adap); - if (ret < 0) - goto unreg_dev; - dev->cec_tx_adap[bus_cnt] = adap; - ret = cec_register_adapter(adap, &pdev->dev); + for (i = 0; i < cec_tx_bus_cnt; i++) { + ret = cec_register_adapter(dev->cec_tx_adap[i], &pdev->dev); if (ret < 0) { - cec_delete_adapter(adap); - dev->cec_tx_adap[bus_cnt] = NULL; + for (; i < cec_tx_bus_cnt; i++) { + cec_delete_adapter(dev->cec_tx_adap[i]); + dev->cec_tx_adap[i] = NULL; + } goto unreg_dev; } v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI output %d\n", - dev_name(&adap->devnode.dev), bus_cnt); - bus_cnt++; - if (bus_cnt <= out_type_counter[HDMI]) - cec_s_phys_addr(adap, bus_cnt << 12, false); + dev_name(&dev->cec_tx_adap[i]->devnode.dev), i); + if (i <= out_type_counter[HDMI]) + cec_s_phys_addr(dev->cec_tx_adap[i], i << 12, false); else - cec_s_phys_addr(adap, 0x1000, false); + cec_s_phys_addr(dev->cec_tx_adap[i], 0x1000, false); } #endif diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index 6697c7009629..7ebb14673c75 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -22,18 +22,6 @@ #define dprintk(dev, level, fmt, arg...) \ v4l2_dbg(level, vivid_debug, &dev->v4l2_dev, fmt, ## arg) -/* Maximum allowed frame rate - * - * vivid will allow setting timeperframe in [1/FPS_MAX - FPS_MAX/1] range. - * - * Ideally FPS_MAX should be infinity, i.e. practically UINT_MAX, but that - * might hit application errors when they manipulate these values. - * - * Besides, for tpf < 10ms image-generation logic should be changed, to avoid - * producing frames with equal content. - */ -#define FPS_MAX 100 - /* The maximum number of clip rectangles */ #define MAX_CLIPS 16 /* The maximum number of inputs */ @@ -180,9 +168,11 @@ struct vivid_dev { /* supported features */ bool multiplanar; unsigned num_inputs; + unsigned int num_hdmi_inputs; u8 input_type[MAX_INPUTS]; u8 input_name_counter[MAX_INPUTS]; unsigned num_outputs; + unsigned int num_hdmi_outputs; u8 output_type[MAX_OUTPUTS]; u8 output_name_counter[MAX_OUTPUTS]; bool has_audio_inputs; @@ -237,6 +227,7 @@ struct vivid_dev { struct v4l2_ctrl *ctrl_dv_timings_signal_mode; struct v4l2_ctrl *ctrl_dv_timings; }; + struct v4l2_ctrl *ctrl_display_present; struct v4l2_ctrl *ctrl_has_crop_cap; struct v4l2_ctrl *ctrl_has_compose_cap; struct v4l2_ctrl *ctrl_has_scaler_cap; @@ -245,6 +236,11 @@ struct vivid_dev { struct v4l2_ctrl *ctrl_has_scaler_out; struct v4l2_ctrl *ctrl_tx_mode; struct v4l2_ctrl *ctrl_tx_rgb_range; + struct v4l2_ctrl *ctrl_tx_edid_present; + struct v4l2_ctrl *ctrl_tx_hotplug; + struct v4l2_ctrl *ctrl_tx_rxsense; + + struct v4l2_ctrl *ctrl_rx_power_present; struct v4l2_ctrl *radio_tx_rds_pi; struct v4l2_ctrl *radio_tx_rds_pty; @@ -299,23 +295,24 @@ struct vivid_dev { bool time_wrap; u64 time_wrap_offset; unsigned perc_dropped_buffers; - enum vivid_signal_mode std_signal_mode; - unsigned query_std_last; - v4l2_std_id query_std; - enum tpg_video_aspect std_aspect_ratio; + enum vivid_signal_mode std_signal_mode[MAX_INPUTS]; + unsigned int query_std_last[MAX_INPUTS]; + v4l2_std_id query_std[MAX_INPUTS]; + enum tpg_video_aspect std_aspect_ratio[MAX_INPUTS]; - enum vivid_signal_mode dv_timings_signal_mode; + enum vivid_signal_mode dv_timings_signal_mode[MAX_INPUTS]; char **query_dv_timings_qmenu; char *query_dv_timings_qmenu_strings; unsigned query_dv_timings_size; - unsigned query_dv_timings_last; - unsigned query_dv_timings; - enum tpg_video_aspect dv_timings_aspect_ratio; + unsigned int query_dv_timings_last[MAX_INPUTS]; + unsigned int query_dv_timings[MAX_INPUTS]; + enum tpg_video_aspect dv_timings_aspect_ratio[MAX_INPUTS]; /* Input */ unsigned input; - v4l2_std_id std_cap; - struct v4l2_dv_timings dv_timings_cap; + v4l2_std_id std_cap[MAX_INPUTS]; + struct v4l2_dv_timings dv_timings_cap[MAX_INPUTS]; + int dv_timings_cap_sel[MAX_INPUTS]; u32 service_set_cap; struct vivid_vbi_gen_data vbi_gen; u8 *edid; @@ -328,6 +325,8 @@ struct vivid_dev { unsigned tv_field_cap; unsigned tv_audio_input; + u32 power_present; + /* Capture Overlay */ struct v4l2_framebuffer fb_cap; struct v4l2_fh *overlay_cap_owner; @@ -360,6 +359,7 @@ struct vivid_dev { u8 *scaled_line; u8 *blended_line; unsigned cur_scaled_line; + bool display_present[MAX_OUTPUTS]; /* Output Overlay */ void *fb_vbase_out; diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index 4cd526ff248b..3e916c8befb7 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -18,6 +18,7 @@ #include "vivid-radio-common.h" #include "vivid-osd.h" #include "vivid-ctrls.h" +#include "vivid-cec.h" #define VIVID_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) #define VIVID_CID_BUTTON (VIVID_CID_CUSTOM_BASE + 0) @@ -68,6 +69,7 @@ #define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 41) #define VIVID_CID_REDUCED_FPS (VIVID_CID_VIVID_BASE + 42) #define VIVID_CID_HSV_ENC (VIVID_CID_VIVID_BASE + 43) +#define VIVID_CID_DISPLAY_PRESENT (VIVID_CID_VIVID_BASE + 44) #define VIVID_CID_STD_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 60) #define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61) @@ -357,7 +359,7 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) V4L2_COLORSPACE_470_SYSTEM_BG, }; struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_cap); - unsigned i; + unsigned int i, j; switch (ctrl->id) { case VIVID_CID_TEST_PATTERN: @@ -463,20 +465,35 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) tpg_s_show_square(&dev->tpg, ctrl->val); break; case VIVID_CID_STD_ASPECT_RATIO: - dev->std_aspect_ratio = ctrl->val; + dev->std_aspect_ratio[dev->input] = ctrl->val; tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); break; case VIVID_CID_DV_TIMINGS_SIGNAL_MODE: - dev->dv_timings_signal_mode = dev->ctrl_dv_timings_signal_mode->val; - if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS) - dev->query_dv_timings = dev->ctrl_dv_timings->val; + dev->dv_timings_signal_mode[dev->input] = + dev->ctrl_dv_timings_signal_mode->val; + dev->query_dv_timings[dev->input] = dev->ctrl_dv_timings->val; + + dev->power_present = 0; + for (i = 0, j = 0; + i < ARRAY_SIZE(dev->dv_timings_signal_mode); + i++) + if (dev->input_type[i] == HDMI) { + if (dev->dv_timings_signal_mode[i] != NO_SIGNAL) + dev->power_present |= (1 << j); + j++; + } + __v4l2_ctrl_s_ctrl(dev->ctrl_rx_power_present, + dev->power_present); + v4l2_ctrl_activate(dev->ctrl_dv_timings, - dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS); + dev->dv_timings_signal_mode[dev->input] == + SELECTED_DV_TIMINGS); + vivid_update_quality(dev); vivid_send_source_change(dev, HDMI); break; case VIVID_CID_DV_TIMINGS_ASPECT_RATIO: - dev->dv_timings_aspect_ratio = ctrl->val; + dev->dv_timings_aspect_ratio[dev->input] = ctrl->val; tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); break; case VIVID_CID_TSTAMP_SRC: @@ -908,6 +925,8 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl) { struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_out); struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; + u32 display_present = 0; + unsigned int i, j, bus_idx; switch (ctrl->id) { case VIVID_CID_HAS_CROP_OUT: @@ -941,6 +960,37 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl) if (dev->loop_video) vivid_send_source_change(dev, HDMI); break; + case VIVID_CID_DISPLAY_PRESENT: + if (dev->output_type[dev->output] != HDMI) + break; + + dev->display_present[dev->output] = ctrl->val; + for (i = 0, j = 0; i < dev->num_outputs; i++) + if (dev->output_type[i] == HDMI) + display_present |= + dev->display_present[i] << j++; + + __v4l2_ctrl_s_ctrl(dev->ctrl_tx_rxsense, display_present); + + if (dev->edid_blocks) { + __v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, + display_present); + __v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, + display_present); + } + + bus_idx = dev->cec_output2bus_map[dev->output]; + if (!dev->cec_tx_adap[bus_idx]) + break; + + if (ctrl->val && dev->edid_blocks) + cec_s_phys_addr(dev->cec_tx_adap[bus_idx], + dev->cec_tx_adap[bus_idx]->phys_addr, + false); + else + cec_phys_addr_invalidate(dev->cec_tx_adap[bus_idx]); + + break; } return 0; } @@ -979,6 +1029,15 @@ static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_out = { .step = 1, }; +static const struct v4l2_ctrl_config vivid_ctrl_display_present = { + .ops = &vivid_vid_out_ctrl_ops, + .id = VIVID_CID_DISPLAY_PRESENT, + .name = "Display Present", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; /* Streaming Controls */ @@ -1127,10 +1186,14 @@ static int vivid_sdtv_cap_s_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case VIVID_CID_STD_SIGNAL_MODE: - dev->std_signal_mode = dev->ctrl_std_signal_mode->val; - if (dev->std_signal_mode == SELECTED_STD) - dev->query_std = vivid_standard[dev->ctrl_standard->val]; - v4l2_ctrl_activate(dev->ctrl_standard, dev->std_signal_mode == SELECTED_STD); + dev->std_signal_mode[dev->input] = + dev->ctrl_std_signal_mode->val; + if (dev->std_signal_mode[dev->input] == SELECTED_STD) + dev->query_std[dev->input] = + vivid_standard[dev->ctrl_standard->val]; + v4l2_ctrl_activate(dev->ctrl_standard, + dev->std_signal_mode[dev->input] == + SELECTED_STD); vivid_update_quality(dev); vivid_send_source_change(dev, TV); vivid_send_source_change(dev, SVID); @@ -1549,7 +1612,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_vbi_cap_interlaced, NULL); } - if (has_hdmi && dev->has_vid_cap) { + if (dev->num_hdmi_inputs) { dev->ctrl_dv_timings_signal_mode = v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_dv_timings_signal_mode, NULL); @@ -1569,8 +1632,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, &vivid_vid_cap_ctrl_ops, V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, 0, V4L2_DV_RGB_RANGE_AUTO); + dev->ctrl_rx_power_present = v4l2_ctrl_new_std(hdl_vid_cap, + NULL, V4L2_CID_DV_RX_POWER_PRESENT, 0, + (2 << (dev->num_hdmi_inputs - 1)) - 1, 0, + (2 << (dev->num_hdmi_inputs - 1)) - 1); + } - if (has_hdmi && dev->has_vid_out) { + if (dev->num_hdmi_outputs) { /* * We aren't doing anything with this at the moment, but * HDMI outputs typically have this controls. @@ -1581,6 +1649,20 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, dev->ctrl_tx_mode = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL, V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI, 0, V4L2_DV_TX_MODE_HDMI); + dev->ctrl_display_present = v4l2_ctrl_new_custom(hdl_vid_out, + &vivid_ctrl_display_present, NULL); + dev->ctrl_tx_hotplug = v4l2_ctrl_new_std(hdl_vid_out, + NULL, V4L2_CID_DV_TX_HOTPLUG, 0, + (2 << (dev->num_hdmi_outputs - 1)) - 1, 0, + (2 << (dev->num_hdmi_outputs - 1)) - 1); + dev->ctrl_tx_rxsense = v4l2_ctrl_new_std(hdl_vid_out, + NULL, V4L2_CID_DV_TX_RXSENSE, 0, + (2 << (dev->num_hdmi_outputs - 1)) - 1, 0, + (2 << (dev->num_hdmi_outputs - 1)) - 1); + dev->ctrl_tx_edid_present = v4l2_ctrl_new_std(hdl_vid_out, + NULL, V4L2_CID_DV_TX_EDID_PRESENT, 0, + (2 << (dev->num_hdmi_outputs - 1)) - 1, 0, + (2 << (dev->num_hdmi_outputs - 1)) - 1); } if ((dev->has_vid_cap && dev->has_vid_out) || (dev->has_vbi_cap && dev->has_vbi_out)) diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index f8006a30c12f..6cf495a7d5cc 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -43,7 +43,7 @@ static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev) { if (vivid_is_sdtv_cap(dev)) - return dev->std_cap; + return dev->std_cap[dev->input]; return 0; } @@ -408,7 +408,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; unsigned line_height = 16 / factor; bool is_tv = vivid_is_sdtv_cap(dev); - bool is_60hz = is_tv && (dev->std_cap & V4L2_STD_525_60); + bool is_60hz = is_tv && (dev->std_cap[dev->input] & V4L2_STD_525_60); unsigned p; int line = 1; u8 *basep[TPG_MAX_PLANES][2]; @@ -419,9 +419,9 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) if (dev->loop_video && dev->can_loop_video && ((vivid_is_svid_cap(dev) && - !VIVID_INVALID_SIGNAL(dev->std_signal_mode)) || + !VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) || (vivid_is_hdmi_cap(dev) && - !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode)))) + !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])))) is_loop = true; buf->vb.sequence = dev->vid_cap_seq_count; diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c index 1a89593b0c86..f2e789bdf4a6 100644 --- a/drivers/media/platform/vivid/vivid-osd.c +++ b/drivers/media/platform/vivid/vivid-osd.c @@ -155,7 +155,7 @@ static int _vivid_fb_check_var(struct fb_var_screeninfo *var, struct vivid_dev * var->nonstd = 0; var->vmode &= ~FB_VMODE_MASK; - var->vmode = FB_VMODE_NONINTERLACED; + var->vmode |= FB_VMODE_NONINTERLACED; /* Dummy values */ var->hsync_len = 24; diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c index 40ecd7902b56..1a9348eea781 100644 --- a/drivers/media/platform/vivid/vivid-vbi-cap.c +++ b/drivers/media/platform/vivid/vivid-vbi-cap.c @@ -18,7 +18,7 @@ static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr) { struct vivid_vbi_gen_data *vbi_gen = &dev->vbi_gen; - bool is_60hz = dev->std_cap & V4L2_STD_525_60; + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; vivid_vbi_gen_sliced(vbi_gen, is_60hz, seqnr); @@ -65,7 +65,7 @@ static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr) static void vivid_g_fmt_vbi_cap(struct vivid_dev *dev, struct v4l2_vbi_format *vbi) { - bool is_60hz = dev->std_cap & V4L2_STD_525_60; + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; vbi->sampling_rate = 27000000; vbi->offset = 24; @@ -93,7 +93,7 @@ void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) memset(vbuf, 0x10, vb2_plane_size(&buf->vb.vb2_buf, 0)); - if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) + if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf); } @@ -111,7 +111,7 @@ void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, vivid_sliced_vbi_cap_fill(dev, buf->vb.sequence); memset(vbuf, 0, vb2_plane_size(&buf->vb.vb2_buf, 0)); - if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) { + if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) { unsigned i; for (i = 0; i < 25; i++) @@ -124,7 +124,7 @@ static int vbi_cap_queue_setup(struct vb2_queue *vq, unsigned sizes[], struct device *alloc_devs[]) { struct vivid_dev *dev = vb2_get_drv_priv(vq); - bool is_60hz = dev->std_cap & V4L2_STD_525_60; + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? 36 * sizeof(struct v4l2_sliced_vbi_data) : 1440 * 2 * (is_60hz ? 12 : 18); @@ -144,7 +144,7 @@ static int vbi_cap_queue_setup(struct vb2_queue *vq, static int vbi_cap_buf_prepare(struct vb2_buffer *vb) { struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - bool is_60hz = dev->std_cap & V4L2_STD_525_60; + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? 36 * sizeof(struct v4l2_sliced_vbi_data) : 1440 * 2 * (is_60hz ? 12 : 18); @@ -302,7 +302,7 @@ int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_forma { struct vivid_dev *dev = video_drvdata(file); struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; - bool is_60hz = dev->std_cap & V4L2_STD_525_60; + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; u32 service_set = vbi->service_set; if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) @@ -337,7 +337,7 @@ int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_ bool is_60hz; if (vdev->vfl_dir == VFL_DIR_RX) { - is_60hz = dev->std_cap & V4L2_STD_525_60; + is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap || cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) return -EINVAL; diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 530ac8decb25..8cbaa0c998ed 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -21,11 +21,6 @@ #include "vivid-kthread-cap.h" #include "vivid-vid-cap.h" -/* timeperframe: min/max and default */ -static const struct v4l2_fract - tpf_min = {.numerator = 1, .denominator = FPS_MAX}, - tpf_max = {.numerator = FPS_MAX, .denominator = 1}; - static const struct vivid_fmt formats_ovl[] = { { .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ @@ -196,7 +191,7 @@ static void vid_cap_buf_finish(struct vb2_buffer *vb) * test this. */ vbuf->flags |= V4L2_BUF_FLAG_TIMECODE; - if (dev->std_cap & V4L2_STD_525_60) + if (dev->std_cap[dev->input] & V4L2_STD_525_60) fps = 30; tc->type = (fps == 30) ? V4L2_TC_TYPE_30FPS : V4L2_TC_TYPE_25FPS; tc->flags = 0; @@ -299,11 +294,13 @@ void vivid_update_quality(struct vivid_dev *dev) tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); return; } - if (vivid_is_hdmi_cap(dev) && VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode)) { + if (vivid_is_hdmi_cap(dev) && + VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])) { tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); return; } - if (vivid_is_sdtv_cap(dev) && VIVID_INVALID_SIGNAL(dev->std_signal_mode)) { + if (vivid_is_sdtv_cap(dev) && + VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) { tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); return; } @@ -358,10 +355,10 @@ static enum tpg_quality vivid_get_quality(struct vivid_dev *dev, s32 *afc) enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev) { if (vivid_is_sdtv_cap(dev)) - return dev->std_aspect_ratio; + return dev->std_aspect_ratio[dev->input]; if (vivid_is_hdmi_cap(dev)) - return dev->dv_timings_aspect_ratio; + return dev->dv_timings_aspect_ratio[dev->input]; return TPG_VIDEO_ASPECT_IMAGE; } @@ -369,7 +366,7 @@ enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev) static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) { if (vivid_is_sdtv_cap(dev)) - return (dev->std_cap & V4L2_STD_525_60) ? + return (dev->std_cap[dev->input] & V4L2_STD_525_60) ? TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; if (vivid_is_hdmi_cap(dev) && @@ -386,7 +383,7 @@ static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) */ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) { - struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt; + struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; unsigned size; u64 pixelclock; @@ -403,7 +400,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) case SVID: dev->field_cap = dev->tv_field_cap; dev->src_rect.width = 720; - if (dev->std_cap & V4L2_STD_525_60) { + if (dev->std_cap[dev->input] & V4L2_STD_525_60) { dev->src_rect.height = 480; dev->timeperframe_vid_cap = (struct v4l2_fract) { 1001, 30000 }; dev->service_set_cap = V4L2_SLICED_CAPTION_525; @@ -486,8 +483,8 @@ static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field fi } } if (vivid_is_hdmi_cap(dev)) - return dev->dv_timings_cap.bt.interlaced ? V4L2_FIELD_ALTERNATE : - V4L2_FIELD_NONE; + return dev->dv_timings_cap[dev->input].bt.interlaced ? + V4L2_FIELD_ALTERNATE : V4L2_FIELD_NONE; return V4L2_FIELD_NONE; } @@ -586,7 +583,7 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, h = sz->height; } else if (vivid_is_sdtv_cap(dev)) { w = 720; - h = (dev->std_cap & V4L2_STD_525_60) ? 480 : 576; + h = (dev->std_cap[dev->input] & V4L2_STD_525_60) ? 480 : 576; } else { w = dev->src_rect.width; h = dev->src_rect.height; @@ -1310,10 +1307,10 @@ int vidioc_enum_input(struct file *file, void *priv, dev->input_name_counter[inp->index]); inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; if (dev->edid_blocks == 0 || - dev->dv_timings_signal_mode == NO_SIGNAL) + dev->dv_timings_signal_mode[dev->input] == NO_SIGNAL) inp->status |= V4L2_IN_ST_NO_SIGNAL; - else if (dev->dv_timings_signal_mode == NO_LOCK || - dev->dv_timings_signal_mode == OUT_OF_RANGE) + else if (dev->dv_timings_signal_mode[dev->input] == NO_LOCK || + dev->dv_timings_signal_mode[dev->input] == OUT_OF_RANGE) inp->status |= V4L2_IN_ST_NO_H_LOCK; break; } @@ -1322,9 +1319,9 @@ int vidioc_enum_input(struct file *file, void *priv, if (dev->sensor_vflip) inp->status |= V4L2_IN_ST_VFLIP; if (dev->input == inp->index && vivid_is_sdtv_cap(dev)) { - if (dev->std_signal_mode == NO_SIGNAL) { + if (dev->std_signal_mode[dev->input] == NO_SIGNAL) { inp->status |= V4L2_IN_ST_NO_SIGNAL; - } else if (dev->std_signal_mode == NO_LOCK) { + } else if (dev->std_signal_mode[dev->input] == NO_LOCK) { inp->status |= V4L2_IN_ST_NO_H_LOCK; } else if (vivid_is_tv_cap(dev)) { switch (tpg_g_quality(&dev->tpg)) { @@ -1353,7 +1350,7 @@ int vidioc_g_input(struct file *file, void *priv, unsigned *i) int vidioc_s_input(struct file *file, void *priv, unsigned i) { struct vivid_dev *dev = video_drvdata(file); - struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt; + struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; unsigned brightness; if (i >= dev->num_inputs) @@ -1407,6 +1404,29 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) v4l2_ctrl_modify_range(dev->brightness, 128 * i, 255 + 128 * i, 1, 128 + 128 * i); v4l2_ctrl_s_ctrl(dev->brightness, brightness); + + /* Restore per-input states. */ + v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, + vivid_is_hdmi_cap(dev)); + v4l2_ctrl_activate(dev->ctrl_dv_timings, vivid_is_hdmi_cap(dev) && + dev->dv_timings_signal_mode[dev->input] == + SELECTED_DV_TIMINGS); + v4l2_ctrl_activate(dev->ctrl_std_signal_mode, vivid_is_sdtv_cap(dev)); + v4l2_ctrl_activate(dev->ctrl_standard, vivid_is_sdtv_cap(dev) && + dev->std_signal_mode[dev->input]); + + if (vivid_is_hdmi_cap(dev)) { + v4l2_ctrl_s_ctrl(dev->ctrl_dv_timings_signal_mode, + dev->dv_timings_signal_mode[dev->input]); + v4l2_ctrl_s_ctrl(dev->ctrl_dv_timings, + dev->query_dv_timings[dev->input]); + } else if (vivid_is_sdtv_cap(dev)) { + v4l2_ctrl_s_ctrl(dev->ctrl_std_signal_mode, + dev->std_signal_mode[dev->input]); + v4l2_ctrl_s_ctrl(dev->ctrl_standard, + dev->std_signal_mode[dev->input]); + } + return 0; } @@ -1499,8 +1519,9 @@ int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) } else if (qual == TPG_QUAL_GRAY) { vt->rxsubchans = V4L2_TUNER_SUB_MONO; } else { - unsigned channel_nr = dev->tv_freq / (6 * 16); - unsigned options = (dev->std_cap & V4L2_STD_NTSC_M) ? 4 : 3; + unsigned int channel_nr = dev->tv_freq / (6 * 16); + unsigned int options = + (dev->std_cap[dev->input] & V4L2_STD_NTSC_M) ? 4 : 3; switch (channel_nr % options) { case 0: @@ -1510,7 +1531,7 @@ int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) vt->rxsubchans = V4L2_TUNER_SUB_STEREO; break; case 2: - if (dev->std_cap & V4L2_STD_NTSC_M) + if (dev->std_cap[dev->input] & V4L2_STD_NTSC_M) vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP; else vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; @@ -1567,23 +1588,25 @@ const char * const vivid_ctrl_standard_strings[] = { int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id) { struct vivid_dev *dev = video_drvdata(file); + unsigned int last = dev->query_std_last[dev->input]; if (!vivid_is_sdtv_cap(dev)) return -ENODATA; - if (dev->std_signal_mode == NO_SIGNAL || - dev->std_signal_mode == NO_LOCK) { + if (dev->std_signal_mode[dev->input] == NO_SIGNAL || + dev->std_signal_mode[dev->input] == NO_LOCK) { *id = V4L2_STD_UNKNOWN; return 0; } if (vivid_is_tv_cap(dev) && tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE) { *id = V4L2_STD_UNKNOWN; - } else if (dev->std_signal_mode == CURRENT_STD) { - *id = dev->std_cap; - } else if (dev->std_signal_mode == SELECTED_STD) { - *id = dev->query_std; + } else if (dev->std_signal_mode[dev->input] == CURRENT_STD) { + *id = dev->std_cap[dev->input]; + } else if (dev->std_signal_mode[dev->input] == SELECTED_STD) { + *id = dev->query_std[dev->input]; } else { - *id = vivid_standard[dev->query_std_last]; - dev->query_std_last = (dev->query_std_last + 1) % ARRAY_SIZE(vivid_standard); + *id = vivid_standard[last]; + dev->query_std_last[dev->input] = + (last + 1) % ARRAY_SIZE(vivid_standard); } return 0; @@ -1595,11 +1618,11 @@ int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id) if (!vivid_is_sdtv_cap(dev)) return -ENODATA; - if (dev->std_cap == id) + if (dev->std_cap[dev->input] == id) return 0; if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q)) return -EBUSY; - dev->std_cap = id; + dev->std_cap[dev->input] = id; vivid_update_format_cap(dev, false); return 0; } @@ -1676,12 +1699,13 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, !valid_cvt_gtf_timings(timings)) return -EINVAL; - if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0, false)) + if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap[dev->input], + 0, false)) return 0; if (vb2_is_busy(&dev->vb_vid_cap_q)) return -EBUSY; - dev->dv_timings_cap = *timings; + dev->dv_timings_cap[dev->input] = *timings; vivid_update_format_cap(dev, false); return 0; } @@ -1690,26 +1714,31 @@ int vidioc_query_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings) { struct vivid_dev *dev = video_drvdata(file); + unsigned int input = dev->input; + unsigned int last = dev->query_dv_timings_last[input]; if (!vivid_is_hdmi_cap(dev)) return -ENODATA; - if (dev->dv_timings_signal_mode == NO_SIGNAL || + if (dev->dv_timings_signal_mode[input] == NO_SIGNAL || dev->edid_blocks == 0) return -ENOLINK; - if (dev->dv_timings_signal_mode == NO_LOCK) + if (dev->dv_timings_signal_mode[input] == NO_LOCK) return -ENOLCK; - if (dev->dv_timings_signal_mode == OUT_OF_RANGE) { + if (dev->dv_timings_signal_mode[input] == OUT_OF_RANGE) { timings->bt.pixelclock = vivid_dv_timings_cap.bt.max_pixelclock * 2; return -ERANGE; } - if (dev->dv_timings_signal_mode == CURRENT_DV_TIMINGS) { - *timings = dev->dv_timings_cap; - } else if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS) { - *timings = v4l2_dv_timings_presets[dev->query_dv_timings]; + if (dev->dv_timings_signal_mode[input] == CURRENT_DV_TIMINGS) { + *timings = dev->dv_timings_cap[input]; + } else if (dev->dv_timings_signal_mode[input] == + SELECTED_DV_TIMINGS) { + *timings = + v4l2_dv_timings_presets[dev->query_dv_timings[input]]; } else { - *timings = v4l2_dv_timings_presets[dev->query_dv_timings_last]; - dev->query_dv_timings_last = (dev->query_dv_timings_last + 1) % - dev->query_dv_timings_size; + *timings = + v4l2_dv_timings_presets[last]; + dev->query_dv_timings_last[input] = + (last + 1) % dev->query_dv_timings_size; } return 0; } @@ -1719,7 +1748,8 @@ int vidioc_s_edid(struct file *file, void *_fh, { struct vivid_dev *dev = video_drvdata(file); u16 phys_addr; - unsigned int i; + u32 display_present = 0; + unsigned int i, j; int ret; memset(edid->reserved, 0, sizeof(edid->reserved)); @@ -1729,6 +1759,8 @@ int vidioc_s_edid(struct file *file, void *_fh, return -EINVAL; if (edid->blocks == 0) { dev->edid_blocks = 0; + v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, 0); + v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, 0); phys_addr = CEC_PHYS_ADDR_INVALID; goto set_phys_addr; } @@ -1747,13 +1779,23 @@ int vidioc_s_edid(struct file *file, void *_fh, dev->edid_blocks = edid->blocks; memcpy(dev->edid, edid->edid, edid->blocks * 128); + for (i = 0, j = 0; i < dev->num_outputs; i++) + if (dev->output_type[i] == HDMI) + display_present |= + dev->display_present[i] << j++; + + v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, display_present); + v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, display_present); + set_phys_addr: /* TODO: a proper hotplug detect cycle should be emulated here */ cec_s_phys_addr(dev->cec_rx_adap, phys_addr, false); for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) cec_s_phys_addr(dev->cec_tx_adap[i], - v4l2_phys_addr_for_input(phys_addr, i + 1), + dev->display_present[i] ? + v4l2_phys_addr_for_input(phys_addr, i + 1) : + CEC_PHYS_ADDR_INVALID, false); return 0; } @@ -1865,8 +1907,6 @@ int vivid_vid_cap_s_parm(struct file *file, void *priv, i = ival_sz - 1; dev->webcam_ival_idx = i; tpf = webcam_intervals[dev->webcam_ival_idx]; - tpf = V4L2_FRACT_COMPARE(tpf, <, tpf_min) ? tpf_min : tpf; - tpf = V4L2_FRACT_COMPARE(tpf, >, tpf_max) ? tpf_max : tpf; /* resync the thread's timings */ dev->cap_seq_resync = true; diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 74b83bcc6119..1f33eb1a76b6 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -645,7 +645,7 @@ bool vivid_vid_can_loop(struct vivid_dev *dev) dev->field_cap == V4L2_FIELD_SEQ_BT) return false; if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) { - if (!(dev->std_cap & V4L2_STD_525_60) != + if (!(dev->std_cap[dev->input] & V4L2_STD_525_60) != !(dev->std_out & V4L2_STD_525_60)) return false; return true; @@ -797,26 +797,6 @@ int vivid_enum_fmt_vid(struct file *file, void *priv, return 0; } -int vidioc_enum_fmt_vid_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->multiplanar) - return -ENOTTY; - return vivid_enum_fmt_vid(file, priv, f); -} - -int vidioc_enum_fmt_vid(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - return vivid_enum_fmt_vid(file, priv, f); -} - int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { struct vivid_dev *dev = video_drvdata(file); @@ -825,7 +805,7 @@ int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) if (vdev->vfl_dir == VFL_DIR_RX) { if (!vivid_is_sdtv_cap(dev)) return -ENODATA; - *id = dev->std_cap; + *id = dev->std_cap[dev->input]; } else { if (!vivid_is_svid_out(dev)) return -ENODATA; @@ -843,7 +823,7 @@ int vidioc_g_dv_timings(struct file *file, void *_fh, if (vdev->vfl_dir == VFL_DIR_RX) { if (!vivid_is_hdmi_cap(dev)) return -ENODATA; - *timings = dev->dv_timings_cap; + *timings = dev->dv_timings_cap[dev->input]; } else { if (!vivid_is_hdmi_out(dev)) return -ENODATA; @@ -907,6 +887,8 @@ int vidioc_g_edid(struct file *file, void *_fh, return -EINVAL; if (dev->output_type[edid->pad] != HDMI) return -EINVAL; + if (!dev->display_present[edid->pad]) + return -ENODATA; bus_idx = dev->cec_output2bus_map[edid->pad]; adap = dev->cec_tx_adap[bus_idx]; } diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h index 29b6c0b40a1b..d908d9725283 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.h +++ b/drivers/media/platform/vivid/vivid-vid-common.h @@ -28,8 +28,6 @@ void vivid_send_source_change(struct vivid_dev *dev, unsigned type); int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r); int vivid_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f); -int vidioc_enum_fmt_vid_mplane(struct file *file, void *priv, struct v4l2_fmtdesc *f); -int vidioc_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f); int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id); int vidioc_g_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); int vidioc_enum_dv_timings(struct file *file, void *_fh, struct v4l2_enum_dv_timings *timings); diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 9350ca65dd91..148b663a6075 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -1094,6 +1094,12 @@ int vidioc_s_output(struct file *file, void *priv, unsigned o) dev->vbi_out_dev.tvnorms = dev->vid_out_dev.tvnorms; vivid_update_format_out(dev); + + v4l2_ctrl_activate(dev->ctrl_display_present, vivid_is_hdmi_out(dev)); + if (vivid_is_hdmi_out(dev)) + v4l2_ctrl_s_ctrl(dev->ctrl_display_present, + dev->display_present[dev->output]); + return 0; } diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 4b41687b2bde..eb79d99787bd 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -233,7 +233,6 @@ source "drivers/media/radio/wl128x/Kconfig" menuconfig V4L_RADIO_ISA_DRIVERS bool "ISA radio devices" depends on ISA || COMPILE_TEST - default n help Say Y here to enable support for these ISA drivers. diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index 9f7e68498321..9a45cda05779 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -168,8 +168,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "dsbr100", sizeof(v->driver)); strscpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card)); usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -378,6 +376,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf, radio->videodev.release = video_device_release_empty; radio->videodev.lock = &radio->v4l2_lock; radio->videodev.ctrl_handler = &radio->hdl; + radio->videodev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; radio->usbdev = interface_to_usbdev(intf); radio->curfreq = FREQ_MIN * FREQ_MUL; diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 12160894839c..a5db9b4dc3de 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -357,9 +357,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "ADS Cadet", sizeof(v->driver)); strscpy(v->card, "ADS Cadet", sizeof(v->card)); strscpy(v->bus_info, "ISA:radio-cadet", sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | - V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -646,6 +643,8 @@ static int __init cadet_init(void) dev->vdev.ioctl_ops = &cadet_ioctl_ops; dev->vdev.release = video_device_release_empty; dev->vdev.lock = &dev->lock; + dev->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | + V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE; video_set_drvdata(&dev->vdev, dev); res = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr); diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c index 9f9c08393756..ad2ac16ff12d 100644 --- a/drivers/media/radio/radio-isa.c +++ b/drivers/media/radio/radio-isa.c @@ -37,9 +37,6 @@ static int radio_isa_querycap(struct file *file, void *priv, strscpy(v->driver, isa->drv->driver.driver.name, sizeof(v->driver)); strscpy(v->card, isa->drv->card, sizeof(v->card)); snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name); - - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -240,6 +237,7 @@ static int radio_isa_common_probe(struct radio_isa_card *isa, isa->vdev.fops = &radio_isa_fops; isa->vdev.ioctl_ops = &radio_isa_ioctl_ops; isa->vdev.release = video_device_release_empty; + isa->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; video_set_drvdata(&isa->vdev, isa); isa->freq = FREQ_LOW; isa->stereo = drv->has_stereo; diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c index 4d41857946de..a35648316aa8 100644 --- a/drivers/media/radio/radio-keene.c +++ b/drivers/media/radio/radio-keene.c @@ -168,8 +168,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "radio-keene", sizeof(v->driver)); strscpy(v->card, "Keene FM Transmitter", sizeof(v->card)); usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -361,6 +359,7 @@ static int usb_keene_probe(struct usb_interface *intf, radio->vdev.lock = &radio->lock; radio->vdev.release = video_device_release_empty; radio->vdev.vfl_dir = VFL_DIR_TX; + radio->vdev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR; radio->usbdev = interface_to_usbdev(intf); radio->intf = intf; diff --git a/drivers/media/radio/radio-ma901.c b/drivers/media/radio/radio-ma901.c index cbcf0ed69223..657c3dda6648 100644 --- a/drivers/media/radio/radio-ma901.c +++ b/drivers/media/radio/radio-ma901.c @@ -191,8 +191,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "radio-ma901", sizeof(v->driver)); strscpy(v->card, "Masterkit MA901 USB FM Radio", sizeof(v->card)); usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -398,6 +396,7 @@ static int usb_ma901radio_probe(struct usb_interface *intf, radio->vdev.ioctl_ops = &usb_ma901radio_ioctl_ops; radio->vdev.release = video_device_release_empty; radio->vdev.lock = &radio->lock; + radio->vdev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; radio->usbdev = interface_to_usbdev(intf); radio->intf = intf; diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 95d12cbff5c9..99788834c646 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -204,8 +204,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "Miro PCM20", sizeof(v->driver)); strscpy(v->card, "Miro PCM20", sizeof(v->card)); snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev->v4l2_dev.name); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -481,6 +479,8 @@ static int __init pcm20_init(void) dev->vdev.ioctl_ops = &pcm20_ioctl_ops; dev->vdev.release = video_device_release_empty; dev->vdev.lock = &dev->lock; + dev->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | + V4L2_CAP_RDS_CAPTURE; video_set_drvdata(&dev->vdev, dev); snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO, dev->audmode == V4L2_TUNER_MODE_MONO, -1); diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index f53f9064e1e9..cb0437b4c331 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -260,9 +260,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "radio-mr800", sizeof(v->driver)); strscpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card)); usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER | - V4L2_CAP_HW_FREQ_SEEK; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -545,6 +542,8 @@ static int usb_amradio_probe(struct usb_interface *intf, radio->vdev.ioctl_ops = &usb_amradio_ioctl_ops; radio->vdev.release = video_device_release_empty; radio->vdev.lock = &radio->lock; + radio->vdev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER | + V4L2_CAP_HW_FREQ_SEEK; radio->usbdev = interface_to_usbdev(intf); radio->intf = intf; diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c index 5e782b3c2fa9..c3180d53c282 100644 --- a/drivers/media/radio/radio-raremono.c +++ b/drivers/media/radio/radio-raremono.c @@ -184,8 +184,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "radio-raremono", sizeof(v->driver)); strscpy(v->card, "Thanko's Raremono", sizeof(v->card)); usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -271,6 +269,14 @@ static int vidioc_g_frequency(struct file *file, void *priv, return 0; } +static void raremono_device_release(struct v4l2_device *v4l2_dev) +{ + struct raremono_device *radio = to_raremono_dev(v4l2_dev); + + kfree(radio->buffer); + kfree(radio); +} + /* File system interface */ static const struct v4l2_file_operations usb_raremono_fops = { .owner = THIS_MODULE, @@ -295,12 +301,14 @@ static int usb_raremono_probe(struct usb_interface *intf, struct raremono_device *radio; int retval = 0; - radio = devm_kzalloc(&intf->dev, sizeof(struct raremono_device), GFP_KERNEL); - if (radio) - radio->buffer = devm_kmalloc(&intf->dev, BUFFER_LENGTH, GFP_KERNEL); - - if (!radio || !radio->buffer) + radio = kzalloc(sizeof(*radio), GFP_KERNEL); + if (!radio) + return -ENOMEM; + radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); + if (!radio->buffer) { + kfree(radio); return -ENOMEM; + } radio->usbdev = interface_to_usbdev(intf); radio->intf = intf; @@ -324,7 +332,8 @@ static int usb_raremono_probe(struct usb_interface *intf, if (retval != 3 || (get_unaligned_be16(&radio->buffer[1]) & 0xfff) == 0x0242) { dev_info(&intf->dev, "this is not Thanko's Raremono.\n"); - return -ENODEV; + retval = -ENODEV; + goto free_mem; } dev_info(&intf->dev, "Thanko's Raremono connected: (%04X:%04X)\n", @@ -333,7 +342,7 @@ static int usb_raremono_probe(struct usb_interface *intf, retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); if (retval < 0) { dev_err(&intf->dev, "couldn't register v4l2_device\n"); - return retval; + goto free_mem; } mutex_init(&radio->lock); @@ -345,6 +354,8 @@ static int usb_raremono_probe(struct usb_interface *intf, radio->vdev.ioctl_ops = &usb_raremono_ioctl_ops; radio->vdev.lock = &radio->lock; radio->vdev.release = video_device_release_empty; + radio->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + radio->v4l2_dev.release = raremono_device_release; usb_set_intfdata(intf, &radio->v4l2_dev); @@ -360,6 +371,10 @@ static int usb_raremono_probe(struct usb_interface *intf, } dev_err(&intf->dev, "could not register video device\n"); v4l2_device_unregister(&radio->v4l2_dev); + +free_mem: + kfree(radio->buffer); + kfree(radio); return retval; } diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 434c03338d7f..54a40d60e4fd 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -133,8 +133,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "radio-sf16fmi", sizeof(v->driver)); strscpy(v->card, "SF16-FMI/FMP/FMD radio", sizeof(v->card)); strscpy(v->bus_info, "ISA:radio-sf16fmi", sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -345,6 +343,7 @@ static int __init fmi_init(void) fmi->vdev.fops = &fmi_fops; fmi->vdev.ioctl_ops = &fmi_ioctl_ops; fmi->vdev.release = video_device_release_empty; + fmi->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; video_set_drvdata(&fmi->vdev, fmi); mutex_init(&fmi->lock); diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index 645242314a09..b203296de977 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -336,19 +336,6 @@ static int si476x_radio_querycap(struct file *file, void *priv, strscpy(capability->card, DRIVER_CARD, sizeof(capability->card)); snprintf(capability->bus_info, sizeof(capability->bus_info), "platform:%s", radio->v4l2dev.name); - - capability->device_caps = V4L2_CAP_TUNER - | V4L2_CAP_RADIO - | V4L2_CAP_HW_FREQ_SEEK; - - si476x_core_lock(radio->core); - if (!si476x_core_is_a_secondary_tuner(radio->core)) - capability->device_caps |= V4L2_CAP_RDS_CAPTURE - | V4L2_CAP_READWRITE; - si476x_core_unlock(radio->core); - - capability->capabilities = capability->device_caps - | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1459,6 +1446,14 @@ static int si476x_radio_probe(struct platform_device *pdev) radio->videodev.v4l2_dev = &radio->v4l2dev; radio->videodev.ioctl_ops = &si4761_ioctl_ops; + radio->videodev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | + V4L2_CAP_HW_FREQ_SEEK; + + si476x_core_lock(radio->core); + if (!si476x_core_is_a_secondary_tuner(radio->core)) + radio->videodev.device_caps |= V4L2_CAP_RDS_CAPTURE | + V4L2_CAP_READWRITE; + si476x_core_unlock(radio->core); video_set_drvdata(&radio->videodev, radio); platform_set_drvdata(pdev, radio); diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index b740646adc53..877a24e5c577 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -282,8 +282,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->card, dev->name, sizeof(v->card)); snprintf(v->bus_info, sizeof(v->bus_info), "I2C:%s", dev_name(&dev->dev)); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -465,6 +463,7 @@ static int tea5764_i2c_probe(struct i2c_client *client, video_set_drvdata(&radio->vdev, radio); radio->vdev.lock = &radio->mutex; radio->vdev.v4l2_dev = v4l2_dev; + radio->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; /* initialize and power off the chip */ tea5764_i2c_read(radio); diff --git a/drivers/media/radio/radio-tea5777.c b/drivers/media/radio/radio-tea5777.c index 49d4beba341e..fb9de7bbcd19 100644 --- a/drivers/media/radio/radio-tea5777.c +++ b/drivers/media/radio/radio-tea5777.c @@ -260,9 +260,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->card, tea->card, sizeof(v->card)); strlcat(v->card, " TEA5777", sizeof(v->card)); strscpy(v->bus_info, tea->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - v->device_caps |= V4L2_CAP_HW_FREQ_SEEK; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -553,6 +550,8 @@ int radio_tea5777_init(struct radio_tea5777 *tea, struct module *owner) strscpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name)); tea->vd.lock = &tea->mutex; tea->vd.v4l2_dev = tea->v4l2_dev; + tea->vd.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | + V4L2_CAP_HW_FREQ_SEEK; tea->fops = tea575x_fops; tea->fops.owner = owner; tea->vd.fops = &tea->fops; diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index 7d196f8ad3b5..948ee3eec914 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -34,8 +34,6 @@ static int timbradio_vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, DRIVER_NAME, sizeof(v->driver)); strscpy(v->card, "Timberdale Radio", sizeof(v->card)); snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -114,6 +112,7 @@ static int timbradio_probe(struct platform_device *pdev) tr->video_dev.release = video_device_release_empty; tr->video_dev.minor = -1; tr->video_dev.lock = &tr->lock; + tr->video_dev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; strscpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name)); err = v4l2_device_register(NULL, &tr->v4l2_dev); diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 330de50f8920..104ac41c6f96 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1284,14 +1284,6 @@ static int wl1273_fm_vidioc_querycap(struct file *file, void *priv, sizeof(capability->card)); strscpy(capability->bus_info, radio->bus_type, sizeof(capability->bus_info)); - - capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | - V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_AUDIO | - V4L2_CAP_RDS_CAPTURE | V4L2_CAP_MODULATOR | - V4L2_CAP_RDS_OUTPUT; - capability->capabilities = capability->device_caps | - V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -1980,6 +1972,10 @@ static const struct video_device wl1273_viddev_template = { .name = WL1273_FM_DRIVER_NAME, .release = wl1273_vdev_release, .vfl_dir = VFL_DIR_TX, + .device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | + V4L2_CAP_RADIO | V4L2_CAP_AUDIO | + V4L2_CAP_RDS_CAPTURE | V4L2_CAP_MODULATOR | + V4L2_CAP_RDS_OUTPUT, }; static int wl1273_fm_radio_remove(struct platform_device *pdev) diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index a3152d646c3a..7d53422b3b56 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -223,10 +223,6 @@ static int si470x_vidioc_querycap(struct file *file, void *priv, { strscpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); strscpy(capability->card, DRIVER_CARD, sizeof(capability->card)); - capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE | - V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; - capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -382,6 +378,9 @@ static int si470x_i2c_probe(struct i2c_client *client, radio->videodev.lock = &radio->lock; radio->videodev.v4l2_dev = &radio->v4l2_dev; radio->videodev.release = video_device_release_empty; + radio->videodev.device_caps = + V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE | V4L2_CAP_TUNER | + V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; video_set_drvdata(&radio->videodev, radio); radio->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset", diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index 58e622d57373..49073747b1e7 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -514,9 +514,6 @@ static int si470x_vidioc_querycap(struct file *file, void *priv, strscpy(capability->card, DRIVER_CARD, sizeof(capability->card)); usb_make_path(radio->usbdev, capability->bus_info, sizeof(capability->bus_info)); - capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE | - V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; - capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -670,6 +667,9 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, radio->videodev.lock = &radio->lock; radio->videodev.v4l2_dev = &radio->v4l2_dev; radio->videodev.release = video_device_release_empty; + radio->videodev.device_caps = + V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE | V4L2_CAP_TUNER | + V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; video_set_drvdata(&radio->videodev, radio); /* get device and chip versions */ diff --git a/drivers/media/radio/si4713/radio-platform-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c index 70d51d3607ff..a7dfe5f55c18 100644 --- a/drivers/media/radio/si4713/radio-platform-si4713.c +++ b/drivers/media/radio/si4713/radio-platform-si4713.c @@ -63,9 +63,6 @@ static int radio_si4713_querycap(struct file *file, void *priv, sizeof(capability->card)); strscpy(capability->bus_info, "platform:radio-si4713", sizeof(capability->bus_info)); - capability->device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT; - capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -175,6 +172,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev) rsdev->radio_dev.ctrl_handler = sd->ctrl_handler; /* Serialize all access to the si4713 */ rsdev->radio_dev.lock = &rsdev->lock; + rsdev->radio_dev.device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT; video_set_drvdata(&rsdev->radio_dev, rsdev); if (video_register_device(&rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) { dev_err(&pdev->dev, "Could not register video device.\n"); diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c index 23065ecce979..33274189c83c 100644 --- a/drivers/media/radio/si4713/radio-usb-si4713.c +++ b/drivers/media/radio/si4713/radio-usb-si4713.c @@ -70,9 +70,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "radio-usb-si4713", sizeof(v->driver)); strscpy(v->card, "Si4713 FM Transmitter", sizeof(v->card)); usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -475,6 +472,7 @@ static int usb_si4713_probe(struct usb_interface *intf, radio->vdev.lock = &radio->lock; radio->vdev.release = video_device_release_empty; radio->vdev.vfl_dir = VFL_DIR_TX; + radio->vdev.device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT; video_set_drvdata(&radio->vdev, radio); diff --git a/drivers/media/radio/tea575x.c b/drivers/media/radio/tea575x.c index 64613dd145a1..b0303cf00387 100644 --- a/drivers/media/radio/tea575x.c +++ b/drivers/media/radio/tea575x.c @@ -226,10 +226,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->card, tea->card, sizeof(v->card)); strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card)); strscpy(v->bus_info, tea->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - if (!tea->cannot_read_data) - v->device_caps |= V4L2_CAP_HW_FREQ_SEEK; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -529,6 +525,9 @@ int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner) strscpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name)); tea->vd.lock = &tea->mutex; tea->vd.v4l2_dev = tea->v4l2_dev; + tea->vd.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + if (!tea->cannot_read_data) + tea->vd.device_caps |= V4L2_CAP_HW_FREQ_SEEK; tea->fops = tea575x_fops; tea->fops.owner = owner; tea->vd.fops = &tea->fops; diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index c80a6df47f5e..1c146d14dbbd 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -185,13 +185,6 @@ static int fm_v4l2_vidioc_querycap(struct file *file, void *priv, strscpy(capability->card, FM_DRV_CARD_SHORT_NAME, sizeof(capability->card)); sprintf(capability->bus_info, "UART"); - capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | - V4L2_CAP_RADIO | V4L2_CAP_MODULATOR | - V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | - V4L2_CAP_RDS_CAPTURE; - capability->capabilities = capability->device_caps | - V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -515,6 +508,9 @@ static const struct video_device fm_viddev_template = { * but that would affect applications using this driver. */ .vfl_dir = VFL_DIR_M2M, + .device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | V4L2_CAP_RADIO | + V4L2_CAP_MODULATOR | V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE, }; int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) @@ -541,6 +537,7 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) /* Register with V4L2 subsystem as RADIO device */ if (video_register_device(&gradio_dev, VFL_TYPE_RADIO, radio_nr)) { + v4l2_device_unregister(&fmdev->v4l2_dev); fmerr("Could not register video device\n"); return -ENOMEM; } @@ -554,6 +551,8 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) if (ret < 0) { fmerr("(fmdev): Can't init ctrl handler\n"); v4l2_ctrl_handler_free(&fmdev->ctrl_handler); + video_unregister_device(fmdev->radio_dev); + v4l2_device_unregister(&fmdev->v4l2_dev); return -EBUSY; } diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c index 66334e8d63ba..c58f2d38a458 100644 --- a/drivers/media/rc/ir-spi.c +++ b/drivers/media/rc/ir-spi.c @@ -161,6 +161,7 @@ static const struct of_device_id ir_spi_of_match[] = { { .compatible = "ir-spi-led" }, {}, }; +MODULE_DEVICE_TABLE(of, ir_spi_of_match); static struct spi_driver ir_spi_driver = { .probe = ir_spi_probe, diff --git a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c index 732687ce0637..0a867ca90038 100644 --- a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c +++ b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c @@ -12,16 +12,16 @@ static struct rc_map_table adstech_dvb_t_pci[] = { /* Keys 0 to 9 */ - { 0x4d, KEY_0 }, - { 0x57, KEY_1 }, - { 0x4f, KEY_2 }, - { 0x53, KEY_3 }, - { 0x56, KEY_4 }, - { 0x4e, KEY_5 }, - { 0x5e, KEY_6 }, - { 0x54, KEY_7 }, - { 0x4c, KEY_8 }, - { 0x5c, KEY_9 }, + { 0x4d, KEY_NUMERIC_0 }, + { 0x57, KEY_NUMERIC_1 }, + { 0x4f, KEY_NUMERIC_2 }, + { 0x53, KEY_NUMERIC_3 }, + { 0x56, KEY_NUMERIC_4 }, + { 0x4e, KEY_NUMERIC_5 }, + { 0x5e, KEY_NUMERIC_6 }, + { 0x54, KEY_NUMERIC_7 }, + { 0x4c, KEY_NUMERIC_8 }, + { 0x5c, KEY_NUMERIC_9 }, { 0x5b, KEY_POWER }, { 0x5f, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-alink-dtu-m.c b/drivers/media/rc/keymaps/rc-alink-dtu-m.c index 530af333af8e..8a2ccaf3b817 100644 --- a/drivers/media/rc/keymaps/rc-alink-dtu-m.c +++ b/drivers/media/rc/keymaps/rc-alink-dtu-m.c @@ -11,22 +11,22 @@ /* A-Link DTU(m) slim remote, 6 rows, 3 columns. */ static struct rc_map_table alink_dtu_m[] = { { 0x0800, KEY_VOLUMEUP }, - { 0x0801, KEY_1 }, - { 0x0802, KEY_3 }, - { 0x0803, KEY_7 }, - { 0x0804, KEY_9 }, + { 0x0801, KEY_NUMERIC_1 }, + { 0x0802, KEY_NUMERIC_3 }, + { 0x0803, KEY_NUMERIC_7 }, + { 0x0804, KEY_NUMERIC_9 }, { 0x0805, KEY_NEW }, /* symbol: PIP */ - { 0x0806, KEY_0 }, + { 0x0806, KEY_NUMERIC_0 }, { 0x0807, KEY_CHANNEL }, /* JUMP */ - { 0x080d, KEY_5 }, - { 0x080f, KEY_2 }, + { 0x080d, KEY_NUMERIC_5 }, + { 0x080f, KEY_NUMERIC_2 }, { 0x0812, KEY_POWER2 }, { 0x0814, KEY_CHANNELUP }, { 0x0816, KEY_VOLUMEDOWN }, - { 0x0818, KEY_6 }, + { 0x0818, KEY_NUMERIC_6 }, { 0x081a, KEY_MUTE }, - { 0x081b, KEY_8 }, - { 0x081c, KEY_4 }, + { 0x081b, KEY_NUMERIC_8 }, + { 0x081c, KEY_NUMERIC_4 }, { 0x081d, KEY_CHANNELDOWN }, }; diff --git a/drivers/media/rc/keymaps/rc-anysee.c b/drivers/media/rc/keymaps/rc-anysee.c index 9d1eee1f0515..34da03c46104 100644 --- a/drivers/media/rc/keymaps/rc-anysee.c +++ b/drivers/media/rc/keymaps/rc-anysee.c @@ -9,16 +9,16 @@ #include <linux/module.h> static struct rc_map_table anysee[] = { - { 0x0800, KEY_0 }, - { 0x0801, KEY_1 }, - { 0x0802, KEY_2 }, - { 0x0803, KEY_3 }, - { 0x0804, KEY_4 }, - { 0x0805, KEY_5 }, - { 0x0806, KEY_6 }, - { 0x0807, KEY_7 }, - { 0x0808, KEY_8 }, - { 0x0809, KEY_9 }, + { 0x0800, KEY_NUMERIC_0 }, + { 0x0801, KEY_NUMERIC_1 }, + { 0x0802, KEY_NUMERIC_2 }, + { 0x0803, KEY_NUMERIC_3 }, + { 0x0804, KEY_NUMERIC_4 }, + { 0x0805, KEY_NUMERIC_5 }, + { 0x0806, KEY_NUMERIC_6 }, + { 0x0807, KEY_NUMERIC_7 }, + { 0x0808, KEY_NUMERIC_8 }, + { 0x0809, KEY_NUMERIC_9 }, { 0x080a, KEY_POWER2 }, /* [red power button] */ { 0x080b, KEY_VIDEO }, /* [*] MODE */ { 0x080c, KEY_CHANNEL }, /* [symbol counterclockwise arrow] */ diff --git a/drivers/media/rc/keymaps/rc-apac-viewcomp.c b/drivers/media/rc/keymaps/rc-apac-viewcomp.c index af2e7fdc7b85..bdc47e25d46e 100644 --- a/drivers/media/rc/keymaps/rc-apac-viewcomp.c +++ b/drivers/media/rc/keymaps/rc-apac-viewcomp.c @@ -12,16 +12,16 @@ static struct rc_map_table apac_viewcomp[] = { - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x00, KEY_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, + { 0x00, KEY_NUMERIC_0 }, { 0x17, KEY_LAST }, /* +100 */ { 0x0a, KEY_LIST }, /* recall */ diff --git a/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c b/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c index 727e35c31039..1d322137898e 100644 --- a/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c +++ b/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c @@ -21,21 +21,21 @@ static struct rc_map_table t2hybrid[] = { { 0x40, KEY_ZOOM }, /* Fullscreen */ { 0x1e, KEY_VOLUMEUP }, - { 0x12, KEY_0 }, + { 0x12, KEY_NUMERIC_0 }, { 0x02, KEY_CHANNELDOWN }, { 0x1c, KEY_AGAIN }, /* Recall */ - { 0x09, KEY_1 }, - { 0x1d, KEY_2 }, - { 0x1f, KEY_3 }, + { 0x09, KEY_NUMERIC_1 }, + { 0x1d, KEY_NUMERIC_2 }, + { 0x1f, KEY_NUMERIC_3 }, - { 0x0d, KEY_4 }, - { 0x19, KEY_5 }, - { 0x1b, KEY_6 }, + { 0x0d, KEY_NUMERIC_4 }, + { 0x19, KEY_NUMERIC_5 }, + { 0x1b, KEY_NUMERIC_6 }, - { 0x11, KEY_7 }, - { 0x15, KEY_8 }, - { 0x17, KEY_9 }, + { 0x11, KEY_NUMERIC_7 }, + { 0x15, KEY_NUMERIC_8 }, + { 0x17, KEY_NUMERIC_9 }, }; static struct rc_map_list t2hybrid_map = { diff --git a/drivers/media/rc/keymaps/rc-asus-pc39.c b/drivers/media/rc/keymaps/rc-asus-pc39.c index 13a935c3ac59..7a4b3a6e3a49 100644 --- a/drivers/media/rc/keymaps/rc-asus-pc39.c +++ b/drivers/media/rc/keymaps/rc-asus-pc39.c @@ -16,16 +16,16 @@ static struct rc_map_table asus_pc39[] = { /* Keys 0 to 9 */ - { 0x082a, KEY_0 }, - { 0x0816, KEY_1 }, - { 0x0812, KEY_2 }, - { 0x0814, KEY_3 }, - { 0x0836, KEY_4 }, - { 0x0832, KEY_5 }, - { 0x0834, KEY_6 }, - { 0x080e, KEY_7 }, - { 0x080a, KEY_8 }, - { 0x080c, KEY_9 }, + { 0x082a, KEY_NUMERIC_0 }, + { 0x0816, KEY_NUMERIC_1 }, + { 0x0812, KEY_NUMERIC_2 }, + { 0x0814, KEY_NUMERIC_3 }, + { 0x0836, KEY_NUMERIC_4 }, + { 0x0832, KEY_NUMERIC_5 }, + { 0x0834, KEY_NUMERIC_6 }, + { 0x080e, KEY_NUMERIC_7 }, + { 0x080a, KEY_NUMERIC_8 }, + { 0x080c, KEY_NUMERIC_9 }, { 0x0801, KEY_RADIO }, /* radio */ { 0x083c, KEY_MENU }, /* dvd/menu */ diff --git a/drivers/media/rc/keymaps/rc-asus-ps3-100.c b/drivers/media/rc/keymaps/rc-asus-ps3-100.c index 7f836fcc68ac..09b60fa335e3 100644 --- a/drivers/media/rc/keymaps/rc-asus-ps3-100.c +++ b/drivers/media/rc/keymaps/rc-asus-ps3-100.c @@ -20,16 +20,16 @@ static struct rc_map_table asus_ps3_100[] = { { 0x0807, KEY_GREEN }, /* green */ /* Keys 0 to 9 */ - { 0x082a, KEY_0 }, - { 0x0816, KEY_1 }, - { 0x0812, KEY_2 }, - { 0x0814, KEY_3 }, - { 0x0836, KEY_4 }, - { 0x0832, KEY_5 }, - { 0x0834, KEY_6 }, - { 0x080e, KEY_7 }, - { 0x080a, KEY_8 }, - { 0x080c, KEY_9 }, + { 0x082a, KEY_NUMERIC_0 }, + { 0x0816, KEY_NUMERIC_1 }, + { 0x0812, KEY_NUMERIC_2 }, + { 0x0814, KEY_NUMERIC_3 }, + { 0x0836, KEY_NUMERIC_4 }, + { 0x0832, KEY_NUMERIC_5 }, + { 0x0834, KEY_NUMERIC_6 }, + { 0x080e, KEY_NUMERIC_7 }, + { 0x080a, KEY_NUMERIC_8 }, + { 0x080c, KEY_NUMERIC_9 }, { 0x0815, KEY_VOLUMEUP }, { 0x0826, KEY_VOLUMEDOWN }, diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c index 2f800dd5aa19..31fe1106b708 100644 --- a/drivers/media/rc/keymaps/rc-ati-x10.c +++ b/drivers/media/rc/keymaps/rc-ati-x10.c @@ -49,18 +49,18 @@ static struct rc_map_table ati_x10[] = { * has problems with keycodes greater than 255, so avoid those high * keycodes in default maps. */ - { 0x0d, KEY_1 }, - { 0x0e, KEY_2 }, - { 0x0f, KEY_3 }, - { 0x10, KEY_4 }, - { 0x11, KEY_5 }, - { 0x12, KEY_6 }, - { 0x13, KEY_7 }, - { 0x14, KEY_8 }, - { 0x15, KEY_9 }, + { 0x0d, KEY_NUMERIC_1 }, + { 0x0e, KEY_NUMERIC_2 }, + { 0x0f, KEY_NUMERIC_3 }, + { 0x10, KEY_NUMERIC_4 }, + { 0x11, KEY_NUMERIC_5 }, + { 0x12, KEY_NUMERIC_6 }, + { 0x13, KEY_NUMERIC_7 }, + { 0x14, KEY_NUMERIC_8 }, + { 0x15, KEY_NUMERIC_9 }, { 0x16, KEY_MENU }, /* "menu": DVD root menu */ /* KEY_NUMERIC_STAR? */ - { 0x17, KEY_0 }, + { 0x17, KEY_NUMERIC_0 }, { 0x18, KEY_SETUP }, /* "check": DVD setup menu */ /* KEY_NUMERIC_POUND? */ diff --git a/drivers/media/rc/keymaps/rc-avermedia-a16d.c b/drivers/media/rc/keymaps/rc-avermedia-a16d.c index 5549c043cfe4..6467ff6e48d7 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-a16d.c +++ b/drivers/media/rc/keymaps/rc-avermedia-a16d.c @@ -11,17 +11,17 @@ static struct rc_map_table avermedia_a16d[] = { { 0x20, KEY_LIST}, { 0x00, KEY_POWER}, - { 0x28, KEY_1}, - { 0x18, KEY_2}, - { 0x38, KEY_3}, - { 0x24, KEY_4}, - { 0x14, KEY_5}, - { 0x34, KEY_6}, - { 0x2c, KEY_7}, - { 0x1c, KEY_8}, - { 0x3c, KEY_9}, + { 0x28, KEY_NUMERIC_1}, + { 0x18, KEY_NUMERIC_2}, + { 0x38, KEY_NUMERIC_3}, + { 0x24, KEY_NUMERIC_4}, + { 0x14, KEY_NUMERIC_5}, + { 0x34, KEY_NUMERIC_6}, + { 0x2c, KEY_NUMERIC_7}, + { 0x1c, KEY_NUMERIC_8}, + { 0x3c, KEY_NUMERIC_9}, { 0x12, KEY_SUBTITLE}, - { 0x22, KEY_0}, + { 0x22, KEY_NUMERIC_0}, { 0x32, KEY_REWIND}, { 0x3a, KEY_SHUFFLE}, { 0x02, KEY_PRINT}, diff --git a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c index 74edcd82e685..54fc6d9022c2 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c +++ b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c @@ -15,19 +15,19 @@ static struct rc_map_table avermedia_cardbus[] = { { 0x01, KEY_TUNER }, /* TV/FM */ { 0x03, KEY_TEXT }, /* Teletext */ { 0x04, KEY_EPG }, - { 0x05, KEY_1 }, - { 0x06, KEY_2 }, - { 0x07, KEY_3 }, + { 0x05, KEY_NUMERIC_1 }, + { 0x06, KEY_NUMERIC_2 }, + { 0x07, KEY_NUMERIC_3 }, { 0x08, KEY_AUDIO }, - { 0x09, KEY_4 }, - { 0x0a, KEY_5 }, - { 0x0b, KEY_6 }, + { 0x09, KEY_NUMERIC_4 }, + { 0x0a, KEY_NUMERIC_5 }, + { 0x0b, KEY_NUMERIC_6 }, { 0x0c, KEY_ZOOM }, /* Full screen */ - { 0x0d, KEY_7 }, - { 0x0e, KEY_8 }, - { 0x0f, KEY_9 }, + { 0x0d, KEY_NUMERIC_7 }, + { 0x0e, KEY_NUMERIC_8 }, + { 0x0f, KEY_NUMERIC_9 }, { 0x10, KEY_PAGEUP }, /* 16-CH PREV */ - { 0x11, KEY_0 }, + { 0x11, KEY_NUMERIC_0 }, { 0x12, KEY_INFO }, { 0x13, KEY_AGAIN }, /* CH RTN - channel return */ { 0x14, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c index 796184160a48..92c6df3360b3 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c +++ b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c @@ -11,16 +11,16 @@ /* Matt Jesson <dvb@jesson.eclipse.co.uk */ static struct rc_map_table avermedia_dvbt[] = { - { 0x28, KEY_0 }, /* '0' / 'enter' */ - { 0x22, KEY_1 }, /* '1' */ - { 0x12, KEY_2 }, /* '2' / 'up arrow' */ - { 0x32, KEY_3 }, /* '3' */ - { 0x24, KEY_4 }, /* '4' / 'left arrow' */ - { 0x14, KEY_5 }, /* '5' */ - { 0x34, KEY_6 }, /* '6' / 'right arrow' */ - { 0x26, KEY_7 }, /* '7' */ - { 0x16, KEY_8 }, /* '8' / 'down arrow' */ - { 0x36, KEY_9 }, /* '9' */ + { 0x28, KEY_NUMERIC_0 }, /* '0' / 'enter' */ + { 0x22, KEY_NUMERIC_1 }, /* '1' */ + { 0x12, KEY_NUMERIC_2 }, /* '2' / 'up arrow' */ + { 0x32, KEY_NUMERIC_3 }, /* '3' */ + { 0x24, KEY_NUMERIC_4 }, /* '4' / 'left arrow' */ + { 0x14, KEY_NUMERIC_5 }, /* '5' */ + { 0x34, KEY_NUMERIC_6 }, /* '6' / 'right arrow' */ + { 0x26, KEY_NUMERIC_7 }, /* '7' */ + { 0x16, KEY_NUMERIC_8 }, /* '8' / 'down arrow' */ + { 0x36, KEY_NUMERIC_9 }, /* '9' */ { 0x20, KEY_VIDEO }, /* 'source' */ { 0x10, KEY_TEXT }, /* 'teletext' */ diff --git a/drivers/media/rc/keymaps/rc-avermedia-m135a.c b/drivers/media/rc/keymaps/rc-avermedia-m135a.c index d275d98d066a..311ddeb061ca 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m135a.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m135a.c @@ -24,16 +24,16 @@ static struct rc_map_table avermedia_m135a[] = { { 0x022e, KEY_DOT }, /* '.' */ { 0x0201, KEY_MODE }, /* TV/FM or SOURCE */ - { 0x0205, KEY_1 }, - { 0x0206, KEY_2 }, - { 0x0207, KEY_3 }, - { 0x0209, KEY_4 }, - { 0x020a, KEY_5 }, - { 0x020b, KEY_6 }, - { 0x020d, KEY_7 }, - { 0x020e, KEY_8 }, - { 0x020f, KEY_9 }, - { 0x0211, KEY_0 }, + { 0x0205, KEY_NUMERIC_1 }, + { 0x0206, KEY_NUMERIC_2 }, + { 0x0207, KEY_NUMERIC_3 }, + { 0x0209, KEY_NUMERIC_4 }, + { 0x020a, KEY_NUMERIC_5 }, + { 0x020b, KEY_NUMERIC_6 }, + { 0x020d, KEY_NUMERIC_7 }, + { 0x020e, KEY_NUMERIC_8 }, + { 0x020f, KEY_NUMERIC_9 }, + { 0x0211, KEY_NUMERIC_0 }, { 0x0213, KEY_RIGHT }, /* -> or L */ { 0x0212, KEY_LEFT }, /* <- or R */ @@ -70,17 +70,17 @@ static struct rc_map_table avermedia_m135a[] = { { 0x0406, KEY_MUTE }, { 0x0408, KEY_MODE }, /* TV/FM */ - { 0x0409, KEY_1 }, - { 0x040a, KEY_2 }, - { 0x040b, KEY_3 }, - { 0x040c, KEY_4 }, - { 0x040d, KEY_5 }, - { 0x040e, KEY_6 }, - { 0x040f, KEY_7 }, - { 0x0410, KEY_8 }, - { 0x0411, KEY_9 }, + { 0x0409, KEY_NUMERIC_1 }, + { 0x040a, KEY_NUMERIC_2 }, + { 0x040b, KEY_NUMERIC_3 }, + { 0x040c, KEY_NUMERIC_4 }, + { 0x040d, KEY_NUMERIC_5 }, + { 0x040e, KEY_NUMERIC_6 }, + { 0x040f, KEY_NUMERIC_7 }, + { 0x0410, KEY_NUMERIC_8 }, + { 0x0411, KEY_NUMERIC_9 }, { 0x044c, KEY_DOT }, /* '.' */ - { 0x0412, KEY_0 }, + { 0x0412, KEY_NUMERIC_0 }, { 0x0407, KEY_REFRESH }, /* Refresh/Reload */ { 0x0413, KEY_AUDIO }, diff --git a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c index 6a70aba92dfb..a970ed5a090b 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c @@ -18,17 +18,17 @@ static struct rc_map_table avermedia_m733a_rm_k6[] = { { 0x0406, KEY_MUTE }, { 0x0408, KEY_MODE }, /* TV/FM */ - { 0x0409, KEY_1 }, - { 0x040a, KEY_2 }, - { 0x040b, KEY_3 }, - { 0x040c, KEY_4 }, - { 0x040d, KEY_5 }, - { 0x040e, KEY_6 }, - { 0x040f, KEY_7 }, - { 0x0410, KEY_8 }, - { 0x0411, KEY_9 }, + { 0x0409, KEY_NUMERIC_1 }, + { 0x040a, KEY_NUMERIC_2 }, + { 0x040b, KEY_NUMERIC_3 }, + { 0x040c, KEY_NUMERIC_4 }, + { 0x040d, KEY_NUMERIC_5 }, + { 0x040e, KEY_NUMERIC_6 }, + { 0x040f, KEY_NUMERIC_7 }, + { 0x0410, KEY_NUMERIC_8 }, + { 0x0411, KEY_NUMERIC_9 }, { 0x044c, KEY_DOT }, /* '.' */ - { 0x0412, KEY_0 }, + { 0x0412, KEY_NUMERIC_0 }, { 0x0407, KEY_REFRESH }, /* Refresh/Reload */ { 0x0413, KEY_AUDIO }, diff --git a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c index 61348894c93b..cf8a4fd107f4 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c +++ b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c @@ -20,16 +20,16 @@ static struct rc_map_table avermedia_rm_ks[] = { { 0x0506, KEY_MUTE }, /* Mute */ { 0x0507, KEY_AGAIN }, /* Recall */ { 0x0508, KEY_VIDEO }, /* Source */ - { 0x0509, KEY_1 }, /* 1 */ - { 0x050a, KEY_2 }, /* 2 */ - { 0x050b, KEY_3 }, /* 3 */ - { 0x050c, KEY_4 }, /* 4 */ - { 0x050d, KEY_5 }, /* 5 */ - { 0x050e, KEY_6 }, /* 6 */ - { 0x050f, KEY_7 }, /* 7 */ - { 0x0510, KEY_8 }, /* 8 */ - { 0x0511, KEY_9 }, /* 9 */ - { 0x0512, KEY_0 }, /* 0 */ + { 0x0509, KEY_NUMERIC_1 }, /* 1 */ + { 0x050a, KEY_NUMERIC_2 }, /* 2 */ + { 0x050b, KEY_NUMERIC_3 }, /* 3 */ + { 0x050c, KEY_NUMERIC_4 }, /* 4 */ + { 0x050d, KEY_NUMERIC_5 }, /* 5 */ + { 0x050e, KEY_NUMERIC_6 }, /* 6 */ + { 0x050f, KEY_NUMERIC_7 }, /* 7 */ + { 0x0510, KEY_NUMERIC_8 }, /* 8 */ + { 0x0511, KEY_NUMERIC_9 }, /* 9 */ + { 0x0512, KEY_NUMERIC_0 }, /* 0 */ { 0x0513, KEY_AUDIO }, /* Audio */ { 0x0515, KEY_EPG }, /* EPG */ { 0x0516, KEY_PLAYPAUSE }, /* Play/Pause */ diff --git a/drivers/media/rc/keymaps/rc-avermedia.c b/drivers/media/rc/keymaps/rc-avermedia.c index 631ff52564f0..f96f229b70bb 100644 --- a/drivers/media/rc/keymaps/rc-avermedia.c +++ b/drivers/media/rc/keymaps/rc-avermedia.c @@ -11,16 +11,16 @@ /* Alex Hermann <gaaf@gmx.net> */ static struct rc_map_table avermedia[] = { - { 0x28, KEY_1 }, - { 0x18, KEY_2 }, - { 0x38, KEY_3 }, - { 0x24, KEY_4 }, - { 0x14, KEY_5 }, - { 0x34, KEY_6 }, - { 0x2c, KEY_7 }, - { 0x1c, KEY_8 }, - { 0x3c, KEY_9 }, - { 0x22, KEY_0 }, + { 0x28, KEY_NUMERIC_1 }, + { 0x18, KEY_NUMERIC_2 }, + { 0x38, KEY_NUMERIC_3 }, + { 0x24, KEY_NUMERIC_4 }, + { 0x14, KEY_NUMERIC_5 }, + { 0x34, KEY_NUMERIC_6 }, + { 0x2c, KEY_NUMERIC_7 }, + { 0x1c, KEY_NUMERIC_8 }, + { 0x3c, KEY_NUMERIC_9 }, + { 0x22, KEY_NUMERIC_0 }, { 0x20, KEY_TV }, /* TV/FM */ { 0x10, KEY_CD }, /* CD */ diff --git a/drivers/media/rc/keymaps/rc-avertv-303.c b/drivers/media/rc/keymaps/rc-avertv-303.c index 47ca8b7ea532..a3e2e945c769 100644 --- a/drivers/media/rc/keymaps/rc-avertv-303.c +++ b/drivers/media/rc/keymaps/rc-avertv-303.c @@ -11,16 +11,16 @@ /* AVERTV STUDIO 303 Remote */ static struct rc_map_table avertv_303[] = { - { 0x2a, KEY_1 }, - { 0x32, KEY_2 }, - { 0x3a, KEY_3 }, - { 0x4a, KEY_4 }, - { 0x52, KEY_5 }, - { 0x5a, KEY_6 }, - { 0x6a, KEY_7 }, - { 0x72, KEY_8 }, - { 0x7a, KEY_9 }, - { 0x0e, KEY_0 }, + { 0x2a, KEY_NUMERIC_1 }, + { 0x32, KEY_NUMERIC_2 }, + { 0x3a, KEY_NUMERIC_3 }, + { 0x4a, KEY_NUMERIC_4 }, + { 0x52, KEY_NUMERIC_5 }, + { 0x5a, KEY_NUMERIC_6 }, + { 0x6a, KEY_NUMERIC_7 }, + { 0x72, KEY_NUMERIC_8 }, + { 0x7a, KEY_NUMERIC_9 }, + { 0x0e, KEY_NUMERIC_0 }, { 0x02, KEY_POWER }, { 0x22, KEY_VIDEO }, diff --git a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c index 8e7e95306a5c..5fc8e4cd102e 100644 --- a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c +++ b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c @@ -10,18 +10,18 @@ static struct rc_map_table azurewave_ad_tu700[] = { { 0x0000, KEY_TAB }, /* Tab */ - { 0x0001, KEY_2 }, + { 0x0001, KEY_NUMERIC_2 }, { 0x0002, KEY_CHANNELDOWN }, - { 0x0003, KEY_1 }, + { 0x0003, KEY_NUMERIC_1 }, { 0x0004, KEY_MENU }, /* Record List */ { 0x0005, KEY_CHANNELUP }, - { 0x0006, KEY_3 }, + { 0x0006, KEY_NUMERIC_3 }, { 0x0007, KEY_SLEEP }, /* Hibernate */ { 0x0008, KEY_VIDEO }, /* A/V */ - { 0x0009, KEY_4 }, + { 0x0009, KEY_NUMERIC_4 }, { 0x000a, KEY_VOLUMEDOWN }, { 0x000c, KEY_CANCEL }, /* Cancel */ - { 0x000d, KEY_7 }, + { 0x000d, KEY_NUMERIC_7 }, { 0x000e, KEY_AGAIN }, /* Recall */ { 0x000f, KEY_TEXT }, /* Teletext */ { 0x0010, KEY_MUTE }, @@ -29,17 +29,17 @@ static struct rc_map_table azurewave_ad_tu700[] = { { 0x0012, KEY_FASTFORWARD }, /* FF >> */ { 0x0013, KEY_BACK }, /* Back */ { 0x0014, KEY_PLAY }, - { 0x0015, KEY_0 }, + { 0x0015, KEY_NUMERIC_0 }, { 0x0016, KEY_POWER2 }, /* [red power button] */ { 0x0017, KEY_FAVORITES }, /* Favorite List */ { 0x0018, KEY_RED }, - { 0x0019, KEY_8 }, + { 0x0019, KEY_NUMERIC_8 }, { 0x001a, KEY_STOP }, - { 0x001b, KEY_9 }, + { 0x001b, KEY_NUMERIC_9 }, { 0x001c, KEY_EPG }, /* Info/EPG */ - { 0x001d, KEY_5 }, + { 0x001d, KEY_NUMERIC_5 }, { 0x001e, KEY_VOLUMEUP }, - { 0x001f, KEY_6 }, + { 0x001f, KEY_NUMERIC_6 }, { 0x0040, KEY_REWIND }, /* FR << */ { 0x0041, KEY_PREVIOUS }, /* Replay */ { 0x0042, KEY_NEXT }, /* Skip */ diff --git a/drivers/media/rc/keymaps/rc-behold-columbus.c b/drivers/media/rc/keymaps/rc-behold-columbus.c index b68380a76010..8579b3d5128d 100644 --- a/drivers/media/rc/keymaps/rc-behold-columbus.c +++ b/drivers/media/rc/keymaps/rc-behold-columbus.c @@ -37,24 +37,24 @@ static struct rc_map_table behold_columbus[] = { * 0x07 0x08 0x09 0x10 * * 7 8 9 Zoom * * */ - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, { 0x0D, KEY_SETUP }, /* Setup key */ - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, { 0x19, KEY_CAMERA }, /* Snapshot key */ - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x10, KEY_ZOOM }, /* 0x0A 0x00 0x0B 0x0C * * RECALL 0 ChannelUp VolumeUp * * */ { 0x0A, KEY_AGAIN }, - { 0x00, KEY_0 }, + { 0x00, KEY_NUMERIC_0 }, { 0x0B, KEY_CHANNELUP }, { 0x0C, KEY_VOLUMEUP }, diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c index 2b7cddb2f36d..28397ce05a7f 100644 --- a/drivers/media/rc/keymaps/rc-behold.c +++ b/drivers/media/rc/keymaps/rc-behold.c @@ -37,21 +37,21 @@ static struct rc_map_table behold[] = { * 0x07 0x08 0x09 * * 7 8 9 * * */ - { 0x866b01, KEY_1 }, - { 0x866b02, KEY_2 }, - { 0x866b03, KEY_3 }, - { 0x866b04, KEY_4 }, - { 0x866b05, KEY_5 }, - { 0x866b06, KEY_6 }, - { 0x866b07, KEY_7 }, - { 0x866b08, KEY_8 }, - { 0x866b09, KEY_9 }, + { 0x866b01, KEY_NUMERIC_1 }, + { 0x866b02, KEY_NUMERIC_2 }, + { 0x866b03, KEY_NUMERIC_3 }, + { 0x866b04, KEY_NUMERIC_4 }, + { 0x866b05, KEY_NUMERIC_5 }, + { 0x866b06, KEY_NUMERIC_6 }, + { 0x866b07, KEY_NUMERIC_7 }, + { 0x866b08, KEY_NUMERIC_8 }, + { 0x866b09, KEY_NUMERIC_9 }, /* 0x0a 0x00 0x17 * * RECALL 0 MODE * * */ { 0x866b0a, KEY_AGAIN }, - { 0x866b00, KEY_0 }, + { 0x866b00, KEY_NUMERIC_0 }, { 0x866b17, KEY_MODE }, /* 0x14 0x10 * diff --git a/drivers/media/rc/keymaps/rc-budget-ci-old.c b/drivers/media/rc/keymaps/rc-budget-ci-old.c index 56f051af6154..6ca822256862 100644 --- a/drivers/media/rc/keymaps/rc-budget-ci-old.c +++ b/drivers/media/rc/keymaps/rc-budget-ci-old.c @@ -16,16 +16,16 @@ */ static struct rc_map_table budget_ci_old[] = { - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x0a, KEY_ENTER }, { 0x0b, KEY_RED }, { 0x0c, KEY_POWER }, /* RADIO on Hauppauge */ diff --git a/drivers/media/rc/keymaps/rc-cinergy-1400.c b/drivers/media/rc/keymaps/rc-cinergy-1400.c index dacb13c53bb4..4433d28b219c 100644 --- a/drivers/media/rc/keymaps/rc-cinergy-1400.c +++ b/drivers/media/rc/keymaps/rc-cinergy-1400.c @@ -12,16 +12,16 @@ static struct rc_map_table cinergy_1400[] = { { 0x01, KEY_POWER }, - { 0x02, KEY_1 }, - { 0x03, KEY_2 }, - { 0x04, KEY_3 }, - { 0x05, KEY_4 }, - { 0x06, KEY_5 }, - { 0x07, KEY_6 }, - { 0x08, KEY_7 }, - { 0x09, KEY_8 }, - { 0x0a, KEY_9 }, - { 0x0c, KEY_0 }, + { 0x02, KEY_NUMERIC_1 }, + { 0x03, KEY_NUMERIC_2 }, + { 0x04, KEY_NUMERIC_3 }, + { 0x05, KEY_NUMERIC_4 }, + { 0x06, KEY_NUMERIC_5 }, + { 0x07, KEY_NUMERIC_6 }, + { 0x08, KEY_NUMERIC_7 }, + { 0x09, KEY_NUMERIC_8 }, + { 0x0a, KEY_NUMERIC_9 }, + { 0x0c, KEY_NUMERIC_0 }, { 0x0b, KEY_VIDEO }, { 0x0d, KEY_REFRESH }, diff --git a/drivers/media/rc/keymaps/rc-cinergy.c b/drivers/media/rc/keymaps/rc-cinergy.c index 6ab2e51b764d..b34a37b8fe61 100644 --- a/drivers/media/rc/keymaps/rc-cinergy.c +++ b/drivers/media/rc/keymaps/rc-cinergy.c @@ -9,16 +9,16 @@ #include <linux/module.h> static struct rc_map_table cinergy[] = { - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x0a, KEY_POWER }, { 0x0b, KEY_MEDIA }, /* app */ diff --git a/drivers/media/rc/keymaps/rc-d680-dmb.c b/drivers/media/rc/keymaps/rc-d680-dmb.c index f67aa597a75b..d491a5e9750f 100644 --- a/drivers/media/rc/keymaps/rc-d680-dmb.c +++ b/drivers/media/rc/keymaps/rc-d680-dmb.c @@ -11,16 +11,16 @@ static struct rc_map_table rc_map_d680_dmb_table[] = { { 0x0038, KEY_SWITCHVIDEOMODE }, /* TV/AV */ { 0x080c, KEY_ZOOM }, - { 0x0800, KEY_0 }, - { 0x0001, KEY_1 }, - { 0x0802, KEY_2 }, - { 0x0003, KEY_3 }, - { 0x0804, KEY_4 }, - { 0x0005, KEY_5 }, - { 0x0806, KEY_6 }, - { 0x0007, KEY_7 }, - { 0x0808, KEY_8 }, - { 0x0009, KEY_9 }, + { 0x0800, KEY_NUMERIC_0 }, + { 0x0001, KEY_NUMERIC_1 }, + { 0x0802, KEY_NUMERIC_2 }, + { 0x0003, KEY_NUMERIC_3 }, + { 0x0804, KEY_NUMERIC_4 }, + { 0x0005, KEY_NUMERIC_5 }, + { 0x0806, KEY_NUMERIC_6 }, + { 0x0007, KEY_NUMERIC_7 }, + { 0x0808, KEY_NUMERIC_8 }, + { 0x0009, KEY_NUMERIC_9 }, { 0x000a, KEY_MUTE }, { 0x0829, KEY_BACK }, { 0x0012, KEY_CHANNELUP }, diff --git a/drivers/media/rc/keymaps/rc-delock-61959.c b/drivers/media/rc/keymaps/rc-delock-61959.c index c60fc1e46fc5..529435e8d416 100644 --- a/drivers/media/rc/keymaps/rc-delock-61959.c +++ b/drivers/media/rc/keymaps/rc-delock-61959.c @@ -14,16 +14,16 @@ static struct rc_map_table delock_61959[] = { { 0x866b16, KEY_POWER2 }, /* Power */ { 0x866b0c, KEY_POWER }, /* Shut Down */ - { 0x866b00, KEY_1}, - { 0x866b01, KEY_2}, - { 0x866b02, KEY_3}, - { 0x866b03, KEY_4}, - { 0x866b04, KEY_5}, - { 0x866b05, KEY_6}, - { 0x866b06, KEY_7}, - { 0x866b07, KEY_8}, - { 0x866b08, KEY_9}, - { 0x866b14, KEY_0}, + { 0x866b00, KEY_NUMERIC_1}, + { 0x866b01, KEY_NUMERIC_2}, + { 0x866b02, KEY_NUMERIC_3}, + { 0x866b03, KEY_NUMERIC_4}, + { 0x866b04, KEY_NUMERIC_5}, + { 0x866b05, KEY_NUMERIC_6}, + { 0x866b06, KEY_NUMERIC_7}, + { 0x866b07, KEY_NUMERIC_8}, + { 0x866b08, KEY_NUMERIC_9}, + { 0x866b14, KEY_NUMERIC_0}, { 0x866b0a, KEY_ZOOM}, /* Full Screen */ { 0x866b10, KEY_CAMERA}, /* Photo */ diff --git a/drivers/media/rc/keymaps/rc-dib0700-nec.c b/drivers/media/rc/keymaps/rc-dib0700-nec.c index 4ee801acb089..f1fcdf16f485 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-nec.c +++ b/drivers/media/rc/keymaps/rc-dib0700-nec.c @@ -17,16 +17,16 @@ static struct rc_map_table dib0700_nec_table[] = { /* Key codes for the Pixelview SBTVD remote */ { 0x866b13, KEY_MUTE }, { 0x866b12, KEY_POWER }, - { 0x866b01, KEY_1 }, - { 0x866b02, KEY_2 }, - { 0x866b03, KEY_3 }, - { 0x866b04, KEY_4 }, - { 0x866b05, KEY_5 }, - { 0x866b06, KEY_6 }, - { 0x866b07, KEY_7 }, - { 0x866b08, KEY_8 }, - { 0x866b09, KEY_9 }, - { 0x866b00, KEY_0 }, + { 0x866b01, KEY_NUMERIC_1 }, + { 0x866b02, KEY_NUMERIC_2 }, + { 0x866b03, KEY_NUMERIC_3 }, + { 0x866b04, KEY_NUMERIC_4 }, + { 0x866b05, KEY_NUMERIC_5 }, + { 0x866b06, KEY_NUMERIC_6 }, + { 0x866b07, KEY_NUMERIC_7 }, + { 0x866b08, KEY_NUMERIC_8 }, + { 0x866b09, KEY_NUMERIC_9 }, + { 0x866b00, KEY_NUMERIC_0 }, { 0x866b0d, KEY_CHANNELUP }, { 0x866b19, KEY_CHANNELDOWN }, { 0x866b10, KEY_VOLUMEUP }, @@ -60,17 +60,17 @@ static struct rc_map_table dib0700_nec_table[] = { /* Key codes for the Elgato EyeTV Diversity silver remote */ { 0x4501, KEY_POWER }, { 0x4502, KEY_MUTE }, - { 0x4503, KEY_1 }, - { 0x4504, KEY_2 }, - { 0x4505, KEY_3 }, - { 0x4506, KEY_4 }, - { 0x4507, KEY_5 }, - { 0x4508, KEY_6 }, - { 0x4509, KEY_7 }, - { 0x450a, KEY_8 }, - { 0x450b, KEY_9 }, + { 0x4503, KEY_NUMERIC_1 }, + { 0x4504, KEY_NUMERIC_2 }, + { 0x4505, KEY_NUMERIC_3 }, + { 0x4506, KEY_NUMERIC_4 }, + { 0x4507, KEY_NUMERIC_5 }, + { 0x4508, KEY_NUMERIC_6 }, + { 0x4509, KEY_NUMERIC_7 }, + { 0x450a, KEY_NUMERIC_8 }, + { 0x450b, KEY_NUMERIC_9 }, { 0x450c, KEY_LAST }, - { 0x450d, KEY_0 }, + { 0x450d, KEY_NUMERIC_0 }, { 0x450e, KEY_ENTER }, { 0x450f, KEY_RED }, { 0x4510, KEY_CHANNELUP }, diff --git a/drivers/media/rc/keymaps/rc-dib0700-rc5.c b/drivers/media/rc/keymaps/rc-dib0700-rc5.c index ef4085a0fda3..002fffcba95d 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-rc5.c +++ b/drivers/media/rc/keymaps/rc-dib0700-rc5.c @@ -22,16 +22,16 @@ static struct rc_map_table dib0700_rc5_table[] = { { 0x0709, KEY_VOLUMEDOWN }, { 0x0706, KEY_CHANNELUP }, { 0x070c, KEY_CHANNELDOWN }, - { 0x070f, KEY_1 }, - { 0x0715, KEY_2 }, - { 0x0710, KEY_3 }, - { 0x0718, KEY_4 }, - { 0x071b, KEY_5 }, - { 0x071e, KEY_6 }, - { 0x0711, KEY_7 }, - { 0x0721, KEY_8 }, - { 0x0712, KEY_9 }, - { 0x0727, KEY_0 }, + { 0x070f, KEY_NUMERIC_1 }, + { 0x0715, KEY_NUMERIC_2 }, + { 0x0710, KEY_NUMERIC_3 }, + { 0x0718, KEY_NUMERIC_4 }, + { 0x071b, KEY_NUMERIC_5 }, + { 0x071e, KEY_NUMERIC_6 }, + { 0x0711, KEY_NUMERIC_7 }, + { 0x0721, KEY_NUMERIC_8 }, + { 0x0712, KEY_NUMERIC_9 }, + { 0x0727, KEY_NUMERIC_0 }, { 0x0724, KEY_SCREEN }, /* 'Square' key */ { 0x072a, KEY_TEXT }, /* 'T' key */ { 0x072d, KEY_REWIND }, @@ -43,17 +43,17 @@ static struct rc_map_table dib0700_rc5_table[] = { /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */ { 0xeb01, KEY_POWER }, - { 0xeb02, KEY_1 }, - { 0xeb03, KEY_2 }, - { 0xeb04, KEY_3 }, - { 0xeb05, KEY_4 }, - { 0xeb06, KEY_5 }, - { 0xeb07, KEY_6 }, - { 0xeb08, KEY_7 }, - { 0xeb09, KEY_8 }, - { 0xeb0a, KEY_9 }, + { 0xeb02, KEY_NUMERIC_1 }, + { 0xeb03, KEY_NUMERIC_2 }, + { 0xeb04, KEY_NUMERIC_3 }, + { 0xeb05, KEY_NUMERIC_4 }, + { 0xeb06, KEY_NUMERIC_5 }, + { 0xeb07, KEY_NUMERIC_6 }, + { 0xeb08, KEY_NUMERIC_7 }, + { 0xeb09, KEY_NUMERIC_8 }, + { 0xeb0a, KEY_NUMERIC_9 }, { 0xeb0b, KEY_VIDEO }, - { 0xeb0c, KEY_0 }, + { 0xeb0c, KEY_NUMERIC_0 }, { 0xeb0d, KEY_REFRESH }, { 0xeb0f, KEY_EPG }, { 0xeb10, KEY_UP }, @@ -92,16 +92,16 @@ static struct rc_map_table dib0700_rc5_table[] = { { 0xeb5c, KEY_NEXT }, /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */ - { 0x1e00, KEY_0 }, - { 0x1e01, KEY_1 }, - { 0x1e02, KEY_2 }, - { 0x1e03, KEY_3 }, - { 0x1e04, KEY_4 }, - { 0x1e05, KEY_5 }, - { 0x1e06, KEY_6 }, - { 0x1e07, KEY_7 }, - { 0x1e08, KEY_8 }, - { 0x1e09, KEY_9 }, + { 0x1e00, KEY_NUMERIC_0 }, + { 0x1e01, KEY_NUMERIC_1 }, + { 0x1e02, KEY_NUMERIC_2 }, + { 0x1e03, KEY_NUMERIC_3 }, + { 0x1e04, KEY_NUMERIC_4 }, + { 0x1e05, KEY_NUMERIC_5 }, + { 0x1e06, KEY_NUMERIC_6 }, + { 0x1e07, KEY_NUMERIC_7 }, + { 0x1e08, KEY_NUMERIC_8 }, + { 0x1e09, KEY_NUMERIC_9 }, { 0x1e0a, KEY_KPASTERISK }, { 0x1e0b, KEY_RED }, { 0x1e0c, KEY_RADIO }, @@ -144,16 +144,16 @@ static struct rc_map_table dib0700_rc5_table[] = { { 0x0f4e, KEY_PRINT }, /* PREVIEW */ { 0x0840, KEY_SCREEN }, /* full screen toggle*/ { 0x0f71, KEY_DOT }, /* frequency */ - { 0x0743, KEY_0 }, - { 0x0c41, KEY_1 }, - { 0x0443, KEY_2 }, - { 0x0b7f, KEY_3 }, - { 0x0e41, KEY_4 }, - { 0x0643, KEY_5 }, - { 0x097f, KEY_6 }, - { 0x0d7e, KEY_7 }, - { 0x057c, KEY_8 }, - { 0x0a40, KEY_9 }, + { 0x0743, KEY_NUMERIC_0 }, + { 0x0c41, KEY_NUMERIC_1 }, + { 0x0443, KEY_NUMERIC_2 }, + { 0x0b7f, KEY_NUMERIC_3 }, + { 0x0e41, KEY_NUMERIC_4 }, + { 0x0643, KEY_NUMERIC_5 }, + { 0x097f, KEY_NUMERIC_6 }, + { 0x0d7e, KEY_NUMERIC_7 }, + { 0x057c, KEY_NUMERIC_8 }, + { 0x0a40, KEY_NUMERIC_9 }, { 0x0e4e, KEY_CLEAR }, { 0x047c, KEY_CHANNEL }, /* show channel number */ { 0x0f41, KEY_LAST }, /* recall */ @@ -168,16 +168,16 @@ static struct rc_map_table dib0700_rc5_table[] = { { 0x007d, KEY_CHANNELDOWN }, /* Key codes for Nova-TD "credit card" remote control. */ - { 0x1d00, KEY_0 }, - { 0x1d01, KEY_1 }, - { 0x1d02, KEY_2 }, - { 0x1d03, KEY_3 }, - { 0x1d04, KEY_4 }, - { 0x1d05, KEY_5 }, - { 0x1d06, KEY_6 }, - { 0x1d07, KEY_7 }, - { 0x1d08, KEY_8 }, - { 0x1d09, KEY_9 }, + { 0x1d00, KEY_NUMERIC_0 }, + { 0x1d01, KEY_NUMERIC_1 }, + { 0x1d02, KEY_NUMERIC_2 }, + { 0x1d03, KEY_NUMERIC_3 }, + { 0x1d04, KEY_NUMERIC_4 }, + { 0x1d05, KEY_NUMERIC_5 }, + { 0x1d06, KEY_NUMERIC_6 }, + { 0x1d07, KEY_NUMERIC_7 }, + { 0x1d08, KEY_NUMERIC_8 }, + { 0x1d09, KEY_NUMERIC_9 }, { 0x1d0a, KEY_TEXT }, { 0x1d0d, KEY_MENU }, { 0x1d0f, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c index f4d0799dcc72..2466d8c50226 100644 --- a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c +++ b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c @@ -12,14 +12,14 @@ static struct rc_map_table digitalnow_tinytwin[] = { { 0x0000, KEY_MUTE }, /* [symbol speaker] */ { 0x0001, KEY_VOLUMEUP }, { 0x0002, KEY_POWER2 }, /* TV [power button] */ - { 0x0003, KEY_2 }, - { 0x0004, KEY_3 }, - { 0x0005, KEY_4 }, - { 0x0006, KEY_6 }, - { 0x0007, KEY_7 }, - { 0x0008, KEY_8 }, + { 0x0003, KEY_NUMERIC_2 }, + { 0x0004, KEY_NUMERIC_3 }, + { 0x0005, KEY_NUMERIC_4 }, + { 0x0006, KEY_NUMERIC_6 }, + { 0x0007, KEY_NUMERIC_7 }, + { 0x0008, KEY_NUMERIC_8 }, { 0x0009, KEY_NUMERIC_STAR }, /* [*] */ - { 0x000a, KEY_0 }, + { 0x000a, KEY_NUMERIC_0 }, { 0x000b, KEY_NUMERIC_POUND }, /* [#] */ { 0x000c, KEY_RIGHT }, /* [right arrow] */ { 0x000d, KEY_HOMEPAGE }, /* [symbol home] Start */ @@ -36,10 +36,10 @@ static struct rc_map_table digitalnow_tinytwin[] = { { 0x0019, KEY_BLUE }, /* [blue] MyTV */ { 0x001a, KEY_REWIND }, /* REW [<<] */ { 0x001b, KEY_PLAY }, /* PLAY */ - { 0x001c, KEY_5 }, - { 0x001d, KEY_9 }, + { 0x001c, KEY_NUMERIC_5 }, + { 0x001d, KEY_NUMERIC_9 }, { 0x001e, KEY_VOLUMEDOWN }, - { 0x001f, KEY_1 }, + { 0x001f, KEY_NUMERIC_1 }, { 0x0040, KEY_STOP }, /* STOP */ { 0x0042, KEY_PAUSE }, /* PAUSE */ { 0x0043, KEY_SCREEN }, /* Aspect */ diff --git a/drivers/media/rc/keymaps/rc-digittrade.c b/drivers/media/rc/keymaps/rc-digittrade.c index 6849f1a5721c..65bc8ad7e52c 100644 --- a/drivers/media/rc/keymaps/rc-digittrade.c +++ b/drivers/media/rc/keymaps/rc-digittrade.c @@ -14,11 +14,11 @@ /* Digittrade DVB-T USB Stick */ static struct rc_map_table digittrade[] = { - { 0x0000, KEY_9 }, + { 0x0000, KEY_NUMERIC_9 }, { 0x0001, KEY_EPG }, /* EPG */ { 0x0002, KEY_VOLUMEDOWN }, /* Vol Dn */ { 0x0003, KEY_TEXT }, /* TELETEXT */ - { 0x0004, KEY_8 }, + { 0x0004, KEY_NUMERIC_8 }, { 0x0005, KEY_MUTE }, /* MUTE */ { 0x0006, KEY_POWER2 }, /* POWER */ { 0x0009, KEY_ZOOM }, /* FULLSCREEN */ @@ -26,22 +26,22 @@ static struct rc_map_table digittrade[] = { { 0x000d, KEY_SUBTITLE }, /* SUBTITLE */ { 0x000e, KEY_STOP }, /* STOP */ { 0x0010, KEY_OK }, /* RETURN */ - { 0x0011, KEY_2 }, - { 0x0012, KEY_4 }, - { 0x0015, KEY_3 }, - { 0x0016, KEY_5 }, + { 0x0011, KEY_NUMERIC_2 }, + { 0x0012, KEY_NUMERIC_4 }, + { 0x0015, KEY_NUMERIC_3 }, + { 0x0016, KEY_NUMERIC_5 }, { 0x0017, KEY_CHANNELDOWN }, /* Ch Dn */ { 0x0019, KEY_CHANNELUP }, /* CH Up */ { 0x001a, KEY_PAUSE }, /* PAUSE */ - { 0x001b, KEY_1 }, + { 0x001b, KEY_NUMERIC_1 }, { 0x001d, KEY_AUDIO }, /* DUAL SOUND */ { 0x001e, KEY_PLAY }, /* PLAY */ { 0x001f, KEY_CAMERA }, /* SNAPSHOT */ { 0x0040, KEY_VOLUMEUP }, /* Vol Up */ - { 0x0048, KEY_7 }, - { 0x004c, KEY_6 }, + { 0x0048, KEY_NUMERIC_7 }, + { 0x004c, KEY_NUMERIC_6 }, { 0x004d, KEY_PLAYPAUSE }, /* TIMESHIFT */ - { 0x0054, KEY_0 }, + { 0x0054, KEY_NUMERIC_0 }, }; static struct rc_map_list digittrade_map = { diff --git a/drivers/media/rc/keymaps/rc-dm1105-nec.c b/drivers/media/rc/keymaps/rc-dm1105-nec.c index d853cd9a0936..cd0b985c994d 100644 --- a/drivers/media/rc/keymaps/rc-dm1105-nec.c +++ b/drivers/media/rc/keymaps/rc-dm1105-nec.c @@ -15,16 +15,16 @@ static struct rc_map_table dm1105_nec[] = { { 0x0a, KEY_POWER2}, /* power */ { 0x0c, KEY_MUTE}, /* mute */ - { 0x11, KEY_1}, - { 0x12, KEY_2}, - { 0x13, KEY_3}, - { 0x14, KEY_4}, - { 0x15, KEY_5}, - { 0x16, KEY_6}, - { 0x17, KEY_7}, - { 0x18, KEY_8}, - { 0x19, KEY_9}, - { 0x10, KEY_0}, + { 0x11, KEY_NUMERIC_1}, + { 0x12, KEY_NUMERIC_2}, + { 0x13, KEY_NUMERIC_3}, + { 0x14, KEY_NUMERIC_4}, + { 0x15, KEY_NUMERIC_5}, + { 0x16, KEY_NUMERIC_6}, + { 0x17, KEY_NUMERIC_7}, + { 0x18, KEY_NUMERIC_8}, + { 0x19, KEY_NUMERIC_9}, + { 0x10, KEY_NUMERIC_0}, { 0x1c, KEY_CHANNELUP}, /* ch+ */ { 0x0f, KEY_CHANNELDOWN}, /* ch- */ { 0x1a, KEY_VOLUMEUP}, /* vol+ */ diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c index cdc1d8c990cb..a82f64dc9411 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c @@ -13,16 +13,16 @@ static struct rc_map_table dntv_live_dvb_t[] = { { 0x00, KEY_ESC }, /* 'go up a level?' */ /* Keys 0 to 9 */ - { 0x0a, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x0a, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x0b, KEY_TUNER }, /* tv/fm */ { 0x0c, KEY_SEARCH }, /* scan */ diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c index 38e1d1b837da..d3f5048a0220 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c @@ -18,17 +18,17 @@ static struct rc_map_table dntv_live_dvbt_pro[] = { { 0x58, KEY_TUNER }, /* digital Radio */ { 0x5a, KEY_RADIO }, /* FM radio */ { 0x59, KEY_DVD }, /* dvd menu */ - { 0x03, KEY_1 }, - { 0x01, KEY_2 }, - { 0x06, KEY_3 }, - { 0x09, KEY_4 }, - { 0x1d, KEY_5 }, - { 0x1f, KEY_6 }, - { 0x0d, KEY_7 }, - { 0x19, KEY_8 }, - { 0x1b, KEY_9 }, + { 0x03, KEY_NUMERIC_1 }, + { 0x01, KEY_NUMERIC_2 }, + { 0x06, KEY_NUMERIC_3 }, + { 0x09, KEY_NUMERIC_4 }, + { 0x1d, KEY_NUMERIC_5 }, + { 0x1f, KEY_NUMERIC_6 }, + { 0x0d, KEY_NUMERIC_7 }, + { 0x19, KEY_NUMERIC_8 }, + { 0x1b, KEY_NUMERIC_9 }, { 0x0c, KEY_CANCEL }, - { 0x15, KEY_0 }, + { 0x15, KEY_NUMERIC_0 }, { 0x4a, KEY_CLEAR }, { 0x13, KEY_BACK }, { 0x00, KEY_TAB }, diff --git a/drivers/media/rc/keymaps/rc-dtt200u.c b/drivers/media/rc/keymaps/rc-dtt200u.c index 86fd6a1668af..e7f87baa3212 100644 --- a/drivers/media/rc/keymaps/rc-dtt200u.c +++ b/drivers/media/rc/keymaps/rc-dtt200u.c @@ -12,21 +12,21 @@ static struct rc_map_table dtt200u_table[] = { { 0x8001, KEY_MUTE }, { 0x8002, KEY_CHANNELDOWN }, { 0x8003, KEY_VOLUMEDOWN }, - { 0x8004, KEY_1 }, - { 0x8005, KEY_2 }, - { 0x8006, KEY_3 }, - { 0x8007, KEY_4 }, - { 0x8008, KEY_5 }, - { 0x8009, KEY_6 }, - { 0x800a, KEY_7 }, + { 0x8004, KEY_NUMERIC_1 }, + { 0x8005, KEY_NUMERIC_2 }, + { 0x8006, KEY_NUMERIC_3 }, + { 0x8007, KEY_NUMERIC_4 }, + { 0x8008, KEY_NUMERIC_5 }, + { 0x8009, KEY_NUMERIC_6 }, + { 0x800a, KEY_NUMERIC_7 }, { 0x800c, KEY_ZOOM }, - { 0x800d, KEY_0 }, + { 0x800d, KEY_NUMERIC_0 }, { 0x800e, KEY_SELECT }, { 0x8012, KEY_POWER }, { 0x801a, KEY_CHANNELUP }, - { 0x801b, KEY_8 }, + { 0x801b, KEY_NUMERIC_8 }, { 0x801e, KEY_VOLUMEUP }, - { 0x801f, KEY_9 }, + { 0x801f, KEY_NUMERIC_9 }, }; static struct rc_map_list dtt200u_map = { diff --git a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c index 4b61f60a4854..f5063af2e5bc 100644 --- a/drivers/media/rc/keymaps/rc-dvbsky.c +++ b/drivers/media/rc/keymaps/rc-dvbsky.c @@ -13,16 +13,16 @@ */ static struct rc_map_table rc5_dvbsky[] = { - { 0x0000, KEY_0 }, - { 0x0001, KEY_1 }, - { 0x0002, KEY_2 }, - { 0x0003, KEY_3 }, - { 0x0004, KEY_4 }, - { 0x0005, KEY_5 }, - { 0x0006, KEY_6 }, - { 0x0007, KEY_7 }, - { 0x0008, KEY_8 }, - { 0x0009, KEY_9 }, + { 0x0000, KEY_NUMERIC_0 }, + { 0x0001, KEY_NUMERIC_1 }, + { 0x0002, KEY_NUMERIC_2 }, + { 0x0003, KEY_NUMERIC_3 }, + { 0x0004, KEY_NUMERIC_4 }, + { 0x0005, KEY_NUMERIC_5 }, + { 0x0006, KEY_NUMERIC_6 }, + { 0x0007, KEY_NUMERIC_7 }, + { 0x0008, KEY_NUMERIC_8 }, + { 0x0009, KEY_NUMERIC_9 }, { 0x000a, KEY_MUTE }, { 0x000d, KEY_OK }, { 0x000b, KEY_STOP }, diff --git a/drivers/media/rc/keymaps/rc-dvico-mce.c b/drivers/media/rc/keymaps/rc-dvico-mce.c index 8342c32f58fd..b1bb8cdb3705 100644 --- a/drivers/media/rc/keymaps/rc-dvico-mce.c +++ b/drivers/media/rc/keymaps/rc-dvico-mce.c @@ -35,17 +35,17 @@ static struct rc_map_table rc_map_dvico_mce_table[] = { { 0x0152, KEY_CAMERA }, { 0x015a, KEY_TUNER }, /* Live */ { 0x0119, KEY_OPEN }, - { 0x010b, KEY_1 }, - { 0x0117, KEY_2 }, - { 0x011b, KEY_3 }, - { 0x0107, KEY_4 }, - { 0x0150, KEY_5 }, - { 0x0154, KEY_6 }, - { 0x0148, KEY_7 }, - { 0x014c, KEY_8 }, - { 0x0158, KEY_9 }, + { 0x010b, KEY_NUMERIC_1 }, + { 0x0117, KEY_NUMERIC_2 }, + { 0x011b, KEY_NUMERIC_3 }, + { 0x0107, KEY_NUMERIC_4 }, + { 0x0150, KEY_NUMERIC_5 }, + { 0x0154, KEY_NUMERIC_6 }, + { 0x0148, KEY_NUMERIC_7 }, + { 0x014c, KEY_NUMERIC_8 }, + { 0x0158, KEY_NUMERIC_9 }, { 0x0113, KEY_ANGLE }, /* Aspect */ - { 0x0103, KEY_0 }, + { 0x0103, KEY_NUMERIC_0 }, { 0x011f, KEY_ZOOM }, { 0x0143, KEY_REWIND }, { 0x0147, KEY_PLAYPAUSE }, diff --git a/drivers/media/rc/keymaps/rc-dvico-portable.c b/drivers/media/rc/keymaps/rc-dvico-portable.c index 366bd10bf987..ec12ba6995dc 100644 --- a/drivers/media/rc/keymaps/rc-dvico-portable.c +++ b/drivers/media/rc/keymaps/rc-dvico-portable.c @@ -24,17 +24,17 @@ static struct rc_map_table rc_map_dvico_portable_table[] = { { 0x0316, KEY_CAMERA }, { 0x0340, KEY_TUNER }, /* ATV/DTV */ { 0x0345, KEY_OPEN }, - { 0x0319, KEY_1 }, - { 0x0318, KEY_2 }, - { 0x031b, KEY_3 }, - { 0x031a, KEY_4 }, - { 0x0358, KEY_5 }, - { 0x0359, KEY_6 }, - { 0x0315, KEY_7 }, - { 0x0314, KEY_8 }, - { 0x0317, KEY_9 }, + { 0x0319, KEY_NUMERIC_1 }, + { 0x0318, KEY_NUMERIC_2 }, + { 0x031b, KEY_NUMERIC_3 }, + { 0x031a, KEY_NUMERIC_4 }, + { 0x0358, KEY_NUMERIC_5 }, + { 0x0359, KEY_NUMERIC_6 }, + { 0x0315, KEY_NUMERIC_7 }, + { 0x0314, KEY_NUMERIC_8 }, + { 0x0317, KEY_NUMERIC_9 }, { 0x0344, KEY_ANGLE }, /* Aspect */ - { 0x0355, KEY_0 }, + { 0x0355, KEY_NUMERIC_0 }, { 0x0307, KEY_ZOOM }, { 0x030a, KEY_REWIND }, { 0x0308, KEY_PLAYPAUSE }, diff --git a/drivers/media/rc/keymaps/rc-em-terratec.c b/drivers/media/rc/keymaps/rc-em-terratec.c index cbbba21484fb..a1f59aa6ff23 100644 --- a/drivers/media/rc/keymaps/rc-em-terratec.c +++ b/drivers/media/rc/keymaps/rc-em-terratec.c @@ -13,19 +13,19 @@ static struct rc_map_table em_terratec[] = { { 0x02, KEY_SELECT }, { 0x03, KEY_MUTE }, { 0x04, KEY_POWER }, - { 0x05, KEY_1 }, - { 0x06, KEY_2 }, - { 0x07, KEY_3 }, + { 0x05, KEY_NUMERIC_1 }, + { 0x06, KEY_NUMERIC_2 }, + { 0x07, KEY_NUMERIC_3 }, { 0x08, KEY_CHANNELUP }, - { 0x09, KEY_4 }, - { 0x0a, KEY_5 }, - { 0x0b, KEY_6 }, + { 0x09, KEY_NUMERIC_4 }, + { 0x0a, KEY_NUMERIC_5 }, + { 0x0b, KEY_NUMERIC_6 }, { 0x0c, KEY_CHANNELDOWN }, - { 0x0d, KEY_7 }, - { 0x0e, KEY_8 }, - { 0x0f, KEY_9 }, + { 0x0d, KEY_NUMERIC_7 }, + { 0x0e, KEY_NUMERIC_8 }, + { 0x0f, KEY_NUMERIC_9 }, { 0x10, KEY_VOLUMEUP }, - { 0x11, KEY_0 }, + { 0x11, KEY_NUMERIC_0 }, { 0x12, KEY_MENU }, { 0x13, KEY_PRINT }, { 0x14, KEY_VOLUMEDOWN }, diff --git a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c index 057c13b765ef..7a00471b6005 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c @@ -16,16 +16,16 @@ static struct rc_map_table encore_enltv_fm53[] = { { 0x10, KEY_POWER2}, { 0x06, KEY_MUTE}, - { 0x09, KEY_1}, - { 0x1d, KEY_2}, - { 0x1f, KEY_3}, - { 0x19, KEY_4}, - { 0x1b, KEY_5}, - { 0x11, KEY_6}, - { 0x17, KEY_7}, - { 0x12, KEY_8}, - { 0x16, KEY_9}, - { 0x48, KEY_0}, + { 0x09, KEY_NUMERIC_1}, + { 0x1d, KEY_NUMERIC_2}, + { 0x1f, KEY_NUMERIC_3}, + { 0x19, KEY_NUMERIC_4}, + { 0x1b, KEY_NUMERIC_5}, + { 0x11, KEY_NUMERIC_6}, + { 0x17, KEY_NUMERIC_7}, + { 0x12, KEY_NUMERIC_8}, + { 0x16, KEY_NUMERIC_9}, + { 0x48, KEY_NUMERIC_0}, { 0x04, KEY_LIST}, /* -/-- */ { 0x40, KEY_LAST}, /* recall */ diff --git a/drivers/media/rc/keymaps/rc-encore-enltv.c b/drivers/media/rc/keymaps/rc-encore-enltv.c index 5b4e832d5fac..712210097b4d 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv.c @@ -22,16 +22,16 @@ static struct rc_map_table encore_enltv[] = { { 0x01, KEY_AUDIO }, /* music */ { 0x02, KEY_CAMERA }, /* picture */ - { 0x1f, KEY_1 }, - { 0x03, KEY_2 }, - { 0x04, KEY_3 }, - { 0x05, KEY_4 }, - { 0x1c, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x1d, KEY_9 }, - { 0x0a, KEY_0 }, + { 0x1f, KEY_NUMERIC_1 }, + { 0x03, KEY_NUMERIC_2 }, + { 0x04, KEY_NUMERIC_3 }, + { 0x05, KEY_NUMERIC_4 }, + { 0x1c, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x1d, KEY_NUMERIC_9 }, + { 0x0a, KEY_NUMERIC_0 }, { 0x09, KEY_LIST }, /* -/-- */ { 0x0b, KEY_LAST }, /* recall */ diff --git a/drivers/media/rc/keymaps/rc-encore-enltv2.c b/drivers/media/rc/keymaps/rc-encore-enltv2.c index cd0555924456..a08470b4f187 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv2.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv2.c @@ -14,16 +14,16 @@ static struct rc_map_table encore_enltv2[] = { { 0x4c, KEY_POWER2 }, { 0x4a, KEY_TUNER }, - { 0x40, KEY_1 }, - { 0x60, KEY_2 }, - { 0x50, KEY_3 }, - { 0x70, KEY_4 }, - { 0x48, KEY_5 }, - { 0x68, KEY_6 }, - { 0x58, KEY_7 }, - { 0x78, KEY_8 }, - { 0x44, KEY_9 }, - { 0x54, KEY_0 }, + { 0x40, KEY_NUMERIC_1 }, + { 0x60, KEY_NUMERIC_2 }, + { 0x50, KEY_NUMERIC_3 }, + { 0x70, KEY_NUMERIC_4 }, + { 0x48, KEY_NUMERIC_5 }, + { 0x68, KEY_NUMERIC_6 }, + { 0x58, KEY_NUMERIC_7 }, + { 0x78, KEY_NUMERIC_8 }, + { 0x44, KEY_NUMERIC_9 }, + { 0x54, KEY_NUMERIC_0 }, { 0x64, KEY_LAST }, /* +100 */ { 0x4e, KEY_AGAIN }, /* Recall */ diff --git a/drivers/media/rc/keymaps/rc-eztv.c b/drivers/media/rc/keymaps/rc-eztv.c index 0e481d51fcb5..4e494d953e33 100644 --- a/drivers/media/rc/keymaps/rc-eztv.c +++ b/drivers/media/rc/keymaps/rc-eztv.c @@ -46,16 +46,16 @@ static struct rc_map_table eztv[] = { { 0x2d, KEY_PLAY }, /* play */ { 0x2e, KEY_CAMERA }, /* snapshot / shuffle */ - { 0x00, KEY_0 }, - { 0x05, KEY_1 }, - { 0x06, KEY_2 }, - { 0x07, KEY_3 }, - { 0x09, KEY_4 }, - { 0x0a, KEY_5 }, - { 0x0b, KEY_6 }, - { 0x0d, KEY_7 }, - { 0x0e, KEY_8 }, - { 0x0f, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x05, KEY_NUMERIC_1 }, + { 0x06, KEY_NUMERIC_2 }, + { 0x07, KEY_NUMERIC_3 }, + { 0x09, KEY_NUMERIC_4 }, + { 0x0a, KEY_NUMERIC_5 }, + { 0x0b, KEY_NUMERIC_6 }, + { 0x0d, KEY_NUMERIC_7 }, + { 0x0e, KEY_NUMERIC_8 }, + { 0x0f, KEY_NUMERIC_9 }, { 0x2a, KEY_VOLUMEUP }, { 0x11, KEY_VOLUMEDOWN }, diff --git a/drivers/media/rc/keymaps/rc-flydvb.c b/drivers/media/rc/keymaps/rc-flydvb.c index 45940d7c92d0..202a1fbd1935 100644 --- a/drivers/media/rc/keymaps/rc-flydvb.c +++ b/drivers/media/rc/keymaps/rc-flydvb.c @@ -12,17 +12,17 @@ static struct rc_map_table flydvb[] = { { 0x01, KEY_ZOOM }, /* Full Screen */ { 0x00, KEY_POWER }, /* Power */ - { 0x03, KEY_1 }, - { 0x04, KEY_2 }, - { 0x05, KEY_3 }, - { 0x07, KEY_4 }, - { 0x08, KEY_5 }, - { 0x09, KEY_6 }, - { 0x0b, KEY_7 }, - { 0x0c, KEY_8 }, - { 0x0d, KEY_9 }, + { 0x03, KEY_NUMERIC_1 }, + { 0x04, KEY_NUMERIC_2 }, + { 0x05, KEY_NUMERIC_3 }, + { 0x07, KEY_NUMERIC_4 }, + { 0x08, KEY_NUMERIC_5 }, + { 0x09, KEY_NUMERIC_6 }, + { 0x0b, KEY_NUMERIC_7 }, + { 0x0c, KEY_NUMERIC_8 }, + { 0x0d, KEY_NUMERIC_9 }, { 0x06, KEY_AGAIN }, /* Recall */ - { 0x0f, KEY_0 }, + { 0x0f, KEY_NUMERIC_0 }, { 0x10, KEY_MUTE }, /* Mute */ { 0x02, KEY_RADIO }, /* TV/Radio */ { 0x1b, KEY_LANGUAGE }, /* SAP (Second Audio Program) */ diff --git a/drivers/media/rc/keymaps/rc-flyvideo.c b/drivers/media/rc/keymaps/rc-flyvideo.c index b2d4e4c7b192..a44467fb15cb 100644 --- a/drivers/media/rc/keymaps/rc-flyvideo.c +++ b/drivers/media/rc/keymaps/rc-flyvideo.c @@ -9,16 +9,16 @@ #include <linux/module.h> static struct rc_map_table flyvideo[] = { - { 0x0f, KEY_0 }, - { 0x03, KEY_1 }, - { 0x04, KEY_2 }, - { 0x05, KEY_3 }, - { 0x07, KEY_4 }, - { 0x08, KEY_5 }, - { 0x09, KEY_6 }, - { 0x0b, KEY_7 }, - { 0x0c, KEY_8 }, - { 0x0d, KEY_9 }, + { 0x0f, KEY_NUMERIC_0 }, + { 0x03, KEY_NUMERIC_1 }, + { 0x04, KEY_NUMERIC_2 }, + { 0x05, KEY_NUMERIC_3 }, + { 0x07, KEY_NUMERIC_4 }, + { 0x08, KEY_NUMERIC_5 }, + { 0x09, KEY_NUMERIC_6 }, + { 0x0b, KEY_NUMERIC_7 }, + { 0x0c, KEY_NUMERIC_8 }, + { 0x0d, KEY_NUMERIC_9 }, { 0x0e, KEY_MODE }, /* Air/Cable */ { 0x11, KEY_VIDEO }, /* Video */ diff --git a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c index 1c63fc7d4576..253199f5531a 100644 --- a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c +++ b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c @@ -12,16 +12,16 @@ static struct rc_map_table fusionhdtv_mce[] = { - { 0x0b, KEY_1 }, - { 0x17, KEY_2 }, - { 0x1b, KEY_3 }, - { 0x07, KEY_4 }, - { 0x50, KEY_5 }, - { 0x54, KEY_6 }, - { 0x48, KEY_7 }, - { 0x4c, KEY_8 }, - { 0x58, KEY_9 }, - { 0x03, KEY_0 }, + { 0x0b, KEY_NUMERIC_1 }, + { 0x17, KEY_NUMERIC_2 }, + { 0x1b, KEY_NUMERIC_3 }, + { 0x07, KEY_NUMERIC_4 }, + { 0x50, KEY_NUMERIC_5 }, + { 0x54, KEY_NUMERIC_6 }, + { 0x48, KEY_NUMERIC_7 }, + { 0x4c, KEY_NUMERIC_8 }, + { 0x58, KEY_NUMERIC_9 }, + { 0x03, KEY_NUMERIC_0 }, { 0x5e, KEY_OK }, { 0x51, KEY_UP }, diff --git a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c index 4a0a9786914f..c630ef306f11 100644 --- a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c +++ b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c @@ -21,16 +21,16 @@ static struct rc_map_table gadmei_rm008z[] = { { 0x0b, KEY_AUDIO}, /* SV */ { 0x0f, KEY_RADIO}, /* FM */ - { 0x00, KEY_1}, - { 0x01, KEY_2}, - { 0x02, KEY_3}, - { 0x03, KEY_4}, - { 0x04, KEY_5}, - { 0x05, KEY_6}, - { 0x06, KEY_7}, - { 0x07, KEY_8}, - { 0x08, KEY_9}, - { 0x09, KEY_0}, + { 0x00, KEY_NUMERIC_1}, + { 0x01, KEY_NUMERIC_2}, + { 0x02, KEY_NUMERIC_3}, + { 0x03, KEY_NUMERIC_4}, + { 0x04, KEY_NUMERIC_5}, + { 0x05, KEY_NUMERIC_6}, + { 0x06, KEY_NUMERIC_7}, + { 0x07, KEY_NUMERIC_8}, + { 0x08, KEY_NUMERIC_9}, + { 0x09, KEY_NUMERIC_0}, { 0x0a, KEY_INFO}, /* OSD */ { 0x1c, KEY_BACKSPACE}, /* LAST */ diff --git a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c index cc876a85cc31..c966c130b05d 100644 --- a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c +++ b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c @@ -15,16 +15,16 @@ static struct rc_map_table genius_tvgo_a11mce[] = { /* Keys 0 to 9 */ - { 0x48, KEY_0 }, - { 0x09, KEY_1 }, - { 0x1d, KEY_2 }, - { 0x1f, KEY_3 }, - { 0x19, KEY_4 }, - { 0x1b, KEY_5 }, - { 0x11, KEY_6 }, - { 0x17, KEY_7 }, - { 0x12, KEY_8 }, - { 0x16, KEY_9 }, + { 0x48, KEY_NUMERIC_0 }, + { 0x09, KEY_NUMERIC_1 }, + { 0x1d, KEY_NUMERIC_2 }, + { 0x1f, KEY_NUMERIC_3 }, + { 0x19, KEY_NUMERIC_4 }, + { 0x1b, KEY_NUMERIC_5 }, + { 0x11, KEY_NUMERIC_6 }, + { 0x17, KEY_NUMERIC_7 }, + { 0x12, KEY_NUMERIC_8 }, + { 0x16, KEY_NUMERIC_9 }, { 0x54, KEY_RECORD }, /* recording */ { 0x06, KEY_MUTE }, /* mute */ diff --git a/drivers/media/rc/keymaps/rc-gotview7135.c b/drivers/media/rc/keymaps/rc-gotview7135.c index 6b94bd39d977..0dc4ef36d76f 100644 --- a/drivers/media/rc/keymaps/rc-gotview7135.c +++ b/drivers/media/rc/keymaps/rc-gotview7135.c @@ -14,16 +14,16 @@ static struct rc_map_table gotview7135[] = { { 0x11, KEY_POWER }, { 0x35, KEY_TV }, - { 0x1b, KEY_0 }, - { 0x29, KEY_1 }, - { 0x19, KEY_2 }, - { 0x39, KEY_3 }, - { 0x1f, KEY_4 }, - { 0x2c, KEY_5 }, - { 0x21, KEY_6 }, - { 0x24, KEY_7 }, - { 0x18, KEY_8 }, - { 0x2b, KEY_9 }, + { 0x1b, KEY_NUMERIC_0 }, + { 0x29, KEY_NUMERIC_1 }, + { 0x19, KEY_NUMERIC_2 }, + { 0x39, KEY_NUMERIC_3 }, + { 0x1f, KEY_NUMERIC_4 }, + { 0x2c, KEY_NUMERIC_5 }, + { 0x21, KEY_NUMERIC_6 }, + { 0x24, KEY_NUMERIC_7 }, + { 0x18, KEY_NUMERIC_8 }, + { 0x2b, KEY_NUMERIC_9 }, { 0x3b, KEY_AGAIN }, /* LOOP */ { 0x06, KEY_AUDIO }, { 0x31, KEY_PRINT }, /* PREVIEW */ diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c index 582aa9012443..82552360c3c3 100644 --- a/drivers/media/rc/keymaps/rc-hauppauge.c +++ b/drivers/media/rc/keymaps/rc-hauppauge.c @@ -67,20 +67,20 @@ static struct rc_map_table rc5_hauppauge_new[] = { { 0x1e30, KEY_PAUSE }, /* pause */ { 0x1e1e, KEY_NEXTSONG }, /* skip >| */ - { 0x1e01, KEY_1 }, - { 0x1e02, KEY_2 }, - { 0x1e03, KEY_3 }, + { 0x1e01, KEY_NUMERIC_1 }, + { 0x1e02, KEY_NUMERIC_2 }, + { 0x1e03, KEY_NUMERIC_3 }, - { 0x1e04, KEY_4 }, - { 0x1e05, KEY_5 }, - { 0x1e06, KEY_6 }, + { 0x1e04, KEY_NUMERIC_4 }, + { 0x1e05, KEY_NUMERIC_5 }, + { 0x1e06, KEY_NUMERIC_6 }, - { 0x1e07, KEY_7 }, - { 0x1e08, KEY_8 }, - { 0x1e09, KEY_9 }, + { 0x1e07, KEY_NUMERIC_7 }, + { 0x1e08, KEY_NUMERIC_8 }, + { 0x1e09, KEY_NUMERIC_9 }, { 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */ - { 0x1e00, KEY_0 }, + { 0x1e00, KEY_NUMERIC_0 }, { 0x1e0e, KEY_SUBTITLE }, /* also the Pound key (#) */ { 0x1e0b, KEY_RED }, /* red button */ @@ -96,16 +96,16 @@ static struct rc_map_table rc5_hauppauge_new[] = { { 0x1f3b, KEY_SELECT }, /* GO */ /* Keys 0 to 9 */ - { 0x1f00, KEY_0 }, - { 0x1f01, KEY_1 }, - { 0x1f02, KEY_2 }, - { 0x1f03, KEY_3 }, - { 0x1f04, KEY_4 }, - { 0x1f05, KEY_5 }, - { 0x1f06, KEY_6 }, - { 0x1f07, KEY_7 }, - { 0x1f08, KEY_8 }, - { 0x1f09, KEY_9 }, + { 0x1f00, KEY_NUMERIC_0 }, + { 0x1f01, KEY_NUMERIC_1 }, + { 0x1f02, KEY_NUMERIC_2 }, + { 0x1f03, KEY_NUMERIC_3 }, + { 0x1f04, KEY_NUMERIC_4 }, + { 0x1f05, KEY_NUMERIC_5 }, + { 0x1f06, KEY_NUMERIC_6 }, + { 0x1f07, KEY_NUMERIC_7 }, + { 0x1f08, KEY_NUMERIC_8 }, + { 0x1f09, KEY_NUMERIC_9 }, { 0x1f1f, KEY_EXIT }, /* back/exit */ { 0x1f0d, KEY_MENU }, @@ -140,16 +140,16 @@ static struct rc_map_table rc5_hauppauge_new[] = { * Keycodes for DSR-0112 remote bundled with Haupauge MiniStick * Keycodes start with address = 0x1d */ - { 0x1d00, KEY_0 }, - { 0x1d01, KEY_1 }, - { 0x1d02, KEY_2 }, - { 0x1d03, KEY_3 }, - { 0x1d04, KEY_4 }, - { 0x1d05, KEY_5 }, - { 0x1d06, KEY_6 }, - { 0x1d07, KEY_7 }, - { 0x1d08, KEY_8 }, - { 0x1d09, KEY_9 }, + { 0x1d00, KEY_NUMERIC_0 }, + { 0x1d01, KEY_NUMERIC_1 }, + { 0x1d02, KEY_NUMERIC_2 }, + { 0x1d03, KEY_NUMERIC_3 }, + { 0x1d04, KEY_NUMERIC_4 }, + { 0x1d05, KEY_NUMERIC_5 }, + { 0x1d06, KEY_NUMERIC_6 }, + { 0x1d07, KEY_NUMERIC_7 }, + { 0x1d08, KEY_NUMERIC_8 }, + { 0x1d09, KEY_NUMERIC_9 }, { 0x1d0a, KEY_TEXT }, { 0x1d0d, KEY_MENU }, { 0x1d0f, KEY_MUTE }, @@ -190,16 +190,16 @@ static struct rc_map_table rc5_hauppauge_new[] = { { 0x1c17, KEY_RIGHT }, { 0x1c25, KEY_OK }, - { 0x1c00, KEY_0 }, - { 0x1c01, KEY_1 }, - { 0x1c02, KEY_2 }, - { 0x1c03, KEY_3 }, - { 0x1c04, KEY_4 }, - { 0x1c05, KEY_5 }, - { 0x1c06, KEY_6 }, - { 0x1c07, KEY_7 }, - { 0x1c08, KEY_8 }, - { 0x1c09, KEY_9 }, + { 0x1c00, KEY_NUMERIC_0 }, + { 0x1c01, KEY_NUMERIC_1 }, + { 0x1c02, KEY_NUMERIC_2 }, + { 0x1c03, KEY_NUMERIC_3 }, + { 0x1c04, KEY_NUMERIC_4 }, + { 0x1c05, KEY_NUMERIC_5 }, + { 0x1c06, KEY_NUMERIC_6 }, + { 0x1c07, KEY_NUMERIC_7 }, + { 0x1c08, KEY_NUMERIC_8 }, + { 0x1c09, KEY_NUMERIC_9 }, { 0x1c1f, KEY_EXIT }, /* BACK */ { 0x1c0d, KEY_MENU }, @@ -233,6 +233,7 @@ static struct rc_map_table rc5_hauppauge_new[] = { * This one also uses RC-5 protocol * Keycodes start with address = 0x00 */ + { 0x000f, KEY_TV }, { 0x001f, KEY_TV }, { 0x0020, KEY_CHANNELUP }, { 0x000c, KEY_RADIO }, @@ -245,20 +246,20 @@ static struct rc_map_table rc5_hauppauge_new[] = { { 0x0021, KEY_CHANNELDOWN }, { 0x0022, KEY_VIDEO }, /* source */ - { 0x0001, KEY_1 }, - { 0x0002, KEY_2 }, - { 0x0003, KEY_3 }, + { 0x0001, KEY_NUMERIC_1 }, + { 0x0002, KEY_NUMERIC_2 }, + { 0x0003, KEY_NUMERIC_3 }, - { 0x0004, KEY_4 }, - { 0x0005, KEY_5 }, - { 0x0006, KEY_6 }, + { 0x0004, KEY_NUMERIC_4 }, + { 0x0005, KEY_NUMERIC_5 }, + { 0x0006, KEY_NUMERIC_6 }, - { 0x0007, KEY_7 }, - { 0x0008, KEY_8 }, - { 0x0009, KEY_9 }, + { 0x0007, KEY_NUMERIC_7 }, + { 0x0008, KEY_NUMERIC_8 }, + { 0x0009, KEY_NUMERIC_9 }, { 0x001e, KEY_RED }, /* Reserved */ - { 0x0000, KEY_0 }, + { 0x0000, KEY_NUMERIC_0 }, { 0x0026, KEY_SLEEP }, /* Minimize */ }; diff --git a/drivers/media/rc/keymaps/rc-hisi-poplar.c b/drivers/media/rc/keymaps/rc-hisi-poplar.c index b4dbec6e70ce..49a18e916915 100644 --- a/drivers/media/rc/keymaps/rc-hisi-poplar.c +++ b/drivers/media/rc/keymaps/rc-hisi-poplar.c @@ -9,16 +9,16 @@ #include <media/rc-map.h> static struct rc_map_table hisi_poplar_keymap[] = { - { 0x0000b292, KEY_1}, - { 0x0000b293, KEY_2}, - { 0x0000b2cc, KEY_3}, - { 0x0000b28e, KEY_4}, - { 0x0000b28f, KEY_5}, - { 0x0000b2c8, KEY_6}, - { 0x0000b28a, KEY_7}, - { 0x0000b28b, KEY_8}, - { 0x0000b2c4, KEY_9}, - { 0x0000b287, KEY_0}, + { 0x0000b292, KEY_NUMERIC_1}, + { 0x0000b293, KEY_NUMERIC_2}, + { 0x0000b2cc, KEY_NUMERIC_3}, + { 0x0000b28e, KEY_NUMERIC_4}, + { 0x0000b28f, KEY_NUMERIC_5}, + { 0x0000b2c8, KEY_NUMERIC_6}, + { 0x0000b28a, KEY_NUMERIC_7}, + { 0x0000b28b, KEY_NUMERIC_8}, + { 0x0000b2c4, KEY_NUMERIC_9}, + { 0x0000b287, KEY_NUMERIC_0}, { 0x0000b282, KEY_HOMEPAGE}, { 0x0000b2ca, KEY_UP}, { 0x0000b299, KEY_LEFT}, diff --git a/drivers/media/rc/keymaps/rc-hisi-tv-demo.c b/drivers/media/rc/keymaps/rc-hisi-tv-demo.c index 8e25b40714f8..c73068b653f7 100644 --- a/drivers/media/rc/keymaps/rc-hisi-tv-demo.c +++ b/drivers/media/rc/keymaps/rc-hisi-tv-demo.c @@ -9,16 +9,16 @@ #include <media/rc-map.h> static struct rc_map_table hisi_tv_demo_keymap[] = { - { 0x00000092, KEY_1}, - { 0x00000093, KEY_2}, - { 0x000000cc, KEY_3}, - { 0x0000009f, KEY_4}, - { 0x0000008e, KEY_5}, - { 0x0000008f, KEY_6}, - { 0x000000c8, KEY_7}, - { 0x00000094, KEY_8}, - { 0x0000008a, KEY_9}, - { 0x0000008b, KEY_0}, + { 0x00000092, KEY_NUMERIC_1}, + { 0x00000093, KEY_NUMERIC_2}, + { 0x000000cc, KEY_NUMERIC_3}, + { 0x0000009f, KEY_NUMERIC_4}, + { 0x0000008e, KEY_NUMERIC_5}, + { 0x0000008f, KEY_NUMERIC_6}, + { 0x000000c8, KEY_NUMERIC_7}, + { 0x00000094, KEY_NUMERIC_8}, + { 0x0000008a, KEY_NUMERIC_9}, + { 0x0000008b, KEY_NUMERIC_0}, { 0x000000ce, KEY_ENTER}, { 0x000000ca, KEY_UP}, { 0x00000099, KEY_LEFT}, diff --git a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c index 6ced43458f2a..9cc6ea0f4226 100644 --- a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c +++ b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c @@ -17,16 +17,16 @@ static struct rc_map_table iodata_bctv7e[] = { { 0x00, KEY_POWER }, /* Keys 0 to 9 */ - { 0x44, KEY_0 }, /* 10 */ - { 0x50, KEY_1 }, - { 0x30, KEY_2 }, - { 0x70, KEY_3 }, - { 0x48, KEY_4 }, - { 0x28, KEY_5 }, - { 0x68, KEY_6 }, - { 0x58, KEY_7 }, - { 0x38, KEY_8 }, - { 0x78, KEY_9 }, + { 0x44, KEY_NUMERIC_0 }, /* 10 */ + { 0x50, KEY_NUMERIC_1 }, + { 0x30, KEY_NUMERIC_2 }, + { 0x70, KEY_NUMERIC_3 }, + { 0x48, KEY_NUMERIC_4 }, + { 0x28, KEY_NUMERIC_5 }, + { 0x68, KEY_NUMERIC_6 }, + { 0x58, KEY_NUMERIC_7 }, + { 0x38, KEY_NUMERIC_8 }, + { 0x78, KEY_NUMERIC_9 }, { 0x10, KEY_L }, /* Live */ { 0x08, KEY_TIME }, /* Time Shift */ diff --git a/drivers/media/rc/keymaps/rc-it913x-v1.c b/drivers/media/rc/keymaps/rc-it913x-v1.c index d8eaba9834c2..1e049f26a246 100644 --- a/drivers/media/rc/keymaps/rc-it913x-v1.c +++ b/drivers/media/rc/keymaps/rc-it913x-v1.c @@ -11,22 +11,22 @@ static struct rc_map_table it913x_v1_rc[] = { /* Type 1 */ { 0x61d601, KEY_VIDEO }, /* Source */ - { 0x61d602, KEY_3 }, + { 0x61d602, KEY_NUMERIC_3 }, { 0x61d603, KEY_POWER }, /* ShutDown */ - { 0x61d604, KEY_1 }, - { 0x61d605, KEY_5 }, - { 0x61d606, KEY_6 }, + { 0x61d604, KEY_NUMERIC_1 }, + { 0x61d605, KEY_NUMERIC_5 }, + { 0x61d606, KEY_NUMERIC_6 }, { 0x61d607, KEY_CHANNELDOWN }, /* CH- */ - { 0x61d608, KEY_2 }, + { 0x61d608, KEY_NUMERIC_2 }, { 0x61d609, KEY_CHANNELUP }, /* CH+ */ - { 0x61d60a, KEY_9 }, + { 0x61d60a, KEY_NUMERIC_9 }, { 0x61d60b, KEY_ZOOM }, /* Zoom */ - { 0x61d60c, KEY_7 }, - { 0x61d60d, KEY_8 }, + { 0x61d60c, KEY_NUMERIC_7 }, + { 0x61d60d, KEY_NUMERIC_8 }, { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */ - { 0x61d60f, KEY_4 }, + { 0x61d60f, KEY_NUMERIC_4 }, { 0x61d610, KEY_ESC }, /* [back up arrow] */ - { 0x61d611, KEY_0 }, + { 0x61d611, KEY_NUMERIC_0 }, { 0x61d612, KEY_OK }, /* [enter arrow] */ { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */ { 0x61d614, KEY_RECORD }, /* Rec */ @@ -43,16 +43,16 @@ static struct rc_map_table it913x_v1_rc[] = { { 0x61d61f, KEY_BLUE }, { 0x61d643, KEY_POWER2 }, /* [red power button] */ /* Type 2 - 20 buttons */ - { 0x807f0d, KEY_0 }, - { 0x807f04, KEY_1 }, - { 0x807f05, KEY_2 }, - { 0x807f06, KEY_3 }, - { 0x807f07, KEY_4 }, - { 0x807f08, KEY_5 }, - { 0x807f09, KEY_6 }, - { 0x807f0a, KEY_7 }, - { 0x807f1b, KEY_8 }, - { 0x807f1f, KEY_9 }, + { 0x807f0d, KEY_NUMERIC_0 }, + { 0x807f04, KEY_NUMERIC_1 }, + { 0x807f05, KEY_NUMERIC_2 }, + { 0x807f06, KEY_NUMERIC_3 }, + { 0x807f07, KEY_NUMERIC_4 }, + { 0x807f08, KEY_NUMERIC_5 }, + { 0x807f09, KEY_NUMERIC_6 }, + { 0x807f0a, KEY_NUMERIC_7 }, + { 0x807f1b, KEY_NUMERIC_8 }, + { 0x807f1f, KEY_NUMERIC_9 }, { 0x807f12, KEY_POWER }, { 0x807f01, KEY_MEDIA_REPEAT}, /* Recall */ { 0x807f19, KEY_PAUSE }, /* Timeshift */ diff --git a/drivers/media/rc/keymaps/rc-it913x-v2.c b/drivers/media/rc/keymaps/rc-it913x-v2.c index 26747a327d91..da3107da26b7 100644 --- a/drivers/media/rc/keymaps/rc-it913x-v2.c +++ b/drivers/media/rc/keymaps/rc-it913x-v2.c @@ -20,31 +20,31 @@ static struct rc_map_table it913x_v2_rc[] = { { 0x807f04, KEY_VOLUMEUP }, /* Volume- */ { 0x807f05, KEY_SCREEN }, /* FullScreen */ { 0x807f06, KEY_VOLUMEDOWN }, /* Volume- */ - { 0x807f07, KEY_0 }, /* 0 */ + { 0x807f07, KEY_NUMERIC_0 }, /* 0 */ { 0x807f08, KEY_CHANNELDOWN }, /* Channel- */ { 0x807f09, KEY_PREVIOUS }, /* Recall */ - { 0x807f0a, KEY_1 }, /* 1 */ - { 0x807f1b, KEY_2 }, /* 2 */ - { 0x807f1f, KEY_3 }, /* 3 */ - { 0x807f0c, KEY_4 }, /* 4 */ - { 0x807f0d, KEY_5 }, /* 5 */ - { 0x807f0e, KEY_6 }, /* 6 */ - { 0x807f00, KEY_7 }, /* 7 */ - { 0x807f0f, KEY_8 }, /* 8 */ - { 0x807f19, KEY_9 }, /* 9 */ + { 0x807f0a, KEY_NUMERIC_1 }, /* 1 */ + { 0x807f1b, KEY_NUMERIC_2 }, /* 2 */ + { 0x807f1f, KEY_NUMERIC_3 }, /* 3 */ + { 0x807f0c, KEY_NUMERIC_4 }, /* 4 */ + { 0x807f0d, KEY_NUMERIC_5 }, /* 5 */ + { 0x807f0e, KEY_NUMERIC_6 }, /* 6 */ + { 0x807f00, KEY_NUMERIC_7 }, /* 7 */ + { 0x807f0f, KEY_NUMERIC_8 }, /* 8 */ + { 0x807f19, KEY_NUMERIC_9 }, /* 9 */ /* Type 2 */ /* keys stereo, snapshot unassigned */ - { 0x866b00, KEY_0 }, - { 0x866b01, KEY_1 }, - { 0x866b02, KEY_2 }, - { 0x866b03, KEY_3 }, - { 0x866b04, KEY_4 }, - { 0x866b05, KEY_5 }, - { 0x866b06, KEY_6 }, - { 0x866b07, KEY_7 }, - { 0x866b08, KEY_8 }, - { 0x866b09, KEY_9 }, + { 0x866b00, KEY_NUMERIC_0 }, + { 0x866b01, KEY_NUMERIC_1 }, + { 0x866b02, KEY_NUMERIC_2 }, + { 0x866b03, KEY_NUMERIC_3 }, + { 0x866b04, KEY_NUMERIC_4 }, + { 0x866b05, KEY_NUMERIC_5 }, + { 0x866b06, KEY_NUMERIC_6 }, + { 0x866b07, KEY_NUMERIC_7 }, + { 0x866b08, KEY_NUMERIC_8 }, + { 0x866b09, KEY_NUMERIC_9 }, { 0x866b12, KEY_POWER }, { 0x866b13, KEY_MUTE }, { 0x866b0a, KEY_PREVIOUS }, /* Recall */ diff --git a/drivers/media/rc/keymaps/rc-kaiomy.c b/drivers/media/rc/keymaps/rc-kaiomy.c index a00051339842..548760e86a2d 100644 --- a/drivers/media/rc/keymaps/rc-kaiomy.c +++ b/drivers/media/rc/keymaps/rc-kaiomy.c @@ -18,19 +18,19 @@ static struct rc_map_table kaiomy[] = { { 0x0b, KEY_ZOOM}, { 0x03, KEY_POWER}, - { 0x04, KEY_1}, - { 0x08, KEY_2}, - { 0x02, KEY_3}, + { 0x04, KEY_NUMERIC_1}, + { 0x08, KEY_NUMERIC_2}, + { 0x02, KEY_NUMERIC_3}, - { 0x0f, KEY_4}, - { 0x05, KEY_5}, - { 0x06, KEY_6}, + { 0x0f, KEY_NUMERIC_4}, + { 0x05, KEY_NUMERIC_5}, + { 0x06, KEY_NUMERIC_6}, - { 0x0c, KEY_7}, - { 0x0d, KEY_8}, - { 0x0a, KEY_9}, + { 0x0c, KEY_NUMERIC_7}, + { 0x0d, KEY_NUMERIC_8}, + { 0x0a, KEY_NUMERIC_9}, - { 0x11, KEY_0}, + { 0x11, KEY_NUMERIC_0}, { 0x09, KEY_CHANNELUP}, { 0x07, KEY_CHANNELDOWN}, diff --git a/drivers/media/rc/keymaps/rc-kworld-315u.c b/drivers/media/rc/keymaps/rc-kworld-315u.c index ed0e0586dea2..f5aed4b96019 100644 --- a/drivers/media/rc/keymaps/rc-kworld-315u.c +++ b/drivers/media/rc/keymaps/rc-kworld-315u.c @@ -17,23 +17,23 @@ static struct rc_map_table kworld_315u[] = { { 0x610b, KEY_ZOOM }, { 0x6103, KEY_POWER2 }, /* shutdown */ - { 0x6104, KEY_1 }, - { 0x6108, KEY_2 }, - { 0x6102, KEY_3 }, + { 0x6104, KEY_NUMERIC_1 }, + { 0x6108, KEY_NUMERIC_2 }, + { 0x6102, KEY_NUMERIC_3 }, { 0x6109, KEY_CHANNELUP }, - { 0x610f, KEY_4 }, - { 0x6105, KEY_5 }, - { 0x6106, KEY_6 }, + { 0x610f, KEY_NUMERIC_4 }, + { 0x6105, KEY_NUMERIC_5 }, + { 0x6106, KEY_NUMERIC_6 }, { 0x6107, KEY_CHANNELDOWN }, - { 0x610c, KEY_7 }, - { 0x610d, KEY_8 }, - { 0x610a, KEY_9 }, + { 0x610c, KEY_NUMERIC_7 }, + { 0x610d, KEY_NUMERIC_8 }, + { 0x610a, KEY_NUMERIC_9 }, { 0x610e, KEY_VOLUMEUP }, { 0x6110, KEY_LAST }, - { 0x6111, KEY_0 }, + { 0x6111, KEY_NUMERIC_0 }, { 0x6112, KEY_ENTER }, { 0x6113, KEY_VOLUMEDOWN }, diff --git a/drivers/media/rc/keymaps/rc-kworld-pc150u.c b/drivers/media/rc/keymaps/rc-kworld-pc150u.c index 9c60cf4f3bf2..7938761eb994 100644 --- a/drivers/media/rc/keymaps/rc-kworld-pc150u.c +++ b/drivers/media/rc/keymaps/rc-kworld-pc150u.c @@ -20,16 +20,16 @@ static struct rc_map_table kworld_pc150u[] = { { 0x16, KEY_EJECTCLOSECD }, /* -> ) */ { 0x1d, KEY_POWER2 }, - { 0x00, KEY_1 }, - { 0x01, KEY_2 }, - { 0x02, KEY_3 }, - { 0x03, KEY_4 }, - { 0x04, KEY_5 }, - { 0x05, KEY_6 }, - { 0x06, KEY_7 }, - { 0x07, KEY_8 }, - { 0x08, KEY_9 }, - { 0x0a, KEY_0 }, + { 0x00, KEY_NUMERIC_1 }, + { 0x01, KEY_NUMERIC_2 }, + { 0x02, KEY_NUMERIC_3 }, + { 0x03, KEY_NUMERIC_4 }, + { 0x04, KEY_NUMERIC_5 }, + { 0x05, KEY_NUMERIC_6 }, + { 0x06, KEY_NUMERIC_7 }, + { 0x07, KEY_NUMERIC_8 }, + { 0x08, KEY_NUMERIC_9 }, + { 0x0a, KEY_NUMERIC_0 }, { 0x09, KEY_AGAIN }, { 0x14, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c index db5edde3eeb1..75389b74e02d 100644 --- a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c +++ b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c @@ -17,16 +17,20 @@ static struct rc_map_table kworld_plus_tv_analog[] = { { 0x16, KEY_CLOSECD }, /* -> ) */ { 0x1d, KEY_POWER2 }, - { 0x00, KEY_1 }, - { 0x01, KEY_2 }, - { 0x02, KEY_3 }, /* Two keys have the same code: 3 and left */ - { 0x03, KEY_4 }, /* Two keys have the same code: 3 and right */ - { 0x04, KEY_5 }, - { 0x05, KEY_6 }, - { 0x06, KEY_7 }, - { 0x07, KEY_8 }, - { 0x08, KEY_9 }, - { 0x0a, KEY_0 }, + { 0x00, KEY_NUMERIC_1 }, + { 0x01, KEY_NUMERIC_2 }, + + /* Two keys have the same code: 3 and left */ + { 0x02, KEY_NUMERIC_3 }, + + /* Two keys have the same code: 4 and right */ + { 0x03, KEY_NUMERIC_4 }, + { 0x04, KEY_NUMERIC_5 }, + { 0x05, KEY_NUMERIC_6 }, + { 0x06, KEY_NUMERIC_7 }, + { 0x07, KEY_NUMERIC_8 }, + { 0x08, KEY_NUMERIC_9 }, + { 0x0a, KEY_NUMERIC_0 }, { 0x09, KEY_AGAIN }, { 0x14, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c index afee942e0edf..2f2b981e1995 100644 --- a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c +++ b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c @@ -12,20 +12,20 @@ static struct rc_map_table leadtek_y04g0051[] = { { 0x0300, KEY_POWER2 }, { 0x0303, KEY_SCREEN }, { 0x0304, KEY_RIGHT }, - { 0x0305, KEY_1 }, - { 0x0306, KEY_2 }, - { 0x0307, KEY_3 }, + { 0x0305, KEY_NUMERIC_1 }, + { 0x0306, KEY_NUMERIC_2 }, + { 0x0307, KEY_NUMERIC_3 }, { 0x0308, KEY_LEFT }, - { 0x0309, KEY_4 }, - { 0x030a, KEY_5 }, - { 0x030b, KEY_6 }, + { 0x0309, KEY_NUMERIC_4 }, + { 0x030a, KEY_NUMERIC_5 }, + { 0x030b, KEY_NUMERIC_6 }, { 0x030c, KEY_UP }, - { 0x030d, KEY_7 }, - { 0x030e, KEY_8 }, - { 0x030f, KEY_9 }, + { 0x030d, KEY_NUMERIC_7 }, + { 0x030e, KEY_NUMERIC_8 }, + { 0x030f, KEY_NUMERIC_9 }, { 0x0310, KEY_DOWN }, { 0x0311, KEY_AGAIN }, - { 0x0312, KEY_0 }, + { 0x0312, KEY_NUMERIC_0 }, { 0x0313, KEY_OK }, /* 1st ok */ { 0x0314, KEY_MUTE }, { 0x0316, KEY_OK }, /* 2nd ok */ diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c index b0901a8a72a6..181e48f0cb67 100644 --- a/drivers/media/rc/keymaps/rc-lme2510.c +++ b/drivers/media/rc/keymaps/rc-lme2510.c @@ -10,16 +10,16 @@ static struct rc_map_table lme2510_rc[] = { /* Type 1 - 26 buttons */ - { 0xef12ba45, KEY_0 }, - { 0xef12a05f, KEY_1 }, - { 0xef12af50, KEY_2 }, - { 0xef12a25d, KEY_3 }, - { 0xef12be41, KEY_4 }, - { 0xef12f50a, KEY_5 }, - { 0xef12bd42, KEY_6 }, - { 0xef12b847, KEY_7 }, - { 0xef12b649, KEY_8 }, - { 0xef12fa05, KEY_9 }, + { 0xef12ba45, KEY_NUMERIC_0 }, + { 0xef12a05f, KEY_NUMERIC_1 }, + { 0xef12af50, KEY_NUMERIC_2 }, + { 0xef12a25d, KEY_NUMERIC_3 }, + { 0xef12be41, KEY_NUMERIC_4 }, + { 0xef12f50a, KEY_NUMERIC_5 }, + { 0xef12bd42, KEY_NUMERIC_6 }, + { 0xef12b847, KEY_NUMERIC_7 }, + { 0xef12b649, KEY_NUMERIC_8 }, + { 0xef12fa05, KEY_NUMERIC_9 }, { 0xef12bc43, KEY_POWER }, { 0xef12b946, KEY_SUBTITLE }, { 0xef12f906, KEY_PAUSE }, @@ -37,16 +37,16 @@ static struct rc_map_table lme2510_rc[] = { { 0xef12f807, KEY_EPG }, { 0xef12fe01, KEY_STOP }, /* Type 2 - 20 buttons */ - { 0xff40ea15, KEY_0 }, - { 0xff40f708, KEY_1 }, - { 0xff40f609, KEY_2 }, - { 0xff40f50a, KEY_3 }, - { 0xff40f30c, KEY_4 }, - { 0xff40f20d, KEY_5 }, - { 0xff40f10e, KEY_6 }, - { 0xff40ef10, KEY_7 }, - { 0xff40ee11, KEY_8 }, - { 0xff40ed12, KEY_9 }, + { 0xff40ea15, KEY_NUMERIC_0 }, + { 0xff40f708, KEY_NUMERIC_1 }, + { 0xff40f609, KEY_NUMERIC_2 }, + { 0xff40f50a, KEY_NUMERIC_3 }, + { 0xff40f30c, KEY_NUMERIC_4 }, + { 0xff40f20d, KEY_NUMERIC_5 }, + { 0xff40f10e, KEY_NUMERIC_6 }, + { 0xff40ef10, KEY_NUMERIC_7 }, + { 0xff40ee11, KEY_NUMERIC_8 }, + { 0xff40ed12, KEY_NUMERIC_9 }, { 0xff40ff00, KEY_POWER }, { 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */ { 0xff40e51a, KEY_PAUSE }, /* Timeshift */ @@ -58,16 +58,16 @@ static struct rc_map_table lme2510_rc[] = { { 0xff40e718, KEY_RECORD }, { 0xff40e916, KEY_STOP }, /* Type 3 - 20 buttons */ - { 0xff00e31c, KEY_0 }, - { 0xff00f807, KEY_1 }, - { 0xff00ea15, KEY_2 }, - { 0xff00f609, KEY_3 }, - { 0xff00e916, KEY_4 }, - { 0xff00e619, KEY_5 }, - { 0xff00f20d, KEY_6 }, - { 0xff00f30c, KEY_7 }, - { 0xff00e718, KEY_8 }, - { 0xff00a15e, KEY_9 }, + { 0xff00e31c, KEY_NUMERIC_0 }, + { 0xff00f807, KEY_NUMERIC_1 }, + { 0xff00ea15, KEY_NUMERIC_2 }, + { 0xff00f609, KEY_NUMERIC_3 }, + { 0xff00e916, KEY_NUMERIC_4 }, + { 0xff00e619, KEY_NUMERIC_5 }, + { 0xff00f20d, KEY_NUMERIC_6 }, + { 0xff00f30c, KEY_NUMERIC_7 }, + { 0xff00e718, KEY_NUMERIC_8 }, + { 0xff00a15e, KEY_NUMERIC_9 }, { 0xff00ba45, KEY_POWER }, { 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */ { 0xff00b54a, KEY_PAUSE }, /* Timeshift */ diff --git a/drivers/media/rc/keymaps/rc-manli.c b/drivers/media/rc/keymaps/rc-manli.c index 5e9a49e2dd6a..e884aeb5c3d6 100644 --- a/drivers/media/rc/keymaps/rc-manli.c +++ b/drivers/media/rc/keymaps/rc-manli.c @@ -35,22 +35,22 @@ static struct rc_map_table manli[] = { * 0x07 0x08 0x09 * * 7 8 9 * * */ - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, /* 0x0a 0x00 0x17 * * RECALL 0 +100 * * PLUS * * */ { 0x0a, KEY_AGAIN }, /*XXX KEY_REWIND? */ - { 0x00, KEY_0 }, + { 0x00, KEY_NUMERIC_0 }, { 0x17, KEY_DIGITS }, /*XXX*/ /* 0x14 0x10 * diff --git a/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c b/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c index 407706b246f2..bf74912859b3 100644 --- a/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c +++ b/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c @@ -63,16 +63,16 @@ static struct rc_map_table medion_x10_digitainer[] = { { 0x27, KEY_RECORD }, { 0x26, KEY_FORWARD }, - { 0x0d, KEY_1 }, - { 0x0e, KEY_2 }, - { 0x0f, KEY_3 }, - { 0x10, KEY_4 }, - { 0x11, KEY_5 }, - { 0x12, KEY_6 }, - { 0x13, KEY_7 }, - { 0x14, KEY_8 }, - { 0x15, KEY_9 }, - { 0x17, KEY_0 }, + { 0x0d, KEY_NUMERIC_1 }, + { 0x0e, KEY_NUMERIC_2 }, + { 0x0f, KEY_NUMERIC_3 }, + { 0x10, KEY_NUMERIC_4 }, + { 0x11, KEY_NUMERIC_5 }, + { 0x12, KEY_NUMERIC_6 }, + { 0x13, KEY_NUMERIC_7 }, + { 0x14, KEY_NUMERIC_8 }, + { 0x15, KEY_NUMERIC_9 }, + { 0x17, KEY_NUMERIC_0 }, /* these do not actually exist on this remote, but these scancodes * exist on all other Medion X10 remotes and adding them here allows diff --git a/drivers/media/rc/keymaps/rc-medion-x10-or2x.c b/drivers/media/rc/keymaps/rc-medion-x10-or2x.c index 2ff5c454304d..293045c9aaa5 100644 --- a/drivers/media/rc/keymaps/rc-medion-x10-or2x.c +++ b/drivers/media/rc/keymaps/rc-medion-x10-or2x.c @@ -52,16 +52,16 @@ static struct rc_map_table medion_x10_or2x[] = { { 0x29, KEY_PAUSE }, { 0x27, KEY_RECORD }, - { 0x0d, KEY_1 }, - { 0x0e, KEY_2 }, - { 0x0f, KEY_3 }, - { 0x10, KEY_4 }, - { 0x11, KEY_5 }, - { 0x12, KEY_6 }, - { 0x13, KEY_7 }, - { 0x14, KEY_8 }, - { 0x15, KEY_9 }, - { 0x17, KEY_0 }, + { 0x0d, KEY_NUMERIC_1 }, + { 0x0e, KEY_NUMERIC_2 }, + { 0x0f, KEY_NUMERIC_3 }, + { 0x10, KEY_NUMERIC_4 }, + { 0x11, KEY_NUMERIC_5 }, + { 0x12, KEY_NUMERIC_6 }, + { 0x13, KEY_NUMERIC_7 }, + { 0x14, KEY_NUMERIC_8 }, + { 0x15, KEY_NUMERIC_9 }, + { 0x17, KEY_NUMERIC_0 }, { 0x30, KEY_CLEAR }, { 0x36, KEY_ENTER }, { 0x37, KEY_NUMERIC_STAR }, diff --git a/drivers/media/rc/keymaps/rc-medion-x10.c b/drivers/media/rc/keymaps/rc-medion-x10.c index 66b962dc982b..843dba3bad73 100644 --- a/drivers/media/rc/keymaps/rc-medion-x10.c +++ b/drivers/media/rc/keymaps/rc-medion-x10.c @@ -37,16 +37,16 @@ static struct rc_map_table medion_x10[] = { { 0x35, KEY_BLUE }, /* blue */ { 0x16, KEY_TEXT }, /* TXT */ - { 0x0d, KEY_1 }, - { 0x0e, KEY_2 }, - { 0x0f, KEY_3 }, - { 0x10, KEY_4 }, - { 0x11, KEY_5 }, - { 0x12, KEY_6 }, - { 0x13, KEY_7 }, - { 0x14, KEY_8 }, - { 0x15, KEY_9 }, - { 0x17, KEY_0 }, + { 0x0d, KEY_NUMERIC_1 }, + { 0x0e, KEY_NUMERIC_2 }, + { 0x0f, KEY_NUMERIC_3 }, + { 0x10, KEY_NUMERIC_4 }, + { 0x11, KEY_NUMERIC_5 }, + { 0x12, KEY_NUMERIC_6 }, + { 0x13, KEY_NUMERIC_7 }, + { 0x14, KEY_NUMERIC_8 }, + { 0x15, KEY_NUMERIC_9 }, + { 0x17, KEY_NUMERIC_0 }, { 0x1c, KEY_SEARCH }, /* TV/RAD, CH SRC */ { 0x20, KEY_DELETE }, /* DELETE */ diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c index d361554e8a2d..ab001d2dac67 100644 --- a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c +++ b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c @@ -9,23 +9,23 @@ #include <linux/module.h> static struct rc_map_table msi_digivox_ii[] = { - { 0x0302, KEY_2 }, + { 0x0302, KEY_NUMERIC_2 }, { 0x0303, KEY_UP }, /* up */ - { 0x0304, KEY_3 }, + { 0x0304, KEY_NUMERIC_3 }, { 0x0305, KEY_CHANNELDOWN }, - { 0x0308, KEY_5 }, - { 0x0309, KEY_0 }, - { 0x030b, KEY_8 }, + { 0x0308, KEY_NUMERIC_5 }, + { 0x0309, KEY_NUMERIC_0 }, + { 0x030b, KEY_NUMERIC_8 }, { 0x030d, KEY_DOWN }, /* down */ - { 0x0310, KEY_9 }, - { 0x0311, KEY_7 }, + { 0x0310, KEY_NUMERIC_9 }, + { 0x0311, KEY_NUMERIC_7 }, { 0x0314, KEY_VOLUMEUP }, { 0x0315, KEY_CHANNELUP }, { 0x0316, KEY_OK }, { 0x0317, KEY_POWER2 }, - { 0x031a, KEY_1 }, - { 0x031c, KEY_4 }, - { 0x031d, KEY_6 }, + { 0x031a, KEY_NUMERIC_1 }, + { 0x031c, KEY_NUMERIC_4 }, + { 0x031d, KEY_NUMERIC_6 }, { 0x031f, KEY_VOLUMEDOWN }, }; diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c index 31d41564a438..6129d3e925e5 100644 --- a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c +++ b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c @@ -14,22 +14,22 @@ since rc-kworld-315u.c lacks NEC extended address byte. */ static struct rc_map_table msi_digivox_iii[] = { { 0x61d601, KEY_VIDEO }, /* Source */ - { 0x61d602, KEY_3 }, + { 0x61d602, KEY_NUMERIC_3 }, { 0x61d603, KEY_POWER }, /* ShutDown */ - { 0x61d604, KEY_1 }, - { 0x61d605, KEY_5 }, - { 0x61d606, KEY_6 }, + { 0x61d604, KEY_NUMERIC_1 }, + { 0x61d605, KEY_NUMERIC_5 }, + { 0x61d606, KEY_NUMERIC_6 }, { 0x61d607, KEY_CHANNELDOWN }, /* CH- */ - { 0x61d608, KEY_2 }, + { 0x61d608, KEY_NUMERIC_2 }, { 0x61d609, KEY_CHANNELUP }, /* CH+ */ - { 0x61d60a, KEY_9 }, + { 0x61d60a, KEY_NUMERIC_9 }, { 0x61d60b, KEY_ZOOM }, /* Zoom */ - { 0x61d60c, KEY_7 }, - { 0x61d60d, KEY_8 }, + { 0x61d60c, KEY_NUMERIC_7 }, + { 0x61d60d, KEY_NUMERIC_8 }, { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */ - { 0x61d60f, KEY_4 }, + { 0x61d60f, KEY_NUMERIC_4 }, { 0x61d610, KEY_ESC }, /* [back up arrow] */ - { 0x61d611, KEY_0 }, + { 0x61d611, KEY_NUMERIC_0 }, { 0x61d612, KEY_OK }, /* [enter arrow] */ { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */ { 0x61d614, KEY_RECORD }, /* Rec */ diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c index 78cf2c286083..42270a7ef3ee 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c @@ -44,16 +44,16 @@ static struct rc_map_table msi_tvanywhere_plus[] = { << FUNC >> RESET */ - { 0x01, KEY_1 }, /* 1 */ - { 0x0b, KEY_2 }, /* 2 */ - { 0x1b, KEY_3 }, /* 3 */ - { 0x05, KEY_4 }, /* 4 */ - { 0x09, KEY_5 }, /* 5 */ - { 0x15, KEY_6 }, /* 6 */ - { 0x06, KEY_7 }, /* 7 */ - { 0x0a, KEY_8 }, /* 8 */ - { 0x12, KEY_9 }, /* 9 */ - { 0x02, KEY_0 }, /* 0 */ + { 0x01, KEY_NUMERIC_1 }, /* 1 */ + { 0x0b, KEY_NUMERIC_2 }, /* 2 */ + { 0x1b, KEY_NUMERIC_3 }, /* 3 */ + { 0x05, KEY_NUMERIC_4 }, /* 4 */ + { 0x09, KEY_NUMERIC_5 }, /* 5 */ + { 0x15, KEY_NUMERIC_6 }, /* 6 */ + { 0x06, KEY_NUMERIC_7 }, /* 7 */ + { 0x0a, KEY_NUMERIC_8 }, /* 8 */ + { 0x12, KEY_NUMERIC_9 }, /* 9 */ + { 0x02, KEY_NUMERIC_0 }, /* 0 */ { 0x10, KEY_KPPLUS }, /* + */ { 0x13, KEY_AGAIN }, /* Recall */ diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c index 359a57be3a66..45793c641009 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c @@ -12,16 +12,16 @@ static struct rc_map_table msi_tvanywhere[] = { /* Keys 0 to 9 */ - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x0c, KEY_MUTE }, { 0x0f, KEY_SCREEN }, /* Full Screen */ diff --git a/drivers/media/rc/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c index 17d7c1b324da..2dc6061f69b3 100644 --- a/drivers/media/rc/keymaps/rc-nebula.c +++ b/drivers/media/rc/keymaps/rc-nebula.c @@ -9,16 +9,16 @@ #include <linux/module.h> static struct rc_map_table nebula[] = { - { 0x0000, KEY_0 }, - { 0x0001, KEY_1 }, - { 0x0002, KEY_2 }, - { 0x0003, KEY_3 }, - { 0x0004, KEY_4 }, - { 0x0005, KEY_5 }, - { 0x0006, KEY_6 }, - { 0x0007, KEY_7 }, - { 0x0008, KEY_8 }, - { 0x0009, KEY_9 }, + { 0x0000, KEY_NUMERIC_0 }, + { 0x0001, KEY_NUMERIC_1 }, + { 0x0002, KEY_NUMERIC_2 }, + { 0x0003, KEY_NUMERIC_3 }, + { 0x0004, KEY_NUMERIC_4 }, + { 0x0005, KEY_NUMERIC_5 }, + { 0x0006, KEY_NUMERIC_6 }, + { 0x0007, KEY_NUMERIC_7 }, + { 0x0008, KEY_NUMERIC_8 }, + { 0x0009, KEY_NUMERIC_9 }, { 0x000a, KEY_TV }, { 0x000b, KEY_AUX }, { 0x000c, KEY_DVD }, diff --git a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c index 76beef44a8d7..b12c54d47db3 100644 --- a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c @@ -23,16 +23,16 @@ static struct rc_map_table nec_terratec_cinergy_xs[] = { { 0x1444, KEY_TEXT}, /* Teletext */ { 0x1445, KEY_DELETE}, - { 0x1402, KEY_1}, - { 0x1403, KEY_2}, - { 0x1404, KEY_3}, - { 0x1405, KEY_4}, - { 0x1406, KEY_5}, - { 0x1407, KEY_6}, - { 0x1408, KEY_7}, - { 0x1409, KEY_8}, - { 0x140a, KEY_9}, - { 0x140c, KEY_0}, + { 0x1402, KEY_NUMERIC_1}, + { 0x1403, KEY_NUMERIC_2}, + { 0x1404, KEY_NUMERIC_3}, + { 0x1405, KEY_NUMERIC_4}, + { 0x1406, KEY_NUMERIC_5}, + { 0x1407, KEY_NUMERIC_6}, + { 0x1408, KEY_NUMERIC_7}, + { 0x1409, KEY_NUMERIC_8}, + { 0x140a, KEY_NUMERIC_9}, + { 0x140c, KEY_NUMERIC_0}, { 0x140b, KEY_TUNER}, /* AV */ { 0x140d, KEY_MODE}, /* A.B */ @@ -79,16 +79,16 @@ static struct rc_map_table nec_terratec_cinergy_xs[] = { /* Terratec Black IR, with most keys in black */ { 0x04eb01, KEY_POWER2}, - { 0x04eb02, KEY_1}, - { 0x04eb03, KEY_2}, - { 0x04eb04, KEY_3}, - { 0x04eb05, KEY_4}, - { 0x04eb06, KEY_5}, - { 0x04eb07, KEY_6}, - { 0x04eb08, KEY_7}, - { 0x04eb09, KEY_8}, - { 0x04eb0a, KEY_9}, - { 0x04eb0c, KEY_0}, + { 0x04eb02, KEY_NUMERIC_1}, + { 0x04eb03, KEY_NUMERIC_2}, + { 0x04eb04, KEY_NUMERIC_3}, + { 0x04eb05, KEY_NUMERIC_4}, + { 0x04eb06, KEY_NUMERIC_5}, + { 0x04eb07, KEY_NUMERIC_6}, + { 0x04eb08, KEY_NUMERIC_7}, + { 0x04eb09, KEY_NUMERIC_8}, + { 0x04eb0a, KEY_NUMERIC_9}, + { 0x04eb0c, KEY_NUMERIC_0}, { 0x04eb0b, KEY_TEXT}, /* TXT */ { 0x04eb0d, KEY_REFRESH}, /* Refresh */ diff --git a/drivers/media/rc/keymaps/rc-norwood.c b/drivers/media/rc/keymaps/rc-norwood.c index 3765705c5549..acd5b1ccf8d0 100644 --- a/drivers/media/rc/keymaps/rc-norwood.c +++ b/drivers/media/rc/keymaps/rc-norwood.c @@ -14,16 +14,16 @@ static struct rc_map_table norwood[] = { /* Keys 0 to 9 */ - { 0x20, KEY_0 }, - { 0x21, KEY_1 }, - { 0x22, KEY_2 }, - { 0x23, KEY_3 }, - { 0x24, KEY_4 }, - { 0x25, KEY_5 }, - { 0x26, KEY_6 }, - { 0x27, KEY_7 }, - { 0x28, KEY_8 }, - { 0x29, KEY_9 }, + { 0x20, KEY_NUMERIC_0 }, + { 0x21, KEY_NUMERIC_1 }, + { 0x22, KEY_NUMERIC_2 }, + { 0x23, KEY_NUMERIC_3 }, + { 0x24, KEY_NUMERIC_4 }, + { 0x25, KEY_NUMERIC_5 }, + { 0x26, KEY_NUMERIC_6 }, + { 0x27, KEY_NUMERIC_7 }, + { 0x28, KEY_NUMERIC_8 }, + { 0x29, KEY_NUMERIC_9 }, { 0x78, KEY_VIDEO }, /* Video Source */ { 0x2c, KEY_EXIT }, /* Open/Close software */ diff --git a/drivers/media/rc/keymaps/rc-npgtech.c b/drivers/media/rc/keymaps/rc-npgtech.c index abaf7f6d4cb7..98a755e8bc18 100644 --- a/drivers/media/rc/keymaps/rc-npgtech.c +++ b/drivers/media/rc/keymaps/rc-npgtech.c @@ -12,16 +12,16 @@ static struct rc_map_table npgtech[] = { { 0x1d, KEY_SWITCHVIDEOMODE }, /* switch inputs */ { 0x2a, KEY_FRONT }, - { 0x3e, KEY_1 }, - { 0x02, KEY_2 }, - { 0x06, KEY_3 }, - { 0x0a, KEY_4 }, - { 0x0e, KEY_5 }, - { 0x12, KEY_6 }, - { 0x16, KEY_7 }, - { 0x1a, KEY_8 }, - { 0x1e, KEY_9 }, - { 0x3a, KEY_0 }, + { 0x3e, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x06, KEY_NUMERIC_3 }, + { 0x0a, KEY_NUMERIC_4 }, + { 0x0e, KEY_NUMERIC_5 }, + { 0x12, KEY_NUMERIC_6 }, + { 0x16, KEY_NUMERIC_7 }, + { 0x1a, KEY_NUMERIC_8 }, + { 0x1e, KEY_NUMERIC_9 }, + { 0x3a, KEY_NUMERIC_0 }, { 0x22, KEY_NUMLOCK }, /* -/-- */ { 0x20, KEY_REFRESH }, diff --git a/drivers/media/rc/keymaps/rc-pctv-sedna.c b/drivers/media/rc/keymaps/rc-pctv-sedna.c index e3462c5c8984..c3bb1ecdd0ca 100644 --- a/drivers/media/rc/keymaps/rc-pctv-sedna.c +++ b/drivers/media/rc/keymaps/rc-pctv-sedna.c @@ -14,16 +14,16 @@ Also for the remote bundled with Kozumi KTV-01C card */ static struct rc_map_table pctv_sedna[] = { - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x0a, KEY_AGAIN }, /* Recall */ { 0x0b, KEY_CHANNELUP }, diff --git a/drivers/media/rc/keymaps/rc-pinnacle-color.c b/drivers/media/rc/keymaps/rc-pinnacle-color.c index 63c2851e9dfe..b862725635b9 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-color.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-color.c @@ -49,16 +49,16 @@ static struct rc_map_table pinnacle_color[] = { { 0x4c, KEY_STOP }, { 0x54, KEY_NEXT }, - { 0x69, KEY_0 }, - { 0x6a, KEY_1 }, - { 0x6b, KEY_2 }, - { 0x6c, KEY_3 }, - { 0x6d, KEY_4 }, - { 0x6e, KEY_5 }, - { 0x6f, KEY_6 }, - { 0x70, KEY_7 }, - { 0x71, KEY_8 }, - { 0x72, KEY_9 }, + { 0x69, KEY_NUMERIC_0 }, + { 0x6a, KEY_NUMERIC_1 }, + { 0x6b, KEY_NUMERIC_2 }, + { 0x6c, KEY_NUMERIC_3 }, + { 0x6d, KEY_NUMERIC_4 }, + { 0x6e, KEY_NUMERIC_5 }, + { 0x6f, KEY_NUMERIC_6 }, + { 0x70, KEY_NUMERIC_7 }, + { 0x71, KEY_NUMERIC_8 }, + { 0x72, KEY_NUMERIC_9 }, { 0x74, KEY_CHANNEL }, { 0x0a, KEY_BACKSPACE }, diff --git a/drivers/media/rc/keymaps/rc-pinnacle-grey.c b/drivers/media/rc/keymaps/rc-pinnacle-grey.c index 31794d4180db..3853b653cee6 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-grey.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-grey.c @@ -9,16 +9,16 @@ #include <linux/module.h> static struct rc_map_table pinnacle_grey[] = { - { 0x3a, KEY_0 }, - { 0x31, KEY_1 }, - { 0x32, KEY_2 }, - { 0x33, KEY_3 }, - { 0x34, KEY_4 }, - { 0x35, KEY_5 }, - { 0x36, KEY_6 }, - { 0x37, KEY_7 }, - { 0x38, KEY_8 }, - { 0x39, KEY_9 }, + { 0x3a, KEY_NUMERIC_0 }, + { 0x31, KEY_NUMERIC_1 }, + { 0x32, KEY_NUMERIC_2 }, + { 0x33, KEY_NUMERIC_3 }, + { 0x34, KEY_NUMERIC_4 }, + { 0x35, KEY_NUMERIC_5 }, + { 0x36, KEY_NUMERIC_6 }, + { 0x37, KEY_NUMERIC_7 }, + { 0x38, KEY_NUMERIC_8 }, + { 0x39, KEY_NUMERIC_9 }, { 0x2f, KEY_POWER }, diff --git a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c index 876aeb6e1d9c..96d8112fb468 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c @@ -20,16 +20,16 @@ static struct rc_map_table pinnacle_pctv_hd[] = { { 0x0709, KEY_VOLUMEDOWN }, { 0x0706, KEY_CHANNELUP }, { 0x070c, KEY_CHANNELDOWN }, - { 0x070f, KEY_1 }, - { 0x0715, KEY_2 }, - { 0x0710, KEY_3 }, - { 0x0718, KEY_4 }, - { 0x071b, KEY_5 }, - { 0x071e, KEY_6 }, - { 0x0711, KEY_7 }, - { 0x0721, KEY_8 }, - { 0x0712, KEY_9 }, - { 0x0727, KEY_0 }, + { 0x070f, KEY_NUMERIC_1 }, + { 0x0715, KEY_NUMERIC_2 }, + { 0x0710, KEY_NUMERIC_3 }, + { 0x0718, KEY_NUMERIC_4 }, + { 0x071b, KEY_NUMERIC_5 }, + { 0x071e, KEY_NUMERIC_6 }, + { 0x0711, KEY_NUMERIC_7 }, + { 0x0721, KEY_NUMERIC_8 }, + { 0x0712, KEY_NUMERIC_9 }, + { 0x0727, KEY_NUMERIC_0 }, { 0x0724, KEY_ZOOM }, /* 'Square' key */ { 0x072a, KEY_SUBTITLE }, /* 'T' key */ { 0x072d, KEY_REWIND }, diff --git a/drivers/media/rc/keymaps/rc-pixelview-002t.c b/drivers/media/rc/keymaps/rc-pixelview-002t.c index c0550e09f255..c3439c46644c 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-002t.c +++ b/drivers/media/rc/keymaps/rc-pixelview-002t.c @@ -16,16 +16,16 @@ static struct rc_map_table pixelview_002t[] = { { 0x866b13, KEY_MUTE }, { 0x866b12, KEY_POWER2 }, /* power */ - { 0x866b01, KEY_1 }, - { 0x866b02, KEY_2 }, - { 0x866b03, KEY_3 }, - { 0x866b04, KEY_4 }, - { 0x866b05, KEY_5 }, - { 0x866b06, KEY_6 }, - { 0x866b07, KEY_7 }, - { 0x866b08, KEY_8 }, - { 0x866b09, KEY_9 }, - { 0x866b00, KEY_0 }, + { 0x866b01, KEY_NUMERIC_1 }, + { 0x866b02, KEY_NUMERIC_2 }, + { 0x866b03, KEY_NUMERIC_3 }, + { 0x866b04, KEY_NUMERIC_4 }, + { 0x866b05, KEY_NUMERIC_5 }, + { 0x866b06, KEY_NUMERIC_6 }, + { 0x866b07, KEY_NUMERIC_7 }, + { 0x866b08, KEY_NUMERIC_8 }, + { 0x866b09, KEY_NUMERIC_9 }, + { 0x866b00, KEY_NUMERIC_0 }, { 0x866b0d, KEY_CHANNELUP }, { 0x866b19, KEY_CHANNELDOWN }, diff --git a/drivers/media/rc/keymaps/rc-pixelview-mk12.c b/drivers/media/rc/keymaps/rc-pixelview-mk12.c index 864c8ea5d8e3..ea11ccde8442 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-mk12.c +++ b/drivers/media/rc/keymaps/rc-pixelview-mk12.c @@ -16,16 +16,16 @@ static struct rc_map_table pixelview_mk12[] = { { 0x866b03, KEY_TUNER }, /* Timeshift */ { 0x866b1e, KEY_POWER2 }, /* power */ - { 0x866b01, KEY_1 }, - { 0x866b0b, KEY_2 }, - { 0x866b1b, KEY_3 }, - { 0x866b05, KEY_4 }, - { 0x866b09, KEY_5 }, - { 0x866b15, KEY_6 }, - { 0x866b06, KEY_7 }, - { 0x866b0a, KEY_8 }, - { 0x866b12, KEY_9 }, - { 0x866b02, KEY_0 }, + { 0x866b01, KEY_NUMERIC_1 }, + { 0x866b0b, KEY_NUMERIC_2 }, + { 0x866b1b, KEY_NUMERIC_3 }, + { 0x866b05, KEY_NUMERIC_4 }, + { 0x866b09, KEY_NUMERIC_5 }, + { 0x866b15, KEY_NUMERIC_6 }, + { 0x866b06, KEY_NUMERIC_7 }, + { 0x866b0a, KEY_NUMERIC_8 }, + { 0x866b12, KEY_NUMERIC_9 }, + { 0x866b02, KEY_NUMERIC_0 }, { 0x866b13, KEY_AGAIN }, /* loop */ { 0x866b10, KEY_DIGITS }, /* +100 */ diff --git a/drivers/media/rc/keymaps/rc-pixelview-new.c b/drivers/media/rc/keymaps/rc-pixelview-new.c index e4e34f2ccf74..0259666831b0 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-new.c +++ b/drivers/media/rc/keymaps/rc-pixelview-new.c @@ -17,16 +17,16 @@ static struct rc_map_table pixelview_new[] = { { 0x3c, KEY_TIME }, /* Timeshift */ { 0x12, KEY_POWER }, - { 0x3d, KEY_1 }, - { 0x38, KEY_2 }, - { 0x18, KEY_3 }, - { 0x35, KEY_4 }, - { 0x39, KEY_5 }, - { 0x15, KEY_6 }, - { 0x36, KEY_7 }, - { 0x3a, KEY_8 }, - { 0x1e, KEY_9 }, - { 0x3e, KEY_0 }, + { 0x3d, KEY_NUMERIC_1 }, + { 0x38, KEY_NUMERIC_2 }, + { 0x18, KEY_NUMERIC_3 }, + { 0x35, KEY_NUMERIC_4 }, + { 0x39, KEY_NUMERIC_5 }, + { 0x15, KEY_NUMERIC_6 }, + { 0x36, KEY_NUMERIC_7 }, + { 0x3a, KEY_NUMERIC_8 }, + { 0x1e, KEY_NUMERIC_9 }, + { 0x3e, KEY_NUMERIC_0 }, { 0x1c, KEY_AGAIN }, /* LOOP */ { 0x3f, KEY_VIDEO }, /* Source */ diff --git a/drivers/media/rc/keymaps/rc-pixelview.c b/drivers/media/rc/keymaps/rc-pixelview.c index 988919735165..29f6d2c013e4 100644 --- a/drivers/media/rc/keymaps/rc-pixelview.c +++ b/drivers/media/rc/keymaps/rc-pixelview.c @@ -25,16 +25,16 @@ static struct rc_map_table pixelview[] = { { 0x19, KEY_ZOOM }, /* zoom */ { 0x0f, KEY_TEXT }, /* min */ - { 0x01, KEY_1 }, - { 0x0b, KEY_2 }, - { 0x1b, KEY_3 }, - { 0x05, KEY_4 }, - { 0x09, KEY_5 }, - { 0x15, KEY_6 }, - { 0x06, KEY_7 }, - { 0x0a, KEY_8 }, - { 0x12, KEY_9 }, - { 0x02, KEY_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x0b, KEY_NUMERIC_2 }, + { 0x1b, KEY_NUMERIC_3 }, + { 0x05, KEY_NUMERIC_4 }, + { 0x09, KEY_NUMERIC_5 }, + { 0x15, KEY_NUMERIC_6 }, + { 0x06, KEY_NUMERIC_7 }, + { 0x0a, KEY_NUMERIC_8 }, + { 0x12, KEY_NUMERIC_9 }, + { 0x02, KEY_NUMERIC_0 }, { 0x10, KEY_LAST }, /* +100 */ { 0x13, KEY_LIST }, /* recall */ diff --git a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c index cf98cf8dc13c..66fe2e52e7c8 100644 --- a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c +++ b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c @@ -16,16 +16,16 @@ static struct rc_map_table powercolor_real_angel[] = { { 0x38, KEY_SWITCHVIDEOMODE }, /* switch inputs */ { 0x0c, KEY_MEDIA }, /* Turn ON/OFF App */ - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x0a, KEY_DIGITS }, /* single, double, triple digit */ { 0x29, KEY_PREVIOUS }, /* previous channel */ { 0x12, KEY_BRIGHTNESSUP }, diff --git a/drivers/media/rc/keymaps/rc-proteus-2309.c b/drivers/media/rc/keymaps/rc-proteus-2309.c index d2c13d0e7bff..36eebefd975c 100644 --- a/drivers/media/rc/keymaps/rc-proteus-2309.c +++ b/drivers/media/rc/keymaps/rc-proteus-2309.c @@ -12,16 +12,16 @@ static struct rc_map_table proteus_2309[] = { /* numeric */ - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x5c, KEY_POWER }, /* power */ { 0x20, KEY_ZOOM }, /* full screen */ diff --git a/drivers/media/rc/keymaps/rc-purpletv.c b/drivers/media/rc/keymaps/rc-purpletv.c index c8011f4d96ea..bf4543fecb6f 100644 --- a/drivers/media/rc/keymaps/rc-purpletv.c +++ b/drivers/media/rc/keymaps/rc-purpletv.c @@ -13,16 +13,16 @@ static struct rc_map_table purpletv[] = { { 0x6f, KEY_MUTE }, { 0x10, KEY_BACKSPACE }, /* Recall */ - { 0x11, KEY_0 }, - { 0x04, KEY_1 }, - { 0x05, KEY_2 }, - { 0x06, KEY_3 }, - { 0x08, KEY_4 }, - { 0x09, KEY_5 }, - { 0x0a, KEY_6 }, - { 0x0c, KEY_7 }, - { 0x0d, KEY_8 }, - { 0x0e, KEY_9 }, + { 0x11, KEY_NUMERIC_0 }, + { 0x04, KEY_NUMERIC_1 }, + { 0x05, KEY_NUMERIC_2 }, + { 0x06, KEY_NUMERIC_3 }, + { 0x08, KEY_NUMERIC_4 }, + { 0x09, KEY_NUMERIC_5 }, + { 0x0a, KEY_NUMERIC_6 }, + { 0x0c, KEY_NUMERIC_7 }, + { 0x0d, KEY_NUMERIC_8 }, + { 0x0e, KEY_NUMERIC_9 }, { 0x12, KEY_DOT }, /* 100+ */ { 0x07, KEY_VOLUMEUP }, diff --git a/drivers/media/rc/keymaps/rc-pv951.c b/drivers/media/rc/keymaps/rc-pv951.c index 5235ee899c30..69db55463000 100644 --- a/drivers/media/rc/keymaps/rc-pv951.c +++ b/drivers/media/rc/keymaps/rc-pv951.c @@ -11,16 +11,16 @@ /* Mark Phalan <phalanm@o2.ie> */ static struct rc_map_table pv951[] = { - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x12, KEY_POWER }, { 0x10, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c index 1cf786649675..33bb458b81fd 100644 --- a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c +++ b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c @@ -14,16 +14,16 @@ static struct rc_map_table real_audio_220_32_keys[] = { { 0x1c, KEY_RADIO}, { 0x12, KEY_POWER2}, - { 0x01, KEY_1}, - { 0x02, KEY_2}, - { 0x03, KEY_3}, - { 0x04, KEY_4}, - { 0x05, KEY_5}, - { 0x06, KEY_6}, - { 0x07, KEY_7}, - { 0x08, KEY_8}, - { 0x09, KEY_9}, - { 0x00, KEY_0}, + { 0x01, KEY_NUMERIC_1}, + { 0x02, KEY_NUMERIC_2}, + { 0x03, KEY_NUMERIC_3}, + { 0x04, KEY_NUMERIC_4}, + { 0x05, KEY_NUMERIC_5}, + { 0x06, KEY_NUMERIC_6}, + { 0x07, KEY_NUMERIC_7}, + { 0x08, KEY_NUMERIC_8}, + { 0x09, KEY_NUMERIC_9}, + { 0x00, KEY_NUMERIC_0}, { 0x0c, KEY_VOLUMEUP}, { 0x18, KEY_VOLUMEDOWN}, diff --git a/drivers/media/rc/keymaps/rc-reddo.c b/drivers/media/rc/keymaps/rc-reddo.c index a68003381540..b70390d19e78 100644 --- a/drivers/media/rc/keymaps/rc-reddo.c +++ b/drivers/media/rc/keymaps/rc-reddo.c @@ -23,21 +23,21 @@ static struct rc_map_table reddo[] = { { 0x61d601, KEY_EPG }, /* EPG */ - { 0x61d602, KEY_3 }, - { 0x61d604, KEY_1 }, - { 0x61d605, KEY_5 }, - { 0x61d606, KEY_6 }, + { 0x61d602, KEY_NUMERIC_3 }, + { 0x61d604, KEY_NUMERIC_1 }, + { 0x61d605, KEY_NUMERIC_5 }, + { 0x61d606, KEY_NUMERIC_6 }, { 0x61d607, KEY_CHANNELDOWN }, /* CH- */ - { 0x61d608, KEY_2 }, + { 0x61d608, KEY_NUMERIC_2 }, { 0x61d609, KEY_CHANNELUP }, /* CH+ */ - { 0x61d60a, KEY_9 }, + { 0x61d60a, KEY_NUMERIC_9 }, { 0x61d60b, KEY_ZOOM }, /* Zoom */ - { 0x61d60c, KEY_7 }, - { 0x61d60d, KEY_8 }, + { 0x61d60c, KEY_NUMERIC_7 }, + { 0x61d60d, KEY_NUMERIC_8 }, { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */ - { 0x61d60f, KEY_4 }, + { 0x61d60f, KEY_NUMERIC_4 }, { 0x61d610, KEY_ESC }, /* [back up arrow] */ - { 0x61d611, KEY_0 }, + { 0x61d611, KEY_NUMERIC_0 }, { 0x61d612, KEY_OK }, /* [enter arrow] */ { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */ { 0x61d614, KEY_RECORD }, /* Rec */ diff --git a/drivers/media/rc/keymaps/rc-snapstream-firefly.c b/drivers/media/rc/keymaps/rc-snapstream-firefly.c index 8d55b4ccee83..e3d5bff3bd9e 100644 --- a/drivers/media/rc/keymaps/rc-snapstream-firefly.c +++ b/drivers/media/rc/keymaps/rc-snapstream-firefly.c @@ -12,16 +12,16 @@ static struct rc_map_table snapstream_firefly[] = { { 0x2c, KEY_ZOOM }, /* Maximize */ { 0x02, KEY_CLOSE }, - { 0x0d, KEY_1 }, - { 0x0e, KEY_2 }, - { 0x0f, KEY_3 }, - { 0x10, KEY_4 }, - { 0x11, KEY_5 }, - { 0x12, KEY_6 }, - { 0x13, KEY_7 }, - { 0x14, KEY_8 }, - { 0x15, KEY_9 }, - { 0x17, KEY_0 }, + { 0x0d, KEY_NUMERIC_1 }, + { 0x0e, KEY_NUMERIC_2 }, + { 0x0f, KEY_NUMERIC_3 }, + { 0x10, KEY_NUMERIC_4 }, + { 0x11, KEY_NUMERIC_5 }, + { 0x12, KEY_NUMERIC_6 }, + { 0x13, KEY_NUMERIC_7 }, + { 0x14, KEY_NUMERIC_8 }, + { 0x15, KEY_NUMERIC_9 }, + { 0x17, KEY_NUMERIC_0 }, { 0x16, KEY_BACK }, { 0x18, KEY_KPENTER }, /* ent */ diff --git a/drivers/media/rc/keymaps/rc-su3000.c b/drivers/media/rc/keymaps/rc-su3000.c index 1c82737e3999..64cfc01aa48f 100644 --- a/drivers/media/rc/keymaps/rc-su3000.c +++ b/drivers/media/rc/keymaps/rc-su3000.c @@ -10,16 +10,16 @@ static struct rc_map_table su3000[] = { { 0x25, KEY_POWER }, /* right-bottom Red */ { 0x0a, KEY_MUTE }, /* -/-- */ - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x00, KEY_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, + { 0x00, KEY_NUMERIC_0 }, { 0x20, KEY_UP }, /* CH+ */ { 0x21, KEY_DOWN }, /* CH+ */ { 0x12, KEY_VOLUMEUP }, /* Brightness Up */ diff --git a/drivers/media/rc/keymaps/rc-tango.c b/drivers/media/rc/keymaps/rc-tango.c index 1c6e8875d46f..2b9cef6ef5b5 100644 --- a/drivers/media/rc/keymaps/rc-tango.c +++ b/drivers/media/rc/keymaps/rc-tango.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 Sigma Designs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #include <linux/module.h> @@ -20,16 +17,16 @@ static struct rc_map_table tango_table[] = { { 0x4cb51, KEY_MUTE }, { 0x4cb52, KEY_VOLUMEDOWN }, - { 0x4cb41, KEY_1 }, - { 0x4cb03, KEY_2 }, - { 0x4cb42, KEY_3 }, - { 0x4cb45, KEY_4 }, - { 0x4cb07, KEY_5 }, - { 0x4cb46, KEY_6 }, - { 0x4cb55, KEY_7 }, - { 0x4cb17, KEY_8 }, - { 0x4cb56, KEY_9 }, - { 0x4cb1b, KEY_0 }, + { 0x4cb41, KEY_NUMERIC_1 }, + { 0x4cb03, KEY_NUMERIC_2 }, + { 0x4cb42, KEY_NUMERIC_3 }, + { 0x4cb45, KEY_NUMERIC_4 }, + { 0x4cb07, KEY_NUMERIC_5 }, + { 0x4cb46, KEY_NUMERIC_6 }, + { 0x4cb55, KEY_NUMERIC_7 }, + { 0x4cb17, KEY_NUMERIC_8 }, + { 0x4cb56, KEY_NUMERIC_9 }, + { 0x4cb1b, KEY_NUMERIC_0 }, { 0x4cb59, KEY_DELETE }, { 0x4cb5a, KEY_CAPSLOCK }, diff --git a/drivers/media/rc/keymaps/rc-tbs-nec.c b/drivers/media/rc/keymaps/rc-tbs-nec.c index 42766cb877c3..420980925f29 100644 --- a/drivers/media/rc/keymaps/rc-tbs-nec.c +++ b/drivers/media/rc/keymaps/rc-tbs-nec.c @@ -11,16 +11,16 @@ static struct rc_map_table tbs_nec[] = { { 0x84, KEY_POWER2}, /* power */ { 0x94, KEY_MUTE}, /* mute */ - { 0x87, KEY_1}, - { 0x86, KEY_2}, - { 0x85, KEY_3}, - { 0x8b, KEY_4}, - { 0x8a, KEY_5}, - { 0x89, KEY_6}, - { 0x8f, KEY_7}, - { 0x8e, KEY_8}, - { 0x8d, KEY_9}, - { 0x92, KEY_0}, + { 0x87, KEY_NUMERIC_1}, + { 0x86, KEY_NUMERIC_2}, + { 0x85, KEY_NUMERIC_3}, + { 0x8b, KEY_NUMERIC_4}, + { 0x8a, KEY_NUMERIC_5}, + { 0x89, KEY_NUMERIC_6}, + { 0x8f, KEY_NUMERIC_7}, + { 0x8e, KEY_NUMERIC_8}, + { 0x8d, KEY_NUMERIC_9}, + { 0x92, KEY_NUMERIC_0}, { 0xc0, KEY_10CHANNELSUP}, /* 10+ */ { 0xd0, KEY_10CHANNELSDOWN}, /* 10- */ { 0x96, KEY_CHANNELUP}, /* ch+ */ diff --git a/drivers/media/rc/keymaps/rc-technisat-ts35.c b/drivers/media/rc/keymaps/rc-technisat-ts35.c index 34bd04a75277..9a917ea0ceba 100644 --- a/drivers/media/rc/keymaps/rc-technisat-ts35.c +++ b/drivers/media/rc/keymaps/rc-technisat-ts35.c @@ -13,16 +13,16 @@ static struct rc_map_table technisat_ts35[] = { {0x1c, KEY_AB}, {0x33, KEY_POWER}, - {0x3e, KEY_1}, - {0x3d, KEY_2}, - {0x3c, KEY_3}, - {0x3b, KEY_4}, - {0x3a, KEY_5}, - {0x39, KEY_6}, - {0x38, KEY_7}, - {0x37, KEY_8}, - {0x36, KEY_9}, - {0x3f, KEY_0}, + {0x3e, KEY_NUMERIC_1}, + {0x3d, KEY_NUMERIC_2}, + {0x3c, KEY_NUMERIC_3}, + {0x3b, KEY_NUMERIC_4}, + {0x3a, KEY_NUMERIC_5}, + {0x39, KEY_NUMERIC_6}, + {0x38, KEY_NUMERIC_7}, + {0x37, KEY_NUMERIC_8}, + {0x36, KEY_NUMERIC_9}, + {0x3f, KEY_NUMERIC_0}, {0x35, KEY_DIGITS}, {0x2c, KEY_TV}, diff --git a/drivers/media/rc/keymaps/rc-technisat-usb2.c b/drivers/media/rc/keymaps/rc-technisat-usb2.c index 58b3baf5ee96..942100686c82 100644 --- a/drivers/media/rc/keymaps/rc-technisat-usb2.c +++ b/drivers/media/rc/keymaps/rc-technisat-usb2.c @@ -30,18 +30,18 @@ static struct rc_map_table technisat_usb2[] = { {0x0a0c, KEY_POWER}, - {0x0a01, KEY_1}, - {0x0a02, KEY_2}, - {0x0a03, KEY_3}, + {0x0a01, KEY_NUMERIC_1}, + {0x0a02, KEY_NUMERIC_2}, + {0x0a03, KEY_NUMERIC_3}, {0x0a0d, KEY_MUTE}, - {0x0a04, KEY_4}, - {0x0a05, KEY_5}, - {0x0a06, KEY_6}, + {0x0a04, KEY_NUMERIC_4}, + {0x0a05, KEY_NUMERIC_5}, + {0x0a06, KEY_NUMERIC_6}, {0x0a38, KEY_VIDEO}, /* EXT */ - {0x0a07, KEY_7}, - {0x0a08, KEY_8}, - {0x0a09, KEY_9}, - {0x0a00, KEY_0}, + {0x0a07, KEY_NUMERIC_7}, + {0x0a08, KEY_NUMERIC_8}, + {0x0a09, KEY_NUMERIC_9}, + {0x0a00, KEY_NUMERIC_0}, {0x0a4f, KEY_INFO}, {0x0a20, KEY_CHANNELUP}, {0x0a52, KEY_MENU}, diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c index 4b2741b158c4..da06f844d8fb 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c @@ -9,17 +9,17 @@ static struct rc_map_table terratec_cinergy_c_pci[] = { { 0x3e, KEY_POWER}, - { 0x3d, KEY_1}, - { 0x3c, KEY_2}, - { 0x3b, KEY_3}, - { 0x3a, KEY_4}, - { 0x39, KEY_5}, - { 0x38, KEY_6}, - { 0x37, KEY_7}, - { 0x36, KEY_8}, - { 0x35, KEY_9}, + { 0x3d, KEY_NUMERIC_1}, + { 0x3c, KEY_NUMERIC_2}, + { 0x3b, KEY_NUMERIC_3}, + { 0x3a, KEY_NUMERIC_4}, + { 0x39, KEY_NUMERIC_5}, + { 0x38, KEY_NUMERIC_6}, + { 0x37, KEY_NUMERIC_7}, + { 0x36, KEY_NUMERIC_8}, + { 0x35, KEY_NUMERIC_9}, { 0x34, KEY_VIDEO_NEXT}, /* AV */ - { 0x33, KEY_0}, + { 0x33, KEY_NUMERIC_0}, { 0x32, KEY_REFRESH}, { 0x30, KEY_EPG}, { 0x2f, KEY_UP}, diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c index 631f86665206..a1844b531572 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c @@ -42,17 +42,17 @@ static struct rc_map_table terratec_cinergy_s2_hd[] = { { 0x2f, KEY_UP}, { 0x30, KEY_EPG}, { 0x32, KEY_VIDEO}, /* A<=>B */ - { 0x33, KEY_0}, + { 0x33, KEY_NUMERIC_0}, { 0x34, KEY_VCR}, /* AV */ - { 0x35, KEY_9}, - { 0x36, KEY_8}, - { 0x37, KEY_7}, - { 0x38, KEY_6}, - { 0x39, KEY_5}, - { 0x3a, KEY_4}, - { 0x3b, KEY_3}, - { 0x3c, KEY_2}, - { 0x3d, KEY_1}, + { 0x35, KEY_NUMERIC_9}, + { 0x36, KEY_NUMERIC_8}, + { 0x37, KEY_NUMERIC_7}, + { 0x38, KEY_NUMERIC_6}, + { 0x39, KEY_NUMERIC_5}, + { 0x3a, KEY_NUMERIC_4}, + { 0x3b, KEY_NUMERIC_3}, + { 0x3c, KEY_NUMERIC_2}, + { 0x3d, KEY_NUMERIC_1}, { 0x3e, KEY_POWER}, }; diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c index 6cf53a56bce4..fe587e3f0240 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c @@ -16,20 +16,20 @@ static struct rc_map_table terratec_cinergy_xs[] = { { 0x41, KEY_HOME}, { 0x01, KEY_POWER}, { 0x42, KEY_MENU}, - { 0x02, KEY_1}, - { 0x03, KEY_2}, - { 0x04, KEY_3}, + { 0x02, KEY_NUMERIC_1}, + { 0x03, KEY_NUMERIC_2}, + { 0x04, KEY_NUMERIC_3}, { 0x43, KEY_SUBTITLE}, - { 0x05, KEY_4}, - { 0x06, KEY_5}, - { 0x07, KEY_6}, + { 0x05, KEY_NUMERIC_4}, + { 0x06, KEY_NUMERIC_5}, + { 0x07, KEY_NUMERIC_6}, { 0x44, KEY_TEXT}, - { 0x08, KEY_7}, - { 0x09, KEY_8}, - { 0x0a, KEY_9}, + { 0x08, KEY_NUMERIC_7}, + { 0x09, KEY_NUMERIC_8}, + { 0x0a, KEY_NUMERIC_9}, { 0x45, KEY_DELETE}, { 0x0b, KEY_TUNER}, - { 0x0c, KEY_0}, + { 0x0c, KEY_NUMERIC_0}, { 0x0d, KEY_MODE}, { 0x46, KEY_TV}, { 0x47, KEY_DVD}, diff --git a/drivers/media/rc/keymaps/rc-terratec-slim-2.c b/drivers/media/rc/keymaps/rc-terratec-slim-2.c index bd1c1761b550..a54a59f90313 100644 --- a/drivers/media/rc/keymaps/rc-terratec-slim-2.c +++ b/drivers/media/rc/keymaps/rc-terratec-slim-2.c @@ -17,21 +17,21 @@ static struct rc_map_table terratec_slim_2[] = { { 0x8001, KEY_MUTE }, /* MUTE */ { 0x8002, KEY_VOLUMEDOWN }, { 0x8003, KEY_CHANNELDOWN }, - { 0x8004, KEY_1 }, - { 0x8005, KEY_2 }, - { 0x8006, KEY_3 }, - { 0x8007, KEY_4 }, - { 0x8008, KEY_5 }, - { 0x8009, KEY_6 }, - { 0x800a, KEY_7 }, + { 0x8004, KEY_NUMERIC_1 }, + { 0x8005, KEY_NUMERIC_2 }, + { 0x8006, KEY_NUMERIC_3 }, + { 0x8007, KEY_NUMERIC_4 }, + { 0x8008, KEY_NUMERIC_5 }, + { 0x8009, KEY_NUMERIC_6 }, + { 0x800a, KEY_NUMERIC_7 }, { 0x800c, KEY_ZOOM }, /* [fullscreen] */ - { 0x800d, KEY_0 }, + { 0x800d, KEY_NUMERIC_0 }, { 0x800e, KEY_AGAIN }, /* [two arrows forming a circle] */ { 0x8012, KEY_POWER2 }, /* [red power button] */ { 0x801a, KEY_VOLUMEUP }, - { 0x801b, KEY_8 }, + { 0x801b, KEY_NUMERIC_8 }, { 0x801e, KEY_CHANNELUP }, - { 0x801f, KEY_9 }, + { 0x801f, KEY_NUMERIC_9 }, }; static struct rc_map_list terratec_slim_2_map = { diff --git a/drivers/media/rc/keymaps/rc-terratec-slim.c b/drivers/media/rc/keymaps/rc-terratec-slim.c index b44942691388..146e3a3480dc 100644 --- a/drivers/media/rc/keymaps/rc-terratec-slim.c +++ b/drivers/media/rc/keymaps/rc-terratec-slim.c @@ -11,16 +11,16 @@ /* TerraTec slim remote, 7 rows, 4 columns. */ /* Uses NEC extended 0x02bd. */ static struct rc_map_table terratec_slim[] = { - { 0x02bd00, KEY_1 }, - { 0x02bd01, KEY_2 }, - { 0x02bd02, KEY_3 }, - { 0x02bd03, KEY_4 }, - { 0x02bd04, KEY_5 }, - { 0x02bd05, KEY_6 }, - { 0x02bd06, KEY_7 }, - { 0x02bd07, KEY_8 }, - { 0x02bd08, KEY_9 }, - { 0x02bd09, KEY_0 }, + { 0x02bd00, KEY_NUMERIC_1 }, + { 0x02bd01, KEY_NUMERIC_2 }, + { 0x02bd02, KEY_NUMERIC_3 }, + { 0x02bd03, KEY_NUMERIC_4 }, + { 0x02bd04, KEY_NUMERIC_5 }, + { 0x02bd05, KEY_NUMERIC_6 }, + { 0x02bd06, KEY_NUMERIC_7 }, + { 0x02bd07, KEY_NUMERIC_8 }, + { 0x02bd08, KEY_NUMERIC_9 }, + { 0x02bd09, KEY_NUMERIC_0 }, { 0x02bd0a, KEY_MUTE }, { 0x02bd0b, KEY_NEW }, /* symbol: PIP */ { 0x02bd0e, KEY_VOLUMEDOWN }, diff --git a/drivers/media/rc/keymaps/rc-tevii-nec.c b/drivers/media/rc/keymaps/rc-tevii-nec.c index 58fcc72f528e..5b96e9a38e9d 100644 --- a/drivers/media/rc/keymaps/rc-tevii-nec.c +++ b/drivers/media/rc/keymaps/rc-tevii-nec.c @@ -11,16 +11,16 @@ static struct rc_map_table tevii_nec[] = { { 0x0a, KEY_POWER2}, { 0x0c, KEY_MUTE}, - { 0x11, KEY_1}, - { 0x12, KEY_2}, - { 0x13, KEY_3}, - { 0x14, KEY_4}, - { 0x15, KEY_5}, - { 0x16, KEY_6}, - { 0x17, KEY_7}, - { 0x18, KEY_8}, - { 0x19, KEY_9}, - { 0x10, KEY_0}, + { 0x11, KEY_NUMERIC_1}, + { 0x12, KEY_NUMERIC_2}, + { 0x13, KEY_NUMERIC_3}, + { 0x14, KEY_NUMERIC_4}, + { 0x15, KEY_NUMERIC_5}, + { 0x16, KEY_NUMERIC_6}, + { 0x17, KEY_NUMERIC_7}, + { 0x18, KEY_NUMERIC_8}, + { 0x19, KEY_NUMERIC_9}, + { 0x10, KEY_NUMERIC_0}, { 0x1c, KEY_MENU}, { 0x0f, KEY_VOLUMEDOWN}, { 0x1a, KEY_LAST}, diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c b/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c index 7dfaf05f4934..40b773ba45b9 100644 --- a/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c +++ b/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c @@ -10,16 +10,16 @@ static struct rc_map_table total_media_in_hand_02[] = { - { 0x0000, KEY_0 }, - { 0x0001, KEY_1 }, - { 0x0002, KEY_2 }, - { 0x0003, KEY_3 }, - { 0x0004, KEY_4 }, - { 0x0005, KEY_5 }, - { 0x0006, KEY_6 }, - { 0x0007, KEY_7 }, - { 0x0008, KEY_8 }, - { 0x0009, KEY_9 }, + { 0x0000, KEY_NUMERIC_0 }, + { 0x0001, KEY_NUMERIC_1 }, + { 0x0002, KEY_NUMERIC_2 }, + { 0x0003, KEY_NUMERIC_3 }, + { 0x0004, KEY_NUMERIC_4 }, + { 0x0005, KEY_NUMERIC_5 }, + { 0x0006, KEY_NUMERIC_6 }, + { 0x0007, KEY_NUMERIC_7 }, + { 0x0008, KEY_NUMERIC_8 }, + { 0x0009, KEY_NUMERIC_9 }, { 0x000a, KEY_MUTE }, { 0x000b, KEY_STOP }, /* Stop */ { 0x000c, KEY_POWER2 }, /* Turn on/off application */ diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand.c b/drivers/media/rc/keymaps/rc-total-media-in-hand.c index a12569425b8b..2144db485d83 100644 --- a/drivers/media/rc/keymaps/rc-total-media-in-hand.c +++ b/drivers/media/rc/keymaps/rc-total-media-in-hand.c @@ -10,16 +10,16 @@ /* Uses NEC extended 0x02bd */ static struct rc_map_table total_media_in_hand[] = { - { 0x02bd00, KEY_1 }, - { 0x02bd01, KEY_2 }, - { 0x02bd02, KEY_3 }, - { 0x02bd03, KEY_4 }, - { 0x02bd04, KEY_5 }, - { 0x02bd05, KEY_6 }, - { 0x02bd06, KEY_7 }, - { 0x02bd07, KEY_8 }, - { 0x02bd08, KEY_9 }, - { 0x02bd09, KEY_0 }, + { 0x02bd00, KEY_NUMERIC_1 }, + { 0x02bd01, KEY_NUMERIC_2 }, + { 0x02bd02, KEY_NUMERIC_3 }, + { 0x02bd03, KEY_NUMERIC_4 }, + { 0x02bd04, KEY_NUMERIC_5 }, + { 0x02bd05, KEY_NUMERIC_6 }, + { 0x02bd06, KEY_NUMERIC_7 }, + { 0x02bd07, KEY_NUMERIC_8 }, + { 0x02bd08, KEY_NUMERIC_9 }, + { 0x02bd09, KEY_NUMERIC_0 }, { 0x02bd0a, KEY_MUTE }, { 0x02bd0b, KEY_CYCLEWINDOWS }, /* yellow, [min / max] */ { 0x02bd0c, KEY_VIDEO }, /* TV / AV */ diff --git a/drivers/media/rc/keymaps/rc-trekstor.c b/drivers/media/rc/keymaps/rc-trekstor.c index 8576831b20bd..e938e0da51a6 100644 --- a/drivers/media/rc/keymaps/rc-trekstor.c +++ b/drivers/media/rc/keymaps/rc-trekstor.c @@ -12,7 +12,7 @@ /* Imported from af9015.h. Initial keytable was from Marc Schneider <macke@macke.org> */ static struct rc_map_table trekstor[] = { - { 0x0084, KEY_0 }, + { 0x0084, KEY_NUMERIC_0 }, { 0x0085, KEY_MUTE }, /* Mute */ { 0x0086, KEY_HOMEPAGE }, /* Home */ { 0x0087, KEY_UP }, /* Up */ @@ -24,17 +24,17 @@ static struct rc_map_table trekstor[] = { { 0x008d, KEY_PLAY }, /* Play/Pause */ { 0x008e, KEY_STOP }, /* Stop */ { 0x008f, KEY_EPG }, /* Info/EPG */ - { 0x0090, KEY_7 }, - { 0x0091, KEY_4 }, - { 0x0092, KEY_1 }, + { 0x0090, KEY_NUMERIC_7 }, + { 0x0091, KEY_NUMERIC_4 }, + { 0x0092, KEY_NUMERIC_1 }, { 0x0093, KEY_CHANNELDOWN }, /* Channel - */ - { 0x0094, KEY_8 }, - { 0x0095, KEY_5 }, - { 0x0096, KEY_2 }, + { 0x0094, KEY_NUMERIC_8 }, + { 0x0095, KEY_NUMERIC_5 }, + { 0x0096, KEY_NUMERIC_2 }, { 0x0097, KEY_CHANNELUP }, /* Channel + */ - { 0x0098, KEY_9 }, - { 0x0099, KEY_6 }, - { 0x009a, KEY_3 }, + { 0x0098, KEY_NUMERIC_9 }, + { 0x0099, KEY_NUMERIC_6 }, + { 0x009a, KEY_NUMERIC_3 }, { 0x009b, KEY_VOLUMEDOWN }, /* Volume - */ { 0x009c, KEY_TV }, /* TV */ { 0x009d, KEY_RECORD }, /* Record */ diff --git a/drivers/media/rc/keymaps/rc-tt-1500.c b/drivers/media/rc/keymaps/rc-tt-1500.c index 52f239d2c025..ff70aab13b48 100644 --- a/drivers/media/rc/keymaps/rc-tt-1500.c +++ b/drivers/media/rc/keymaps/rc-tt-1500.c @@ -13,16 +13,16 @@ static struct rc_map_table tt_1500[] = { { 0x1501, KEY_POWER }, { 0x1502, KEY_SHUFFLE }, /* ? double-arrow key */ - { 0x1503, KEY_1 }, - { 0x1504, KEY_2 }, - { 0x1505, KEY_3 }, - { 0x1506, KEY_4 }, - { 0x1507, KEY_5 }, - { 0x1508, KEY_6 }, - { 0x1509, KEY_7 }, - { 0x150a, KEY_8 }, - { 0x150b, KEY_9 }, - { 0x150c, KEY_0 }, + { 0x1503, KEY_NUMERIC_1 }, + { 0x1504, KEY_NUMERIC_2 }, + { 0x1505, KEY_NUMERIC_3 }, + { 0x1506, KEY_NUMERIC_4 }, + { 0x1507, KEY_NUMERIC_5 }, + { 0x1508, KEY_NUMERIC_6 }, + { 0x1509, KEY_NUMERIC_7 }, + { 0x150a, KEY_NUMERIC_8 }, + { 0x150b, KEY_NUMERIC_9 }, + { 0x150c, KEY_NUMERIC_0 }, { 0x150d, KEY_UP }, { 0x150e, KEY_LEFT }, { 0x150f, KEY_OK }, diff --git a/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c b/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c index a72cb06a811e..5fc696d9e583 100644 --- a/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c +++ b/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c @@ -15,16 +15,16 @@ static struct rc_map_table twinhan_dtv_cab_ci[] = { { 0x23, KEY_EPG}, { 0x3b, KEY_F22}, /* Record List */ - { 0x3c, KEY_1}, - { 0x3e, KEY_2}, - { 0x39, KEY_3}, - { 0x36, KEY_4}, - { 0x22, KEY_5}, - { 0x20, KEY_6}, - { 0x32, KEY_7}, - { 0x26, KEY_8}, - { 0x24, KEY_9}, - { 0x2a, KEY_0}, + { 0x3c, KEY_NUMERIC_1}, + { 0x3e, KEY_NUMERIC_2}, + { 0x39, KEY_NUMERIC_3}, + { 0x36, KEY_NUMERIC_4}, + { 0x22, KEY_NUMERIC_5}, + { 0x20, KEY_NUMERIC_6}, + { 0x32, KEY_NUMERIC_7}, + { 0x26, KEY_NUMERIC_8}, + { 0x24, KEY_NUMERIC_9}, + { 0x2a, KEY_NUMERIC_0}, { 0x33, KEY_CANCEL}, { 0x2c, KEY_BACK}, diff --git a/drivers/media/rc/keymaps/rc-twinhan1027.c b/drivers/media/rc/keymaps/rc-twinhan1027.c index 3ee28bcf31dc..e1cdcfa792dc 100644 --- a/drivers/media/rc/keymaps/rc-twinhan1027.c +++ b/drivers/media/rc/keymaps/rc-twinhan1027.c @@ -10,16 +10,16 @@ static struct rc_map_table twinhan_vp1027[] = { { 0x1c, KEY_EPG }, { 0x04, KEY_LIST }, - { 0x03, KEY_1 }, - { 0x01, KEY_2 }, - { 0x06, KEY_3 }, - { 0x09, KEY_4 }, - { 0x1d, KEY_5 }, - { 0x1f, KEY_6 }, - { 0x0d, KEY_7 }, - { 0x19, KEY_8 }, - { 0x1b, KEY_9 }, - { 0x15, KEY_0 }, + { 0x03, KEY_NUMERIC_1 }, + { 0x01, KEY_NUMERIC_2 }, + { 0x06, KEY_NUMERIC_3 }, + { 0x09, KEY_NUMERIC_4 }, + { 0x1d, KEY_NUMERIC_5 }, + { 0x1f, KEY_NUMERIC_6 }, + { 0x0d, KEY_NUMERIC_7 }, + { 0x19, KEY_NUMERIC_8 }, + { 0x1b, KEY_NUMERIC_9 }, + { 0x15, KEY_NUMERIC_0 }, { 0x0c, KEY_CANCEL }, { 0x4a, KEY_CLEAR }, diff --git a/drivers/media/rc/keymaps/rc-videomate-m1f.c b/drivers/media/rc/keymaps/rc-videomate-m1f.c index d2d183759a03..e16b9b851c72 100644 --- a/drivers/media/rc/keymaps/rc-videomate-m1f.c +++ b/drivers/media/rc/keymaps/rc-videomate-m1f.c @@ -41,17 +41,17 @@ static struct rc_map_table videomate_k100[] = { { 0x10, KEY_PREVIOUS }, { 0x0d, KEY_PAUSE }, { 0x0f, KEY_NEXT }, - { 0x1e, KEY_1 }, - { 0x1f, KEY_2 }, - { 0x20, KEY_3 }, - { 0x21, KEY_4 }, - { 0x22, KEY_5 }, - { 0x23, KEY_6 }, - { 0x24, KEY_7 }, - { 0x25, KEY_8 }, - { 0x26, KEY_9 }, + { 0x1e, KEY_NUMERIC_1 }, + { 0x1f, KEY_NUMERIC_2 }, + { 0x20, KEY_NUMERIC_3 }, + { 0x21, KEY_NUMERIC_4 }, + { 0x22, KEY_NUMERIC_5 }, + { 0x23, KEY_NUMERIC_6 }, + { 0x24, KEY_NUMERIC_7 }, + { 0x25, KEY_NUMERIC_8 }, + { 0x26, KEY_NUMERIC_9 }, { 0x2a, KEY_NUMERIC_STAR }, /* * key */ - { 0x1d, KEY_0 }, + { 0x1d, KEY_NUMERIC_0 }, { 0x29, KEY_SUBTITLE }, /* # key */ { 0x27, KEY_CLEAR }, { 0x34, KEY_SCREEN }, diff --git a/drivers/media/rc/keymaps/rc-videomate-s350.c b/drivers/media/rc/keymaps/rc-videomate-s350.c index e4d4dff06a24..a867d7a08055 100644 --- a/drivers/media/rc/keymaps/rc-videomate-s350.c +++ b/drivers/media/rc/keymaps/rc-videomate-s350.c @@ -22,16 +22,16 @@ static struct rc_map_table videomate_s350[] = { { 0x13, KEY_CHANNELDOWN}, { 0x14, KEY_MUTE}, { 0x15, KEY_VOLUMEDOWN}, - { 0x16, KEY_1}, - { 0x17, KEY_2}, - { 0x18, KEY_3}, - { 0x19, KEY_4}, - { 0x1a, KEY_5}, - { 0x1b, KEY_6}, - { 0x1c, KEY_7}, - { 0x1d, KEY_8}, - { 0x1e, KEY_9}, - { 0x1f, KEY_0}, + { 0x16, KEY_NUMERIC_1}, + { 0x17, KEY_NUMERIC_2}, + { 0x18, KEY_NUMERIC_3}, + { 0x19, KEY_NUMERIC_4}, + { 0x1a, KEY_NUMERIC_5}, + { 0x1b, KEY_NUMERIC_6}, + { 0x1c, KEY_NUMERIC_7}, + { 0x1d, KEY_NUMERIC_8}, + { 0x1e, KEY_NUMERIC_9}, + { 0x1f, KEY_NUMERIC_0}, { 0x21, KEY_SLEEP}, { 0x24, KEY_ZOOM}, { 0x25, KEY_LAST}, /* Recall */ diff --git a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c index 7c4890944407..fdc3b0e1350f 100644 --- a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c +++ b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c @@ -42,16 +42,16 @@ static struct rc_map_table videomate_tv_pvr[] = { { 0x04, KEY_RECORD }, - { 0x16, KEY_1 }, - { 0x17, KEY_2 }, - { 0x18, KEY_3 }, - { 0x19, KEY_4 }, - { 0x1a, KEY_5 }, - { 0x1b, KEY_6 }, - { 0x1c, KEY_7 }, - { 0x1d, KEY_8 }, - { 0x1e, KEY_9 }, - { 0x1f, KEY_0 }, + { 0x16, KEY_NUMERIC_1 }, + { 0x17, KEY_NUMERIC_2 }, + { 0x18, KEY_NUMERIC_3 }, + { 0x19, KEY_NUMERIC_4 }, + { 0x1a, KEY_NUMERIC_5 }, + { 0x1b, KEY_NUMERIC_6 }, + { 0x1c, KEY_NUMERIC_7 }, + { 0x1d, KEY_NUMERIC_8 }, + { 0x1e, KEY_NUMERIC_9 }, + { 0x1f, KEY_NUMERIC_0 }, { 0x20, KEY_LANGUAGE }, { 0x21, KEY_SLEEP }, diff --git a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c index e443192dbe14..999ba4e084ae 100644 --- a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c +++ b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c @@ -13,16 +13,16 @@ */ static struct rc_map_table winfast_usbii_deluxe[] = { - { 0x62, KEY_0}, - { 0x75, KEY_1}, - { 0x76, KEY_2}, - { 0x77, KEY_3}, - { 0x79, KEY_4}, - { 0x7a, KEY_5}, - { 0x7b, KEY_6}, - { 0x7d, KEY_7}, - { 0x7e, KEY_8}, - { 0x7f, KEY_9}, + { 0x62, KEY_NUMERIC_0}, + { 0x75, KEY_NUMERIC_1}, + { 0x76, KEY_NUMERIC_2}, + { 0x77, KEY_NUMERIC_3}, + { 0x79, KEY_NUMERIC_4}, + { 0x7a, KEY_NUMERIC_5}, + { 0x7b, KEY_NUMERIC_6}, + { 0x7d, KEY_NUMERIC_7}, + { 0x7e, KEY_NUMERIC_8}, + { 0x7f, KEY_NUMERIC_9}, { 0x38, KEY_CAMERA}, /* SNAPSHOT */ { 0x37, KEY_RECORD}, /* RECORD */ diff --git a/drivers/media/rc/keymaps/rc-winfast.c b/drivers/media/rc/keymaps/rc-winfast.c index ee7f4c349fd6..be52a3e1f8ae 100644 --- a/drivers/media/rc/keymaps/rc-winfast.c +++ b/drivers/media/rc/keymaps/rc-winfast.c @@ -12,16 +12,16 @@ static struct rc_map_table winfast[] = { /* Keys 0 to 9 */ - { 0x12, KEY_0 }, - { 0x05, KEY_1 }, - { 0x06, KEY_2 }, - { 0x07, KEY_3 }, - { 0x09, KEY_4 }, - { 0x0a, KEY_5 }, - { 0x0b, KEY_6 }, - { 0x0d, KEY_7 }, - { 0x0e, KEY_8 }, - { 0x0f, KEY_9 }, + { 0x12, KEY_NUMERIC_0 }, + { 0x05, KEY_NUMERIC_1 }, + { 0x06, KEY_NUMERIC_2 }, + { 0x07, KEY_NUMERIC_3 }, + { 0x09, KEY_NUMERIC_4 }, + { 0x0a, KEY_NUMERIC_5 }, + { 0x0b, KEY_NUMERIC_6 }, + { 0x0d, KEY_NUMERIC_7 }, + { 0x0e, KEY_NUMERIC_8 }, + { 0x0f, KEY_NUMERIC_9 }, { 0x00, KEY_POWER2 }, { 0x1b, KEY_AUDIO }, /* Audio Source */ diff --git a/drivers/media/rc/keymaps/rc-xbox-dvd.c b/drivers/media/rc/keymaps/rc-xbox-dvd.c index 42815ab57bff..9d656042a81f 100644 --- a/drivers/media/rc/keymaps/rc-xbox-dvd.c +++ b/drivers/media/rc/keymaps/rc-xbox-dvd.c @@ -14,16 +14,16 @@ static struct rc_map_table xbox_dvd[] = { {0xaa9, KEY_LEFT}, {0xac3, KEY_INFO}, - {0xac6, KEY_9}, - {0xac7, KEY_8}, - {0xac8, KEY_7}, - {0xac9, KEY_6}, - {0xaca, KEY_5}, - {0xacb, KEY_4}, - {0xacc, KEY_3}, - {0xacd, KEY_2}, - {0xace, KEY_1}, - {0xacf, KEY_0}, + {0xac6, KEY_NUMERIC_9}, + {0xac7, KEY_NUMERIC_8}, + {0xac8, KEY_NUMERIC_7}, + {0xac9, KEY_NUMERIC_6}, + {0xaca, KEY_NUMERIC_5}, + {0xacb, KEY_NUMERIC_4}, + {0xacc, KEY_NUMERIC_3}, + {0xacd, KEY_NUMERIC_2}, + {0xace, KEY_NUMERIC_1}, + {0xacf, KEY_NUMERIC_0}, {0xad5, KEY_ANGLE}, {0xad8, KEY_BACK}, diff --git a/drivers/media/rc/keymaps/rc-zx-irdec.c b/drivers/media/rc/keymaps/rc-zx-irdec.c index 5bf3ab002afc..7bb0c05eb759 100644 --- a/drivers/media/rc/keymaps/rc-zx-irdec.c +++ b/drivers/media/rc/keymaps/rc-zx-irdec.c @@ -1,26 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 Sanechips Technology Co., Ltd. * Copyright 2017 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> #include <media/rc-map.h> static struct rc_map_table zx_irdec_table[] = { - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x31, KEY_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, + { 0x31, KEY_NUMERIC_0 }, { 0x16, KEY_DELETE }, { 0x0a, KEY_MODE }, /* Input method */ { 0x0c, KEY_VOLUMEUP }, diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 10830605c734..f078f8a3aec8 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -19,7 +19,7 @@ #include "rc-core-priv.h" #include <uapi/linux/lirc.h> -#define LIRCBUF_SIZE 256 +#define LIRCBUF_SIZE 1024 static dev_t lirc_base_dev; diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 72862e4bec62..4d5351ebb940 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1176,8 +1176,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK); if (unlikely(!rawir.duration)) { - dev_warn(ir->dev, "nonsensical irdata %02x with duration 0", - ir->buf_in[i]); + dev_dbg(ir->dev, "nonsensical irdata %02x with duration 0", + ir->buf_in[i]); break; } if (rawir.pulse) { diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 9e1a978a5fd9..72a7bbbf6b1f 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Driver for Amlogic Meson IR remote receiver * @@ -113,10 +113,8 @@ static int meson_ir_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ir->reg = devm_ioremap_resource(dev, res); - if (IS_ERR(ir->reg)) { - dev_err(dev, "failed to map registers\n"); + if (IS_ERR(ir->reg)) return PTR_ERR(ir->reg); - } irq = platform_get_irq(pdev, 0); if (irq < 0) { diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c index 46101efe017b..50fb0aebb8d4 100644 --- a/drivers/media/rc/mtk-cir.c +++ b/drivers/media/rc/mtk-cir.c @@ -320,10 +320,8 @@ static int mtk_ir_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ir->base = devm_ioremap_resource(dev, res); - if (IS_ERR(ir->base)) { - dev_err(dev, "failed to map registers\n"); + if (IS_ERR(ir->base)) return PTR_ERR(ir->base); - } ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW); if (!ir->rc) { diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index be5fd129d728..13da4c5c7d17 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1502,7 +1502,7 @@ static ssize_t store_wakeup_protocols(struct device *device, const char *buf, size_t len) { struct rc_dev *dev = to_rc_dev(device); - enum rc_proto protocol; + enum rc_proto protocol = RC_PROTO_UNKNOWN; ssize_t rc; u64 allowed; int i; @@ -1511,9 +1511,7 @@ static ssize_t store_wakeup_protocols(struct device *device, allowed = dev->allowed_wakeup_protocols; - if (sysfs_streq(buf, "none")) { - protocol = RC_PROTO_UNKNOWN; - } else { + if (!sysfs_streq(buf, "none")) { for (i = 0; i < ARRAY_SIZE(protocols); i++) { if ((allowed & (1ULL << i)) && sysfs_streq(buf, protocols[i].name)) { diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index a48f68539231..aa719d0ae6b0 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -195,7 +195,6 @@ static int sunxi_ir_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ir->base = devm_ioremap_resource(dev, res); if (IS_ERR(ir->base)) { - dev_err(dev, "failed to map registers\n"); ret = PTR_ERR(ir->base); goto exit_clkdisable_clk; } diff --git a/drivers/media/rc/zx-irdec.c b/drivers/media/rc/zx-irdec.c index 12d322ec8a29..948ad90ae5d8 100644 --- a/drivers/media/rc/zx-irdec.c +++ b/drivers/media/rc/zx-irdec.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 Sanechips Technology Co., Ltd. * Copyright 2017 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig index ba464efdab03..08386abb9bbc 100644 --- a/drivers/media/spi/Kconfig +++ b/drivers/media/spi/Kconfig @@ -2,7 +2,7 @@ if VIDEO_V4L2 menu "SPI helper chips" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST + visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT config VIDEO_GS1662 tristate "Gennum Serializers video" diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index 72805e5abc68..a7108e575e9b 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -16,7 +16,7 @@ config MEDIA_TUNER select MEDIA_TUNER_MC44S803 if MEDIA_SUBDRV_AUTOSELECT menu "Customize TV tuners" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST + visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT config MEDIA_TUNER_SIMPLE diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index f4c8a7293ebb..2240d214dfac 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for mt2063 Micronas tuner * @@ -7,16 +8,6 @@ * Henry Wang <Henry.wang@AzureWave.com> * Made publicly available by Terratec, at: * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz - * The original driver's license is GPL, as declared with MODULE_LICENSE() - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation under version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/init.h> diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 7be893def190..e87040d6eca7 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -129,6 +129,7 @@ static int si2157_init(struct dvb_frontend *fe) chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 | cmd.args[4] << 0; + #define SI2177_A30 ('A' << 24 | 77 << 16 | '3' << 8 | '0' << 0) #define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0) #define SI2148_A20 ('A' << 24 | 48 << 16 | '2' << 8 | '0' << 0) #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0) @@ -144,6 +145,9 @@ static int si2157_init(struct dvb_frontend *fe) case SI2141_A10: fw_name = SI2141_A10_FIRMWARE; break; + case SI2177_A30: + fw_name = SI2157_A30_FIRMWARE; + break; case SI2157_A30: case SI2147_A30: case SI2146_A10: @@ -520,6 +524,7 @@ static const struct i2c_device_id si2157_id_table[] = { {"si2157", SI2157_CHIPTYPE_SI2157}, {"si2146", SI2157_CHIPTYPE_SI2146}, {"si2141", SI2157_CHIPTYPE_SI2141}, + {"si2177", SI2157_CHIPTYPE_SI2177}, {} }; MODULE_DEVICE_TABLE(i2c, si2157_id_table); @@ -541,3 +546,4 @@ MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(SI2158_A20_FIRMWARE); MODULE_FIRMWARE(SI2141_A10_FIRMWARE); +MODULE_FIRMWARE(SI2157_A30_FIRMWARE); diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index 7d16934c7708..2bda903358da 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -41,6 +41,7 @@ struct si2157_dev { #define SI2157_CHIPTYPE_SI2157 0 #define SI2157_CHIPTYPE_SI2146 1 #define SI2157_CHIPTYPE_SI2141 2 +#define SI2157_CHIPTYPE_SI2177 3 /* firmware command struct */ #define SI2157_ARGLEN 30 @@ -52,5 +53,5 @@ struct si2157_cmd { #define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw" #define SI2141_A10_FIRMWARE "dvb-tuner-si2141-a10-01.fw" - +#define SI2157_A30_FIRMWARE "dvb-tuner-si2157-a30-01.fw" #endif diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 3329de6671ce..b35231ffe503 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -613,10 +613,6 @@ static int airspy_querycap(struct file *file, void *fh, strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, s->vdev.name, sizeof(cap->card)); usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE | V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -1057,6 +1053,8 @@ static int airspy_probe(struct usb_interface *intf, s->v4l2_dev.ctrl_handler = &s->hdl; s->vdev.v4l2_dev = &s->v4l2_dev; s->vdev.lock = &s->v4l2_lock; + s->vdev.device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE | V4L2_CAP_TUNER; ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1); if (ret) { diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index f746f6e2f686..a8a72d5fbd12 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -719,6 +719,12 @@ static int au0828_usb_probe(struct usb_interface *interface, /* Setup */ au0828_card_setup(dev); + /* + * Store the pointer to the au0828_dev so it can be accessed in + * au0828_usb_disconnect + */ + usb_set_intfdata(interface, dev); + /* Analog TV */ retval = au0828_analog_register(dev, interface); if (retval) { @@ -737,12 +743,6 @@ static int au0828_usb_probe(struct usb_interface *interface, /* Remote controller */ au0828_rc_register(dev); - /* - * Store the pointer to the au0828_dev so it can be accessed in - * au0828_usb_disconnect - */ - usb_set_intfdata(interface, dev); - pr_info("Registered device AU0828 [%s]\n", dev->board.name == NULL ? "Unset" : dev->board.name); diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index a414a25e48a8..5e00019bce8a 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1182,7 +1182,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); struct au0828_dev *dev = video_drvdata(file); dprintk(1, "%s called std_set %d dev_state %ld\n", __func__, @@ -1193,16 +1192,10 @@ static int vidioc_querycap(struct file *file, void *priv, usb_make_path(dev->usbdev, cap->bus_info, sizeof(cap->bus_info)); /* set the device capabilities */ - cap->device_caps = V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_TUNER; - if (vdev->vfl_type == VFL_TYPE_GRABBER) - cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; - else - cap->device_caps |= V4L2_CAP_VBI_CAPTURE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS | - V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE; + cap->capabilities = + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1991,6 +1984,9 @@ int au0828_analog_register(struct au0828_dev *dev, dev->vdev.lock = &dev->lock; dev->vdev.queue = &dev->vb_vidq; dev->vdev.queue->lock = &dev->vb_queue_lock; + dev->vdev.device_caps = + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_TUNER | V4L2_CAP_VIDEO_CAPTURE; strscpy(dev->vdev.name, "au0828a video", sizeof(dev->vdev.name)); /* Setup the VBI device */ @@ -1999,6 +1995,9 @@ int au0828_analog_register(struct au0828_dev *dev, dev->vbi_dev.lock = &dev->lock; dev->vbi_dev.queue = &dev->vb_vbiq; dev->vbi_dev.queue->lock = &dev->vb_vbi_queue_lock; + dev->vbi_dev.device_caps = + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE; strscpy(dev->vbi_dev.name, "au0828a vbi", sizeof(dev->vbi_dev.name)); /* Init entities at the Media Controller */ diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c index b2268981c963..17468f7d78ed 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/media/usb/cpia2/cpia2_usb.c @@ -893,7 +893,6 @@ static void cpia2_usb_disconnect(struct usb_interface *intf) cpia2_unregister_camera(cam); v4l2_device_disconnect(&cam->v4l2_dev); mutex_unlock(&cam->v4l2_lock); - v4l2_device_put(&cam->v4l2_dev); if(cam->buffers) { DBG("Wakeup waiting processes\n"); @@ -902,6 +901,8 @@ static void cpia2_usb_disconnect(struct usb_interface *intf) wake_up_interruptible(&cam->wq_stream); } + v4l2_device_put(&cam->v4l2_dev); + LOG("CPiA2 camera disconnected.\n"); } diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c index da6a5b2f86d1..0feae825cebb 100644 --- a/drivers/media/usb/cpia2/cpia2_v4l.c +++ b/drivers/media/usb/cpia2/cpia2_v4l.c @@ -250,13 +250,6 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0) memset(vc->bus_info,0, sizeof(vc->bus_info)); - - vc->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - vc->capabilities = vc->device_caps | - V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -1152,6 +1145,8 @@ int cpia2_register_camera(struct camera_data *cam) cam->vdev.lock = &cam->v4l2_lock; cam->vdev.ctrl_handler = hdl; cam->vdev.v4l2_dev = &cam->v4l2_dev; + cam->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; reset_camera_struct_v4l(cam); diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 26b05df698f0..e0d98ba8fdbf 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -1023,6 +1023,8 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER}, {USB_DEVICE(0x2040, 0xb123), .driver_info = CX231XX_BOARD_HAUPPAUGE_955Q}, + {USB_DEVICE(0x2040, 0xb124), + .driver_info = CX231XX_BOARD_HAUPPAUGE_955Q}, {USB_DEVICE(0x2040, 0xb151), .driver_info = CX231XX_BOARD_HAUPPAUGE_935C}, {USB_DEVICE(0x2040, 0xb150), diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 8fbb9523c88d..e205f7f0a56a 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -1147,6 +1147,7 @@ static int dvb_fini(struct cx231xx *dev) if (dev->dvb) { unregister_dvb(dev->dvb); + kfree(dev->dvb); dev->dvb = NULL; } diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index f8820478d46b..b651ac7713ea 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1555,30 +1555,19 @@ static int vidioc_streamoff(struct file *file, void *priv, int cx231xx_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; strscpy(cap->driver, "cx231xx", sizeof(cap->driver)); strscpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - - if (vdev->vfl_type == VFL_TYPE_RADIO) - cap->device_caps = V4L2_CAP_RADIO; - else { - cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if (vdev->vfl_type == VFL_TYPE_VBI) - cap->device_caps |= V4L2_CAP_VBI_CAPTURE; - else - cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; - } - if (dev->tuner_type != TUNER_ABSENT) - cap->device_caps |= V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | V4L2_CAP_READWRITE | + cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; if (video_is_registered(&dev->radio_dev)) cap->capabilities |= V4L2_CAP_RADIO; + if (dev->tuner_type != TUNER_ABSENT) + cap->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -2234,6 +2223,11 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) dev_err(dev->dev, "failed to initialize video media entity!\n"); #endif dev->vdev.ctrl_handler = &dev->ctrl_handler; + dev->vdev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT) + dev->vdev.device_caps |= V4L2_CAP_TUNER; + /* register v4l2 video video_device */ ret = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]); @@ -2262,6 +2256,11 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) dev_err(dev->dev, "failed to initialize vbi media entity!\n"); #endif dev->vbi_dev.ctrl_handler = &dev->ctrl_handler; + dev->vbi_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VBI_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT) + dev->vbi_dev.device_caps |= V4L2_CAP_TUNER; + /* register v4l2 vbi video_device */ ret = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]); @@ -2277,6 +2276,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) cx231xx_vdev_init(dev, &dev->radio_dev, &cx231xx_radio_template, "radio"); dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler; + dev->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO, radio_nr[dev->devno]); if (ret < 0) { diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index de52309eaaab..3afd18733614 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -107,8 +107,6 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) memcpy(req->rbuf, &state->buf[ACK_HDR_LEN], req->rlen); exit: mutex_unlock(&d->usb_mutex); - if (ret < 0) - dev_dbg(&intf->dev, "failed=%d\n", ret); return ret; } diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c index 746926364535..62ee09f28a0b 100644 --- a/drivers/media/usb/dvb-usb-v2/az6007.c +++ b/drivers/media/usb/dvb-usb-v2/az6007.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for AzureWave 6007 DVB-C/T USB2.0 and clones * @@ -10,15 +11,6 @@ * Copyright (c) 2010-2012 Mauro Carvalho Chehab * Driver modified by in order to work with upstream drxk driver, and * tons of bugs got fixed, and converted to use dvb-usb-v2. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation under version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include "drxk.h" diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c index 91729a39a306..7e817ea506c6 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c @@ -24,14 +24,19 @@ static int dvb_usb_v2_generic_io(struct dvb_usb_device *d, ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, d->props->generic_bulk_ctrl_endpoint), wbuf, wlen, &actual_length, 2000); - if (ret < 0) + if (ret) { dev_err(&d->udev->dev, "%s: usb_bulk_msg() failed=%d\n", KBUILD_MODNAME, ret); - else - ret = actual_length != wlen ? -EIO : 0; + return ret; + } + if (actual_length != wlen) { + dev_err(&d->udev->dev, "%s: usb_bulk_msg() write length=%d, actual=%d\n", + KBUILD_MODNAME, wlen, actual_length); + return -EIO; + } - /* an answer is expected, and no error before */ - if (!ret && rbuf && rlen) { + /* an answer is expected */ + if (rbuf && rlen) { if (d->props->generic_bulk_ctrl_delay) usleep_range(d->props->generic_bulk_ctrl_delay, d->props->generic_bulk_ctrl_delay diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c index c41e10bd6ef7..8610487f2d72 100644 --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -91,8 +91,6 @@ static int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value) obuf[1] = gport; obuf[2] = value; ret = dvbsky_usb_generic_rw(d, obuf, 3, ibuf, 1); - if (ret) - dev_err(&d->udev->dev, "failed=%d\n", ret); return ret; } @@ -130,8 +128,6 @@ static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[3] = msg[0].addr; ret = dvbsky_usb_generic_rw(d, obuf, 4, ibuf, msg[0].len + 1); - if (ret) - dev_err(&d->udev->dev, "failed=%d\n", ret); if (!ret) memcpy(msg[0].buf, &ibuf[1], msg[0].len); } else { @@ -142,8 +138,6 @@ static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], memcpy(&obuf[3], msg[0].buf, msg[0].len); ret = dvbsky_usb_generic_rw(d, obuf, msg[0].len + 3, ibuf, 1); - if (ret) - dev_err(&d->udev->dev, "failed=%d\n", ret); } } else { if ((msg[0].len > 60) || (msg[1].len > 60)) { @@ -161,9 +155,6 @@ static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], memcpy(&obuf[4], msg[0].buf, msg[0].len); ret = dvbsky_usb_generic_rw(d, obuf, msg[0].len + 4, ibuf, msg[1].len + 1); - if (ret) - dev_err(&d->udev->dev, "failed=%d\n", ret); - if (!ret) memcpy(msg[1].buf, &ibuf[1], msg[1].len); } @@ -192,8 +183,6 @@ static int dvbsky_rc_query(struct dvb_usb_device *d) obuf[0] = 0x10; ret = dvbsky_usb_generic_rw(d, obuf, 1, ibuf, 2); - if (ret) - dev_err(&d->udev->dev, "failed=%d\n", ret); if (ret == 0) code = (ibuf[0] << 8) | ibuf[1]; if (code != 0xffff) { diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig index 87dbae875177..1a3e5f965ae4 100644 --- a/drivers/media/usb/dvb-usb/Kconfig +++ b/drivers/media/usb/dvb-usb/Kconfig @@ -139,12 +139,24 @@ config DVB_USB_CXUSB select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Conexant USB2.0 hybrid reference design. - Currently, only DVB and ATSC modes are supported, analog mode - shall be added in the future. Devices that require this module: + DVB and ATSC modes are supported, for a basic analog mode support + see the next option ("Analog support for the Conexant USB2.0 hybrid + reference design"). + Devices that require this module: Medion MD95700 hybrid USB2.0 device. DViCO FusionHDTV (Bluebird) USB2.0 devices +config DVB_USB_CXUSB_ANALOG + bool "Analog support for the Conexant USB2.0 hybrid reference design" + depends on DVB_USB_CXUSB && VIDEO_V4L2 + select VIDEO_CX25840 + select VIDEOBUF2_VMALLOC + help + Say Y here to enable basic analog mode support for the Conexant + USB2.0 hybrid reference design. + Currently this mode is supported only on a Medion MD95700 device. + config DVB_USB_M920X tristate "Uli m920x DVB-T USB2.0 support" depends on DVB_USB diff --git a/drivers/media/usb/dvb-usb/Makefile b/drivers/media/usb/dvb-usb/Makefile index 407d90ca8be0..28e4806a87cd 100644 --- a/drivers/media/usb/dvb-usb/Makefile +++ b/drivers/media/usb/dvb-usb/Makefile @@ -42,6 +42,9 @@ dvb-usb-digitv-objs := digitv.o obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o dvb-usb-cxusb-objs := cxusb.o +ifeq ($(CONFIG_DVB_USB_CXUSB_ANALOG),y) +dvb-usb-cxusb-objs += cxusb-analog.o +endif obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o dvb-usb-ttusb2-objs := ttusb2.o diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c new file mode 100644 index 000000000000..0699f718d052 --- /dev/null +++ b/drivers/media/usb/dvb-usb/cxusb-analog.c @@ -0,0 +1,1845 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// DVB USB compliant linux driver for Conexant USB reference design - +// (analog part). +// +// Copyright (C) 2011, 2017, 2018 +// Maciej S. Szmigiero (mail@maciej.szmigiero.name) +// +// In case there are new analog / DVB-T hybrid devices released in the market +// using the same general design as Medion MD95700: a CX25840 video decoder +// outputting a BT.656 stream to a USB bridge chip which then forwards it to +// the host in isochronous USB packets this code should be made generic, with +// board specific bits implemented via separate card structures. +// +// This is, however, unlikely as the Medion model was released +// years ago (in 2005). +// +// TODO: +// * audio support, +// * finish radio support (requires audio of course), +// * VBI support, +// * controls support + +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/ktime.h> +#include <linux/vmalloc.h> +#include <media/drv-intf/cx25840.h> +#include <media/tuner.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-subdev.h> +#include <media/videobuf2-vmalloc.h> + +#include "cxusb.h" + +static int cxusb_medion_v_queue_setup(struct vb2_queue *q, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + unsigned int size = cxdev->width * cxdev->height * 2; + + if (*num_planes > 0) { + if (*num_planes != 1) + return -EINVAL; + + if (sizes[0] < size) + return -EINVAL; + } else { + *num_planes = 1; + sizes[0] = size; + } + + return 0; +} + +static int cxusb_medion_v_buf_init(struct vb2_buffer *vb) +{ + struct dvb_usb_device *dvbdev = vb2_get_drv_priv(vb->vb2_queue); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + cxusb_vprintk(dvbdev, OPS, "buffer init\n"); + + if (vb2_plane_size(vb, 0) < cxdev->width * cxdev->height * 2) + return -ENOMEM; + + cxusb_vprintk(dvbdev, OPS, "buffer OK\n"); + + return 0; +} + +static void cxusb_auxbuf_init(struct dvb_usb_device *dvbdev, + struct cxusb_medion_auxbuf *auxbuf, + u8 *buf, unsigned int len) +{ + cxusb_vprintk(dvbdev, AUXB, "initializing auxbuf of len %u\n", len); + + auxbuf->buf = buf; + auxbuf->len = len; + auxbuf->paylen = 0; +} + +static void cxusb_auxbuf_head_trim(struct dvb_usb_device *dvbdev, + struct cxusb_medion_auxbuf *auxbuf, + unsigned int pos) +{ + if (pos == 0) + return; + + if (WARN_ON(pos > auxbuf->paylen)) + return; + + cxusb_vprintk(dvbdev, AUXB, + "trimming auxbuf len by %u to %u\n", + pos, auxbuf->paylen - pos); + + memmove(auxbuf->buf, auxbuf->buf + pos, auxbuf->paylen - pos); + auxbuf->paylen -= pos; +} + +static unsigned int cxusb_auxbuf_paylen(struct cxusb_medion_auxbuf *auxbuf) +{ + return auxbuf->paylen; +} + +static bool cxusb_auxbuf_make_space(struct dvb_usb_device *dvbdev, + struct cxusb_medion_auxbuf *auxbuf, + unsigned int howmuch) +{ + unsigned int freespace; + + if (WARN_ON(howmuch >= auxbuf->len)) + howmuch = auxbuf->len - 1; + + freespace = auxbuf->len - cxusb_auxbuf_paylen(auxbuf); + + cxusb_vprintk(dvbdev, AUXB, "freespace is %u\n", freespace); + + if (freespace >= howmuch) + return true; + + howmuch -= freespace; + + cxusb_vprintk(dvbdev, AUXB, "will overwrite %u bytes of buffer\n", + howmuch); + + cxusb_auxbuf_head_trim(dvbdev, auxbuf, howmuch); + + return false; +} + +/* returns false if some data was overwritten */ +static bool cxusb_auxbuf_append_urb(struct dvb_usb_device *dvbdev, + struct cxusb_medion_auxbuf *auxbuf, + struct urb *urb) +{ + unsigned long len; + int i; + bool ret; + + for (i = 0, len = 0; i < urb->number_of_packets; i++) + len += urb->iso_frame_desc[i].actual_length; + + ret = cxusb_auxbuf_make_space(dvbdev, auxbuf, len); + + for (i = 0; i < urb->number_of_packets; i++) { + unsigned int to_copy; + + to_copy = urb->iso_frame_desc[i].actual_length; + + memcpy(auxbuf->buf + auxbuf->paylen, urb->transfer_buffer + + urb->iso_frame_desc[i].offset, to_copy); + + auxbuf->paylen += to_copy; + } + + return ret; +} + +static bool cxusb_auxbuf_copy(struct cxusb_medion_auxbuf *auxbuf, + unsigned int pos, unsigned char *dest, + unsigned int len) +{ + if (pos + len > auxbuf->paylen) + return false; + + memcpy(dest, auxbuf->buf + pos, len); + + return true; +} + +static bool cxusb_medion_cf_refc_fld_chg(struct dvb_usb_device *dvbdev, + struct cxusb_bt656_params *bt656, + bool firstfield, + unsigned int maxlines, + unsigned int maxlinesamples, + unsigned char buf[4]) +{ + bool firstfield_code = (buf[3] & CXUSB_BT656_FIELD_MASK) == + CXUSB_BT656_FIELD_1; + unsigned int remlines; + + if (bt656->line == 0 || firstfield == firstfield_code) + return false; + + if (bt656->fmode == LINE_SAMPLES) { + unsigned int remsamples = maxlinesamples - + bt656->linesamples; + + cxusb_vprintk(dvbdev, BT656, + "field %c after line %u field change\n", + firstfield ? '1' : '2', bt656->line); + + if (bt656->buf && remsamples > 0) { + memset(bt656->buf, 0, remsamples); + bt656->buf += remsamples; + + cxusb_vprintk(dvbdev, BT656, + "field %c line %u %u samples still remaining (of %u)\n", + firstfield ? '1' : '2', + bt656->line, remsamples, + maxlinesamples); + } + + bt656->line++; + } + + remlines = maxlines - bt656->line; + if (bt656->buf && remlines > 0) { + memset(bt656->buf, 0, remlines * maxlinesamples); + bt656->buf += remlines * maxlinesamples; + + cxusb_vprintk(dvbdev, BT656, + "field %c %u lines still remaining (of %u)\n", + firstfield ? '1' : '2', remlines, + maxlines); + } + + return true; +} + +static void cxusb_medion_cf_refc_start_sch(struct dvb_usb_device *dvbdev, + struct cxusb_bt656_params *bt656, + bool firstfield, + unsigned char buf[4]) +{ + bool firstfield_code = (buf[3] & CXUSB_BT656_FIELD_MASK) == + CXUSB_BT656_FIELD_1; + bool sav_code = (buf[3] & CXUSB_BT656_SEAV_MASK) == + CXUSB_BT656_SEAV_SAV; + bool vbi_code = (buf[3] & CXUSB_BT656_VBI_MASK) == + CXUSB_BT656_VBI_ON; + + if (!sav_code || firstfield != firstfield_code) + return; + + if (!vbi_code) { + cxusb_vprintk(dvbdev, BT656, "line start @ pos %u\n", + bt656->pos); + + bt656->linesamples = 0; + bt656->fmode = LINE_SAMPLES; + } else { + cxusb_vprintk(dvbdev, BT656, "VBI start @ pos %u\n", + bt656->pos); + + bt656->fmode = VBI_SAMPLES; + } +} + +static void cxusb_medion_cf_refc_line_smpl(struct dvb_usb_device *dvbdev, + struct cxusb_bt656_params *bt656, + bool firstfield, + unsigned int maxlinesamples, + unsigned char buf[4]) +{ + bool sav_code = (buf[3] & CXUSB_BT656_SEAV_MASK) == + CXUSB_BT656_SEAV_SAV; + unsigned int remsamples; + + if (sav_code) + cxusb_vprintk(dvbdev, BT656, + "SAV in line samples @ line %u, pos %u\n", + bt656->line, bt656->pos); + + remsamples = maxlinesamples - bt656->linesamples; + if (bt656->buf && remsamples > 0) { + memset(bt656->buf, 0, remsamples); + bt656->buf += remsamples; + + cxusb_vprintk(dvbdev, BT656, + "field %c line %u %u samples still remaining (of %u)\n", + firstfield ? '1' : '2', bt656->line, remsamples, + maxlinesamples); + } + + bt656->fmode = START_SEARCH; + bt656->line++; +} + +static void cxusb_medion_cf_refc_vbi_smpl(struct dvb_usb_device *dvbdev, + struct cxusb_bt656_params *bt656, + unsigned char buf[4]) +{ + bool sav_code = (buf[3] & CXUSB_BT656_SEAV_MASK) == + CXUSB_BT656_SEAV_SAV; + + if (sav_code) + cxusb_vprintk(dvbdev, BT656, "SAV in VBI samples @ pos %u\n", + bt656->pos); + + bt656->fmode = START_SEARCH; +} + +/* returns whether the whole 4-byte code should be skipped in the buffer */ +static bool cxusb_medion_cf_ref_code(struct dvb_usb_device *dvbdev, + struct cxusb_bt656_params *bt656, + bool firstfield, + unsigned int maxlines, + unsigned int maxlinesamples, + unsigned char buf[4]) +{ + if (bt656->fmode == START_SEARCH) { + cxusb_medion_cf_refc_start_sch(dvbdev, bt656, firstfield, buf); + } else if (bt656->fmode == LINE_SAMPLES) { + cxusb_medion_cf_refc_line_smpl(dvbdev, bt656, firstfield, + maxlinesamples, buf); + return false; + } else if (bt656->fmode == VBI_SAMPLES) { + cxusb_medion_cf_refc_vbi_smpl(dvbdev, bt656, buf); + return false; + } + + return true; +} + +static bool cxusb_medion_cs_start_sch(struct dvb_usb_device *dvbdev, + struct cxusb_medion_auxbuf *auxbuf, + struct cxusb_bt656_params *bt656, + unsigned int maxlinesamples) +{ + unsigned char buf[64]; + unsigned int idx; + unsigned int tocheck = clamp_t(size_t, maxlinesamples / 4, 3, + sizeof(buf)); + + if (!cxusb_auxbuf_copy(auxbuf, bt656->pos + 1, buf, tocheck)) + return false; + + for (idx = 0; idx <= tocheck - 3; idx++) + if (memcmp(buf + idx, CXUSB_BT656_PREAMBLE, 3) == 0) { + bt656->pos += (1 + idx); + return true; + } + + cxusb_vprintk(dvbdev, BT656, "line %u early start, pos %u\n", + bt656->line, bt656->pos); + + bt656->linesamples = 0; + bt656->fmode = LINE_SAMPLES; + + return true; +} + +static void cxusb_medion_cs_line_smpl(struct cxusb_bt656_params *bt656, + unsigned int maxlinesamples, + unsigned char val) +{ + if (bt656->buf) + *(bt656->buf++) = val; + + bt656->linesamples++; + bt656->pos++; + + if (bt656->linesamples >= maxlinesamples) { + bt656->fmode = START_SEARCH; + bt656->line++; + } +} + +static bool cxusb_medion_copy_samples(struct dvb_usb_device *dvbdev, + struct cxusb_medion_auxbuf *auxbuf, + struct cxusb_bt656_params *bt656, + unsigned int maxlinesamples, + unsigned char val) +{ + if (bt656->fmode == START_SEARCH && bt656->line > 0) + return cxusb_medion_cs_start_sch(dvbdev, auxbuf, bt656, + maxlinesamples); + else if (bt656->fmode == LINE_SAMPLES) + cxusb_medion_cs_line_smpl(bt656, maxlinesamples, val); + else /* TODO: copy VBI samples */ + bt656->pos++; + + return true; +} + +static bool cxusb_medion_copy_field(struct dvb_usb_device *dvbdev, + struct cxusb_medion_auxbuf *auxbuf, + struct cxusb_bt656_params *bt656, + bool firstfield, + unsigned int maxlines, + unsigned int maxlinesmpls) +{ + while (bt656->line < maxlines) { + unsigned char val; + + if (!cxusb_auxbuf_copy(auxbuf, bt656->pos, &val, 1)) + break; + + if (val == CXUSB_BT656_PREAMBLE[0]) { + unsigned char buf[4]; + + buf[0] = val; + if (!cxusb_auxbuf_copy(auxbuf, bt656->pos + 1, + buf + 1, 3)) + break; + + if (buf[1] == CXUSB_BT656_PREAMBLE[1] && + buf[2] == CXUSB_BT656_PREAMBLE[2]) { + /* + * is this a field change? + * if so, terminate copying the current field + */ + if (cxusb_medion_cf_refc_fld_chg(dvbdev, + bt656, + firstfield, + maxlines, + maxlinesmpls, + buf)) + return true; + + if (cxusb_medion_cf_ref_code(dvbdev, bt656, + firstfield, + maxlines, + maxlinesmpls, + buf)) + bt656->pos += 4; + + continue; + } + } + + if (!cxusb_medion_copy_samples(dvbdev, auxbuf, bt656, + maxlinesmpls, val)) + break; + } + + if (bt656->line < maxlines) { + cxusb_vprintk(dvbdev, BT656, + "end of buffer pos = %u, line = %u\n", + bt656->pos, bt656->line); + return false; + } + + return true; +} + +static bool cxusb_medion_v_process_auxbuf(struct cxusb_medion_dev *cxdev, + bool reset) +{ + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + struct cxusb_bt656_params *bt656 = &cxdev->bt656; + + /* + * if this is a new frame + * fetch a buffer from list + */ + if (bt656->mode == NEW_FRAME) { + if (!list_empty(&cxdev->buflist)) { + cxdev->vbuf = + list_first_entry(&cxdev->buflist, + struct cxusb_medion_vbuffer, + list); + list_del(&cxdev->vbuf->list); + } else { + dev_warn(&dvbdev->udev->dev, "no free buffers\n"); + } + } + + if (bt656->mode == NEW_FRAME || reset) { + cxusb_vprintk(dvbdev, URB, "will copy field 1\n"); + bt656->pos = 0; + bt656->mode = FIRST_FIELD; + bt656->fmode = START_SEARCH; + bt656->line = 0; + + if (cxdev->vbuf) { + cxdev->vbuf->vb2.vb2_buf.timestamp = ktime_get_ns(); + bt656->buf = vb2_plane_vaddr(&cxdev->vbuf->vb2.vb2_buf, + 0); + } + } + + if (bt656->mode == FIRST_FIELD) { + if (!cxusb_medion_copy_field(dvbdev, &cxdev->auxbuf, bt656, + true, cxdev->height / 2, + cxdev->width * 2)) + return false; + + /* + * do not trim buffer there in case + * we need to reset the search later + */ + + cxusb_vprintk(dvbdev, URB, "will copy field 2\n"); + bt656->mode = SECOND_FIELD; + bt656->fmode = START_SEARCH; + bt656->line = 0; + } + + if (bt656->mode == SECOND_FIELD) { + if (!cxusb_medion_copy_field(dvbdev, &cxdev->auxbuf, bt656, + false, cxdev->height / 2, + cxdev->width * 2)) + return false; + + cxusb_auxbuf_head_trim(dvbdev, &cxdev->auxbuf, bt656->pos); + + bt656->mode = NEW_FRAME; + + if (cxdev->vbuf) { + vb2_set_plane_payload(&cxdev->vbuf->vb2.vb2_buf, 0, + cxdev->width * cxdev->height * 2); + + cxdev->vbuf->vb2.field = cxdev->field_order; + cxdev->vbuf->vb2.sequence = cxdev->vbuf_sequence++; + + vb2_buffer_done(&cxdev->vbuf->vb2.vb2_buf, + VB2_BUF_STATE_DONE); + + cxdev->vbuf = NULL; + cxdev->bt656.buf = NULL; + + cxusb_vprintk(dvbdev, URB, "frame done\n"); + } else { + cxusb_vprintk(dvbdev, URB, "frame skipped\n"); + cxdev->vbuf_sequence++; + } + } + + return true; +} + +static bool cxusb_medion_v_complete_handle_urb(struct cxusb_medion_dev *cxdev, + bool *auxbuf_reset) +{ + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + unsigned int urbn; + struct urb *urb; + int ret; + + *auxbuf_reset = false; + + urbn = cxdev->nexturb; + if (!test_bit(urbn, &cxdev->urbcomplete)) + return false; + + clear_bit(urbn, &cxdev->urbcomplete); + + do { + cxdev->nexturb++; + cxdev->nexturb %= CXUSB_VIDEO_URBS; + urb = cxdev->streamurbs[cxdev->nexturb]; + } while (!urb); + + urb = cxdev->streamurbs[urbn]; + cxusb_vprintk(dvbdev, URB, "URB %u status = %d\n", urbn, urb->status); + + if (urb->status == 0 || urb->status == -EXDEV) { + int i; + unsigned long len; + + for (i = 0, len = 0; i < urb->number_of_packets; i++) + len += urb->iso_frame_desc[i].actual_length; + + cxusb_vprintk(dvbdev, URB, "URB %u data len = %lu\n", urbn, + len); + + if (len > 0) { + cxusb_vprintk(dvbdev, URB, "appending URB\n"); + + /* + * append new data to auxbuf while + * overwriting old data if necessary + * + * if any overwrite happens then we can no + * longer rely on consistency of the whole + * data so let's start again the current + * auxbuf frame assembling process from + * the beginning + */ + *auxbuf_reset = + !cxusb_auxbuf_append_urb(dvbdev, + &cxdev->auxbuf, + urb); + } + } + + cxusb_vprintk(dvbdev, URB, "URB %u resubmit\n", urbn); + + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret != 0) + dev_err(&dvbdev->udev->dev, + "unable to resubmit URB %u (%d), you'll have to restart streaming\n", + urbn, ret); + + /* next URB is complete already? reschedule us then to handle it */ + return test_bit(cxdev->nexturb, &cxdev->urbcomplete); +} + +static void cxusb_medion_v_complete_work(struct work_struct *work) +{ + struct cxusb_medion_dev *cxdev = container_of(work, + struct cxusb_medion_dev, + urbwork); + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + bool auxbuf_reset; + bool reschedule; + + mutex_lock(cxdev->videodev->lock); + + cxusb_vprintk(dvbdev, URB, "worker called, stop_streaming = %d\n", + (int)cxdev->stop_streaming); + + if (cxdev->stop_streaming) + goto unlock; + + reschedule = cxusb_medion_v_complete_handle_urb(cxdev, &auxbuf_reset); + + if (cxusb_medion_v_process_auxbuf(cxdev, auxbuf_reset)) + /* reschedule us until auxbuf no longer can produce any frame */ + reschedule = true; + + if (reschedule) { + cxusb_vprintk(dvbdev, URB, "rescheduling worker\n"); + schedule_work(&cxdev->urbwork); + } + +unlock: + mutex_unlock(cxdev->videodev->lock); +} + +static void cxusb_medion_v_complete(struct urb *u) +{ + struct dvb_usb_device *dvbdev = u->context; + struct cxusb_medion_dev *cxdev = dvbdev->priv; + unsigned int i; + + for (i = 0; i < CXUSB_VIDEO_URBS; i++) + if (cxdev->streamurbs[i] == u) + break; + + if (i >= CXUSB_VIDEO_URBS) { + dev_err(&dvbdev->udev->dev, + "complete on unknown URB\n"); + return; + } + + cxusb_vprintk(dvbdev, URB, "URB %u complete\n", i); + + set_bit(i, &cxdev->urbcomplete); + schedule_work(&cxdev->urbwork); +} + +static void cxusb_medion_urbs_free(struct cxusb_medion_dev *cxdev) +{ + unsigned int i; + + for (i = 0; i < CXUSB_VIDEO_URBS; i++) + if (cxdev->streamurbs[i]) { + kfree(cxdev->streamurbs[i]->transfer_buffer); + usb_free_urb(cxdev->streamurbs[i]); + cxdev->streamurbs[i] = NULL; + } +} + +static void cxusb_medion_return_buffers(struct cxusb_medion_dev *cxdev, + bool requeue) +{ + struct cxusb_medion_vbuffer *vbuf, *vbuf_tmp; + + list_for_each_entry_safe(vbuf, vbuf_tmp, &cxdev->buflist, + list) { + list_del(&vbuf->list); + vb2_buffer_done(&vbuf->vb2.vb2_buf, + requeue ? VB2_BUF_STATE_QUEUED : + VB2_BUF_STATE_ERROR); + } + + if (cxdev->vbuf) { + vb2_buffer_done(&cxdev->vbuf->vb2.vb2_buf, + requeue ? VB2_BUF_STATE_QUEUED : + VB2_BUF_STATE_ERROR); + + cxdev->vbuf = NULL; + cxdev->bt656.buf = NULL; + } +} + +static int cxusb_medion_v_ss_auxbuf_alloc(struct cxusb_medion_dev *cxdev, + int *npackets) +{ + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + u8 *buf; + unsigned int framelen, urblen, auxbuflen; + + framelen = (cxdev->width * 2 + 4 + 4) * + (cxdev->height + 50 /* VBI lines */); + + /* + * try to fit a whole frame into each URB, as long as doing so + * does not require very high order memory allocations + */ + BUILD_BUG_ON(CXUSB_VIDEO_URB_MAX_SIZE / CXUSB_VIDEO_PKT_SIZE > + CXUSB_VIDEO_MAX_FRAME_PKTS); + *npackets = min_t(int, (framelen + CXUSB_VIDEO_PKT_SIZE - 1) / + CXUSB_VIDEO_PKT_SIZE, + CXUSB_VIDEO_URB_MAX_SIZE / CXUSB_VIDEO_PKT_SIZE); + urblen = *npackets * CXUSB_VIDEO_PKT_SIZE; + + cxusb_vprintk(dvbdev, URB, + "each URB will have %d packets for total of %u bytes (%u x %u @ %u)\n", + *npackets, urblen, (unsigned int)cxdev->width, + (unsigned int)cxdev->height, framelen); + + auxbuflen = framelen + urblen; + + buf = vmalloc(auxbuflen); + if (!buf) + return -ENOMEM; + + cxusb_auxbuf_init(dvbdev, &cxdev->auxbuf, buf, auxbuflen); + + return 0; +} + +static u32 cxusb_medion_norm2field_order(v4l2_std_id norm) +{ + bool is625 = norm & V4L2_STD_625_50; + bool is525 = norm & V4L2_STD_525_60; + + if (!is625 && !is525) + return V4L2_FIELD_NONE; + + if (is625 && is525) + return V4L2_FIELD_NONE; + + if (is625) + return V4L2_FIELD_SEQ_TB; + else /* is525 */ + return V4L2_FIELD_SEQ_BT; +} + +static u32 cxusb_medion_field_order(struct cxusb_medion_dev *cxdev) +{ + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + u32 field; + int ret; + v4l2_std_id norm; + + /* TV tuner is PAL-only so it is always TB */ + if (cxdev->input == 0) + return V4L2_FIELD_SEQ_TB; + + field = cxusb_medion_norm2field_order(cxdev->norm); + if (field != V4L2_FIELD_NONE) + return field; + + ret = v4l2_subdev_call(cxdev->cx25840, video, g_std, &norm); + if (ret != 0) { + cxusb_vprintk(dvbdev, OPS, + "cannot get current standard for input %u\n", + (unsigned int)cxdev->input); + } else { + field = cxusb_medion_norm2field_order(norm); + if (field != V4L2_FIELD_NONE) + return field; + } + + dev_warn(&dvbdev->udev->dev, + "cannot determine field order for the current standard setup and received signal, using TB\n"); + return V4L2_FIELD_SEQ_TB; +} + +static int cxusb_medion_v_start_streaming(struct vb2_queue *q, + unsigned int count) +{ + struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + u8 streamon_params[2] = { 0x03, 0x00 }; + int npackets, i; + int ret; + + cxusb_vprintk(dvbdev, OPS, "should start streaming\n"); + + if (cxdev->stop_streaming) { + /* stream is being stopped */ + ret = -EBUSY; + goto ret_retbufs; + } + + cxdev->field_order = cxusb_medion_field_order(cxdev); + + ret = v4l2_subdev_call(cxdev->cx25840, video, s_stream, 1); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "unable to start stream (%d)\n", ret); + goto ret_retbufs; + } + + ret = cxusb_ctrl_msg(dvbdev, CMD_STREAMING_ON, streamon_params, 2, + NULL, 0); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "unable to start streaming (%d)\n", ret); + goto ret_unstream_cx; + } + + ret = cxusb_medion_v_ss_auxbuf_alloc(cxdev, &npackets); + if (ret != 0) + goto ret_unstream_md; + + for (i = 0; i < CXUSB_VIDEO_URBS; i++) { + int framen; + u8 *streambuf; + struct urb *surb; + + /* + * TODO: change this to an array of single pages to avoid + * doing a large continuous allocation when (if) + * s-g isochronous USB transfers are supported + */ + streambuf = kmalloc(npackets * CXUSB_VIDEO_PKT_SIZE, + GFP_KERNEL); + if (!streambuf) { + if (i < 2) { + ret = -ENOMEM; + goto ret_freeab; + } + break; + } + + surb = usb_alloc_urb(npackets, GFP_KERNEL); + if (!surb) { + kfree(streambuf); + ret = -ENOMEM; + goto ret_freeu; + } + + cxdev->streamurbs[i] = surb; + surb->dev = dvbdev->udev; + surb->context = dvbdev; + surb->pipe = usb_rcvisocpipe(dvbdev->udev, 2); + + surb->interval = 1; + surb->transfer_flags = URB_ISO_ASAP; + + surb->transfer_buffer = streambuf; + + surb->complete = cxusb_medion_v_complete; + surb->number_of_packets = npackets; + surb->transfer_buffer_length = npackets * CXUSB_VIDEO_PKT_SIZE; + + for (framen = 0; framen < npackets; framen++) { + surb->iso_frame_desc[framen].offset = + CXUSB_VIDEO_PKT_SIZE * framen; + + surb->iso_frame_desc[framen].length = + CXUSB_VIDEO_PKT_SIZE; + } + } + + cxdev->urbcomplete = 0; + cxdev->nexturb = 0; + cxdev->vbuf_sequence = 0; + + cxdev->vbuf = NULL; + cxdev->bt656.mode = NEW_FRAME; + cxdev->bt656.buf = NULL; + + for (i = 0; i < CXUSB_VIDEO_URBS; i++) + if (cxdev->streamurbs[i]) { + ret = usb_submit_urb(cxdev->streamurbs[i], + GFP_KERNEL); + if (ret != 0) + dev_err(&dvbdev->udev->dev, + "URB %d submission failed (%d)\n", i, + ret); + } + + return 0; + +ret_freeu: + cxusb_medion_urbs_free(cxdev); + +ret_freeab: + vfree(cxdev->auxbuf.buf); + +ret_unstream_md: + cxusb_ctrl_msg(dvbdev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); + +ret_unstream_cx: + v4l2_subdev_call(cxdev->cx25840, video, s_stream, 0); + +ret_retbufs: + cxusb_medion_return_buffers(cxdev, true); + + return ret; +} + +static void cxusb_medion_v_stop_streaming(struct vb2_queue *q) +{ + struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret; + unsigned int i; + + cxusb_vprintk(dvbdev, OPS, "should stop streaming\n"); + + if (WARN_ON(cxdev->stop_streaming)) + return; + + cxdev->stop_streaming = true; + + cxusb_ctrl_msg(dvbdev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); + + ret = v4l2_subdev_call(cxdev->cx25840, video, s_stream, 0); + if (ret != 0) + dev_err(&dvbdev->udev->dev, "unable to stop stream (%d)\n", + ret); + + /* let URB completion run */ + mutex_unlock(cxdev->videodev->lock); + + for (i = 0; i < CXUSB_VIDEO_URBS; i++) + if (cxdev->streamurbs[i]) + usb_kill_urb(cxdev->streamurbs[i]); + + flush_work(&cxdev->urbwork); + + mutex_lock(cxdev->videodev->lock); + + /* free transfer buffer and URB */ + vfree(cxdev->auxbuf.buf); + + cxusb_medion_urbs_free(cxdev); + + cxusb_medion_return_buffers(cxdev, false); + + cxdev->stop_streaming = false; +} + +static void cxusub_medion_v_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *v4l2buf = to_vb2_v4l2_buffer(vb); + struct cxusb_medion_vbuffer *vbuf = + container_of(v4l2buf, struct cxusb_medion_vbuffer, vb2); + struct dvb_usb_device *dvbdev = vb2_get_drv_priv(vb->vb2_queue); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + /* cxusb_vprintk(dvbdev, OPS, "mmmm.. a fresh buffer...\n"); */ + + list_add_tail(&vbuf->list, &cxdev->buflist); +} + +static const struct vb2_ops cxdev_video_qops = { + .queue_setup = cxusb_medion_v_queue_setup, + .buf_init = cxusb_medion_v_buf_init, + .start_streaming = cxusb_medion_v_start_streaming, + .stop_streaming = cxusb_medion_v_stop_streaming, + .buf_queue = cxusub_medion_v_buf_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish +}; + +static const __u32 videocaps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; +static const __u32 radiocaps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + +static int cxusb_medion_v_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + + strscpy(cap->driver, dvbdev->udev->dev.driver->name, + sizeof(cap->driver)); + strscpy(cap->card, "Medion 95700", sizeof(cap->card)); + usb_make_path(dvbdev->udev, cap->bus_info, sizeof(cap->bus_info)); + + cap->capabilities = videocaps | radiocaps | V4L2_CAP_DEVICE_CAPS; + + return 0; +} + +static int cxusb_medion_v_enum_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + if (f->index != 0) + return -EINVAL; + + f->pixelformat = V4L2_PIX_FMT_UYVY; + + return 0; +} + +static int cxusb_medion_g_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + f->fmt.pix.width = cxdev->width; + f->fmt.pix.height = cxdev->height; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; + f->fmt.pix.field = vb2_start_streaming_called(&cxdev->videoqueue) ? + cxdev->field_order : cxusb_medion_field_order(cxdev); + f->fmt.pix.bytesperline = cxdev->width * 2; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + + return 0; +} + +static int cxusb_medion_try_s_fmt_vid_cap(struct file *file, + struct v4l2_format *f, + bool isset) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + struct v4l2_subdev_format subfmt; + u32 field; + int ret; + + if (isset && vb2_is_busy(&cxdev->videoqueue)) + return -EBUSY; + + field = vb2_start_streaming_called(&cxdev->videoqueue) ? + cxdev->field_order : cxusb_medion_field_order(cxdev); + + memset(&subfmt, 0, sizeof(subfmt)); + subfmt.which = isset ? V4L2_SUBDEV_FORMAT_ACTIVE : + V4L2_SUBDEV_FORMAT_TRY; + subfmt.format.width = f->fmt.pix.width & ~1; + subfmt.format.height = f->fmt.pix.height & ~1; + subfmt.format.code = MEDIA_BUS_FMT_FIXED; + subfmt.format.field = field; + subfmt.format.colorspace = V4L2_COLORSPACE_SMPTE170M; + + ret = v4l2_subdev_call(cxdev->cx25840, pad, set_fmt, NULL, &subfmt); + if (ret != 0) + return ret; + + f->fmt.pix.width = subfmt.format.width; + f->fmt.pix.height = subfmt.format.height; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; + f->fmt.pix.field = field; + f->fmt.pix.bytesperline = f->fmt.pix.width * 2; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + + if (isset) { + cxdev->width = f->fmt.pix.width; + cxdev->height = f->fmt.pix.height; + } + + return 0; +} + +static int cxusb_medion_try_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + return cxusb_medion_try_s_fmt_vid_cap(file, f, false); +} + +static int cxusb_medion_s_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + return cxusb_medion_try_s_fmt_vid_cap(file, f, true); +} + +static const struct { + struct v4l2_input input; + u32 inputcfg; +} cxusb_medion_inputs[] = { + { .input = { .name = "TV tuner", .type = V4L2_INPUT_TYPE_TUNER, + .tuner = 0, .std = V4L2_STD_PAL }, + .inputcfg = CX25840_COMPOSITE2, }, + + { .input = { .name = "Composite", .type = V4L2_INPUT_TYPE_CAMERA, + .std = V4L2_STD_ALL }, + .inputcfg = CX25840_COMPOSITE1, }, + + { .input = { .name = "S-Video", .type = V4L2_INPUT_TYPE_CAMERA, + .std = V4L2_STD_ALL }, + .inputcfg = CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 } +}; + +#define CXUSB_INPUT_CNT ARRAY_SIZE(cxusb_medion_inputs) + +static int cxusb_medion_enum_input(struct file *file, void *fh, + struct v4l2_input *inp) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + u32 index = inp->index; + + if (index >= CXUSB_INPUT_CNT) + return -EINVAL; + + *inp = cxusb_medion_inputs[index].input; + inp->index = index; + inp->capabilities |= V4L2_IN_CAP_STD; + + if (index == cxdev->input) { + int ret; + u32 status = 0; + + ret = v4l2_subdev_call(cxdev->cx25840, video, g_input_status, + &status); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "cx25840 input status query failed (%d)\n", + ret); + else + inp->status = status; + } + + return 0; +} + +static int cxusb_medion_g_input(struct file *file, void *fh, + unsigned int *i) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + *i = cxdev->input; + + return 0; +} + +static int cxusb_medion_set_norm(struct cxusb_medion_dev *cxdev, + v4l2_std_id norm) +{ + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + int ret; + + cxusb_vprintk(dvbdev, OPS, + "trying to set standard for input %u to %lx\n", + (unsigned int)cxdev->input, + (unsigned long)norm); + + /* no autodetection support */ + if (norm == V4L2_STD_UNKNOWN) + return -EINVAL; + + /* on composite or S-Video any std is acceptable */ + if (cxdev->input != 0) { + ret = v4l2_subdev_call(cxdev->cx25840, video, s_std, norm); + if (ret) + return ret; + + goto ret_savenorm; + } + + /* TV tuner is only able to demodulate PAL */ + if ((norm & ~V4L2_STD_PAL) != 0) + return -EINVAL; + + ret = v4l2_subdev_call(cxdev->tda9887, video, s_std, norm); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "tda9887 norm setup failed (%d)\n", + ret); + return ret; + } + + ret = v4l2_subdev_call(cxdev->tuner, video, s_std, norm); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "tuner norm setup failed (%d)\n", + ret); + return ret; + } + + ret = v4l2_subdev_call(cxdev->cx25840, video, s_std, norm); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "cx25840 norm setup failed (%d)\n", + ret); + return ret; + } + +ret_savenorm: + cxdev->norm = norm; + + return 0; +} + +static int cxusb_medion_s_input(struct file *file, void *fh, + unsigned int i) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret; + v4l2_std_id norm; + + if (i >= CXUSB_INPUT_CNT) + return -EINVAL; + + ret = v4l2_subdev_call(cxdev->cx25840, video, s_routing, + cxusb_medion_inputs[i].inputcfg, 0, 0); + if (ret != 0) + return ret; + + cxdev->input = i; + cxdev->videodev->tvnorms = cxusb_medion_inputs[i].input.std; + + norm = cxdev->norm & cxusb_medion_inputs[i].input.std; + if (norm == 0) + norm = cxusb_medion_inputs[i].input.std; + + cxusb_medion_set_norm(cxdev, norm); + + return 0; +} + +static int cxusb_medion_g_tuner(struct file *file, void *fh, + struct v4l2_tuner *tuner) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + struct video_device *vdev = video_devdata(file); + int ret; + + if (tuner->index != 0) + return -EINVAL; + + if (vdev->vfl_type == VFL_TYPE_GRABBER) + tuner->type = V4L2_TUNER_ANALOG_TV; + else + tuner->type = V4L2_TUNER_RADIO; + + tuner->capability = 0; + tuner->afc = 0; + + /* + * fills: + * always: capability (static), rangelow (static), rangehigh (static) + * radio mode: afc (may fail silently), rxsubchans (static), audmode + */ + ret = v4l2_subdev_call(cxdev->tda9887, tuner, g_tuner, tuner); + if (ret != 0) + return ret; + + /* + * fills: + * always: capability (static), rangelow (static), rangehigh (static) + * radio mode: rxsubchans (always stereo), audmode, + * signal (might be wrong) + */ + ret = v4l2_subdev_call(cxdev->tuner, tuner, g_tuner, tuner); + if (ret != 0) + return ret; + + tuner->signal = 0; + + /* + * fills: TV mode: capability, rxsubchans, audmode, signal + */ + ret = v4l2_subdev_call(cxdev->cx25840, tuner, g_tuner, tuner); + if (ret != 0) + return ret; + + if (vdev->vfl_type == VFL_TYPE_GRABBER) + strscpy(tuner->name, "TV tuner", sizeof(tuner->name)); + else + strscpy(tuner->name, "Radio tuner", sizeof(tuner->name)); + + memset(tuner->reserved, 0, sizeof(tuner->reserved)); + + return 0; +} + +static int cxusb_medion_s_tuner(struct file *file, void *fh, + const struct v4l2_tuner *tuner) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + struct video_device *vdev = video_devdata(file); + int ret; + + if (tuner->index != 0) + return -EINVAL; + + ret = v4l2_subdev_call(cxdev->tda9887, tuner, s_tuner, tuner); + if (ret != 0) + return ret; + + ret = v4l2_subdev_call(cxdev->tuner, tuner, s_tuner, tuner); + if (ret != 0) + return ret; + + /* + * make sure that cx25840 is in a correct TV / radio mode, + * since calls above may have changed it for tuner / IF demod + */ + if (vdev->vfl_type == VFL_TYPE_GRABBER) + v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm); + else + v4l2_subdev_call(cxdev->cx25840, tuner, s_radio); + + return v4l2_subdev_call(cxdev->cx25840, tuner, s_tuner, tuner); +} + +static int cxusb_medion_g_frequency(struct file *file, void *fh, + struct v4l2_frequency *freq) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + if (freq->tuner != 0) + return -EINVAL; + + return v4l2_subdev_call(cxdev->tuner, tuner, g_frequency, freq); +} + +static int cxusb_medion_s_frequency(struct file *file, void *fh, + const struct v4l2_frequency *freq) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + struct video_device *vdev = video_devdata(file); + int ret; + + if (freq->tuner != 0) + return -EINVAL; + + ret = v4l2_subdev_call(cxdev->tda9887, tuner, s_frequency, freq); + if (ret != 0) + return ret; + + ret = v4l2_subdev_call(cxdev->tuner, tuner, s_frequency, freq); + if (ret != 0) + return ret; + + /* + * make sure that cx25840 is in a correct TV / radio mode, + * since calls above may have changed it for tuner / IF demod + */ + if (vdev->vfl_type == VFL_TYPE_GRABBER) + v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm); + else + v4l2_subdev_call(cxdev->cx25840, tuner, s_radio); + + return v4l2_subdev_call(cxdev->cx25840, tuner, s_frequency, freq); +} + +static int cxusb_medion_g_std(struct file *file, void *fh, + v4l2_std_id *norm) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + *norm = cxdev->norm; + + if (*norm == V4L2_STD_UNKNOWN) + return -ENODATA; + + return 0; +} + +static int cxusb_medion_s_std(struct file *file, void *fh, + v4l2_std_id norm) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + return cxusb_medion_set_norm(cxdev, norm); +} + +static int cxusb_medion_querystd(struct file *file, void *fh, + v4l2_std_id *norm) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + v4l2_std_id norm_mask; + int ret; + + /* + * make sure we don't have improper std bits set for the TV tuner + * (could happen when no signal was present yet after reset) + */ + if (cxdev->input == 0) + norm_mask = V4L2_STD_PAL; + else + norm_mask = V4L2_STD_ALL; + + ret = v4l2_subdev_call(cxdev->cx25840, video, querystd, norm); + if (ret != 0) { + cxusb_vprintk(dvbdev, OPS, + "cannot get detected standard for input %u\n", + (unsigned int)cxdev->input); + return ret; + } + + cxusb_vprintk(dvbdev, OPS, "input %u detected standard is %lx\n", + (unsigned int)cxdev->input, (unsigned long)*norm); + *norm &= norm_mask; + + return 0; +} + +static int cxusb_medion_log_status(struct file *file, void *fh) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + v4l2_device_call_all(&cxdev->v4l2dev, 0, core, log_status); + + return 0; +} + +static const struct v4l2_ioctl_ops cxusb_video_ioctl = { + .vidioc_querycap = cxusb_medion_v_querycap, + .vidioc_enum_fmt_vid_cap = cxusb_medion_v_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = cxusb_medion_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = cxusb_medion_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = cxusb_medion_try_fmt_vid_cap, + .vidioc_enum_input = cxusb_medion_enum_input, + .vidioc_g_input = cxusb_medion_g_input, + .vidioc_s_input = cxusb_medion_s_input, + .vidioc_g_tuner = cxusb_medion_g_tuner, + .vidioc_s_tuner = cxusb_medion_s_tuner, + .vidioc_g_frequency = cxusb_medion_g_frequency, + .vidioc_s_frequency = cxusb_medion_s_frequency, + .vidioc_g_std = cxusb_medion_g_std, + .vidioc_s_std = cxusb_medion_s_std, + .vidioc_querystd = cxusb_medion_querystd, + .vidioc_log_status = cxusb_medion_log_status, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff +}; + +static const struct v4l2_ioctl_ops cxusb_radio_ioctl = { + .vidioc_querycap = cxusb_medion_v_querycap, + .vidioc_g_tuner = cxusb_medion_g_tuner, + .vidioc_s_tuner = cxusb_medion_s_tuner, + .vidioc_g_frequency = cxusb_medion_g_frequency, + .vidioc_s_frequency = cxusb_medion_s_frequency, + .vidioc_log_status = cxusb_medion_log_status +}; + +/* + * in principle, this should be const, but s_io_pin_config is declared + * to take non-const, and gcc complains + */ +static struct v4l2_subdev_io_pin_config cxusub_medion_pin_config[] = { + { .pin = CX25840_PIN_DVALID_PRGM0, .function = CX25840_PAD_DEFAULT, + .strength = CX25840_PIN_DRIVE_MEDIUM }, + { .pin = CX25840_PIN_PLL_CLK_PRGM7, .function = CX25840_PAD_AUX_PLL }, + { .pin = CX25840_PIN_HRESET_PRGM2, .function = CX25840_PAD_ACTIVE, + .strength = CX25840_PIN_DRIVE_MEDIUM } +}; + +int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + u8 tuner_analog_msg_data[] = { 0x9c, 0x60, 0x85, 0x54 }; + struct i2c_msg tuner_analog_msg = { .addr = 0x61, .flags = 0, + .buf = tuner_analog_msg_data, + .len = + sizeof(tuner_analog_msg_data) }; + struct v4l2_subdev_format subfmt; + int ret; + + /* switch tuner to analog mode so IF demod will become accessible */ + ret = i2c_transfer(&dvbdev->i2c_adap, &tuner_analog_msg, 1); + if (ret != 1) + dev_warn(&dvbdev->udev->dev, + "tuner analog switch failed (%d)\n", ret); + + /* + * cx25840 might have lost power during mode switching so we need + * to set it again + */ + ret = v4l2_subdev_call(cxdev->cx25840, core, reset, 0); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "cx25840 reset failed (%d)\n", ret); + + ret = v4l2_subdev_call(cxdev->cx25840, video, s_routing, + CX25840_COMPOSITE1, 0, 0); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "cx25840 initial input setting failed (%d)\n", ret); + + /* composite */ + cxdev->input = 1; + cxdev->videodev->tvnorms = V4L2_STD_ALL; + cxdev->norm = V4L2_STD_PAL; + + /* TODO: setup audio samples insertion */ + + ret = v4l2_subdev_call(cxdev->cx25840, core, s_io_pin_config, + ARRAY_SIZE(cxusub_medion_pin_config), + cxusub_medion_pin_config); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "cx25840 pin config failed (%d)\n", ret); + + /* make sure that we aren't in radio mode */ + v4l2_subdev_call(cxdev->tda9887, video, s_std, cxdev->norm); + v4l2_subdev_call(cxdev->tuner, video, s_std, cxdev->norm); + v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm); + + memset(&subfmt, 0, sizeof(subfmt)); + subfmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + subfmt.format.width = cxdev->width; + subfmt.format.height = cxdev->height; + subfmt.format.code = MEDIA_BUS_FMT_FIXED; + subfmt.format.field = V4L2_FIELD_SEQ_TB; + subfmt.format.colorspace = V4L2_COLORSPACE_SMPTE170M; + + ret = v4l2_subdev_call(cxdev->cx25840, pad, set_fmt, NULL, &subfmt); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "cx25840 format set failed (%d)\n", ret); + + if (ret == 0) { + cxdev->width = subfmt.format.width; + cxdev->height = subfmt.format.height; + } + + return 0; +} + +static int cxusb_videoradio_open(struct file *f) +{ + struct dvb_usb_device *dvbdev = video_drvdata(f); + int ret; + + /* + * no locking needed since this call only modifies analog + * state if there are no other analog handles currenly + * opened so ops done via them cannot create a conflict + */ + ret = cxusb_medion_get(dvbdev, CXUSB_OPEN_ANALOG); + if (ret != 0) + return ret; + + ret = v4l2_fh_open(f); + if (ret != 0) + goto ret_release; + + cxusb_vprintk(dvbdev, OPS, "got open\n"); + + return 0; + +ret_release: + cxusb_medion_put(dvbdev); + + return ret; +} + +static int cxusb_videoradio_release(struct file *f) +{ + struct video_device *vdev = video_devdata(f); + struct dvb_usb_device *dvbdev = video_drvdata(f); + int ret; + + cxusb_vprintk(dvbdev, OPS, "got release\n"); + + if (vdev->vfl_type == VFL_TYPE_GRABBER) + ret = vb2_fop_release(f); + else + ret = v4l2_fh_release(f); + + cxusb_medion_put(dvbdev); + + return ret; +} + +static const struct v4l2_file_operations cxusb_video_fops = { + .owner = THIS_MODULE, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, + .open = cxusb_videoradio_open, + .release = cxusb_videoradio_release +}; + +static const struct v4l2_file_operations cxusb_radio_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = cxusb_videoradio_open, + .release = cxusb_videoradio_release +}; + +static void cxusb_medion_v4l2_release(struct v4l2_device *v4l2_dev) +{ + struct cxusb_medion_dev *cxdev = + container_of(v4l2_dev, struct cxusb_medion_dev, v4l2dev); + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + + cxusb_vprintk(dvbdev, OPS, "v4l2 device release\n"); + + v4l2_device_unregister(&cxdev->v4l2dev); + + mutex_destroy(&cxdev->dev_lock); + + while (completion_done(&cxdev->v4l2_release)) + schedule(); + + complete(&cxdev->v4l2_release); +} + +static void cxusb_medion_videodev_release(struct video_device *vdev) +{ + struct dvb_usb_device *dvbdev = video_get_drvdata(vdev); + + cxusb_vprintk(dvbdev, OPS, "video device release\n"); + + vb2_queue_release(vdev->queue); + + video_device_release(vdev); +} + +static int cxusb_medion_register_analog_video(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret; + + cxdev->videoqueue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cxdev->videoqueue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | + VB2_DMABUF; + cxdev->videoqueue.ops = &cxdev_video_qops; + cxdev->videoqueue.mem_ops = &vb2_vmalloc_memops; + cxdev->videoqueue.drv_priv = dvbdev; + cxdev->videoqueue.buf_struct_size = + sizeof(struct cxusb_medion_vbuffer); + cxdev->videoqueue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + cxdev->videoqueue.min_buffers_needed = 6; + cxdev->videoqueue.lock = &cxdev->dev_lock; + + ret = vb2_queue_init(&cxdev->videoqueue); + if (ret) { + dev_err(&dvbdev->udev->dev, + "video queue init failed, ret = %d\n", ret); + return ret; + } + + cxdev->videodev = video_device_alloc(); + if (!cxdev->videodev) { + dev_err(&dvbdev->udev->dev, "video device alloc failed\n"); + ret = -ENOMEM; + goto ret_qrelease; + } + + cxdev->videodev->device_caps = videocaps; + cxdev->videodev->fops = &cxusb_video_fops; + cxdev->videodev->v4l2_dev = &cxdev->v4l2dev; + cxdev->videodev->queue = &cxdev->videoqueue; + strscpy(cxdev->videodev->name, "cxusb", sizeof(cxdev->videodev->name)); + cxdev->videodev->vfl_dir = VFL_DIR_RX; + cxdev->videodev->ioctl_ops = &cxusb_video_ioctl; + cxdev->videodev->tvnorms = V4L2_STD_ALL; + cxdev->videodev->release = cxusb_medion_videodev_release; + cxdev->videodev->lock = &cxdev->dev_lock; + video_set_drvdata(cxdev->videodev, dvbdev); + + ret = video_register_device(cxdev->videodev, VFL_TYPE_GRABBER, -1); + if (ret) { + dev_err(&dvbdev->udev->dev, + "video device register failed, ret = %d\n", ret); + goto ret_vrelease; + } + + return 0; + +ret_vrelease: + video_device_release(cxdev->videodev); + +ret_qrelease: + vb2_queue_release(&cxdev->videoqueue); + + return ret; +} + +static int cxusb_medion_register_analog_radio(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret; + + cxdev->radiodev = video_device_alloc(); + if (!cxdev->radiodev) { + dev_err(&dvbdev->udev->dev, "radio device alloc failed\n"); + return -ENOMEM; + } + + cxdev->radiodev->device_caps = radiocaps; + cxdev->radiodev->fops = &cxusb_radio_fops; + cxdev->radiodev->v4l2_dev = &cxdev->v4l2dev; + strscpy(cxdev->radiodev->name, "cxusb", sizeof(cxdev->radiodev->name)); + cxdev->radiodev->vfl_dir = VFL_DIR_RX; + cxdev->radiodev->ioctl_ops = &cxusb_radio_ioctl; + cxdev->radiodev->release = video_device_release; + cxdev->radiodev->lock = &cxdev->dev_lock; + video_set_drvdata(cxdev->radiodev, dvbdev); + + ret = video_register_device(cxdev->radiodev, VFL_TYPE_RADIO, -1); + if (ret) { + dev_err(&dvbdev->udev->dev, + "radio device register failed, ret = %d\n", ret); + video_device_release(cxdev->radiodev); + return ret; + } + + return 0; +} + +static int cxusb_medion_register_analog_subdevs(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret; + struct tuner_setup tun_setup; + + /* attach cx25840 capture chip */ + cxdev->cx25840 = v4l2_i2c_new_subdev(&cxdev->v4l2dev, + &dvbdev->i2c_adap, + "cx25840", 0x44, NULL); + if (!cxdev->cx25840) { + dev_err(&dvbdev->udev->dev, "cx25840 not found\n"); + return -ENODEV; + } + + /* + * Initialize cx25840 chip by calling its subdevice init core op. + * + * This switches it into the generic mode that disables some of + * ivtv-related hacks in the cx25840 driver while allowing setting + * of the chip video output configuration (passed in the call below + * as the last argument). + */ + ret = v4l2_subdev_call(cxdev->cx25840, core, init, + CX25840_VCONFIG_FMT_BT656 | + CX25840_VCONFIG_RES_8BIT | + CX25840_VCONFIG_VBIRAW_DISABLED | + CX25840_VCONFIG_ANCDATA_DISABLED | + CX25840_VCONFIG_ACTIVE_COMPOSITE | + CX25840_VCONFIG_VALID_ANDACTIVE | + CX25840_VCONFIG_HRESETW_NORMAL | + CX25840_VCONFIG_CLKGATE_NONE | + CX25840_VCONFIG_DCMODE_DWORDS); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "cx25840 init failed (%d)\n", ret); + return ret; + } + + /* attach analog tuner */ + cxdev->tuner = v4l2_i2c_new_subdev(&cxdev->v4l2dev, + &dvbdev->i2c_adap, + "tuner", 0x61, NULL); + if (!cxdev->tuner) { + dev_err(&dvbdev->udev->dev, "tuner not found\n"); + return -ENODEV; + } + + /* configure it */ + memset(&tun_setup, 0, sizeof(tun_setup)); + tun_setup.addr = 0x61; + tun_setup.type = TUNER_PHILIPS_FMD1216ME_MK3; + tun_setup.mode_mask = T_RADIO | T_ANALOG_TV; + v4l2_subdev_call(cxdev->tuner, tuner, s_type_addr, &tun_setup); + + /* attach IF demod */ + cxdev->tda9887 = v4l2_i2c_new_subdev(&cxdev->v4l2dev, + &dvbdev->i2c_adap, + "tuner", 0x43, NULL); + if (!cxdev->tda9887) { + dev_err(&dvbdev->udev->dev, "tda9887 not found\n"); + return -ENODEV; + } + + return 0; +} + +int cxusb_medion_register_analog(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret; + + mutex_init(&cxdev->dev_lock); + + init_completion(&cxdev->v4l2_release); + + cxdev->v4l2dev.release = cxusb_medion_v4l2_release; + + ret = v4l2_device_register(&dvbdev->udev->dev, &cxdev->v4l2dev); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "V4L2 device registration failed, ret = %d\n", ret); + mutex_destroy(&cxdev->dev_lock); + return ret; + } + + ret = cxusb_medion_register_analog_subdevs(dvbdev); + if (ret) + goto ret_unregister; + + INIT_WORK(&cxdev->urbwork, cxusb_medion_v_complete_work); + INIT_LIST_HEAD(&cxdev->buflist); + + cxdev->width = 320; + cxdev->height = 240; + + ret = cxusb_medion_register_analog_video(dvbdev); + if (ret) + goto ret_unregister; + + ret = cxusb_medion_register_analog_radio(dvbdev); + if (ret) + goto ret_vunreg; + + return 0; + +ret_vunreg: + video_unregister_device(cxdev->videodev); + +ret_unregister: + v4l2_device_put(&cxdev->v4l2dev); + wait_for_completion(&cxdev->v4l2_release); + + return ret; +} + +void cxusb_medion_unregister_analog(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + cxusb_vprintk(dvbdev, OPS, "unregistering analog\n"); + + video_unregister_device(cxdev->radiodev); + video_unregister_device(cxdev->videodev); + + v4l2_device_put(&cxdev->v4l2dev); + wait_for_completion(&cxdev->v4l2_release); + + cxusb_vprintk(dvbdev, OPS, "analog unregistered\n"); +} diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 8039ba4ebf68..bac0778f7def 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -12,18 +12,21 @@ * design, so it can be reused for the "analogue-only" device (if it will * appear at all). * - * TODO: Use the cx25840-driver for the analogue part * * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@posteo.de) * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org) * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au) + * Copyright (C) 2011, 2017 Maciej S. Szmigiero (mail@maciej.szmigiero.name) * * see Documentation/media/dvb-drivers/dvb-usb.rst for more information */ #include <media/tuner.h> -#include <linux/vmalloc.h> -#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/device.h> #include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/vmalloc.h> #include "cxusb.h" @@ -44,17 +47,45 @@ #include "si2157.h" /* debug */ -static int dvb_usb_cxusb_debug; +int dvb_usb_cxusb_debug; module_param_named(debug, dvb_usb_cxusb_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); +MODULE_PARM_DESC(debug, "set debugging level (see cxusb.h)." + DVB_USB_DEBUG_STATUS); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#define deb_info(args...) dprintk(dvb_usb_cxusb_debug, 0x03, args) -#define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, 0x02, args) +#define deb_info(args...) dprintk(dvb_usb_cxusb_debug, CXUSB_DBG_MISC, args) +#define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, CXUSB_DBG_I2C, args) -static int cxusb_ctrl_msg(struct dvb_usb_device *d, - u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen) +enum cxusb_table_index { + MEDION_MD95700, + DVICO_BLUEBIRD_LG064F_COLD, + DVICO_BLUEBIRD_LG064F_WARM, + DVICO_BLUEBIRD_DUAL_1_COLD, + DVICO_BLUEBIRD_DUAL_1_WARM, + DVICO_BLUEBIRD_LGZ201_COLD, + DVICO_BLUEBIRD_LGZ201_WARM, + DVICO_BLUEBIRD_TH7579_COLD, + DVICO_BLUEBIRD_TH7579_WARM, + DIGITALNOW_BLUEBIRD_DUAL_1_COLD, + DIGITALNOW_BLUEBIRD_DUAL_1_WARM, + DVICO_BLUEBIRD_DUAL_2_COLD, + DVICO_BLUEBIRD_DUAL_2_WARM, + DVICO_BLUEBIRD_DUAL_4, + DVICO_BLUEBIRD_DVB_T_NANO_2, + DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM, + AVERMEDIA_VOLAR_A868R, + DVICO_BLUEBIRD_DUAL_4_REV_2, + CONEXANT_D680_DMB, + MYGICA_D689, + MYGICA_T230, + NR__cxusb_table_index +}; + +static struct usb_device_id cxusb_table[]; + +int cxusb_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen) { struct cxusb_state *st = d->priv; int ret; @@ -86,7 +117,8 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) struct cxusb_state *st = d->priv; u8 o[2], i; - if (st->gpio_write_state[GPIO_TUNER] == onoff) + if (st->gpio_write_state[GPIO_TUNER] == onoff && + !st->gpio_write_refresh[GPIO_TUNER]) return; o[0] = GPIO_TUNER; @@ -97,10 +129,11 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) deb_info("gpio_write failed.\n"); st->gpio_write_state[GPIO_TUNER] = onoff; + st->gpio_write_refresh[GPIO_TUNER] = false; } static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask, - u8 newval) + u8 newval) { u8 o[2], gpio_state; int rc; @@ -128,7 +161,7 @@ static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff) } static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d, - u8 addr, int onoff) + u8 addr, int onoff) { u8 o[2] = {addr, onoff}; u8 i; @@ -138,12 +171,12 @@ static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d, if (rc < 0) return rc; + if (i == 0x01) return 0; - else { - deb_info("gpio_write failed.\n"); - return -EIO; - } + + deb_info("gpio_write failed.\n"); + return -EIO; } /* I2C */ @@ -158,7 +191,6 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], return -EAGAIN; for (i = 0; i < num; i++) { - if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_MEDION) switch (msg[i].addr) { case 0x63: @@ -184,13 +216,13 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[2] = msg[i].addr; if (cxusb_ctrl_msg(d, CMD_I2C_READ, obuf, 3, - ibuf, 1+msg[i].len) < 0) { + ibuf, 1 + msg[i].len) < 0) { warn("i2c read failed"); break; } memcpy(msg[i].buf, &ibuf[1], msg[i].len); - } else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) && - msg[i].addr == msg[i+1].addr) { + } else if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD) && + msg[i].addr == msg[i + 1].addr) { /* write to then read from same address */ u8 obuf[MAX_XFER_SIZE], ibuf[MAX_XFER_SIZE]; @@ -207,19 +239,19 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], goto unlock; } obuf[0] = msg[i].len; - obuf[1] = msg[i+1].len; + obuf[1] = msg[i + 1].len; obuf[2] = msg[i].addr; memcpy(&obuf[3], msg[i].buf, msg[i].len); if (cxusb_ctrl_msg(d, CMD_I2C_READ, - obuf, 3+msg[i].len, - ibuf, 1+msg[i+1].len) < 0) + obuf, 3 + msg[i].len, + ibuf, 1 + msg[i + 1].len) < 0) break; if (ibuf[0] != 0x08) deb_i2c("i2c read may have failed\n"); - memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); + memcpy(msg[i + 1].buf, &ibuf[1], msg[i + 1].len); i++; } else { @@ -237,7 +269,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], memcpy(&obuf[2], msg[i].buf, msg[i].len); if (cxusb_ctrl_msg(d, CMD_I2C_WRITE, obuf, - 2+msg[i].len, &ibuf,1) < 0) + 2 + msg[i].len, &ibuf, 1) < 0) break; if (ibuf != 0x08) deb_i2c("i2c write may have failed\n"); @@ -256,7 +288,7 @@ unlock: static u32 cxusb_i2c_func(struct i2c_adapter *adapter) { - return I2C_FUNC_I2C; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } static struct i2c_algorithm cxusb_i2c_algo = { @@ -264,29 +296,67 @@ static struct i2c_algorithm cxusb_i2c_algo = { .functionality = cxusb_i2c_func, }; -static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) +static int _cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) { u8 b = 0; + + deb_info("setting power %s\n", onoff ? "ON" : "OFF"); + if (onoff) return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); else return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0); } +static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + bool is_medion = d->props.devices[0].warm_ids[0] == &cxusb_table[MEDION_MD95700]; + int ret; + + if (is_medion && !onoff) { + struct cxusb_medion_dev *cxdev = d->priv; + + mutex_lock(&cxdev->open_lock); + + if (cxdev->open_type == CXUSB_OPEN_ANALOG) { + deb_info("preventing DVB core from setting power OFF while we are in analog mode\n"); + ret = -EBUSY; + goto ret_unlock; + } + } + + ret = _cxusb_power_ctrl(d, onoff); + +ret_unlock: + if (is_medion && !onoff) { + struct cxusb_medion_dev *cxdev = d->priv; + + mutex_unlock(&cxdev->open_lock); + } + + return ret; +} + static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) { int ret; + if (!onoff) return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0); if (d->state == DVB_USB_STATE_INIT && usb_set_interface(d->udev, 0, 0) < 0) err("set interface failed"); - do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) && - !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) && - !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0); + do { + /* Nothing */ + } while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) && + !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) && + !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0); + if (!ret) { - /* FIXME: We don't know why, but we need to configure the - * lgdt3303 with the register settings below on resume */ + /* + * FIXME: We don't know why, but we need to configure the + * lgdt3303 with the register settings below on resume + */ int i; u8 buf; static const u8 bufs[] = { @@ -304,7 +374,7 @@ static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) msleep(20); for (i = 0; i < ARRAY_SIZE(bufs); i += 4 / sizeof(u8)) { ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE, - bufs+i, 4, &buf, 1); + bufs + i, 4, &buf, 1); if (ret) break; if (buf != 0x8) @@ -317,6 +387,7 @@ static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff) { u8 b = 0; + if (onoff) return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); else @@ -338,6 +409,7 @@ static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff) { int ret; u8 b; + ret = cxusb_power_ctrl(d, onoff); if (!onoff) return ret; @@ -350,11 +422,26 @@ static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff) static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { + struct dvb_usb_device *dvbdev = adap->dev; + bool is_medion = dvbdev->props.devices[0].warm_ids[0] == + &cxusb_table[MEDION_MD95700]; u8 buf[2] = { 0x03, 0x00 }; + + if (is_medion && onoff) { + int ret; + + ret = cxusb_medion_get(dvbdev, CXUSB_OPEN_DIGITAL); + if (ret != 0) + return ret; + } + if (onoff) - cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, buf, 2, NULL, 0); + cxusb_ctrl_msg(dvbdev, CMD_STREAMING_ON, buf, 2, NULL, 0); else - cxusb_ctrl_msg(adap->dev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); + cxusb_ctrl_msg(dvbdev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); + + if (is_medion && !onoff) + cxusb_medion_put(dvbdev); return 0; } @@ -370,7 +457,7 @@ static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) } static int cxusb_read_status(struct dvb_frontend *fe, - enum fe_status *status) + enum fe_status *status) { struct dvb_usb_adapter *adap = (struct dvb_usb_adapter *)fe->dvb->priv; struct cxusb_state *state = (struct cxusb_state *)adap->dev->priv; @@ -403,8 +490,8 @@ static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d) return; while (1) { if (usb_bulk_msg(d->udev, - usb_rcvbulkpipe(d->udev, ep), - junk, junk_len, &rd_count, timeout) < 0) + usb_rcvbulkpipe(d->udev, ep), + junk, junk_len, &rd_count, timeout) < 0) break; if (!rd_count) break; @@ -426,8 +513,8 @@ static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d) return; while (1) { if (usb_bulk_msg(d->udev, - usb_rcvbulkpipe(d->udev, p->endpoint), - junk, junk_len, &rd_count, timeout) < 0) + usb_rcvbulkpipe(d->udev, p->endpoint), + junk, junk_len, &rd_count, timeout) < 0) break; if (!rd_count) break; @@ -435,17 +522,18 @@ static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d) kfree(junk); } -static int cxusb_d680_dmb_streaming_ctrl( - struct dvb_usb_adapter *adap, int onoff) +static int cxusb_d680_dmb_streaming_ctrl(struct dvb_usb_adapter *adap, + int onoff) { if (onoff) { u8 buf[2] = { 0x03, 0x00 }; + cxusb_d680_dmb_drain_video(adap->dev); return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, - buf, sizeof(buf), NULL, 0); + buf, sizeof(buf), NULL, 0); } else { int ret = cxusb_ctrl_msg(adap->dev, - CMD_STREAMING_OFF, NULL, 0, NULL, 0); + CMD_STREAMING_OFF, NULL, 0, NULL, 0); return ret; } } @@ -465,8 +553,12 @@ static int cxusb_rc_query(struct dvb_usb_device *d) static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d) { u8 ircode[4]; - struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, - .buf = ircode, .len = 4 }; + struct i2c_msg msg = { + .addr = 0x6b, + .flags = I2C_M_RD, + .buf = ircode, + .len = 4 + }; if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1) return 0; @@ -490,13 +582,13 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d) return 0; } -static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) +static int cxusb_dee1601_demod_init(struct dvb_frontend *fe) { - static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; - static u8 reset [] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 }; - static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; + static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x28 }; + static u8 reset[] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0x20 }; + static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 }; static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; mt352_write(fe, clock_config, sizeof(clock_config)); @@ -511,13 +603,14 @@ static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) return 0; } -static int cxusb_mt352_demod_init(struct dvb_frontend* fe) -{ /* used in both lgz201 and th7579 */ - static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x29 }; - static u8 reset [] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 }; - static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; +static int cxusb_mt352_demod_init(struct dvb_frontend *fe) +{ + /* used in both lgz201 and th7579 */ + static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x29 }; + static u8 reset[] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg[] = { AGC_TARGET, 0x24, 0x20 }; + static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 }; static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; mt352_write(fe, clock_config, sizeof(clock_config)); @@ -627,9 +720,21 @@ static struct max2165_config mygica_d689_max2165_cfg = { /* Callbacks for DVB USB */ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { + struct dvb_usb_device *dvbdev = adap->dev; + bool is_medion = dvbdev->props.devices[0].warm_ids[0] == + &cxusb_table[MEDION_MD95700]; + dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe, - &adap->dev->i2c_adap, 0x61, + &dvbdev->i2c_adap, 0x61, TUNER_PHILIPS_FMD1216ME_MK3); + + if (is_medion && adap->fe_adap[0].fe) + /* + * make sure that DVB core won't put to sleep (reset, really) + * tuner when we might be open in analog mode + */ + adap->fe_adap[0].fe->ops.tuner_ops.sleep = NULL; + return 0; } @@ -642,7 +747,8 @@ static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_LG_Z201); + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, + NULL, DVB_PLL_LG_Z201); return 0; } @@ -702,7 +808,7 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) adap->fe_adap[0].fe->callback = dvico_bluebird_xc2028_callback; fe = dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &cfg); - if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) + if (!fe || !fe->ops.tuner_ops.set_config) return -EIO; fe->ops.tuner_ops.set_config(fe, &ctl); @@ -720,33 +826,120 @@ static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) { struct dvb_frontend *fe; + fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &d680_dmb_tuner); - return (fe == NULL) ? -EIO : 0; + return (!fe) ? -EIO : 0; } static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap) { struct dvb_frontend *fe; + fe = dvb_attach(max2165_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &mygica_d689_max2165_cfg); - return (fe == NULL) ? -EIO : 0; + return (!fe) ? -EIO : 0; } -static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) +static int cxusb_medion_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) { + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *dvbdev = adap->dev; + + if (acquire) + return cxusb_medion_get(dvbdev, CXUSB_OPEN_DIGITAL); + + cxusb_medion_put(dvbdev); + + return 0; +} + +static int cxusb_medion_set_mode(struct dvb_usb_device *dvbdev, bool digital) +{ + struct cxusb_state *st = dvbdev->priv; + int ret; u8 b; - if (usb_set_interface(adap->dev->udev, 0, 6) < 0) - err("set interface failed"); + unsigned int i; - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1); + /* + * switching mode while doing an I2C transaction often causes + * the device to crash + */ + mutex_lock(&dvbdev->i2c_mutex); + + if (digital) { + ret = usb_set_interface(dvbdev->udev, 0, 6); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "digital interface selection failed (%d)\n", + ret); + goto ret_unlock; + } + } else { + ret = usb_set_interface(dvbdev->udev, 0, 1); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "analog interface selection failed (%d)\n", + ret); + goto ret_unlock; + } + } + + /* pipes need to be cleared after setting interface */ + ret = usb_clear_halt(dvbdev->udev, usb_rcvbulkpipe(dvbdev->udev, 1)); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "clear halt on IN pipe failed (%d)\n", + ret); + + ret = usb_clear_halt(dvbdev->udev, usb_sndbulkpipe(dvbdev->udev, 1)); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "clear halt on OUT pipe failed (%d)\n", + ret); + + ret = cxusb_ctrl_msg(dvbdev, digital ? CMD_DIGITAL : CMD_ANALOG, + NULL, 0, &b, 1); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, "mode switch failed (%d)\n", + ret); + goto ret_unlock; + } + + /* mode switch seems to reset GPIO states */ + for (i = 0; i < ARRAY_SIZE(st->gpio_write_refresh); i++) + st->gpio_write_refresh[i] = true; + +ret_unlock: + mutex_unlock(&dvbdev->i2c_mutex); + + return ret; +} + +static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *dvbdev = adap->dev; + bool is_medion = dvbdev->props.devices[0].warm_ids[0] == + &cxusb_table[MEDION_MD95700]; + + if (is_medion) { + int ret; + + ret = cxusb_medion_set_mode(dvbdev, true); + if (ret) + return ret; + } adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) - return 0; + &dvbdev->i2c_adap); + if (!adap->fe_adap[0].fe) + return -EIO; - return -EIO; + if (is_medion) + adap->fe_adap[0].fe->ops.ts_bus_ctrl = + cxusb_medion_fe_ts_bus_ctrl; + + return 0; } static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) @@ -760,7 +953,7 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) &cxusb_lgdt3303_config, 0x0e, &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) + if (adap->fe_adap[0].fe) return 0; return -EIO; @@ -772,7 +965,7 @@ static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) &cxusb_aver_lgdt3303_config, 0x0e, &adap->dev->i2c_adap); - if (adap->fe_adap[0].fe != NULL) + if (adap->fe_adap[0].fe) return 0; return -EIO; @@ -788,7 +981,7 @@ static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap) adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_config, &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) + if (adap->fe_adap[0].fe) return 0; return -EIO; @@ -803,13 +996,13 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) + if (adap->fe_adap[0].fe) return 0; adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &cxusb_zl10353_dee1601_config, &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) + if (adap->fe_adap[0].fe) return 0; return -EIO; @@ -819,8 +1012,12 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) { u8 ircode[4]; int i; - struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, - .buf = ircode, .len = 4 }; + struct i2c_msg msg = { + .addr = 0x6b, + .flags = I2C_M_RD, + .buf = ircode, + .len = 4 + }; if (usb_set_interface(adap->dev->udev, 0, 1) < 0) err("set interface failed"); @@ -836,7 +1033,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) dvb_attach(zl10353_attach, &cxusb_zl10353_xc3028_config_no_i2c_gate, &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) == NULL) + if (!adap->fe_adap[0].fe) return -EIO; /* try to determine if there is no IR decoder on the I2C bus */ @@ -934,7 +1131,7 @@ static struct dib7000p_config cxusb_dualdig4_rev2_config = { }; struct dib0700_adapter_state { - int (*set_param_save)(struct dvb_frontend *); + int (*set_param_save)(struct dvb_frontend *fe); struct dib7000p_ops dib7000p_ops; }; @@ -953,14 +1150,15 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - &cxusb_dualdig4_rev2_config) < 0) { - printk(KERN_WARNING "Unable to enumerate dib7000p\n"); + &cxusb_dualdig4_rev2_config) < 0) { + pr_warn("Unable to enumerate dib7000p\n"); return -ENODEV; } - adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, - &cxusb_dualdig4_rev2_config); - if (adap->fe_adap[0].fe == NULL) + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, + 0x80, + &cxusb_dualdig4_rev2_config); + if (!adap->fe_adap[0].fe) return -EIO; return 0; @@ -993,11 +1191,16 @@ static int dib7070_set_param_override(struct dvb_frontend *fe) struct dib0700_adapter_state *state = adap->priv; u16 offset; - u8 band = BAND_OF_FREQUENCY(p->frequency/1000); + u8 band = BAND_OF_FREQUENCY(p->frequency / 1000); + switch (band) { - case BAND_VHF: offset = 950; break; + case BAND_VHF: + offset = 950; + break; default: - case BAND_UHF: offset = 550; break; + case BAND_UHF: + offset = 550; + break; } state->dib7000p_ops.set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); @@ -1019,7 +1222,7 @@ static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) DIBX000_I2C_INTERFACE_TUNER, 1); if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, - &dib7070p_dib0070_config) == NULL) + &dib7070p_dib0070_config) == NULL) return -ENODEV; st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; @@ -1042,13 +1245,13 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &cxusb_zl10353_xc3028_config, &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) + if (adap->fe_adap[0].fe) return 0; adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_xc3028_config, &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) + if (adap->fe_adap[0].fe) return 0; return -EIO; @@ -1079,11 +1282,14 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) /* Unblock all USB pipes */ usb_clear_halt(d->udev, - usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_sndbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint)); usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_rcvbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint)); usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); + usb_rcvbulkpipe(d->udev, + d->props.adapter[0].fe[0].stream.endpoint)); /* Drain USB pipes to avoid hang after reboot */ for (n = 0; n < 5; n++) { @@ -1105,8 +1311,9 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) msleep(100); /* Attach frontend */ - adap->fe_adap[0].fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap); - if (adap->fe_adap[0].fe == NULL) + adap->fe_adap[0].fe = dvb_attach(lgs8gxx_attach, + &d680_lgs8gl5_cfg, &d->i2c_adap); + if (!adap->fe_adap[0].fe) return -EIO; return 0; @@ -1136,12 +1343,14 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap) /* Unblock all USB pipes */ usb_clear_halt(d->udev, - usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_sndbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint)); usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_rcvbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint)); usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); - + usb_rcvbulkpipe(d->udev, + d->props.adapter[0].fe[0].stream.endpoint)); /* Reset the tuner */ if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) { @@ -1156,9 +1365,10 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap) msleep(100); /* Attach frontend */ - adap->fe_adap[0].fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg, - &d->i2c_adap); - if (adap->fe_adap[0].fe == NULL) + adap->fe_adap[0].fe = dvb_attach(atbm8830_attach, + &mygica_d689_atbm8830_cfg, + &d->i2c_adap); + if (!adap->fe_adap[0].fe) return -EIO; return 0; @@ -1181,11 +1391,14 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap) /* Unblock all USB pipes */ usb_clear_halt(d->udev, - usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_sndbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint)); usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_rcvbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint)); usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); + usb_rcvbulkpipe(d->udev, + d->props.adapter[0].fe[0].stream.endpoint)); /* attach frontend */ si2168_config.i2c_adapter = &adapter; @@ -1198,7 +1411,7 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap) info.platform_data = &si2168_config; request_module(info.type); client_demod = i2c_new_device(&d->i2c_adap, &info); - if (client_demod == NULL || client_demod->dev.driver == NULL) + if (!client_demod || !client_demod->dev.driver) return -ENODEV; if (!try_module_get(client_demod->dev.driver->owner)) { @@ -1218,7 +1431,7 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap) info.platform_data = &si2157_config; request_module(info.type); client_tuner = i2c_new_device(adapter, &info); - if (client_tuner == NULL || client_tuner->dev.driver == NULL) { + if (!client_tuner || !client_tuner->dev.driver) { module_put(client_demod->dev.driver->owner); i2c_unregister_device(client_demod); return -ENODEV; @@ -1309,6 +1522,104 @@ static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, return -EINVAL; } +int cxusb_medion_get(struct dvb_usb_device *dvbdev, + enum cxusb_open_type open_type) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret = 0; + + mutex_lock(&cxdev->open_lock); + + if (WARN_ON((cxdev->open_type == CXUSB_OPEN_INIT || + cxdev->open_type == CXUSB_OPEN_NONE) && + cxdev->open_ctr != 0)) { + ret = -EINVAL; + goto ret_unlock; + } + + if (cxdev->open_type == CXUSB_OPEN_INIT) { + ret = -EAGAIN; + goto ret_unlock; + } + + if (cxdev->open_ctr == 0) { + if (cxdev->open_type != open_type) { + deb_info("will acquire and switch to %s\n", + open_type == CXUSB_OPEN_ANALOG ? + "analog" : "digital"); + + if (open_type == CXUSB_OPEN_ANALOG) { + ret = _cxusb_power_ctrl(dvbdev, 1); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "powerup for analog switch failed (%d)\n", + ret); + + ret = cxusb_medion_set_mode(dvbdev, false); + if (ret != 0) + goto ret_unlock; + + ret = cxusb_medion_analog_init(dvbdev); + if (ret != 0) + goto ret_unlock; + } else { /* digital */ + ret = _cxusb_power_ctrl(dvbdev, 1); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "powerup for digital switch failed (%d)\n", + ret); + + ret = cxusb_medion_set_mode(dvbdev, true); + if (ret != 0) + goto ret_unlock; + } + + cxdev->open_type = open_type; + } else { + deb_info("reacquired idle %s\n", + open_type == CXUSB_OPEN_ANALOG ? + "analog" : "digital"); + } + + cxdev->open_ctr = 1; + } else if (cxdev->open_type == open_type) { + cxdev->open_ctr++; + deb_info("acquired %s\n", open_type == CXUSB_OPEN_ANALOG ? + "analog" : "digital"); + } else { + ret = -EBUSY; + } + +ret_unlock: + mutex_unlock(&cxdev->open_lock); + + return ret; +} + +void cxusb_medion_put(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + mutex_lock(&cxdev->open_lock); + + if (cxdev->open_type == CXUSB_OPEN_INIT) { + WARN_ON(cxdev->open_ctr != 0); + cxdev->open_type = CXUSB_OPEN_NONE; + goto unlock; + } + + if (!WARN_ON(cxdev->open_ctr < 1)) { + cxdev->open_ctr--; + + deb_info("release %s\n", + cxdev->open_type == CXUSB_OPEN_ANALOG ? + "analog" : "digital"); + } + +unlock: + mutex_unlock(&cxdev->open_lock); +} + /* DVB USB Driver stuff */ static struct dvb_usb_device_properties cxusb_medion_properties; static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties; @@ -1324,41 +1635,141 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties; static struct dvb_usb_device_properties cxusb_mygica_d689_properties; static struct dvb_usb_device_properties cxusb_mygica_t230_properties; +static int cxusb_medion_priv_init(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + cxdev->dvbdev = dvbdev; + cxdev->open_type = CXUSB_OPEN_INIT; + mutex_init(&cxdev->open_lock); + + return 0; +} + +static void cxusb_medion_priv_destroy(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + mutex_destroy(&cxdev->open_lock); +} + +static bool cxusb_medion_check_altsetting(struct usb_host_interface *as) +{ + unsigned int ctr; + + for (ctr = 0; ctr < as->desc.bNumEndpoints; ctr++) { + if ((as->endpoint[ctr].desc.bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK) != 2) + continue; + + if (as->endpoint[ctr].desc.bEndpointAddress & USB_DIR_IN && + ((as->endpoint[ctr].desc.bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)) + return true; + + break; + } + + return false; +} + +static bool cxusb_medion_check_intf(struct usb_interface *intf) +{ + unsigned int ctr; + + if (intf->num_altsetting < 2) { + dev_err(intf->usb_dev, "no alternate interface"); + + return false; + } + + for (ctr = 0; ctr < intf->num_altsetting; ctr++) { + if (intf->altsetting[ctr].desc.bAlternateSetting != 1) + continue; + + if (cxusb_medion_check_altsetting(&intf->altsetting[ctr])) + return true; + + break; + } + + dev_err(intf->usb_dev, "no iso interface"); + + return false; +} + static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - if (0 == dvb_usb_device_init(intf, &cxusb_medion_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dee1601_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgz201_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dtt7579_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dualdig4_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_nano2_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &cxusb_bluebird_nano2_needsfirmware_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &cxusb_bluebird_dualdig4_rev2_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_mygica_t230_properties, - THIS_MODULE, NULL, adapter_nr) || - 0) + struct dvb_usb_device *dvbdev; + int ret; + + /* Medion 95700 */ + if (!dvb_usb_device_init(intf, &cxusb_medion_properties, + THIS_MODULE, &dvbdev, adapter_nr)) { + if (!cxusb_medion_check_intf(intf)) { + ret = -ENODEV; + goto ret_uninit; + } + + _cxusb_power_ctrl(dvbdev, 1); + ret = cxusb_medion_set_mode(dvbdev, false); + if (ret) + goto ret_uninit; + + ret = cxusb_medion_register_analog(dvbdev); + + cxusb_medion_set_mode(dvbdev, true); + _cxusb_power_ctrl(dvbdev, 0); + + if (ret != 0) + goto ret_uninit; + + /* release device from INIT mode to normal operation */ + cxusb_medion_put(dvbdev); + + return 0; + } else if (!dvb_usb_device_init(intf, + &cxusb_bluebird_lgh064f_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, + &cxusb_bluebird_dee1601_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, + &cxusb_bluebird_lgz201_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, + &cxusb_bluebird_dtt7579_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, + &cxusb_bluebird_dualdig4_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, + &cxusb_bluebird_nano2_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, + &cxusb_bluebird_nano2_needsfirmware_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, &cxusb_aver_a868r_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, + &cxusb_bluebird_dualdig4_rev2_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, &cxusb_d680_dmb_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, &cxusb_mygica_d689_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, &cxusb_mygica_t230_properties, + THIS_MODULE, NULL, adapter_nr) || + 0) return 0; return -EINVAL; + +ret_uninit: + dvb_usb_device_exit(intf); + + return ret; } static void cxusb_disconnect(struct usb_interface *intf) @@ -1367,6 +1778,9 @@ static void cxusb_disconnect(struct usb_interface *intf) struct cxusb_state *st = d->priv; struct i2c_client *client; + if (d->props.devices[0].warm_ids[0] == &cxusb_table[MEDION_MD95700]) + cxusb_medion_unregister_analog(d); + /* remove I2C client for tuner */ client = st->i2c_client_tuner; if (client) { @@ -1384,31 +1798,6 @@ static void cxusb_disconnect(struct usb_interface *intf) dvb_usb_device_exit(intf); } -enum cxusb_table_index { - MEDION_MD95700, - DVICO_BLUEBIRD_LG064F_COLD, - DVICO_BLUEBIRD_LG064F_WARM, - DVICO_BLUEBIRD_DUAL_1_COLD, - DVICO_BLUEBIRD_DUAL_1_WARM, - DVICO_BLUEBIRD_LGZ201_COLD, - DVICO_BLUEBIRD_LGZ201_WARM, - DVICO_BLUEBIRD_TH7579_COLD, - DVICO_BLUEBIRD_TH7579_WARM, - DIGITALNOW_BLUEBIRD_DUAL_1_COLD, - DIGITALNOW_BLUEBIRD_DUAL_1_WARM, - DVICO_BLUEBIRD_DUAL_2_COLD, - DVICO_BLUEBIRD_DUAL_2_WARM, - DVICO_BLUEBIRD_DUAL_4, - DVICO_BLUEBIRD_DVB_T_NANO_2, - DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM, - AVERMEDIA_VOLAR_A868R, - DVICO_BLUEBIRD_DUAL_4_REV_2, - CONEXANT_D680_DMB, - MYGICA_D689, - MYGICA_T230, - NR__cxusb_table_index -}; - static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { [MEDION_MD95700] = { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) @@ -1438,10 +1827,12 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) }, [DIGITALNOW_BLUEBIRD_DUAL_1_COLD] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) + USB_DEVICE(USB_VID_DVICO, + USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) }, [DIGITALNOW_BLUEBIRD_DUAL_1_WARM] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) + USB_DEVICE(USB_VID_DVICO, + USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) }, [DVICO_BLUEBIRD_DUAL_2_COLD] = { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) @@ -1456,7 +1847,8 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, [DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) + USB_DEVICE(USB_VID_DVICO, + USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, [AVERMEDIA_VOLAR_A868R] = { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) @@ -1475,14 +1867,16 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { }, {} /* Terminating entry */ }; -MODULE_DEVICE_TABLE (usb, cxusb_table); +MODULE_DEVICE_TABLE(usb, cxusb_table); static struct dvb_usb_device_properties cxusb_medion_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, - .size_of_priv = sizeof(struct cxusb_state), + .size_of_priv = sizeof(struct cxusb_medion_dev), + .priv_init = cxusb_medion_priv_init, + .priv_destroy = cxusb_medion_priv_destroy, .num_adapters = 1, .adapter = { @@ -1503,7 +1897,7 @@ static struct dvb_usb_device_properties cxusb_medion_properties = { } } }, - }}, + } }, }, }, .power_ctrl = cxusb_power_ctrl, @@ -1514,7 +1908,8 @@ static struct dvb_usb_device_properties cxusb_medion_properties = { .num_device_descs = 1, .devices = { - { "Medion MD95700 (MDUSBTV-HYBRID)", + { + "Medion MD95700 (MDUSBTV-HYBRID)", { NULL }, { &cxusb_table[MEDION_MD95700], NULL }, }, @@ -1527,8 +1922,10 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = { .usb_ctrl = DEVICE_SPECIFIC, .firmware = "dvb-usb-bluebird-01.fw", .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ + /* + * use usb alt setting 0 for EP4 transfer (dvb-t), + * use usb alt setting 7 for EP2 transfer (atsc) + */ .size_of_priv = sizeof(struct cxusb_state), @@ -1552,7 +1949,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = { } } }, - }}, + } }, }, }, @@ -1585,8 +1982,10 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { .usb_ctrl = DEVICE_SPECIFIC, .firmware = "dvb-usb-bluebird-01.fw", .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ + /* + * use usb alt setting 0 for EP4 transfer (dvb-t), + * use usb alt setting 7 for EP2 transfer (atsc) + */ .size_of_priv = sizeof(struct cxusb_state), @@ -1609,7 +2008,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { } } }, - }}, + } }, }, }, @@ -1634,7 +2033,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { { &cxusb_table[DVICO_BLUEBIRD_DUAL_1_WARM], NULL }, }, { "DigitalNow DVB-T Dual USB", - { &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_COLD], NULL }, + { &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_COLD], NULL }, { &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_WARM], NULL }, }, { "DViCO FusionHDTV DVB-T Dual Digital 2", @@ -1650,8 +2049,10 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = { .usb_ctrl = DEVICE_SPECIFIC, .firmware = "dvb-usb-bluebird-01.fw", .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ + /* + * use usb alt setting 0 for EP4 transfer (dvb-t), + * use usb alt setting 7 for EP2 transfer (atsc) + */ .size_of_priv = sizeof(struct cxusb_state), @@ -1675,7 +2076,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = { } } }, - }}, + } }, }, }, .power_ctrl = cxusb_bluebird_power_ctrl, @@ -1706,8 +2107,11 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { .usb_ctrl = DEVICE_SPECIFIC, .firmware = "dvb-usb-bluebird-01.fw", .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ + + /* + * use usb alt setting 0 for EP4 transfer (dvb-t), + * use usb alt setting 7 for EP2 transfer (atsc) + */ .size_of_priv = sizeof(struct cxusb_state), @@ -1731,7 +2135,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { } } }, - }}, + } }, }, }, .power_ctrl = cxusb_bluebird_power_ctrl, @@ -1783,7 +2187,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { } } }, - }}, + } }, }, }, @@ -1837,7 +2241,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { } } }, - }}, + } }, }, }, @@ -1864,7 +2268,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { } }; -static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = { +static struct dvb_usb_device_properties +cxusb_bluebird_nano2_needsfirmware_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, @@ -1893,7 +2298,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope } } }, - }}, + } }, }, }, @@ -1912,10 +2317,11 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope }, .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T NANO2 w/o firmware", + .devices = { { + "DViCO FusionHDTV DVB-T NANO2 w/o firmware", { &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2], NULL }, - { &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM], + NULL }, }, } }; @@ -1946,7 +2352,7 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { } } }, - }}, + } }, }, }, .power_ctrl = cxusb_aver_power_ctrl, @@ -1992,7 +2398,7 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { } } }, - }}, + } }, }, }, @@ -2046,7 +2452,7 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { } } }, - }}, + } }, }, }, @@ -2101,7 +2507,7 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = { } } }, - }}, + } }, }, }, @@ -2195,6 +2601,6 @@ module_usb_driver(cxusb_driver); MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>"); +MODULE_AUTHOR("Maciej S. Szmigiero <mail@maciej.szmigiero.name>"); MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design"); -MODULE_VERSION("1.0-alpha"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h index 88f9b9804b25..9e374e53125b 100644 --- a/drivers/media/usb/dvb-usb/cxusb.h +++ b/drivers/media/usb/dvb-usb/cxusb.h @@ -2,9 +2,29 @@ #ifndef _DVB_USB_CXUSB_H_ #define _DVB_USB_CXUSB_H_ +#include <linux/completion.h> +#include <linux/i2c.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/usb.h> +#include <linux/workqueue.h> +#include <media/v4l2-common.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-device.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-v4l2.h> + #define DVB_USB_LOG_PREFIX "cxusb" #include "dvb-usb.h" +#define CXUSB_VIDEO_URBS (5) +#define CXUSB_VIDEO_URB_MAX_SIZE (512 * 1024) + +#define CXUSB_VIDEO_PKT_SIZE 3030 +#define CXUSB_VIDEO_MAX_FRAME_PKTS 346 +#define CXUSB_VIDEO_MAX_FRAME_SIZE (CXUSB_VIDEO_MAX_FRAME_PKTS * \ + CXUSB_VIDEO_PKT_SIZE) + /* usb commands - some of it are guesses, don't have a reference yet */ #define CMD_BLUEBIRD_GPIO_RW 0x05 @@ -29,11 +49,26 @@ #define CMD_ANALOG 0x50 #define CMD_DIGITAL 0x51 +#define CXUSB_BT656_PREAMBLE ((const u8 *)"\xff\x00\x00") + +#define CXUSB_BT656_FIELD_MASK BIT(6) +#define CXUSB_BT656_FIELD_1 0 +#define CXUSB_BT656_FIELD_2 BIT(6) + +#define CXUSB_BT656_VBI_MASK BIT(5) +#define CXUSB_BT656_VBI_ON BIT(5) +#define CXUSB_BT656_VBI_OFF 0 + +#define CXUSB_BT656_SEAV_MASK BIT(4) +#define CXUSB_BT656_SEAV_EAV BIT(4) +#define CXUSB_BT656_SEAV_SAV 0 + /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 80 struct cxusb_state { u8 gpio_write_state[3]; + bool gpio_write_refresh[3]; struct i2c_client *i2c_client_demod; struct i2c_client *i2c_client_tuner; @@ -42,7 +77,128 @@ struct cxusb_state { struct mutex stream_mutex; u8 last_lock; int (*fe_read_status)(struct dvb_frontend *fe, - enum fe_status *status); + enum fe_status *status); +}; + +enum cxusb_open_type { + CXUSB_OPEN_INIT, + CXUSB_OPEN_NONE, + CXUSB_OPEN_ANALOG, + CXUSB_OPEN_DIGITAL +}; + +struct cxusb_medion_auxbuf { + u8 *buf; + unsigned int len; + unsigned int paylen; +}; + +enum cxusb_bt656_mode { + NEW_FRAME, FIRST_FIELD, SECOND_FIELD +}; + +enum cxusb_bt656_fmode { + START_SEARCH, LINE_SAMPLES, VBI_SAMPLES }; +struct cxusb_bt656_params { + enum cxusb_bt656_mode mode; + enum cxusb_bt656_fmode fmode; + unsigned int pos; + unsigned int line; + unsigned int linesamples; + u8 *buf; +}; + +struct cxusb_medion_dev { + /* has to be the first one */ + struct cxusb_state state; + + struct dvb_usb_device *dvbdev; + + enum cxusb_open_type open_type; + unsigned int open_ctr; + struct mutex open_lock; + +#ifdef CONFIG_DVB_USB_CXUSB_ANALOG + struct v4l2_device v4l2dev; + struct v4l2_subdev *cx25840; + struct v4l2_subdev *tuner; + struct v4l2_subdev *tda9887; + struct video_device *videodev, *radiodev; + struct mutex dev_lock; + + struct vb2_queue videoqueue; + u32 input; + bool stop_streaming; + u32 width, height; + u32 field_order; + struct cxusb_medion_auxbuf auxbuf; + v4l2_std_id norm; + + struct urb *streamurbs[CXUSB_VIDEO_URBS]; + unsigned long urbcomplete; + struct work_struct urbwork; + unsigned int nexturb; + + struct cxusb_bt656_params bt656; + struct cxusb_medion_vbuffer *vbuf; + __u32 vbuf_sequence; + + struct list_head buflist; + + struct completion v4l2_release; +#endif +}; + +struct cxusb_medion_vbuffer { + struct vb2_v4l2_buffer vb2; + struct list_head list; +}; + +/* defines for "debug" module parameter */ +#define CXUSB_DBG_RC BIT(0) +#define CXUSB_DBG_I2C BIT(1) +#define CXUSB_DBG_MISC BIT(2) +#define CXUSB_DBG_BT656 BIT(3) +#define CXUSB_DBG_URB BIT(4) +#define CXUSB_DBG_OPS BIT(5) +#define CXUSB_DBG_AUXB BIT(6) + +extern int dvb_usb_cxusb_debug; + +#define cxusb_vprintk(dvbdev, lvl, ...) do { \ + struct cxusb_medion_dev *_cxdev = (dvbdev)->priv; \ + if (dvb_usb_cxusb_debug & CXUSB_DBG_##lvl) \ + v4l2_printk(KERN_DEBUG, \ + &_cxdev->v4l2dev, __VA_ARGS__); \ + } while (0) + +int cxusb_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen); + +#ifdef CONFIG_DVB_USB_CXUSB_ANALOG +int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev); +int cxusb_medion_register_analog(struct dvb_usb_device *dvbdev); +void cxusb_medion_unregister_analog(struct dvb_usb_device *dvbdev); +#else +static inline int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev) +{ + return -EINVAL; +} + +static inline int cxusb_medion_register_analog(struct dvb_usb_device *dvbdev) +{ + return 0; +} + +static inline void cxusb_medion_unregister_analog(struct dvb_usb_device *dvbdev) +{ +} +#endif + +int cxusb_medion_get(struct dvb_usb_device *dvbdev, + enum cxusb_open_type open_type); +void cxusb_medion_put(struct dvb_usb_device *dvbdev); + #endif diff --git a/drivers/media/usb/dvb-usb/dibusb-mb.c b/drivers/media/usb/dvb-usb/dibusb-mb.c index 408920577716..d4ea72bf09c5 100644 --- a/drivers/media/usb/dvb-usb/dibusb-mb.c +++ b/drivers/media/usb/dvb-usb/dibusb-mb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* DVB USB compliant linux driver for mobile DVB-T USB devices based on * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B) * @@ -6,10 +7,6 @@ * based on GPL code from DiBcom, which has * Copyright (C) 2004 Amaury Demol for DiBcom * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * * see Documentation/media/dvb-drivers/dvb-usb.rst for more information */ #include "dibusb.h" diff --git a/drivers/media/usb/dvb-usb/dibusb-mc.c b/drivers/media/usb/dvb-usb/dibusb-mc.c index bce8ffe640ca..ada3bee296c2 100644 --- a/drivers/media/usb/dvb-usb/dibusb-mc.c +++ b/drivers/media/usb/dvb-usb/dibusb-mc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* DVB USB compliant linux driver for mobile DVB-T USB devices based on * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-C/P) * @@ -6,10 +7,6 @@ * based on GPL code from DiBcom, which has * Copyright (C) 2004 Amaury Demol for DiBcom * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * * see Documentation/media/dvb-drivers/dvb-usb.rst for more information */ #include "dibusb.h" diff --git a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c index 8056053c9ab0..0a7f8ba90992 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c @@ -56,9 +56,6 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) * for reception. */ if (adap->feedcount == onoff && adap->feedcount > 0) { - deb_ts("submitting all URBs\n"); - usb_urb_submit(&adap->fe_adap[adap->active_fe].stream); - deb_ts("controlling pid parser\n"); if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && adap->props.fe[adap->active_fe].caps & @@ -80,6 +77,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) } } + deb_ts("submitting all URBs\n"); + usb_urb_submit(&adap->fe_adap[adap->active_fe].stream); } return 0; } diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c index e97f6edc98de..16a0b4a359ea 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c @@ -130,6 +130,10 @@ static int dvb_usb_exit(struct dvb_usb_device *d) dvb_usb_i2c_exit(d); deb_info("state should be zero now: %x\n", d->state); d->state = DVB_USB_STATE_INIT; + + if (d->priv != NULL && d->props.priv_destroy != NULL) + d->props.priv_destroy(d); + kfree(d->priv); kfree(d); return 0; @@ -151,6 +155,15 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) err("no memory for priv in 'struct dvb_usb_device'"); return -ENOMEM; } + + if (d->props.priv_init != NULL) { + ret = d->props.priv_init(d); + if (ret != 0) { + kfree(d->priv); + d->priv = NULL; + return ret; + } + } } /* check the capabilities and set appropriate variables */ @@ -284,12 +297,15 @@ EXPORT_SYMBOL(dvb_usb_device_init); void dvb_usb_device_exit(struct usb_interface *intf) { struct dvb_usb_device *d = usb_get_intfdata(intf); - const char *name = "generic DVB-USB module"; + const char *default_name = "generic DVB-USB module"; + char name[40]; usb_set_intfdata(intf, NULL); if (d != NULL && d->desc != NULL) { - name = d->desc->name; + strscpy(name, d->desc->name, sizeof(name)); dvb_usb_exit(d); + } else { + strscpy(name, default_name, sizeof(name)); } info("%s successfully deinitialized and disconnected.", name); diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h index 32829bdd5f22..2eb0e24e8943 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb.h +++ b/drivers/media/usb/dvb-usb/dvb-usb.h @@ -129,6 +129,9 @@ struct usb_data_stream_properties { * @frontend_ctrl: called to power on/off active frontend. * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the * device (not URB submitting/killing). + * This callback will be called without data URBs being active - data URBs + * will be submitted only after streaming_ctrl(1) returns successfully and + * they will be killed before streaming_ctrl(0) gets called. * @pid_filter_ctrl: called to en/disable the PID filter, if any. * @pid_filter: called to set/unset a PID for filtering. * @frontend_attach: called to attach the possible frontends (fill fe-field @@ -234,6 +237,11 @@ enum dvb_usb_mode { * * @size_of_priv: how many bytes shall be allocated for the private field * of struct dvb_usb_device. + * @priv_init: optional callback to initialize the variable that private field + * of struct dvb_usb_device has pointer to just after it had been allocated and + * zeroed. + * @priv_destroy: just like priv_init, only called before deallocating + * the memory pointed by private field of struct dvb_usb_device. * * @power_ctrl: called to enable/disable power of the device. * @read_mac_address: called to read the MAC address of the device. @@ -275,6 +283,8 @@ struct dvb_usb_device_properties { int no_reconnect; int size_of_priv; + int (*priv_init)(struct dvb_usb_device *); + void (*priv_destroy)(struct dvb_usb_device *); int num_adapters; struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index d85ea1af6aa1..5aa15a7a49de 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -24,6 +24,7 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/usb.h> +#include <linux/usb/input.h> #include <linux/slab.h> #include <linux/bitrev.h> @@ -58,7 +59,6 @@ struct em28xx_ir_poll_result { struct em28xx_IR { struct em28xx *dev; struct rc_dev *rc; - char name[32]; char phys[32]; /* poll decoder */ @@ -277,21 +277,8 @@ static int em2874_polling_getkey(struct em28xx_IR *ir, break; case RC_PROTO_BIT_NEC: - poll_result->scancode = msg[1] << 8 | msg[2]; - if ((msg[3] ^ msg[4]) != 0xff) { /* 32 bits NEC */ - poll_result->protocol = RC_PROTO_NEC32; - poll_result->scancode = RC_SCANCODE_NEC32((msg[1] << 24) | - (msg[2] << 16) | - (msg[3] << 8) | - (msg[4])); - } else if ((msg[1] ^ msg[2]) != 0xff) { /* 24 bits NEC */ - poll_result->protocol = RC_PROTO_NECX; - poll_result->scancode = RC_SCANCODE_NECX(msg[1] << 8 | - msg[2], msg[3]); - } else { /* Normal NEC */ - poll_result->protocol = RC_PROTO_NEC; - poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[3]); - } + poll_result->scancode = ir_nec_bytes_to_scancode(msg[1], msg[2], msg[3], msg[4], + &poll_result->protocol); break; case RC_PROTO_BIT_RC6_0: @@ -617,10 +604,7 @@ static int em28xx_register_snapshot_button(struct em28xx *dev) set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit); input_dev->keycodesize = 0; input_dev->keycodemax = 0; - input_dev->id.bustype = BUS_USB; - input_dev->id.vendor = le16_to_cpu(udev->descriptor.idVendor); - input_dev->id.product = le16_to_cpu(udev->descriptor.idProduct); - input_dev->id.version = 1; + usb_to_input_id(udev, &input_dev->id); input_dev->dev.parent = &dev->intf->dev; err = input_register_device(input_dev); @@ -832,19 +816,12 @@ static int em28xx_ir_init(struct em28xx *dev) /* This is how often we ask the chip for IR information */ ir->polling = 100; /* ms */ - /* init input device */ - snprintf(ir->name, sizeof(ir->name), "%s IR", - dev_name(&dev->intf->dev)); - usb_make_path(udev, ir->phys, sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys)); - rc->device_name = ir->name; + rc->device_name = em28xx_boards[dev->model].name; rc->input_phys = ir->phys; - rc->input_id.bustype = BUS_USB; - rc->input_id.version = 1; - rc->input_id.vendor = le16_to_cpu(udev->descriptor.idVendor); - rc->input_id.product = le16_to_cpu(udev->descriptor.idProduct); + usb_to_input_id(udev, &rc->input_id); rc->dev.parent = &dev->intf->dev; rc->driver_name = MODULE_NAME; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index f43717ea831d..0512e1959394 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1984,7 +1984,6 @@ static int vidioc_s_register(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); struct em28xx *dev = video_drvdata(file); struct em28xx_v4l2 *v4l2 = dev->v4l2; struct usb_device *udev = interface_to_usbdev(dev->intf); @@ -1993,23 +1992,12 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(udev, cap->bus_info, sizeof(cap->bus_info)); - if (vdev->vfl_type == VFL_TYPE_GRABBER) - cap->device_caps = V4L2_CAP_READWRITE | - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - else if (vdev->vfl_type == VFL_TYPE_RADIO) - cap->device_caps = V4L2_CAP_RADIO; - else - cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE; - + cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_READWRITE | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; if (dev->int_audio_type != EM28XX_INT_AUDIO_NONE) - cap->device_caps |= V4L2_CAP_AUDIO; - + cap->capabilities |= V4L2_CAP_AUDIO; if (dev->tuner_type != TUNER_ABSENT) - cap->device_caps |= V4L2_CAP_TUNER; - - cap->capabilities = cap->device_caps | - V4L2_CAP_DEVICE_CAPS | V4L2_CAP_READWRITE | - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities |= V4L2_CAP_TUNER; if (video_is_registered(&v4l2->vbi_dev)) cap->capabilities |= V4L2_CAP_VBI_CAPTURE; if (video_is_registered(&v4l2->radio_dev)) @@ -2782,6 +2770,13 @@ static int em28xx_v4l2_init(struct em28xx *dev) mutex_init(&v4l2->vb_vbi_queue_lock); v4l2->vdev.queue = &v4l2->vb_vidq; v4l2->vdev.queue->lock = &v4l2->vb_queue_lock; + v4l2->vdev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING; + if (dev->int_audio_type != EM28XX_INT_AUDIO_NONE) + v4l2->vdev.device_caps |= V4L2_CAP_AUDIO; + if (dev->tuner_type != TUNER_ABSENT) + v4l2->vdev.device_caps |= V4L2_CAP_TUNER; + /* disable inapplicable ioctls */ if (dev->is_webcam) { @@ -2818,6 +2813,10 @@ static int em28xx_v4l2_init(struct em28xx *dev) v4l2->vbi_dev.queue = &v4l2->vb_vbiq; v4l2->vbi_dev.queue->lock = &v4l2->vb_vbi_queue_lock; + v4l2->vbi_dev.device_caps = V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT) + v4l2->vbi_dev.device_caps |= V4L2_CAP_TUNER; /* disable inapplicable ioctls */ v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_PARM); @@ -2845,6 +2844,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { em28xx_vdev_init(dev, &v4l2->radio_dev, &em28xx_radio_template, "radio"); + v4l2->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; ret = video_register_device(&v4l2->radio_dev, VFL_TYPE_RADIO, radio_nr[dev->devno]); if (ret < 0) { diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index b63b7bb7745c..88edfef80b40 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -279,15 +279,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, "go7007", sizeof(cap->driver)); strscpy(cap->card, go->name, sizeof(cap->card)); strscpy(cap->bus_info, go->bus_info, sizeof(cap->bus_info)); - - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - - if (go->board_info->num_aud_inputs) - cap->device_caps |= V4L2_CAP_AUDIO; - if (go->board_info->flags & GO7007_BOARD_HAS_TUNER) - cap->device_caps |= V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1114,6 +1105,12 @@ int go7007_v4l2_init(struct go7007 *go) *vdev = go7007_template; vdev->lock = &go->serialize_lock; vdev->queue = &go->vidq; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + if (go->board_info->num_aud_inputs) + vdev->device_caps |= V4L2_CAP_AUDIO; + if (go->board_info->flags & GO7007_BOARD_HAS_TUNER) + vdev->device_caps |= V4L2_CAP_TUNER; video_set_drvdata(vdev, go); vdev->v4l2_dev = &go->v4l2_dev; if (!v4l2_device_has_op(&go->v4l2_dev, 0, video, querystd)) diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index a7ed5257cdba..be11f7830bca 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1209,10 +1209,6 @@ static int vidioc_querycap(struct file *file, void *priv, } usb_make_path(gspca_dev->dev, (char *) cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE - | V4L2_CAP_STREAMING - | V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1508,6 +1504,8 @@ int gspca_dev_probe2(struct usb_interface *intf, gspca_dev->empty_packet = -1; /* don't check the empty packets */ gspca_dev->vdev = gspca_template; gspca_dev->vdev.v4l2_dev = &gspca_dev->v4l2_dev; + gspca_dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; video_set_drvdata(&gspca_dev->vdev, gspca_dev); gspca_dev->module = module; diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c index 7d4a9452f545..cec841ad7495 100644 --- a/drivers/media/usb/hackrf/hackrf.c +++ b/drivers/media/usb/hackrf/hackrf.c @@ -896,19 +896,13 @@ static int hackrf_querycap(struct file *file, void *fh, { struct hackrf_dev *dev = video_drvdata(file); struct usb_interface *intf = dev->intf; - struct video_device *vdev = video_devdata(file); dev_dbg(&intf->dev, "\n"); - cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - if (vdev->vfl_dir == VFL_DIR_RX) - cap->device_caps |= V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER; - else - cap->device_caps |= V4L2_CAP_SDR_OUTPUT | V4L2_CAP_MODULATOR; - cap->capabilities = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER | V4L2_CAP_SDR_OUTPUT | V4L2_CAP_MODULATOR | - V4L2_CAP_DEVICE_CAPS | cap->device_caps; + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | + V4L2_CAP_DEVICE_CAPS; strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, dev->rx_vdev.name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); @@ -1487,6 +1481,8 @@ static int hackrf_probe(struct usb_interface *intf, dev->rx_vdev.ctrl_handler = &dev->rx_ctrl_handler; dev->rx_vdev.lock = &dev->v4l2_lock; dev->rx_vdev.vfl_dir = VFL_DIR_RX; + dev->rx_vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | + V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER; video_set_drvdata(&dev->rx_vdev, dev); ret = video_register_device(&dev->rx_vdev, VFL_TYPE_SDR, -1); if (ret) { @@ -1505,6 +1501,8 @@ static int hackrf_probe(struct usb_interface *intf, dev->tx_vdev.ctrl_handler = &dev->tx_ctrl_handler; dev->tx_vdev.lock = &dev->v4l2_lock; dev->tx_vdev.vfl_dir = VFL_DIR_TX; + dev->tx_vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | + V4L2_CAP_SDR_OUTPUT | V4L2_CAP_MODULATOR; video_set_drvdata(&dev->tx_vdev, dev); ret = video_register_device(&dev->tx_vdev, VFL_TYPE_SDR, -1); if (ret) { diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 7580fc5f2f12..5b3e67b80627 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -435,7 +435,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, /* wait for the first buffer */ if (!(file->f_flags & O_NONBLOCK)) { if (wait_event_interruptible(dev->wait_data, - hdpvr_get_next_buffer(dev))) + !list_empty_careful(&dev->rec_buff_list))) return -ERESTARTSYS; } @@ -461,10 +461,17 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, goto err; } if (!err) { - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "timeout: restart streaming\n"); + v4l2_info(&dev->v4l2_dev, + "timeout: restart streaming\n"); + mutex_lock(&dev->io_mutex); hdpvr_stop_streaming(dev); - msecs_to_jiffies(4000); + mutex_unlock(&dev->io_mutex); + /* + * The FW needs about 4 seconds after streaming + * stopped before it is ready to restart + * streaming. + */ + msleep(4000); err = hdpvr_start_streaming(dev); if (err) { ret = err; @@ -577,9 +584,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, "hdpvr", sizeof(cap->driver)); strscpy(cap->card, "Hauppauge HD PVR", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1127,9 +1131,7 @@ static void hdpvr_device_release(struct video_device *vdev) struct hdpvr_device *dev = video_get_drvdata(vdev); hdpvr_delete(dev); - mutex_lock(&dev->io_mutex); flush_work(&dev->worker); - mutex_unlock(&dev->io_mutex); v4l2_device_unregister(&dev->v4l2_dev); v4l2_ctrl_handler_free(&dev->hdl); @@ -1150,6 +1152,8 @@ static const struct video_device hdpvr_video_template = { .release = hdpvr_device_release, .ioctl_ops = &hdpvr_ioctl_ops, .tvnorms = V4L2_STD_ALL, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE, }; static const struct v4l2_ctrl_ops hdpvr_ctrl_ops = { diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index b405bc3c2781..4c9b2a12acfb 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -598,9 +598,6 @@ static int msi2500_querycap(struct file *file, void *fh, strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, dev->vdev.name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE | V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1274,6 +1271,8 @@ static int msi2500_probe(struct usb_interface *intf, dev->v4l2_dev.ctrl_handler = &dev->hdl; dev->vdev.v4l2_dev = &dev->v4l2_dev; dev->vdev.lock = &dev->v4l2_lock; + dev->vdev.device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE | V4L2_CAP_TUNER; ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1); if (ret) { diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig index 64f9df067269..e6a4f730591b 100644 --- a/drivers/media/usb/pvrusb2/Kconfig +++ b/drivers/media/usb/pvrusb2/Kconfig @@ -41,6 +41,8 @@ config VIDEO_PVRUSB2_DVB select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LGDT3306A if MEDIA_SUBDRV_AUTOSELECT + select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/pvrusb2/pvrusb2-audio.c b/drivers/media/usb/pvrusb2/pvrusb2-audio.c index 356afa250cd6..13051f0e2512 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-audio.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.c @@ -1,18 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include "pvrusb2-audio.h" diff --git a/drivers/media/usb/pvrusb2/pvrusb2-audio.h b/drivers/media/usb/pvrusb2/pvrusb2-audio.h index 4f3898473165..87fb4c0747ad 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-audio.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.h @@ -1,18 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_AUDIO_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c index d9e8481e9e28..14170a5d72b3 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-context.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c @@ -1,16 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include "pvrusb2-context.h" diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.h b/drivers/media/usb/pvrusb2/pvrusb2-context.h index 13e00c529611..5840b2ce8f1e 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-context.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-context.h @@ -1,16 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_CONTEXT_H #define __PVRUSB2_CONTEXT_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c index 679f3ff3b0a5..7eefa0f86ad4 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c @@ -1,18 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ /* diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h index 90dfb8b3f3e5..800841ba8376 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h @@ -1,18 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_CS53L32A_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c index 5f4ba84e5557..9f71d8c2a3c6 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c @@ -1,17 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include "pvrusb2-ctrl.h" diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h index 4b9152e36fe4..7dd4b73f783c 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h @@ -1,17 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_CTRL_H #define __PVRUSB2_CTRL_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c index d5bec0f69bec..e4b31ae02f59 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -1,18 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ /* @@ -111,10 +101,35 @@ static const struct routing_scheme routing_defav400 = { .cnt = ARRAY_SIZE(routing_schemeav400), }; +static const struct routing_scheme_item routing_scheme160xxx[] = { + [PVR2_CVAL_INPUT_TV] = { + .vid = CX25840_COMPOSITE7, + .aud = CX25840_AUDIO8, + }, + [PVR2_CVAL_INPUT_RADIO] = { + .vid = CX25840_COMPOSITE4, + .aud = CX25840_AUDIO6, + }, + [PVR2_CVAL_INPUT_COMPOSITE] = { + .vid = CX25840_COMPOSITE3, + .aud = CX25840_AUDIO_SERIAL, + }, + [PVR2_CVAL_INPUT_SVIDEO] = { + .vid = CX25840_SVIDEO1, + .aud = CX25840_AUDIO_SERIAL, + }, +}; + +static const struct routing_scheme routing_def160xxx = { + .def = routing_scheme160xxx, + .cnt = ARRAY_SIZE(routing_scheme160xxx), +}; + static const struct routing_scheme *routing_schemes[] = { [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0, [PVR2_ROUTING_SCHEME_GOTVIEW] = &routing_defgv, [PVR2_ROUTING_SCHEME_AV400] = &routing_defav400, + [PVR2_ROUTING_SCHEME_HAUP160XXX] = &routing_def160xxx, }; void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h index dfddc88750d9..57c9504793e0 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h @@ -1,18 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_CX2584X_V4L_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debug.h b/drivers/media/usb/pvrusb2/pvrusb2-debug.h index 1323f949f454..7854c1d87af1 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-debug.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-debug.h @@ -1,16 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_DEBUG_H #define __PVRUSB2_DEBUG_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c index d3f3bd96885f..84cfb5ce8b8d 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c @@ -1,17 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/string.h> diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h index fcaaa8dd68b8..9b9c0f553480 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h @@ -1,17 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_DEBUGIFC_H #define __PVRUSB2_DEBUGIFC_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c index 06de1c83f444..1fcf63218885 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c @@ -1,17 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2007 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ /* @@ -37,6 +27,9 @@ pvr2_device_desc structures. #include "tda18271.h" #include "tda8290.h" #include "tuner-simple.h" +#include "si2157.h" +#include "lgdt3306a.h" +#include "si2168.h" #endif @@ -188,10 +181,10 @@ static struct lgdt330x_config pvr2_lgdt3303_config = { static int pvr2_lgdt3303_attach(struct pvr2_dvb_adapter *adap) { - adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3303_config, - 0x0e, - &adap->channel.hdw->i2c_adap); - if (adap->fe) + adap->fe[0] = dvb_attach(lgdt330x_attach, &pvr2_lgdt3303_config, + 0x0e, + &adap->channel.hdw->i2c_adap); + if (adap->fe[0]) return 0; return -EIO; @@ -199,7 +192,7 @@ static int pvr2_lgdt3303_attach(struct pvr2_dvb_adapter *adap) static int pvr2_lgh06xf_attach(struct pvr2_dvb_adapter *adap) { - dvb_attach(simple_tuner_attach, adap->fe, + dvb_attach(simple_tuner_attach, adap->fe[0], &adap->channel.hdw->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF); @@ -248,10 +241,10 @@ static struct lgdt330x_config pvr2_lgdt3302_config = { static int pvr2_lgdt3302_attach(struct pvr2_dvb_adapter *adap) { - adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3302_config, - 0x0e, - &adap->channel.hdw->i2c_adap); - if (adap->fe) + adap->fe[0] = dvb_attach(lgdt330x_attach, &pvr2_lgdt3302_config, + 0x0e, + &adap->channel.hdw->i2c_adap); + if (adap->fe[0]) return 0; return -EIO; @@ -259,7 +252,7 @@ static int pvr2_lgdt3302_attach(struct pvr2_dvb_adapter *adap) static int pvr2_fcv1236d_attach(struct pvr2_dvb_adapter *adap) { - dvb_attach(simple_tuner_attach, adap->fe, + dvb_attach(simple_tuner_attach, adap->fe[0], &adap->channel.hdw->i2c_adap, 0x61, TUNER_PHILIPS_FCV1236D); @@ -335,9 +328,9 @@ static struct tda18271_config hauppauge_tda18271_dvb_config = { static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap) { - adap->fe = dvb_attach(tda10048_attach, &hauppauge_tda10048_config, - &adap->channel.hdw->i2c_adap); - if (adap->fe) + adap->fe[0] = dvb_attach(tda10048_attach, &hauppauge_tda10048_config, + &adap->channel.hdw->i2c_adap); + if (adap->fe[0]) return 0; return -EIO; @@ -345,10 +338,10 @@ static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap) static int pvr2_73xxx_tda18271_8295_attach(struct pvr2_dvb_adapter *adap) { - dvb_attach(tda829x_attach, adap->fe, + dvb_attach(tda829x_attach, adap->fe[0], &adap->channel.hdw->i2c_adap, 0x42, &tda829x_no_probe); - dvb_attach(tda18271_attach, adap->fe, 0x60, + dvb_attach(tda18271_attach, adap->fe[0], 0x60, &adap->channel.hdw->i2c_adap, &hauppauge_tda18271_dvb_config); @@ -433,9 +426,9 @@ static struct tda18271_config hauppauge_tda18271_config = { static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap) { - adap->fe = dvb_attach(s5h1409_attach, &pvr2_s5h1409_config, - &adap->channel.hdw->i2c_adap); - if (adap->fe) + adap->fe[0] = dvb_attach(s5h1409_attach, &pvr2_s5h1409_config, + &adap->channel.hdw->i2c_adap); + if (adap->fe[0]) return 0; return -EIO; @@ -443,9 +436,9 @@ static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap) static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap) { - adap->fe = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config, - &adap->channel.hdw->i2c_adap); - if (adap->fe) + adap->fe[0] = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config, + &adap->channel.hdw->i2c_adap); + if (adap->fe[0]) return 0; return -EIO; @@ -453,10 +446,10 @@ static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap) static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap) { - dvb_attach(tda829x_attach, adap->fe, + dvb_attach(tda829x_attach, adap->fe[0], &adap->channel.hdw->i2c_adap, 0x42, &tda829x_no_probe); - dvb_attach(tda18271_attach, adap->fe, 0x60, + dvb_attach(tda18271_attach, adap->fe[0], 0x60, &adap->channel.hdw->i2c_adap, &hauppauge_tda18271_config); @@ -525,7 +518,166 @@ static const struct pvr2_device_desc pvr2_device_751xx = { #endif }; +/*------------------------------------------------------------------------*/ +/* Hauppauge PVR-USB2 Model 160000 / 160111 -- HVR-1955 / HVR-1975 */ + +#ifdef CONFIG_VIDEO_PVRUSB2_DVB +static int pvr2_si2157_attach(struct pvr2_dvb_adapter *adap); +static int pvr2_si2168_attach(struct pvr2_dvb_adapter *adap); +static int pvr2_dual_fe_attach(struct pvr2_dvb_adapter *adap); +static int pvr2_lgdt3306a_attach(struct pvr2_dvb_adapter *adap); + +static const struct pvr2_dvb_props pvr2_160000_dvb_props = { + .frontend_attach = pvr2_dual_fe_attach, + .tuner_attach = pvr2_si2157_attach, +}; + +static const struct pvr2_dvb_props pvr2_160111_dvb_props = { + .frontend_attach = pvr2_lgdt3306a_attach, + .tuner_attach = pvr2_si2157_attach, +}; + +static int pvr2_si2157_attach(struct pvr2_dvb_adapter *adap) +{ + struct si2157_config si2157_config = {}; + + si2157_config.inversion = 1; + si2157_config.fe = adap->fe[0]; + + adap->i2c_client_tuner = dvb_module_probe("si2157", "si2177", + &adap->channel.hdw->i2c_adap, + 0x60, &si2157_config); + + if (!adap->i2c_client_tuner) + return -ENODEV; + + return 0; +} + +static int pvr2_si2168_attach(struct pvr2_dvb_adapter *adap) +{ + struct si2168_config si2168_config = {}; + struct i2c_adapter *adapter; + + pr_debug("%s()\n", __func__); + + si2168_config.fe = &adap->fe[1]; + si2168_config.i2c_adapter = &adapter; + si2168_config.ts_mode = SI2168_TS_PARALLEL; /*2, 1-serial, 2-parallel.*/ + si2168_config.ts_clock_gapped = 1; /*0-disabled, 1-enabled.*/ + si2168_config.ts_clock_inv = 0; /*0-not-invert, 1-invert*/ + si2168_config.spectral_inversion = 1; /*0-not-invert, 1-invert*/ + + adap->i2c_client_demod[1] = dvb_module_probe("si2168", NULL, + &adap->channel.hdw->i2c_adap, + 0x64, &si2168_config); + + if (!adap->i2c_client_demod[1]) + return -ENODEV; + + return 0; +} + +static int pvr2_lgdt3306a_attach(struct pvr2_dvb_adapter *adap) +{ + struct lgdt3306a_config lgdt3306a_config; + struct i2c_adapter *adapter; + + pr_debug("%s()\n", __func__); + + lgdt3306a_config.fe = &adap->fe[0]; + lgdt3306a_config.i2c_adapter = &adapter; + lgdt3306a_config.deny_i2c_rptr = 1; + lgdt3306a_config.spectral_inversion = 1; + lgdt3306a_config.qam_if_khz = 4000; + lgdt3306a_config.vsb_if_khz = 3250; + lgdt3306a_config.mpeg_mode = LGDT3306A_MPEG_PARALLEL; + lgdt3306a_config.tpclk_edge = LGDT3306A_TPCLK_FALLING_EDGE; + lgdt3306a_config.tpvalid_polarity = LGDT3306A_TP_VALID_LOW; + lgdt3306a_config.xtalMHz = 25, /* demod clock MHz; 24/25 supported */ + + adap->i2c_client_demod[0] = dvb_module_probe("lgdt3306a", NULL, + &adap->channel.hdw->i2c_adap, + 0x59, &lgdt3306a_config); + + if (!adap->i2c_client_demod[0]) + return -ENODEV; + return 0; +} + +static int pvr2_dual_fe_attach(struct pvr2_dvb_adapter *adap) +{ + pr_debug("%s()\n", __func__); + + if (pvr2_lgdt3306a_attach(adap) != 0) + return -ENODEV; + + if (pvr2_si2168_attach(adap) != 0) { + dvb_module_release(adap->i2c_client_demod[0]); + return -ENODEV; + } + + return 0; +} +#endif + +#define PVR2_FIRMWARE_160xxx "v4l-pvrusb2-160xxx-01.fw" +static const char *pvr2_fw1_names_160xxx[] = { + PVR2_FIRMWARE_160xxx, +}; + +static const struct pvr2_device_client_desc pvr2_cli_160xxx[] = { + { .module_id = PVR2_CLIENT_ID_CX25840 }, +}; + +static const struct pvr2_device_desc pvr2_device_160000 = { + .description = "WinTV HVR-1975 Model 160000", + .shortname = "160000", + .client_table.lst = pvr2_cli_160xxx, + .client_table.cnt = ARRAY_SIZE(pvr2_cli_160xxx), + .fx2_firmware.lst = pvr2_fw1_names_160xxx, + .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_160xxx), + .default_tuner_type = TUNER_ABSENT, + .flag_has_cx25840 = 1, + .flag_has_hauppauge_rom = 1, + .flag_has_analogtuner = 1, + .flag_has_composite = 1, + .flag_has_svideo = 1, + .flag_fx2_16kb = 1, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, + .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, + .default_std_mask = V4L2_STD_NTSC_M, + .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, + .ir_scheme = PVR2_IR_SCHEME_ZILOG, +#ifdef CONFIG_VIDEO_PVRUSB2_DVB + .dvb_props = &pvr2_160000_dvb_props, +#endif +}; + +static const struct pvr2_device_desc pvr2_device_160111 = { + .description = "WinTV HVR-1955 Model 160111", + .shortname = "160111", + .client_table.lst = pvr2_cli_160xxx, + .client_table.cnt = ARRAY_SIZE(pvr2_cli_160xxx), + .fx2_firmware.lst = pvr2_fw1_names_160xxx, + .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_160xxx), + .default_tuner_type = TUNER_ABSENT, + .flag_has_cx25840 = 1, + .flag_has_hauppauge_rom = 1, + .flag_has_analogtuner = 1, + .flag_has_composite = 1, + .flag_has_svideo = 1, + .flag_fx2_16kb = 1, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, + .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, + .default_std_mask = V4L2_STD_NTSC_M, + .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, + .ir_scheme = PVR2_IR_SCHEME_ZILOG, +#ifdef CONFIG_VIDEO_PVRUSB2_DVB + .dvb_props = &pvr2_160111_dvb_props, +#endif +}; /*------------------------------------------------------------------------*/ @@ -552,6 +704,10 @@ struct usb_device_id pvr2_device_table[] = { .driver_info = (kernel_ulong_t)&pvr2_device_751xx}, { USB_DEVICE(0x0ccd, 0x0039), .driver_info = (kernel_ulong_t)&pvr2_device_av400}, + { USB_DEVICE(0x2040, 0x7502), + .driver_info = (kernel_ulong_t)&pvr2_device_160111}, + { USB_DEVICE(0x2040, 0x7510), + .driver_info = (kernel_ulong_t)&pvr2_device_160000}, { } }; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.h b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h index c1e7d4822cd1..3c88f05d82d9 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h @@ -1,17 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_DEVATTR_H #define __PVRUSB2_DEVATTR_H @@ -66,6 +56,7 @@ struct pvr2_string_table { #define PVR2_ROUTING_SCHEME_GOTVIEW 1 #define PVR2_ROUTING_SCHEME_ONAIR 2 #define PVR2_ROUTING_SCHEME_AV400 3 +#define PVR2_ROUTING_SCHEME_HAUP160XXX 4 #define PVR2_DIGITAL_SCHEME_NONE 0 #define PVR2_DIGITAL_SCHEME_HAUPPAUGE 1 diff --git a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c index 4b32b2141169..6954584526a3 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c @@ -1,17 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * pvrusb2-dvb.c - linux-dvb api interface to the pvrusb2 driver. * * Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/kthread.h> @@ -343,26 +334,19 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) goto done; } - if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) { - - if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) { + if (dvb_props->frontend_attach(adap) == 0 && adap->fe[0]) { + if (dvb_register_frontend(&adap->dvb_adap, adap->fe[0])) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "frontend registration failed!"); - dvb_frontend_detach(adap->fe); - adap->fe = NULL; ret = -ENODEV; - goto done; + goto fail_frontend0; } + if (adap->fe[0]->ops.analog_ops.standby) + adap->fe[0]->ops.analog_ops.standby(adap->fe[0]); - if (dvb_props->tuner_attach) - dvb_props->tuner_attach(adap); - - if (adap->fe->ops.analog_ops.standby) - adap->fe->ops.analog_ops.standby(adap->fe); - - /* Ensure all frontends negotiate bus access */ - adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl; - + pvr2_trace(PVR2_TRACE_INFO, "transferring fe[%d] ts_bus_ctrl() to pvr2_dvb_bus_ctrl()", + adap->fe[0]->id); + adap->fe[0]->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl; } else { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "no frontend was attached!"); @@ -370,17 +354,74 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) return ret; } - done: + if (dvb_props->tuner_attach && dvb_props->tuner_attach(adap)) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, "tuner attach failed"); + ret = -ENODEV; + goto fail_tuner; + } + + if (adap->fe[1]) { + adap->fe[1]->id = 1; + adap->fe[1]->tuner_priv = adap->fe[0]->tuner_priv; + memcpy(&adap->fe[1]->ops.tuner_ops, + &adap->fe[0]->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); + + if (dvb_register_frontend(&adap->dvb_adap, adap->fe[1])) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "frontend registration failed!"); + ret = -ENODEV; + goto fail_frontend1; + } + /* MFE lock */ + adap->dvb_adap.mfe_shared = 1; + + if (adap->fe[1]->ops.analog_ops.standby) + adap->fe[1]->ops.analog_ops.standby(adap->fe[1]); + + pvr2_trace(PVR2_TRACE_INFO, "transferring fe[%d] ts_bus_ctrl() to pvr2_dvb_bus_ctrl()", + adap->fe[1]->id); + adap->fe[1]->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl; + } +done: pvr2_channel_limit_inputs(&adap->channel, 0); return ret; + +fail_frontend1: + dvb_frontend_detach(adap->fe[1]); + adap->fe[1] = NULL; +fail_tuner: + dvb_unregister_frontend(adap->fe[0]); +fail_frontend0: + dvb_frontend_detach(adap->fe[0]); + adap->fe[0] = NULL; + dvb_module_release(adap->i2c_client_tuner); + dvb_module_release(adap->i2c_client_demod[1]); + dvb_module_release(adap->i2c_client_demod[0]); + + return ret; } static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap) { - if (adap->fe != NULL) { - dvb_unregister_frontend(adap->fe); - dvb_frontend_detach(adap->fe); + if (adap->fe[1]) { + dvb_unregister_frontend(adap->fe[1]); + dvb_frontend_detach(adap->fe[1]); + adap->fe[1] = NULL; } + if (adap->fe[0]) { + dvb_unregister_frontend(adap->fe[0]); + dvb_frontend_detach(adap->fe[0]); + adap->fe[0] = NULL; + } + + dvb_module_release(adap->i2c_client_tuner); + adap->i2c_client_tuner = NULL; + dvb_module_release(adap->i2c_client_demod[1]); + adap->i2c_client_demod[1] = NULL; + dvb_module_release(adap->i2c_client_demod[0]); + adap->i2c_client_demod[0] = NULL; + return 0; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-dvb.h b/drivers/media/usb/pvrusb2/pvrusb2-dvb.h index e7f71fb94a6e..c0b27f5211bf 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-dvb.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.h @@ -18,7 +18,10 @@ struct pvr2_dvb_adapter { struct dmxdev dmxdev; struct dvb_demux demux; struct dvb_net dvb_net; - struct dvb_frontend *fe; + struct dvb_frontend *fe[2]; + + struct i2c_client *i2c_client_demod[2]; + struct i2c_client *i2c_client_tuner; int feedcount; int max_feed_count; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c index 8b643d511a0b..79f0e0c6df37 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c @@ -1,18 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/slab.h> diff --git a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h index 1d81cac30f3d..a65cc695fd68 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h @@ -1,18 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_EEPROM_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c index 43e43404095f..fb3178d909ce 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c @@ -1,18 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/device.h> // for linux/firmware.h diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.h b/drivers/media/usb/pvrusb2/pvrusb2-encoder.h index 10d7f0b48264..bcb5ab65f4fb 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.h @@ -1,18 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_ENCODER_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h index 0a01de4e54db..e54aa42b4115 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h @@ -1,17 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2007 Michael Krufky <mkrufky@linuxtv.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef _PVRUSB2_FX2_CMD_H_ @@ -38,6 +28,10 @@ #define FX2CMD_FWPOST1 0x52u +/* These 2 only exist on Model 160xxx */ +#define FX2CMD_HCW_DEMOD_RESET_PIN 0xd4u +#define FX2CMD_HCW_MAKO_SLEEP_PIN 0xd5u + #define FX2CMD_POWER_OFF 0xdcu #define FX2CMD_POWER_ON 0xdeu diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h index 7a824196d5fa..7c998ca616ac 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h @@ -1,17 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_HDW_INTERNAL_H #define __PVRUSB2_HDW_INTERNAL_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index 816c85786c2a..6fe8b9af858a 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -1,17 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/errno.h> @@ -316,6 +306,8 @@ static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = { {FX2CMD_ONAIR_DTV_STREAMING_OFF, "onair dtv stream off"}, {FX2CMD_ONAIR_DTV_POWER_ON, "onair dtv power on"}, {FX2CMD_ONAIR_DTV_POWER_OFF, "onair dtv power off"}, + {FX2CMD_HCW_DEMOD_RESET_PIN, "hcw demod reset pin"}, + {FX2CMD_HCW_MAKO_SLEEP_PIN, "hcw mako sleep pin"}, }; @@ -1680,7 +1672,7 @@ static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl) } if (!hdw->flag_decoder_missed) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: No decoder present"); + "***WARNING*** No decoder present"); hdw->flag_decoder_missed = !0; trace_stbit("flag_decoder_missed", hdw->flag_decoder_missed); @@ -2139,10 +2131,28 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) ((0) << 16)); } - // This step MUST happen after the earlier powerup step. + /* This step MUST happen after the earlier powerup step */ pvr2_i2c_core_init(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; + /* Reset demod only on Hauppauge 160xxx platform */ + if (le16_to_cpu(hdw->usb_dev->descriptor.idVendor) == 0x2040 && + (le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7502 || + le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7510)) { + pr_info("%s(): resetting 160xxx demod\n", __func__); + /* TODO: not sure this is proper place to reset once only */ + pvr2_issue_simple_cmd(hdw, + FX2CMD_HCW_DEMOD_RESET_PIN | + (1 << 8) | + ((0) << 16)); + usleep_range(10000, 10500); + pvr2_issue_simple_cmd(hdw, + FX2CMD_HCW_DEMOD_RESET_PIN | + (1 << 8) | + ((1) << 16)); + usleep_range(10000, 10500); + } + pvr2_hdw_load_modules(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; @@ -2366,7 +2376,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, if (hdw_desc->flag_is_experimental) { pvr2_trace(PVR2_TRACE_INFO, "**********"); pvr2_trace(PVR2_TRACE_INFO, - "WARNING: Support for this device (%s) is experimental.", + "***WARNING*** Support for this device (%s) is experimental.", hdw_desc->description); pvr2_trace(PVR2_TRACE_INFO, "Important functionality might not be entirely working."); @@ -4012,6 +4022,20 @@ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw) static int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff) { hdw->flag_ok = !0; + + /* Use this for Hauppauge 160xxx only */ + if (le16_to_cpu(hdw->usb_dev->descriptor.idVendor) == 0x2040 && + (le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7502 || + le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7510)) { + pr_debug("%s(): resetting demod on Hauppauge 160xxx platform skipped\n", + __func__); + /* Can't reset 160xxx or it will trash Demod tristate */ + return pvr2_issue_simple_cmd(hdw, + FX2CMD_HCW_MAKO_SLEEP_PIN | + (1 << 8) | + ((onoff ? 1 : 0) << 16)); + } + return pvr2_issue_simple_cmd(hdw, FX2CMD_HCW_DEMOD_RESETIN | (1 << 8) | diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h index bd2b7a67b732..860f0a6b099c 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h @@ -1,17 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_HDW_H #define __PVRUSB2_HDW_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c index 8f023085c2d9..275394bafe7d 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c @@ -1,17 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/i2c.h> @@ -343,11 +333,11 @@ static int i2c_hack_cx25840(struct pvr2_hdw *hdw, if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: Detected a wedged cx25840 chip; the device will not work."); + "***WARNING*** Detected a wedged cx25840 chip; the device will not work."); pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: Try power cycling the pvrusb2 device."); + "***WARNING*** Try power cycling the pvrusb2 device."); pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: Disabling further access to the device to prevent other foul-ups."); + "***WARNING*** Disabling further access to the device to prevent other foul-ups."); // This blocks all further communication with the part. hdw->i2c_func[0x44] = NULL; pvr2_hdw_render_useless(hdw); diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h index 1c44dee7fd69..6da66a80a1aa 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h @@ -1,17 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_I2C_CORE_H #define __PVRUSB2_I2C_CORE_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c index 6d153fc23ec2..675dc7153e2b 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-io.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c @@ -1,17 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include "pvrusb2-io.h" diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.h b/drivers/media/usb/pvrusb2/pvrusb2-io.h index e769aeb9d529..80e4f831f5e2 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-io.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-io.h @@ -1,17 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_IO_H #define __PVRUSB2_IO_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c index 602097bdcf14..46f8013849b9 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c @@ -1,17 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include "pvrusb2-ioread.h" diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ioread.h b/drivers/media/usb/pvrusb2/pvrusb2-ioread.h index 5827ea09c5e3..33df00a7e515 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ioread.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.h @@ -1,17 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_IOREAD_H #define __PVRUSB2_IOREAD_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-main.c b/drivers/media/usb/pvrusb2/pvrusb2-main.c index 23672dd352f5..ce4d566e4e5a 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-main.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-main.c @@ -1,18 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/kernel.h> diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.c b/drivers/media/usb/pvrusb2/pvrusb2-std.c index 6b651f8b54df..e7ab41401577 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-std.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-std.c @@ -1,17 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include "pvrusb2-std.h" @@ -353,7 +343,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk); pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "WARNING: Failed to classify the following standard(s): %.*s", + "***WARNING*** Failed to classify the following standard(s): %.*s", bcnt,buf); } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.h b/drivers/media/usb/pvrusb2/pvrusb2-std.h index b48304f41472..d8b4c6dc72fe 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-std.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-std.h @@ -1,17 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_STD_H #define __PVRUSB2_STD_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c index 7bc6d090358e..3e42e209be37 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c @@ -1,17 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/string.h> @@ -802,7 +792,8 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) { pvr2_sysfs_trace("Unregistering pvr2_sysfs_class id=%p", clp); - class_unregister(&clp->class); + if (clp) + class_unregister(&clp->class); } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h index 431f4fd19015..ac580ff39b5f 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h @@ -1,17 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_SYSFS_H #define __PVRUSB2_SYSFS_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-util.h b/drivers/media/usb/pvrusb2/pvrusb2-util.h index b03ca3ef1ba0..7059772a4906 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-util.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-util.h @@ -1,17 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_UTIL_H #define __PVRUSB2_UTIL_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index cb6668580d77..0aff2f396392 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -1,18 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/kernel.h> @@ -128,17 +118,6 @@ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability * cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | V4L2_CAP_READWRITE | V4L2_CAP_DEVICE_CAPS; - switch (fh->pdi->devbase.vfl_type) { - case VFL_TYPE_GRABBER: - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO; - break; - case VFL_TYPE_RADIO: - cap->device_caps = V4L2_CAP_RADIO; - break; - default: - return -EINVAL; - } - cap->device_caps |= V4L2_CAP_TUNER | V4L2_CAP_READWRITE; return 0; } @@ -1205,6 +1184,8 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, int unit_number; struct pvr2_hdw *hdw; int *nr_ptr = NULL; + u32 caps = V4L2_CAP_TUNER | V4L2_CAP_READWRITE; + dip->v4lp = vp; hdw = vp->channel.mc_head->hdw; @@ -1215,6 +1196,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, dip->config = pvr2_config_mpeg; dip->minor_type = pvr2_v4l_type_video; nr_ptr = video_nr; + caps |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO; if (!dip->stream) { pr_err(KBUILD_MODNAME ": Failed to set up pvrusb2 v4l video dev due to missing stream instance\n"); @@ -1225,12 +1207,14 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, dip->config = pvr2_config_vbi; dip->minor_type = pvr2_v4l_type_vbi; nr_ptr = vbi_nr; + caps |= V4L2_CAP_VBI_CAPTURE; break; case VFL_TYPE_RADIO: dip->stream = &vp->channel.mc_head->video_stream; dip->config = pvr2_config_mpeg; dip->minor_type = pvr2_v4l_type_radio; nr_ptr = radio_nr; + caps |= V4L2_CAP_RADIO; break; default: /* Bail out (this should be impossible) */ @@ -1241,6 +1225,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, dip->devbase = vdev_template; dip->devbase.release = pvr2_video_device_release; dip->devbase.ioctl_ops = &pvr2_ioctl_ops; + dip->devbase.device_caps = caps; { int val; pvr2_ctrl_get_value( diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h index ec755ee8f86a..e1f9f09b6dd0 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h @@ -1,17 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_V4L2_H #define __PVRUSB2_V4L2_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c index b68aec2124b2..16dd3e859977 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c @@ -1,18 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ /* diff --git a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h index fa33f20655f4..2a1776ba4b2d 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h @@ -1,18 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_VIDEO_V4L_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c index 8f357f771ba7..5f800f4a829c 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c @@ -1,18 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ /* diff --git a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h index c4ac7c2701d0..806d8b758570 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h @@ -1,18 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_WM8775_H diff --git a/drivers/media/usb/pvrusb2/pvrusb2.h b/drivers/media/usb/pvrusb2/pvrusb2.h index 955290ba2d54..1185b72a5fed 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2.h +++ b/drivers/media/usb/pvrusb2/pvrusb2.h @@ -1,18 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * - * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __PVRUSB2_H diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index a15ad0f3faf1..9b76cf133d52 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -1113,6 +1113,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler; pdev->vdev.v4l2_dev = &pdev->v4l2_dev; pdev->vdev.lock = &pdev->v4l2_lock; + pdev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1); if (rc < 0) { diff --git a/drivers/media/usb/pwc/pwc-v4l.c b/drivers/media/usb/pwc/pwc-v4l.c index 5212898db77c..76c498cccc49 100644 --- a/drivers/media/usb/pwc/pwc-v4l.c +++ b/drivers/media/usb/pwc/pwc-v4l.c @@ -483,9 +483,6 @@ static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap strscpy(cap->driver, PWC_NAME, sizeof(cap->driver)); strscpy(cap->card, pdev->vdev.name, sizeof(cap->card)); usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/media/usb/pwc/pwc.h b/drivers/media/usb/pwc/pwc.h index 8aa7e868e6b1..3362962d0d00 100644 --- a/drivers/media/usb/pwc/pwc.h +++ b/drivers/media/usb/pwc/pwc.h @@ -43,15 +43,15 @@ /* Trace certain actions in the driver */ -#define PWC_DEBUG_LEVEL_MODULE (1<<0) -#define PWC_DEBUG_LEVEL_PROBE (1<<1) -#define PWC_DEBUG_LEVEL_OPEN (1<<2) -#define PWC_DEBUG_LEVEL_READ (1<<3) -#define PWC_DEBUG_LEVEL_MEMORY (1<<4) -#define PWC_DEBUG_LEVEL_FLOW (1<<5) -#define PWC_DEBUG_LEVEL_SIZE (1<<6) -#define PWC_DEBUG_LEVEL_IOCTL (1<<7) -#define PWC_DEBUG_LEVEL_TRACE (1<<8) +#define PWC_DEBUG_LEVEL_MODULE BIT(0) +#define PWC_DEBUG_LEVEL_PROBE BIT(1) +#define PWC_DEBUG_LEVEL_OPEN BIT(2) +#define PWC_DEBUG_LEVEL_READ BIT(3) +#define PWC_DEBUG_LEVEL_MEMORY BIT(4) +#define PWC_DEBUG_LEVEL_FLOW BIT(5) +#define PWC_DEBUG_LEVEL_SIZE BIT(6) +#define PWC_DEBUG_LEVEL_IOCTL BIT(7) +#define PWC_DEBUG_LEVEL_TRACE BIT(8) #define PWC_DEBUG_MODULE(fmt, args...) PWC_DEBUG(MODULE, fmt, ##args) #define PWC_DEBUG_PROBE(fmt, args...) PWC_DEBUG(PROBE, fmt, ##args) diff --git a/drivers/media/usb/s2255/Kconfig b/drivers/media/usb/s2255/Kconfig index e0e3c0ba3f23..e4a0c914d9c3 100644 --- a/drivers/media/usb/s2255/Kconfig +++ b/drivers/media/usb/s2255/Kconfig @@ -3,7 +3,6 @@ config USB_S2255 tristate "USB Sensoray 2255 video capture device" depends on VIDEO_V4L2 select VIDEOBUF2_VMALLOC - default n help Say Y here if you want support for the Sensoray 2255 USB device. This driver can be compiled as a module, called s2255drv. diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 3eccbd48bdac..aa90558479f7 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -724,9 +724,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, "s2255", sizeof(cap->driver)); strscpy(cap->card, "s2255", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1657,6 +1654,8 @@ static int s2255_probe_v4l(struct s2255_dev *dev) vc->vdev.ctrl_handler = &vc->hdl; vc->vdev.lock = &dev->lock; vc->vdev.v4l2_dev = &dev->v4l2_dev; + vc->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; video_set_drvdata(&vc->vdev, vc); if (video_nr == -1) ret = video_register_device(&vc->vdev, diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 38016632c6d8..b71a0f4b40b5 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -337,11 +337,6 @@ static int vidioc_querycap(struct file *file, strscpy(cap->driver, "stk1160", sizeof(cap->driver)); strscpy(cap->card, "stk1160", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -821,6 +816,8 @@ int stk1160_video_register(struct stk1160 *dev) /* This will be used to set video_device parent */ dev->vdev.v4l2_dev = &dev->v4l2_dev; + dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; /* NTSC is default */ dev->norm = V4L2_STD_NTSC_M; diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index cb7d6454bbe1..be8041e3e6b8 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -798,10 +798,6 @@ static int stk_vidioc_querycap(struct file *filp, strscpy(cap->driver, "stk", sizeof(cap->driver)); strscpy(cap->card, "stk", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE - | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1261,6 +1257,8 @@ static int stk_register_video_device(struct stk_camera *dev) dev->vdev = stk_v4l_data; dev->vdev.lock = &dev->lock; dev->vdev.v4l2_dev = &dev->v4l2_dev; + dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; video_set_drvdata(&dev->vdev, dev); err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); if (err) diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 072210f5f92f..85fcddfb0202 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -854,22 +854,17 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev; - struct video_device *vdev = video_devdata(file); strscpy(cap->driver, "tm6000", sizeof(cap->driver)); strscpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_DEVICE_CAPS; if (dev->tuner_type != TUNER_ABSENT) - cap->device_caps |= V4L2_CAP_TUNER; - if (vdev->vfl_type == VFL_TYPE_GRABBER) - cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - else - cap->device_caps |= V4L2_CAP_RADIO; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS | - V4L2_CAP_RADIO | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; + cap->capabilities |= V4L2_CAP_TUNER; + if (dev->caps.has_radio) + cap->capabilities |= V4L2_CAP_RADIO; return 0; } @@ -1639,6 +1634,10 @@ int tm6000_v4l2_register(struct tm6000_core *dev) vdev_init(dev, &dev->vfd, &tm6000_template, "video"); dev->vfd.ctrl_handler = &dev->ctrl_handler; + dev->vfd.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; + if (dev->tuner_type != TUNER_ABSENT) + dev->vfd.device_caps |= V4L2_CAP_TUNER; /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); @@ -1659,6 +1658,7 @@ int tm6000_v4l2_register(struct tm6000_core *dev) vdev_init(dev, &dev->radio_dev, &tm6000_radio_template, "radio"); dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler; + dev->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO, radio_nr); if (ret < 0) { diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 4a1eab711bdc..51f784479e91 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -603,9 +603,6 @@ static int usbtv_querycap(struct file *file, void *priv, strscpy(cap->driver, "usbtv", sizeof(cap->driver)); strscpy(cap->card, "usbtv", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE; - cap->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -942,6 +939,8 @@ int usbtv_video_init(struct usbtv *usbtv) usbtv->vdev.tvnorms = USBTV_TV_STD; usbtv->vdev.queue = &usbtv->vb2q; usbtv->vdev.lock = &usbtv->v4l2_lock; + usbtv->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; video_set_drvdata(&usbtv->vdev, usbtv); ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1); if (ret < 0) { diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index 6d42154e3d0a..93750af82d98 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -452,24 +452,18 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *vc) { struct usb_usbvision *usbvision = video_drvdata(file); - struct video_device *vdev = video_devdata(file); strscpy(vc->driver, "USBVision", sizeof(vc->driver)); strscpy(vc->card, usbvision_device_data[usbvision->dev_model].model_string, sizeof(vc->card)); usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info)); - vc->device_caps = usbvision->have_tuner ? V4L2_CAP_TUNER : 0; - if (vdev->vfl_type == VFL_TYPE_GRABBER) - vc->device_caps |= V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - else - vc->device_caps |= V4L2_CAP_RADIO; - - vc->capabilities = vc->device_caps | V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; + vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; if (usbvision_device_data[usbvision->dev_model].radio) vc->capabilities |= V4L2_CAP_RADIO; + if (usbvision->have_tuner) + vc->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -1267,6 +1261,11 @@ static int usbvision_register_video(struct usb_usbvision *usbvision) v4l2_disable_ioctl(&usbvision->vdev, VIDIOC_G_FREQUENCY); v4l2_disable_ioctl(&usbvision->vdev, VIDIOC_S_TUNER); } + usbvision->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + if (usbvision->have_tuner) + usbvision->vdev.device_caps |= V4L2_CAP_TUNER; + if (video_register_device(&usbvision->vdev, VFL_TYPE_GRABBER, video_nr) < 0) goto err_exit; printk(KERN_INFO "USBVision[%d]: registered USBVision Video device %s [v4l2]\n", @@ -1277,6 +1276,7 @@ static int usbvision_register_video(struct usb_usbvision *usbvision) /* usbvision has radio */ usbvision_vdev_init(usbvision, &usbvision->rdev, &usbvision_radio_template, "USBVision Radio"); + usbvision->rdev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; if (video_register_device(&usbvision->rdev, VFL_TYPE_RADIO, radio_nr) < 0) goto err_exit; printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device %s [v4l2]\n", diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 26163a5bde7d..e399b9fad757 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -2345,7 +2345,9 @@ void uvc_ctrl_cleanup_device(struct uvc_device *dev) struct uvc_entity *entity; unsigned int i; - cancel_work_sync(&dev->async_ctrl.work); + /* Can be uninitialized if we are aborting on probe error. */ + if (dev->async_ctrl.work.func) + cancel_work_sync(&dev->async_ctrl.work); /* Free controls and control mappings for all entities. */ list_for_each_entry(entity, &dev->entities, list) { diff --git a/drivers/media/usb/uvc/uvc_debugfs.c b/drivers/media/usb/uvc/uvc_debugfs.c index 8ba54139a087..d2b109959d82 100644 --- a/drivers/media/usb/uvc/uvc_debugfs.c +++ b/drivers/media/usb/uvc/uvc_debugfs.c @@ -74,12 +74,13 @@ void uvc_debugfs_init_stream(struct uvc_streaming *stream) { struct usb_device *udev = stream->dev->udev; struct dentry *dent; - char dir_name[32]; + char dir_name[33]; if (uvc_debugfs_root_dir == NULL) return; - sprintf(dir_name, "%u-%u", udev->bus->busnum, udev->devnum); + snprintf(dir_name, sizeof(dir_name), "%u-%u-%u", udev->bus->busnum, + udev->devnum, stream->intfnum); dent = debugfs_create_dir(dir_name, uvc_debugfs_root_dir); if (IS_ERR_OR_NULL(dent)) { diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 37a7992585df..a9bcba4fa9c6 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -694,14 +694,10 @@ static int zr364xx_vidioc_querycap(struct file *file, void *priv, struct zr364xx_camera *cam = video_drvdata(file); strscpy(cap->driver, DRIVER_DESC, sizeof(cap->driver)); - strscpy(cap->card, cam->udev->product, sizeof(cap->card)); + if (cam->udev->product) + strscpy(cap->card, cam->udev->product, sizeof(cap->card)); strscpy(cap->bus_info, dev_name(&cam->udev->dev), sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -1328,6 +1324,8 @@ static const struct video_device zr364xx_template = { .fops = &zr364xx_fops, .ioctl_ops = &zr364xx_ioctl_ops, .release = video_device_release_empty, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 8b9d4b3ec10e..7c5f62f196e5 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -13,7 +13,6 @@ config VIDEO_V4L2 config VIDEO_ADV_DEBUG bool "Enable advanced debug functionality on V4L2 drivers" - default n help Say Y here to enable advanced debugging functionality on some V4L devices. @@ -21,7 +20,6 @@ config VIDEO_ADV_DEBUG config VIDEO_FIXED_MINOR_RANGES bool "Enable old-style fixed minor ranges on drivers/video devices" - default n help Say Y here to enable the old-style fixed-range minor assignments. Only useful if you rely on the old behavior and use mknod instead of udev. diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 15b0c44a76e7..8d307b538f52 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * V4L2 asynchronous subdevice registration API * * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c index 90628d7a04de..91274eee6977 100644 --- a/drivers/media/v4l2-core/v4l2-clk.c +++ b/drivers/media/v4l2-core/v4l2-clk.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * V4L2 clock service * * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/atomic.h> diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index c9efb2de710d..f8ad1c580a3e 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -321,6 +321,16 @@ static unsigned int clamp_align(unsigned int x, unsigned int min, return x; } +static unsigned int clamp_roundup(unsigned int x, unsigned int min, + unsigned int max, unsigned int alignment) +{ + x = clamp(x, min, max); + if (alignment) + x = round_up(x, alignment); + + return x; +} + void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, unsigned int walign, u32 *h, unsigned int hmin, unsigned int hmax, @@ -531,8 +541,25 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf return info->block_h[plane]; } +void v4l2_apply_frmsize_constraints(u32 *width, u32 *height, + const struct v4l2_frmsize_stepwise *frmsize) +{ + if (!frmsize) + return; + + /* + * Clamp width/height to meet min/max constraints and round it up to + * macroblock alignment. + */ + *width = clamp_roundup(*width, frmsize->min_width, frmsize->max_width, + frmsize->step_width); + *height = clamp_roundup(*height, frmsize->min_height, frmsize->max_height, + frmsize->step_height); +} +EXPORT_SYMBOL_GPL(v4l2_apply_frmsize_constraints); + int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, - int pixelformat, int width, int height) + u32 pixelformat, u32 width, u32 height) { const struct v4l2_format_info *info; struct v4l2_plane_pix_format *plane; @@ -586,7 +613,8 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, } EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp); -int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, int pixelformat, int width, int height) +int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat, + u32 width, u32 height) { const struct v4l2_format_info *info; int i; diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 7d3a33258748..371537dd8cd3 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -394,6 +394,21 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Explicit", NULL, }; + static const char * const mpeg_mpeg2_level[] = { + "Low", + "Main", + "High 1440", + "High", + NULL, + }; + static const char * const mpeg2_profile[] = { + "Simple", + "Main", + "SNR Scalable", + "Spatially Scalable", + "High", + NULL, + }; static const char * const mpeg_mpeg4_level[] = { "0", "0b", @@ -610,6 +625,10 @@ const char * const *v4l2_ctrl_get_menu(u32 id) return h264_fp_arrangement_type; case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: return h264_fmo_map_type; + case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: + return mpeg_mpeg2_level; + case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: + return mpeg2_profile; case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: return mpeg_mpeg4_level; case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: @@ -820,6 +839,13 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP: return "H264 I-Frame Maximum QP Value"; case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP: return "H264 P-Frame Minimum QP Value"; case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP: return "H264 P-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_SPS: return "H264 Sequence Parameter Set"; + case V4L2_CID_MPEG_VIDEO_H264_PPS: return "H264 Picture Parameter Set"; + case V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX: return "H264 Scaling Matrix"; + case V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS: return "H264 Slice Parameters"; + case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: return "H264 Decode Parameters"; + case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return "MPEG2 Level"; + case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: return "MPEG2 Profile"; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B-Frame QP Value"; @@ -1145,6 +1171,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_FLASH_STROBE_STOP: case V4L2_CID_AUTO_FOCUS_START: case V4L2_CID_AUTO_FOCUS_STOP: + case V4L2_CID_DO_WHITE_BALANCE: *type = V4L2_CTRL_TYPE_BUTTON; *flags |= V4L2_CTRL_FLAG_WRITE_ONLY | V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; @@ -1184,6 +1211,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: + case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: + case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: @@ -1301,6 +1330,21 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: *type = V4L2_CTRL_TYPE_FWHT_PARAMS; break; + case V4L2_CID_MPEG_VIDEO_H264_SPS: + *type = V4L2_CTRL_TYPE_H264_SPS; + break; + case V4L2_CID_MPEG_VIDEO_H264_PPS: + *type = V4L2_CTRL_TYPE_H264_PPS; + break; + case V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX: + *type = V4L2_CTRL_TYPE_H264_SCALING_MATRIX; + break; + case V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS: + *type = V4L2_CTRL_TYPE_H264_SLICE_PARAMS; + break; + case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: + *type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS; + break; default: *type = V4L2_CTRL_TYPE_INTEGER; break; @@ -1450,6 +1494,32 @@ static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx, } } +static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, + union v4l2_ctrl_ptr ptr) +{ + struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; + void *p = ptr.p + idx * ctrl->elem_size; + + memset(p, 0, ctrl->elem_size); + + /* + * The cast is needed to get rid of a gcc warning complaining that + * V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS is not part of the + * v4l2_ctrl_type enum. + */ + switch ((u32)ctrl->type) { + case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS: + p_mpeg2_slice_params = p; + /* 4:2:0 */ + p_mpeg2_slice_params->sequence.chroma_format = 1; + /* interlaced top field */ + p_mpeg2_slice_params->picture.picture_structure = 1; + p_mpeg2_slice_params->picture.picture_coding_type = + V4L2_MPEG2_PICTURE_CODING_TYPE_I; + break; + } +} + static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, union v4l2_ctrl_ptr ptr) { @@ -1469,6 +1539,10 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, case V4L2_CTRL_TYPE_BOOLEAN: ptr.p_s32[idx] = ctrl->default_value; break; + case V4L2_CTRL_TYPE_BUTTON: + case V4L2_CTRL_TYPE_CTRL_CLASS: + ptr.p_s32[idx] = 0; + break; case V4L2_CTRL_TYPE_U8: ptr.p_u8[idx] = ctrl->default_value; break; @@ -1479,8 +1553,7 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, ptr.p_u32[idx] = ctrl->default_value; break; default: - idx *= ctrl->elem_size; - memset(ptr.p + idx, 0, ctrl->elem_size); + std_init_compound(ctrl, idx, ptr); break; } } @@ -1670,6 +1743,13 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, case V4L2_CTRL_TYPE_FWHT_PARAMS: return 0; + case V4L2_CTRL_TYPE_H264_SPS: + case V4L2_CTRL_TYPE_H264_PPS: + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: + return 0; + default: return -EINVAL; } @@ -2149,15 +2229,6 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl, if (size_extra_req) new_ref->p_req.p = &new_ref[1]; - if (ctrl->handler == hdl) { - /* By default each control starts in a cluster of its own. - new_ref->ctrl is basically a cluster array with one - element, so that's perfect to use as the cluster pointer. - But only do this for the handler that owns the control. */ - ctrl->cluster = &new_ref->ctrl; - ctrl->ncontrols = 1; - } - INIT_LIST_HEAD(&new_ref->node); mutex_lock(hdl->lock); @@ -2190,6 +2261,15 @@ insert_in_hash: hdl->buckets[bucket] = new_ref; if (ctrl_ref) *ctrl_ref = new_ref; + if (ctrl->handler == hdl) { + /* By default each control starts in a cluster of its own. + * new_ref->ctrl is basically a cluster array with one + * element, so that's perfect to use as the cluster pointer. + * But only do this for the handler that owns the control. + */ + ctrl->cluster = &new_ref->ctrl; + ctrl->ncontrols = 1; + } unlock: mutex_unlock(hdl->lock); @@ -2253,6 +2333,21 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, case V4L2_CTRL_TYPE_FWHT_PARAMS: elem_size = sizeof(struct v4l2_ctrl_fwht_params); break; + case V4L2_CTRL_TYPE_H264_SPS: + elem_size = sizeof(struct v4l2_ctrl_h264_sps); + break; + case V4L2_CTRL_TYPE_H264_PPS: + elem_size = sizeof(struct v4l2_ctrl_h264_pps); + break; + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix); + break; + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_h264_slice_params); + break; + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_h264_decode_params); + break; default: if (type < V4L2_CTRL_COMPOUND_TYPES) elem_size = sizeof(s32); @@ -2369,16 +2464,15 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step, &def, &flags); - is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU || - cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU); + is_menu = (type == V4L2_CTRL_TYPE_MENU || + type == V4L2_CTRL_TYPE_INTEGER_MENU); if (is_menu) WARN_ON(step); else WARN_ON(cfg->menu_skip_mask); - if (cfg->type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) + if (type == V4L2_CTRL_TYPE_MENU && !qmenu) { qmenu = v4l2_ctrl_get_menu(cfg->id); - else if (cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU && - qmenu_int == NULL) { + } else if (type == V4L2_CTRL_TYPE_INTEGER_MENU && !qmenu_int) { handler_set_err(hdl, -EINVAL); return NULL; } diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 414636dedffd..cbb74f748555 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -589,11 +589,9 @@ static void determine_valid_ioctls(struct video_device *vdev) if (is_vid || is_tch) { /* video and metadata specific ioctls */ if ((is_rx && (ops->vidioc_enum_fmt_vid_cap || - ops->vidioc_enum_fmt_vid_cap_mplane || ops->vidioc_enum_fmt_vid_overlay || ops->vidioc_enum_fmt_meta_cap)) || (is_tx && (ops->vidioc_enum_fmt_vid_out || - ops->vidioc_enum_fmt_vid_out_mplane || ops->vidioc_enum_fmt_meta_out))) set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls); if ((is_rx && (ops->vidioc_g_fmt_vid_cap || diff --git a/drivers/media/v4l2-core/v4l2-flash-led-class.c b/drivers/media/v4l2-core/v4l2-flash-led-class.c index 1697932af5ea..10ddcc48aa17 100644 --- a/drivers/media/v4l2-core/v4l2-flash-led-class.c +++ b/drivers/media/v4l2-core/v4l2-flash-led-class.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * V4L2 flash LED sub-device registration helpers. * * Copyright (C) 2015 Samsung Electronics Co., Ltd * Author: Jacek Anaszewski <j.anaszewski@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/led-class-flash.h> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index c2d980ab3af7..7e740d332a54 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -209,10 +209,10 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, have_clk_lane = true; } - if (lanes_used & BIT(clock_lane)) { - if (have_clk_lane || !use_default_lane_mapping) - pr_warn("duplicated lane %u in clock-lanes, using defaults\n", - v); + if (have_clk_lane && lanes_used & BIT(clock_lane) && + !use_default_lane_mapping) { + pr_warn("duplicated lane %u in clock-lanes, using defaults\n", + v); use_default_lane_mapping = true; } @@ -1095,7 +1095,7 @@ v4l2_fwnode_reference_parse_int_props(struct device *dev, } } - return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode); + return !fwnode || PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode); error: fwnode_handle_put(fwnode); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 6859bdac86fe..b1f4b991dba6 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1321,6 +1321,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_H264: descr = "H.264"; break; case V4L2_PIX_FMT_H264_NO_SC: descr = "H.264 (No Start Codes)"; break; case V4L2_PIX_FMT_H264_MVC: descr = "H.264 MVC"; break; + case V4L2_PIX_FMT_H264_SLICE_RAW: descr = "H.264 Parsed Slice Data"; break; case V4L2_PIX_FMT_H263: descr = "H.263"; break; case V4L2_PIX_FMT_MPEG1: descr = "MPEG-1 ES"; break; case V4L2_PIX_FMT_MPEG2: descr = "MPEG-2 ES"; break; @@ -1377,8 +1378,10 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vdev = video_devdata(file); struct v4l2_fmtdesc *p = arg; int ret = check_fmt(file, p->type); + u32 cap_mask; if (ret) return ret; @@ -1386,30 +1389,34 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, switch (p->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + cap_mask = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_M2M_MPLANE; + if (!!(vdev->device_caps & cap_mask) != + (p->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) + break; + if (unlikely(!ops->vidioc_enum_fmt_vid_cap)) break; ret = ops->vidioc_enum_fmt_vid_cap(file, fh, arg); break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (unlikely(!ops->vidioc_enum_fmt_vid_cap_mplane)) - break; - ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, fh, arg); - break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_enum_fmt_vid_overlay)) break; ret = ops->vidioc_enum_fmt_vid_overlay(file, fh, arg); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + cap_mask = V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_M2M_MPLANE; + if (!!(vdev->device_caps & cap_mask) != + (p->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) + break; + if (unlikely(!ops->vidioc_enum_fmt_vid_out)) break; ret = ops->vidioc_enum_fmt_vid_out(file, fh, arg); break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (unlikely(!ops->vidioc_enum_fmt_vid_out_mplane)) - break; - ret = ops->vidioc_enum_fmt_vid_out_mplane(file, fh, arg); - break; case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_enum_fmt_sdr_cap)) break; diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index fd96df98c780..4f5176702937 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -1118,6 +1118,35 @@ int v4l2_m2m_ioctl_streamoff(struct file *file, void *priv, } EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamoff); +int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *fh, + struct v4l2_encoder_cmd *ec) +{ + if (ec->cmd != V4L2_ENC_CMD_STOP && ec->cmd != V4L2_ENC_CMD_START) + return -EINVAL; + + ec->flags = 0; + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_try_encoder_cmd); + +int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *fh, + struct v4l2_decoder_cmd *dc) +{ + if (dc->cmd != V4L2_DEC_CMD_STOP && dc->cmd != V4L2_DEC_CMD_START) + return -EINVAL; + + dc->flags = 0; + + if (dc->cmd == V4L2_DEC_CMD_STOP) { + dc->stop.pts = 0; + } else if (dc->cmd == V4L2_DEC_CMD_START) { + dc->start.speed = 0; + dc->start.format = V4L2_DEC_START_FMT_NONE; + } + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_try_decoder_cmd); + /* * v4l2_file_operations helpers. It is assumed here same lock is used * for the output and the capture buffer queue. diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index f24978b80440..21fb90d66bfc 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -112,56 +112,217 @@ static int subdev_close(struct file *file) return 0; } -#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) -static int check_format(struct v4l2_subdev *sd, - struct v4l2_subdev_format *format) +static inline int check_which(__u32 which) { - if (format->which != V4L2_SUBDEV_FORMAT_TRY && - format->which != V4L2_SUBDEV_FORMAT_ACTIVE) + if (which != V4L2_SUBDEV_FORMAT_TRY && + which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; - if (format->pad >= sd->entity.num_pads) + return 0; +} + +static inline int check_pad(struct v4l2_subdev *sd, __u32 pad) +{ +#if defined(CONFIG_MEDIA_CONTROLLER) + if (sd->entity.graph_obj.mdev) { + if (pad >= sd->entity.num_pads) + return -EINVAL; + return 0; + } +#endif + /* allow pad 0 on subdevices not registered as media entities */ + if (pad > 0) + return -EINVAL; + return 0; +} + +static int check_cfg(__u32 which, struct v4l2_subdev_pad_config *cfg) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY && !cfg) return -EINVAL; return 0; } -static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop) +static inline int check_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { - if (crop->which != V4L2_SUBDEV_FORMAT_TRY && - crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) + if (!format) return -EINVAL; - if (crop->pad >= sd->entity.num_pads) + return check_which(format->which) ? : check_pad(sd, format->pad) ? : + check_cfg(format->which, cfg); +} + +static int call_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + return check_format(sd, cfg, format) ? : + sd->ops->pad->get_fmt(sd, cfg, format); +} + +static int call_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + return check_format(sd, cfg, format) ? : + sd->ops->pad->set_fmt(sd, cfg, format); +} + +static int call_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (!code) return -EINVAL; - return 0; + return check_which(code->which) ? : check_pad(sd, code->pad) ? : + check_cfg(code->which, cfg) ? : + sd->ops->pad->enum_mbus_code(sd, cfg, code); } -static int check_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_selection *sel) +static int call_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) { - if (sel->which != V4L2_SUBDEV_FORMAT_TRY && - sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + if (!fse) return -EINVAL; - if (sel->pad >= sd->entity.num_pads) + return check_which(fse->which) ? : check_pad(sd, fse->pad) ? : + check_cfg(fse->which, cfg) ? : + sd->ops->pad->enum_frame_size(sd, cfg, fse); +} + +static inline int check_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + if (!fi) return -EINVAL; - return 0; + return check_pad(sd, fi->pad); +} + +static int call_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + return check_frame_interval(sd, fi) ? : + sd->ops->video->g_frame_interval(sd, fi); +} + +static int call_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + return check_frame_interval(sd, fi) ? : + sd->ops->video->s_frame_interval(sd, fi); +} + +static int call_enum_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) +{ + if (!fie) + return -EINVAL; + + return check_which(fie->which) ? : check_pad(sd, fie->pad) ? : + check_cfg(fie->which, cfg) ? : + sd->ops->pad->enum_frame_interval(sd, cfg, fie); +} + +static inline int check_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + if (!sel) + return -EINVAL; + + return check_which(sel->which) ? : check_pad(sd, sel->pad) ? : + check_cfg(sel->which, cfg); +} + +static int call_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + return check_selection(sd, cfg, sel) ? : + sd->ops->pad->get_selection(sd, cfg, sel); +} + +static int call_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + return check_selection(sd, cfg, sel) ? : + sd->ops->pad->set_selection(sd, cfg, sel); } -static int check_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) +static inline int check_edid(struct v4l2_subdev *sd, + struct v4l2_subdev_edid *edid) { - if (edid->pad >= sd->entity.num_pads) + if (!edid) return -EINVAL; if (edid->blocks && edid->edid == NULL) return -EINVAL; - return 0; + return check_pad(sd, edid->pad); +} + +static int call_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) +{ + return check_edid(sd, edid) ? : sd->ops->pad->get_edid(sd, edid); +} + +static int call_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) +{ + return check_edid(sd, edid) ? : sd->ops->pad->set_edid(sd, edid); +} + +static int call_dv_timings_cap(struct v4l2_subdev *sd, + struct v4l2_dv_timings_cap *cap) +{ + if (!cap) + return -EINVAL; + + return check_pad(sd, cap->pad) ? : + sd->ops->pad->dv_timings_cap(sd, cap); } -#endif + +static int call_enum_dv_timings(struct v4l2_subdev *sd, + struct v4l2_enum_dv_timings *dvt) +{ + if (!dvt) + return -EINVAL; + + return check_pad(sd, dvt->pad) ? : + sd->ops->pad->enum_dv_timings(sd, dvt); +} + +static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = { + .get_fmt = call_get_fmt, + .set_fmt = call_set_fmt, + .enum_mbus_code = call_enum_mbus_code, + .enum_frame_size = call_enum_frame_size, + .enum_frame_interval = call_enum_frame_interval, + .get_selection = call_get_selection, + .set_selection = call_set_selection, + .get_edid = call_get_edid, + .set_edid = call_set_edid, + .dv_timings_cap = call_dv_timings_cap, + .enum_dv_timings = call_enum_dv_timings, +}; + +static const struct v4l2_subdev_video_ops v4l2_subdev_call_video_wrappers = { + .g_frame_interval = call_g_frame_interval, + .s_frame_interval = call_s_frame_interval, +}; + +const struct v4l2_subdev_ops v4l2_subdev_call_wrappers = { + .pad = &v4l2_subdev_call_pad_wrappers, + .video = &v4l2_subdev_call_video_wrappers, +}; +EXPORT_SYMBOL(v4l2_subdev_call_wrappers); static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) { @@ -284,10 +445,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_G_FMT: { struct v4l2_subdev_format *format = arg; - rval = check_format(sd, format); - if (rval) - return rval; - memset(format->reserved, 0, sizeof(format->reserved)); memset(format->format.reserved, 0, sizeof(format->format.reserved)); return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format); @@ -296,10 +453,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_S_FMT: { struct v4l2_subdev_format *format = arg; - rval = check_format(sd, format); - if (rval) - return rval; - memset(format->reserved, 0, sizeof(format->reserved)); memset(format->format.reserved, 0, sizeof(format->format.reserved)); return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format); @@ -309,10 +462,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_subdev_crop *crop = arg; struct v4l2_subdev_selection sel; - rval = check_crop(sd, crop); - if (rval) - return rval; - memset(crop->reserved, 0, sizeof(crop->reserved)); memset(&sel, 0, sizeof(sel)); sel.which = crop->which; @@ -332,10 +481,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_subdev_selection sel; memset(crop->reserved, 0, sizeof(crop->reserved)); - rval = check_crop(sd, crop); - if (rval) - return rval; - memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; @@ -353,13 +498,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_ENUM_MBUS_CODE: { struct v4l2_subdev_mbus_code_enum *code = arg; - if (code->which != V4L2_SUBDEV_FORMAT_TRY && - code->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (code->pad >= sd->entity.num_pads) - return -EINVAL; - memset(code->reserved, 0, sizeof(code->reserved)); return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad, code); @@ -368,13 +506,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: { struct v4l2_subdev_frame_size_enum *fse = arg; - if (fse->which != V4L2_SUBDEV_FORMAT_TRY && - fse->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (fse->pad >= sd->entity.num_pads) - return -EINVAL; - memset(fse->reserved, 0, sizeof(fse->reserved)); return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad, fse); @@ -383,9 +514,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_G_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval *fi = arg; - if (fi->pad >= sd->entity.num_pads) - return -EINVAL; - memset(fi->reserved, 0, sizeof(fi->reserved)); return v4l2_subdev_call(sd, video, g_frame_interval, arg); } @@ -393,9 +521,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_S_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval *fi = arg; - if (fi->pad >= sd->entity.num_pads) - return -EINVAL; - memset(fi->reserved, 0, sizeof(fi->reserved)); return v4l2_subdev_call(sd, video, s_frame_interval, arg); } @@ -403,13 +528,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval_enum *fie = arg; - if (fie->which != V4L2_SUBDEV_FORMAT_TRY && - fie->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (fie->pad >= sd->entity.num_pads) - return -EINVAL; - memset(fie->reserved, 0, sizeof(fie->reserved)); return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad, fie); @@ -418,10 +536,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_G_SELECTION: { struct v4l2_subdev_selection *sel = arg; - rval = check_selection(sd, sel); - if (rval) - return rval; - memset(sel->reserved, 0, sizeof(sel->reserved)); return v4l2_subdev_call( sd, pad, get_selection, subdev_fh->pad, sel); @@ -430,10 +544,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_S_SELECTION: { struct v4l2_subdev_selection *sel = arg; - rval = check_selection(sd, sel); - if (rval) - return rval; - memset(sel->reserved, 0, sizeof(sel->reserved)); return v4l2_subdev_call( sd, pad, set_selection, subdev_fh->pad, sel); @@ -442,38 +552,24 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_G_EDID: { struct v4l2_subdev_edid *edid = arg; - rval = check_edid(sd, edid); - if (rval) - return rval; - return v4l2_subdev_call(sd, pad, get_edid, edid); } case VIDIOC_S_EDID: { struct v4l2_subdev_edid *edid = arg; - rval = check_edid(sd, edid); - if (rval) - return rval; - return v4l2_subdev_call(sd, pad, set_edid, edid); } case VIDIOC_SUBDEV_DV_TIMINGS_CAP: { struct v4l2_dv_timings_cap *cap = arg; - if (cap->pad >= sd->entity.num_pads) - return -EINVAL; - return v4l2_subdev_call(sd, pad, dv_timings_cap, cap); } case VIDIOC_SUBDEV_ENUM_DV_TIMINGS: { struct v4l2_enum_dv_timings *dvt = arg; - if (dvt->pad >= sd->entity.num_pads) - return -EINVAL; - return v4l2_subdev_call(sd, pad, enum_dv_timings, dvt); } diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c index bf7dfb2a34af..7ef3e4d22bf6 100644 --- a/drivers/media/v4l2-core/videobuf-core.c +++ b/drivers/media/v4l2-core/videobuf-core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * generic helper functions for handling video4linux capture buffers * @@ -7,10 +8,6 @@ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> * (c) 2006 Mauro Carvalho Chehab, <mchehab@kernel.org> * (c) 2006 Ted Walther and John Sokol - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 */ #include <linux/init.h> diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c index e1bf50df4c70..76b4ac7b1678 100644 --- a/drivers/media/v4l2-core/videobuf-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf-dma-contig.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * helper functions for physically contiguous capture buffers * @@ -8,10 +9,6 @@ * * Based on videobuf-vmalloc.c, * (c) 2007 Mauro Carvalho Chehab, <mchehab@kernel.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 */ #include <linux/init.h> @@ -280,7 +277,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, struct videobuf_dma_contig_memory *mem; struct videobuf_mapping *map; int retval; - unsigned long size; dev_dbg(q->dev, "%s\n", __func__); @@ -303,7 +299,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, goto error; /* Try to remap memory */ - size = vma->vm_end - vma->vm_start; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* the "vm_pgoff" is just used in v4l2 to find the @@ -314,7 +309,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, */ vma->vm_pgoff = 0; - retval = vm_iomap_memory(vma, mem->dma_handle, size); + retval = vm_iomap_memory(vma, mem->dma_handle, mem->size); if (retval) { dev_err(q->dev, "mmap: remap failed with error %d. ", retval); diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index 870a2a526e0b..66a6c6c236a7 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * helper functions for SG DMA video4linux capture buffers * @@ -12,10 +13,6 @@ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> * (c) 2006 Mauro Carvalho Chehab, <mchehab@kernel.org> * (c) 2006 Ted Walther and John Sokol - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 */ #include <linux/init.h> diff --git a/drivers/media/v4l2-core/videobuf-vmalloc.c b/drivers/media/v4l2-core/videobuf-vmalloc.c index cb50f1957828..f8bd5a369560 100644 --- a/drivers/media/v4l2-core/videobuf-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf-vmalloc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * helper functions for vmalloc video4linux capture buffers * @@ -6,11 +7,7 @@ * into PAGE_SIZE chunks). They also assume the driver does not need * to touch the video data. * - * (c) 2007 Mauro Carvalho Chehab, <mchehab@kernel.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 + * (c) 2007 Mauro Carvalho Chehab <mchehab@kernel.org> */ #include <linux/init.h> diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c index 04599eccd604..3065a8bc8fd6 100644 --- a/drivers/memory/brcmstb_dpfe.c +++ b/drivers/memory/brcmstb_dpfe.c @@ -1,10 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * DDR PHY Front End (DPFE) driver for Broadcom set top box SoCs * * Copyright (c) 2017 Broadcom - * - * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ /* diff --git a/drivers/memory/da8xx-ddrctl.c b/drivers/memory/da8xx-ddrctl.c index 030afbe29d0c..e8f9b3f461f5 100644 --- a/drivers/memory/da8xx-ddrctl.c +++ b/drivers/memory/da8xx-ddrctl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI da8xx DDR2/mDDR controller driver * @@ -5,10 +6,6 @@ * * Author: * Bartosz Golaszewski <bgolaszewski@baylibre.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 2f214440008c..ee67a9a5d775 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * EMIF driver * @@ -5,10 +6,6 @@ * * Aneesh V <aneesh@ti.com> * Santosh Shilimkar <santosh.shilimkar@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> #include <linux/kernel.h> diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h index 6b71fadb3cfa..55aeb36a5bf2 100644 --- a/drivers/memory/emif.h +++ b/drivers/memory/emif.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Defines for the EMIF driver * * Copyright (C) 2012 Texas Instruments, Inc. * * Benoit Cousson (b-cousson@ti.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __EMIF_H #define __EMIF_H diff --git a/drivers/memory/jz4780-nemc.c b/drivers/memory/jz4780-nemc.c index bcf06adefc96..698da973de35 100644 --- a/drivers/memory/jz4780-nemc.c +++ b/drivers/memory/jz4780-nemc.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * JZ4780 NAND/external memory controller (NEMC) * * Copyright (c) 2015 Imagination Technologies * Author: Alex Smith <alex@alex-smith.me.uk> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index f6297599433f..eff26c1b1394 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * GPMC support functions * @@ -7,10 +8,6 @@ * * Copyright (C) 2009 Texas Instruments * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/irq.h> #include <linux/kernel.h> @@ -22,6 +19,7 @@ #include <linux/io.h> #include <linux/gpio/driver.h> #include <linux/gpio/consumer.h> /* GPIO descriptor enum */ +#include <linux/gpio/machine.h> #include <linux/interrupt.h> #include <linux/irqdomain.h> #include <linux/platform_device.h> @@ -2172,7 +2170,8 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, waitpin_desc = gpiochip_request_own_desc(&gpmc->gpio_chip, wait_pin, "WAITPIN", - 0); + GPIO_ACTIVE_HIGH, + GPIOD_IN); if (IS_ERR(waitpin_desc)) { dev_err(&pdev->dev, "invalid wait-pin: %d\n", wait_pin); ret = PTR_ERR(waitpin_desc); diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 163b6c69e651..3d8d322511c5 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h index 392993955c93..f9353494b708 100644 --- a/drivers/memory/tegra/mc.h +++ b/drivers/memory/tegra/mc.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef MEMORY_TEGRA_MC_H diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c index 62305fafd641..ac8351b5beeb 100644 --- a/drivers/memory/tegra/tegra114.c +++ b/drivers/memory/tegra/tegra114.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/of.h> diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c index 8f8487bda642..41f08b2effd2 100644 --- a/drivers/memory/tegra/tegra124.c +++ b/drivers/memory/tegra/tegra124.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/of.h> diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c index ffda903c49bb..441213a35930 100644 --- a/drivers/memory/tegra/tegra186.c +++ b/drivers/memory/tegra/tegra186.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/io.h> diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c index 121237b16add..a8098bff91d9 100644 --- a/drivers/memory/tegra/tegra20.c +++ b/drivers/memory/tegra/tegra20.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <dt-bindings/memory/tegra20-mc.h> diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c index aa22cda637eb..b420268173fc 100644 --- a/drivers/memory/tegra/tegra210.c +++ b/drivers/memory/tegra/tegra210.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <dt-bindings/memory/tegra210-mc.h> diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c index c9af0f682ead..14788fc2f9e8 100644 --- a/drivers/memory/tegra/tegra30.c +++ b/drivers/memory/tegra/tegra30.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/of.h> diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c index 475e5b3790ed..db526dbf71ee 100644 --- a/drivers/memory/ti-aemif.c +++ b/drivers/memory/ti-aemif.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI AEMIF driver * @@ -6,10 +7,6 @@ * Authors: * Murali Karicheri <m-karicheri2@ti.com> * Ivan Khoronzhuk <ivan.khoronzhuk@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index 1246d69ba187..6cfb293396f2 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c @@ -1,15 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Sony MemoryStick support * * Copyright (C) 2007 Alex Dubov <oakad@yahoo.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Special thanks to Carlos Corbacho for providing various MemoryStick cards * that made this driver possible. - * */ #include <linux/memstick.h> diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c index 82daccc9ea62..384927ebde74 100644 --- a/drivers/memstick/core/ms_block.c +++ b/drivers/memstick/core/ms_block.c @@ -1,15 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ms_block.c - Sony MemoryStick (legacy) storage support * Copyright (C) 2013 Maxim Levitsky <maximlevitsky@gmail.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Minor portions of the driver were copied from mspro_block.c which is * Copyright (C) 2007 Alex Dubov <oakad@yahoo.com> - * */ #define DRIVER_NAME "ms_block" #define pr_fmt(fmt) DRIVER_NAME ": " fmt diff --git a/drivers/memstick/core/ms_block.h b/drivers/memstick/core/ms_block.h index 9ba84e0ced63..122e1a8a8bd5 100644 --- a/drivers/memstick/core/ms_block.h +++ b/drivers/memstick/core/ms_block.h @@ -1,18 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ms_block.h - Sony MemoryStick (legacy) storage support * Copyright (C) 2013 Maxim Levitsky <maximlevitsky@gmail.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Minor portions of the driver are copied from mspro_block.c which is * Copyright (C) 2007 Alex Dubov <oakad@yahoo.com> * * Also ms structures were copied from old broken driver by same author * These probably come from MS spec - * */ #ifndef MS_BLOCK_NEW_H diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 9545e87b6085..cd6b8d4f2335 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -1,15 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Sony MemoryStick Pro storage support * * Copyright (C) 2007 Alex Dubov <oakad@yahoo.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Special thanks to Carlos Corbacho for providing various MemoryStick cards * that made this driver possible. - * */ #include <linux/blk-mq.h> diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index 5733e8fe1aef..32747425297d 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * jmb38x_ms.c - JMicron jmb38x MemoryStick card reader * * Copyright (C) 2008 Alex Dubov <oakad@yahoo.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/spinlock.h> diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c index 627d6e62fe31..2932f421b3ea 100644 --- a/drivers/memstick/host/r592.c +++ b/drivers/memstick/host/r592.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2010 - Maxim Levitsky * driver for Ricoh memstick readers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/memstick/host/r592.h b/drivers/memstick/host/r592.h index c5726c1e8832..c161db70c8f5 100644 --- a/drivers/memstick/host/r592.h +++ b/drivers/memstick/host/r592.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2010 - Maxim Levitsky * driver for Ricoh memstick readers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef R592_H diff --git a/drivers/memstick/host/rtsx_usb_ms.c b/drivers/memstick/host/rtsx_usb_ms.c index 97308dc28ccf..102dbb8080da 100644 --- a/drivers/memstick/host/rtsx_usb_ms.c +++ b/drivers/memstick/host/rtsx_usb_ms.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Realtek USB Memstick Card Interface driver * * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - * * Author: * Roger Tseng <rogerable@realtek.com> */ diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index 6b13ac56eb27..5b966b54d6e9 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c @@ -1,15 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI FlashMedia driver * * Copyright (C) 2007 Alex Dubov <oakad@yahoo.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Special thanks to Carlos Corbacho for providing various MemoryStick cards * that made this driver possible. - * */ #include <linux/tifm.h> diff --git a/drivers/mfd/88pm80x.c b/drivers/mfd/88pm80x.c index 3f24ecbe2576..be036e7e787b 100644 --- a/drivers/mfd/88pm80x.c +++ b/drivers/mfd/88pm80x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C driver for Marvell 88PM80x * @@ -5,10 +6,6 @@ * Haojian Zhuang <haojian.zhuang@marvell.com> * Joseph(Yossi) Hanin <yhanin@marvell.com> * Qiao Zhou <zhouqiao@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 227b99018657..9e0bd135730f 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Base driver for Marvell 88PM8607 * * Copyright (C) 2009 Marvell International Ltd. * * Author: Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index 7b9052ea7413..a000aed35755 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C driver for Marvell 88PM860x * * Copyright (C) 2009 Marvell International Ltd. * * Author: Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index a17d275bf1d4..6855ff443e04 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1336,9 +1336,8 @@ config MFD_TI_LMU select REGMAP_I2C help Say yes here to enable support for TI LMU chips. - - TI LMU MFD supports LM3532, LM3631, LM3632, LM3633, LM3695 and LM3697. - It consists of backlight, LED and regulator driver. + TI LMU MFD supports LM3532, LM3631, LM3632, LM3633, LM3695 and + LM36274. It consists of backlight, LED and regulator driver. It provides consistent device controls for lighting functions. config MFD_OMAP_USB_HOST diff --git a/drivers/mfd/ac100.c b/drivers/mfd/ac100.c index 9bc69cd7807d..6d49d7fb5f14 100644 --- a/drivers/mfd/ac100.c +++ b/drivers/mfd/ac100.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * MFD core driver for X-Powers' AC100 Audio Codec IC * @@ -12,10 +13,6 @@ * Copyright (2016) Chen-Yu Tsai * * Author: Chen-Yu Tsai <wens@csie.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/interrupt.h> diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 27b61639cdc7..2bdc7b02157a 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Arizona core driver * * Copyright 2012 Wolfson Microelectronics plc * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c index 5fe12961cfe5..4b58e3ad6eb6 100644 --- a/drivers/mfd/arizona-i2c.c +++ b/drivers/mfd/arizona-i2c.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Arizona-i2c.c -- Arizona I2C bus interface * * Copyright 2012 Wolfson Microelectronics plc * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index a307832d7e45..077d9ab112b7 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Arizona interrupt support * * Copyright 2012 Wolfson Microelectronics plc * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c index 5c1ccdeb9b70..2633e147b76c 100644 --- a/drivers/mfd/arizona-spi.c +++ b/drivers/mfd/arizona-spi.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arizona-spi.c -- Arizona SPI bus interface * * Copyright 2012 Wolfson Microelectronics plc * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/mfd/arizona.h b/drivers/mfd/arizona.h index a0bddc5bd043..995efc6d7f32 100644 --- a/drivers/mfd/arizona.h +++ b/drivers/mfd/arizona.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * wm5102.h -- WM5102 MFD internals * * Copyright 2012 Wolfson Microelectronics plc * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _WM5102_H diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 1531302a50ec..83b18c998d6f 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -1,19 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * driver/mfd/asic3.c * * Compaq ASIC3 support. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Copyright 2001 Compaq Computer Corporation. * Copyright 2004-2005 Phil Blundell * Copyright 2007-2008 OpenedHand Ltd. * * Authors: Phil Blundell <pb@handhelds.org>, * Samuel Ortiz <sameo@openedhand.com> - * */ #include <linux/kernel.h> diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c index f684a93a3340..d2f5c073fdf3 100644 --- a/drivers/mfd/atmel-flexcom.c +++ b/drivers/mfd/atmel-flexcom.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Atmel Flexcom * * Copyright (C) 2015 Atmel Corporation * * Author: Cyrille Pitchen <cyrille.pitchen@atmel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> diff --git a/drivers/mfd/atmel-hlcdc.c b/drivers/mfd/atmel-hlcdc.c index 35a9e16f9902..64013c57a920 100644 --- a/drivers/mfd/atmel-hlcdc.c +++ b/drivers/mfd/atmel-hlcdc.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Free Electrons * Copyright (C) 2014 Atmel * * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/clk.h> diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c index 0adbd2e796fe..1fa2ec950e7d 100644 --- a/drivers/mfd/atmel-smc.c +++ b/drivers/mfd/atmel-smc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Atmel SMC (Static Memory Controller) helper functions. * @@ -5,10 +6,6 @@ * Copyright (C) 2017 Free Electrons * * Author: Boris Brezillon <boris.brezillon@free-electrons.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/mfd/syscon/atmel-smc.h> diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c index c2e8a0dee7f8..14f9df74f855 100644 --- a/drivers/mfd/axp20x-i2c.c +++ b/drivers/mfd/axp20x-i2c.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C driver for the X-Powers' Power Management ICs * @@ -10,10 +11,6 @@ * Copyright (C) 2014 Carlo Caione * * Author: Carlo Caione <carlo@caione.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/mfd/axp20x-rsb.c b/drivers/mfd/axp20x-rsb.c index 7ddbd9e8dd03..4cdc79f5cc48 100644 --- a/drivers/mfd/axp20x-rsb.c +++ b/drivers/mfd/axp20x-rsb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * RSB driver for the X-Powers' Power Management ICs * @@ -10,10 +11,6 @@ * Copyright (C) 2015 Chen-Yu Tsai * * Author: Chen-Yu Tsai <wens@csie.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 2215660dfa05..a4aaadaa0cb0 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * MFD core driver for the X-Powers' Power Management ICs * @@ -10,10 +11,6 @@ * Copyright (C) 2014 Carlo Caione * * Author: Carlo Caione <carlo@caione.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/mfd/cs47l24-tables.c b/drivers/mfd/cs47l24-tables.c index c090974340ad..c289d92a5c1d 100644 --- a/drivers/mfd/cs47l24-tables.c +++ b/drivers/mfd/cs47l24-tables.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Data tables for CS47L24 codec * * Copyright 2015 Cirrus Logic, Inc. * * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index 09f367571c58..a818fbb55988 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Base driver for Dialog Semiconductor DA9030/DA9034 * @@ -6,10 +7,6 @@ * * Copyright (C) 2006-2008 Marvell International Ltd. * Eric Miao <eric.miao@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/mfd/da9052-irq.c b/drivers/mfd/da9052-irq.c index cd4ca849ca44..abbdbf0337e2 100644 --- a/drivers/mfd/da9052-irq.c +++ b/drivers/mfd/da9052-irq.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * DA9052 interrupt support * @@ -7,10 +8,6 @@ * Copyright 2012 Wolfson Microelectronics plc * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 542b47c6bcd2..f505e3e1274b 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Motorola PCAP2 as present in EZX phones * * Copyright (C) 2006 Harald Welte <laforge@openezx.org> * Copyright (C) 2009 Daniel Ribeiro <drwyrm@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c index dbb85caaafed..20791cab7263 100644 --- a/drivers/mfd/fsl-imx25-tsadc.c +++ b/drivers/mfd/fsl-imx25-tsadc.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014-2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/mfd/hi6421-pmic-core.c b/drivers/mfd/hi6421-pmic-core.c index 6fb7ba272e09..edfc172b8607 100644 --- a/drivers/mfd/hi6421-pmic-core.c +++ b/drivers/mfd/hi6421-pmic-core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device driver for Hi6421 PMIC * @@ -7,10 +8,6 @@ * http://www.linaro.org * * Author: Guodong Xu <guodong.xu@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c index 96c07fa1802a..f1c51ce309fa 100644 --- a/drivers/mfd/hi655x-pmic.c +++ b/drivers/mfd/hi655x-pmic.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device driver for MFD hi655x PMIC * @@ -6,10 +7,6 @@ * Authors: * Chen Feng <puck.chen@hisilicon.com> * Fei Wang <w.f@huawei.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/gpio.h> diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c index 6d9f03363ee7..61ffb8b393e4 100644 --- a/drivers/mfd/intel-lpss-acpi.c +++ b/drivers/mfd/intel-lpss-acpi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Intel LPSS ACPI support. * @@ -5,10 +6,6 @@ * * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> * Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 6b111be944d9..aed2c0447966 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Intel LPSS PCI support. * @@ -5,10 +6,6 @@ * * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> * Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/ioport.h> diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index fc6aa4c50144..a475cbd2b9ef 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Intel Sunrisepoint LPSS core support. * @@ -7,10 +8,6 @@ * Mika Westerberg <mika.westerberg@linux.intel.com> * Heikki Krogerus <heikki.krogerus@linux.intel.com> * Jarkko Nikula <jarkko.nikula@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/mfd/intel-lpss.h b/drivers/mfd/intel-lpss.h index 3a120fecd2dc..4ae58a86bb42 100644 --- a/drivers/mfd/intel-lpss.h +++ b/drivers/mfd/intel-lpss.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Intel LPSS core support. * @@ -5,10 +6,6 @@ * * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> * Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __MFD_INTEL_LPSS_H diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c index cd762d08f116..a1d9be82734d 100644 --- a/drivers/mfd/ipaq-micro.c +++ b/drivers/mfd/ipaq-micro.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Compaq iPAQ h3xxx Atmel microcontroller companion support * @@ -8,10 +9,6 @@ * Author : Alessandro Gardich <gremlin@gremlin.it> * Author : Dmitry Artamonow <mad_soft@inbox.ru> * Author : Linus Walleij <linus.walleij@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/mfd/lp3943.c b/drivers/mfd/lp3943.c index 65a2a8f14e74..13cb89be3d66 100644 --- a/drivers/mfd/lp3943.c +++ b/drivers/mfd/lp3943.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI/National Semiconductor LP3943 MFD Core Driver * @@ -5,10 +6,6 @@ * * Author: Milo Kim <milo.kim@ti.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Driver structure: * LP3943 is an integrated device capable of driving 16 output channels. * It can be used for a GPIO expander and PWM generators. diff --git a/drivers/mfd/lp8788-irq.c b/drivers/mfd/lp8788-irq.c index 792d51bae20f..348439a3fbbd 100644 --- a/drivers/mfd/lp8788-irq.c +++ b/drivers/mfd/lp8788-irq.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LP8788 MFD - interrupt handler * * Copyright 2012 Texas Instruments * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/delay.h> diff --git a/drivers/mfd/lp8788.c b/drivers/mfd/lp8788.c index acf616559512..768d556b3fe9 100644 --- a/drivers/mfd/lp8788.c +++ b/drivers/mfd/lp8788.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LP8788 MFD - core interface * * Copyright 2012 Texas Instruments * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/err.h> diff --git a/drivers/mfd/madera.h b/drivers/mfd/madera.h index 891b84efb9a7..0ff05cd74211 100644 --- a/drivers/mfd/madera.h +++ b/drivers/mfd/madera.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * MFD internals for Cirrus Logic Madera codecs * * Copyright 2015-2018 Cirrus Logic - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef MADERA_MFD_H diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c index 436361ce3737..0c28965fcc6a 100644 --- a/drivers/mfd/max77620.c +++ b/drivers/mfd/max77620.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Maxim MAX77620 MFD Driver * @@ -7,10 +8,6 @@ * Laxman Dewangan <ldewangan@nvidia.com> * Chaitanya Bandi <bandik@nvidia.com> * Mallikarjun Kasoju <mkasoju@nvidia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /****************** Teminology used in driver ******************** diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c index 2974c8b1273b..cc01f706cb32 100644 --- a/drivers/mfd/max8907.c +++ b/drivers/mfd/max8907.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * max8907.c - mfd driver for MAX8907 * * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com> * Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 87c724ba9793..0af6833b4080 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Base driver for Maxim MAX8925 * * Copyright (C) 2009-2010 Marvell International Ltd. * Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index 10063236132c..20bb19b71109 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C driver for Maxim MAX8925 * * Copyright (C) 2009 Marvell International Ltd. * Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/init.h> diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index d0bf50e3568d..1abe7432aad8 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2009-2010 Pengutronix * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> * * loosely based on an earlier driver that has * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/mfd/mc13xxx-i2c.c b/drivers/mfd/mc13xxx-i2c.c index 67e4c9aa7d18..65b4dd8e5afb 100644 --- a/drivers/mfd/mc13xxx-i2c.c +++ b/drivers/mfd/mc13xxx-i2c.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2009-2010 Creative Product Design * Marc Reilly marc@cpdesign.com.au - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. */ #include <linux/slab.h> diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c index ee3411cc5ce4..286ddcf5ddc6 100644 --- a/drivers/mfd/mc13xxx-spi.c +++ b/drivers/mfd/mc13xxx-spi.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2009-2010 Pengutronix * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> * * loosely based on an earlier driver that has * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. */ #include <linux/slab.h> diff --git a/drivers/mfd/mc13xxx.h b/drivers/mfd/mc13xxx.h index 33677d1dcf66..ce6eec52e8eb 100644 --- a/drivers/mfd/mc13xxx.h +++ b/drivers/mfd/mc13xxx.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2012 Creative Product Design * Marc Reilly <marc@cpdesign.com.au> - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. */ #ifndef __DRIVERS_MFD_MC13XXX_H #define __DRIVERS_MFD_MC13XXX_H diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 1ade4c8cc91f..dbf684c4ebfb 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/mfd/mfd-core.c * * core MFD support * Copyright (c) 2006 Ian Molton * Copyright (c) 2007,2008 Dmitry Baryshkov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c index 20d9692640e1..52f38e57cdc1 100644 --- a/drivers/mfd/motorola-cpcap.c +++ b/drivers/mfd/motorola-cpcap.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Motorola CPCAP PMIC core driver * * Copyright (C) 2016 Tony Lindgren <tony@atomide.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/mfd/sky81452.c b/drivers/mfd/sky81452.c index 30a2a677100f..76eedfae8553 100644 --- a/drivers/mfd/sky81452.c +++ b/drivers/mfd/sky81452.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * sky81452.c SKY81452 MFD driver * * Copyright 2014 Skyworks Solutions Inc. * Author : Gyungoh Yoo <jack.yoo@skyworksinc.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index d217debf382e..9b9b06d36cb1 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* linux/drivers/mfd/sm501.c * * Copyright (C) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * Vincent Sanders <vince@simtec.co.uk> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * SM501 MFD driver */ diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c index fe8efba2d45f..857991cb3cbb 100644 --- a/drivers/mfd/stmfx.c +++ b/drivers/mfd/stmfx.c @@ -204,12 +204,11 @@ static struct irq_chip stmfx_irq_chip = { static irqreturn_t stmfx_irq_handler(int irq, void *data) { struct stmfx *stmfx = data; - unsigned long n, pending; - u32 ack; - int ret; + unsigned long bits; + u32 pending, ack; + int n, ret; - ret = regmap_read(stmfx->map, STMFX_REG_IRQ_PENDING, - (u32 *)&pending); + ret = regmap_read(stmfx->map, STMFX_REG_IRQ_PENDING, &pending); if (ret) return IRQ_NONE; @@ -224,7 +223,8 @@ static irqreturn_t stmfx_irq_handler(int irq, void *data) return IRQ_NONE; } - for_each_set_bit(n, &pending, STMFX_REG_IRQ_SRC_MAX) + bits = pending; + for_each_set_bit(n, &bits, STMFX_REG_IRQ_SRC_MAX) handle_nested_irq(irq_find_mapping(stmfx->irq_domain, n)); return IRQ_HANDLED; diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c index 863c39a3353c..61aa020199f5 100644 --- a/drivers/mfd/stmpe-i2c.c +++ b/drivers/mfd/stmpe-i2c.c @@ -1,10 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ST Microelectronics MFD: stmpe's i2c client specific driver * * Copyright (C) ST-Ericsson SA 2010 * Copyright (C) ST Microelectronics SA 2011 * - * License Terms: GNU General Public License, version 2 * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson * Author: Viresh Kumar <vireshk@kernel.org> for ST Microelectronics */ diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c index f8b14ab8b9d7..7351734f7593 100644 --- a/drivers/mfd/stmpe-spi.c +++ b/drivers/mfd/stmpe-spi.c @@ -1,9 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ST Microelectronics MFD: stmpe's spi client specific driver * * Copyright (C) ST Microelectronics SA 2011 * - * License Terms: GNU General Public License, version 2 * Author: Viresh Kumar <vireshk@kernel.org> for ST Microelectronics */ diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index f2acb1f6a29c..1aee3b3253fc 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -1,9 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ST Microelectronics MFD: stmpe's driver * * Copyright (C) ST-Ericsson SA 2010 * - * License Terms: GNU General Public License, version 2 * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson */ diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h index f7efdd8a5fc6..83491e99ba3c 100644 --- a/drivers/mfd/stmpe.h +++ b/drivers/mfd/stmpe.h @@ -1,7 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) ST-Ericsson SA 2010 * - * License Terms: GNU General Public License, version 2 * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson */ diff --git a/drivers/mfd/sun4i-gpadc.c b/drivers/mfd/sun4i-gpadc.c index 9cfc88134d03..b346fbce3c01 100644 --- a/drivers/mfd/sun4i-gpadc.c +++ b/drivers/mfd/sun4i-gpadc.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* ADC MFD core driver for sunxi platforms * * Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/interrupt.h> diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index e9cfb147345e..70da0c4ae457 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * * Toshiba T7L66XB core mfd support @@ -5,10 +6,6 @@ * Copyright (c) 2005, 2007, 2008 Ian Molton * Copyright (c) 2008 Dmitry Baryshkov * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * T7L66 features: * * Supported in this driver: diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index cc9e563f23aa..67c9995bb1aa 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) ST-Ericsson SA 2010 * - * License Terms: GNU General Public License, version 2 * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson */ diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index f417c6fecfe2..c66a701ab21c 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Toshiba TC6387XB support * Copyright (c) 2005 Ian Molton * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This file contains TC6387XB base support. - * */ #include <linux/module.h> diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 6943048a64c2..05d5059ca203 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Toshiba TC6393XB SoC support * @@ -8,10 +9,6 @@ * * Based on code written by Sharp/Lineo for 2.4 kernels * Based on locomo.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/mfd/ti-lmu.c b/drivers/mfd/ti-lmu.c index b06cb908d1aa..fd6e8c417baa 100644 --- a/drivers/mfd/ti-lmu.c +++ b/drivers/mfd/ti-lmu.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LMU (Lighting Management Unit) Core Driver * * Copyright 2017 Texas Instruments * * Author: Milo Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> @@ -111,17 +108,14 @@ static const struct mfd_cell lm3695_devices[] = { }, }; -static const struct mfd_cell lm3697_devices[] = { - { - .name = "ti-lmu-backlight", - .id = LM3697, - .of_compatible = "ti,lm3697-backlight", - }, - /* Monitoring driver for open/short circuit detection */ +static const struct mfd_cell lm36274_devices[] = { + LM363X_REGULATOR(LM36274_BOOST), + LM363X_REGULATOR(LM36274_LDO_POS), + LM363X_REGULATOR(LM36274_LDO_NEG), { - .name = "ti-lmu-fault-monitor", - .id = LM3697, - .of_compatible = "ti,lm3697-fault-monitor", + .name = "lm36274-leds", + .id = LM36274, + .of_compatible = "ti,lm36274-backlight", }, }; @@ -137,7 +131,7 @@ TI_LMU_DATA(lm3631, LM3631_MAX_REG); TI_LMU_DATA(lm3632, LM3632_MAX_REG); TI_LMU_DATA(lm3633, LM3633_MAX_REG); TI_LMU_DATA(lm3695, LM3695_MAX_REG); -TI_LMU_DATA(lm3697, LM3697_MAX_REG); +TI_LMU_DATA(lm36274, LM36274_MAX_REG); static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id) { @@ -206,7 +200,7 @@ static const struct of_device_id ti_lmu_of_match[] = { { .compatible = "ti,lm3632", .data = &lm3632_data }, { .compatible = "ti,lm3633", .data = &lm3633_data }, { .compatible = "ti,lm3695", .data = &lm3695_data }, - { .compatible = "ti,lm3697", .data = &lm3697_data }, + { .compatible = "ti,lm36274", .data = &lm36274_data }, { } }; MODULE_DEVICE_TABLE(of, ti_lmu_of_match); @@ -216,7 +210,7 @@ static const struct i2c_device_id ti_lmu_ids[] = { { "lm3632", LM3632 }, { "lm3633", LM3633 }, { "lm3695", LM3695 }, - { "lm3697", LM3697 }, + { "lm36274", LM36274 }, { } }; MODULE_DEVICE_TABLE(i2c, ti_lmu_ids); diff --git a/drivers/mfd/tmio_core.c b/drivers/mfd/tmio_core.c index ebf54cc28f7a..7ee873551482 100644 --- a/drivers/mfd/tmio_core.c +++ b/drivers/mfd/tmio_core.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2009 Ian Molton <spyro@f2s.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/export.h> diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 9c7925ca13cf..c8aadd39324e 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Core driver for TI TPS6586x PMIC family * @@ -9,10 +10,6 @@ * Mike Rapoport <mike@compulab.co.il> * Copyright (C) 2006-2008 Marvell International Ltd. * Eric Miao <eric.miao@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/interrupt.h> diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c index ebb20edf9c17..8c3832a58ef6 100644 --- a/drivers/mfd/ucb1400_core.c +++ b/drivers/mfd/ucb1400_core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Core functions for: * Philips UCB1400 multifunction chip @@ -11,10 +12,6 @@ * If something doesn't work and it worked before spliting, e-mail me, * dont bother Nicolas please ;-) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This code is heavily based on ucb1x00-*.c copyrighted by Russell King * covering the UCB1100, UCB1200 and UCB1300.. Support for the UCB1400 has * been made separate from ucb1x00-core/ucb1x00-ts on Russell's request. diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 1e0e20c0e082..6e1b38f9f26c 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Touchscreen driver for UCB1x00-based touchscreens * * Copyright (C) 2001 Russell King, All Rights Reserved. * Copyright (C) 2005 Pavel Machek * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * 21-Jan-2002 <jco@ict.es> : * * Added support for synchronous A/D mode. This mode is useful to diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index 853113d97c1e..6bba39657991 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * wm5102-tables.c -- WM5102 data tables * * Copyright 2012 Wolfson Microelectronics plc * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 16c6e2accfaa..65b9b1d6daec 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * wm5110-tables.c -- WM5110 data tables * * Copyright 2012 Wolfson Microelectronics plc * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/mfd/wm8997-tables.c b/drivers/mfd/wm8997-tables.c index ca41a561bfd3..3476787c485e 100644 --- a/drivers/mfd/wm8997-tables.c +++ b/drivers/mfd/wm8997-tables.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * wm8997-tables.c -- WM8997 data tables * * Copyright 2012 Wolfson Microelectronics plc * * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/mfd/wm8998-tables.c b/drivers/mfd/wm8998-tables.c index a0de3002cdad..ebf0eadd2075 100644 --- a/drivers/mfd/wm8998-tables.c +++ b/drivers/mfd/wm8998-tables.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * wm8998-tables.c -- data tables for wm8998-class codecs * * Copyright 2014 Wolfson Microelectronics plc * * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index d8e3cc2dc747..ab4144ea1f11 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Atmel SSC driver * * Copyright (C) 2007 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/platform_device.h> diff --git a/drivers/misc/c2port/c2port-duramar2150.c b/drivers/misc/c2port/c2port-duramar2150.c index 3dc61ea7dc64..7e370949e00e 100644 --- a/drivers/misc/c2port/c2port-duramar2150.c +++ b/drivers/misc/c2port/c2port-duramar2150.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Silicon Labs C2 port Linux support for Eurotech Duramar 2150 * * Copyright (c) 2008 Rodolfo Giometti <giometti@linux.it> * Copyright (c) 2008 Eurotech S.p.A. <info@eurotech.it> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation */ #include <linux/errno.h> diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c index 1c5b7aec13d4..33bba1802289 100644 --- a/drivers/misc/c2port/core.c +++ b/drivers/misc/c2port/core.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Silicon Labs C2 port core Linux support * * Copyright (c) 2007 Rodolfo Giometti <giometti@linux.it> * Copyright (c) 2007 Eurotech S.p.A. <info@eurotech.it> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation */ #include <linux/module.h> diff --git a/drivers/misc/cardreader/rtsx_usb.c b/drivers/misc/cardreader/rtsx_usb.c index f7a66f614085..a328cab11014 100644 --- a/drivers/misc/cardreader/rtsx_usb.c +++ b/drivers/misc/cardreader/rtsx_usb.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Driver for Realtek USB card reader * * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - * * Author: * Roger Tseng <rogerable@realtek.com> */ diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c index 2c43fd09d602..b290bc2ee240 100644 --- a/drivers/misc/cb710/core.c +++ b/drivers/misc/cb710/core.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cb710/core.c * * Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/misc/cb710/debug.c b/drivers/misc/cb710/debug.c index fcb3b8e30c52..20d672edf7cd 100644 --- a/drivers/misc/cb710/debug.c +++ b/drivers/misc/cb710/debug.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cb710/debug.c * * Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/cb710.h> #include <linux/kernel.h> diff --git a/drivers/misc/cb710/sgbuf2.c b/drivers/misc/cb710/sgbuf2.c index 2a40d0efdff5..dfd2969e3628 100644 --- a/drivers/misc/cb710/sgbuf2.c +++ b/drivers/misc/cb710/sgbuf2.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cb710/sgbuf2.c * * Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/misc/ds1682.c b/drivers/misc/ds1682.c index 98a921ea9ee8..42f316c2d719 100644 --- a/drivers/misc/ds1682.c +++ b/drivers/misc/ds1682.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Dallas Semiconductor DS1682 Elapsed Time Recorder device driver * * Written by: Grant Likely <grant.likely@secretlab.ca> * * Copyright (C) 2007 Secret Lab Technologies Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /* diff --git a/drivers/misc/dummy-irq.c b/drivers/misc/dummy-irq.c index 76a1015d5783..fe3bfcb31a4c 100644 --- a/drivers/misc/dummy-irq.c +++ b/drivers/misc/dummy-irq.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Dummy IRQ handler driver. * @@ -10,11 +11,6 @@ * Copyright (C) 2013 Jiri Kosina */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ #include <linux/module.h> #include <linux/irq.h> #include <linux/interrupt.h> diff --git a/drivers/misc/eeprom/digsy_mtc_eeprom.c b/drivers/misc/eeprom/digsy_mtc_eeprom.c index fbde2516c04f..f1f766b70965 100644 --- a/drivers/misc/eeprom/digsy_mtc_eeprom.c +++ b/drivers/misc/eeprom/digsy_mtc_eeprom.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * EEPROMs access control driver for display configuration EEPROMs * on DigsyMTC board. * * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * FIXME: this driver is used on a device-tree probed platform: it * should be defined as a bit-banged SPI device and probed from the device * tree and not like this with static grabbing of a few numbered GPIO diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index c6dd9ad9bf7b..94cfb675fe4e 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for 93xx46 EEPROMs * * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c index 607b489a6501..fab02f2da077 100644 --- a/drivers/misc/fsa9480.c +++ b/drivers/misc/fsa9480.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * fsa9480.c - FSA9480 micro USB switch device driver * * Copyright (C) 2010 Samsung Electronics * Minkyu Kang <mk7.kang@samsung.com> * Wonguk Jeong <wonguk.jeong@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/misc/habanalabs/habanalabs_ioctl.c b/drivers/misc/habanalabs/habanalabs_ioctl.c index eeefb22023e9..b7a0eecf6b6c 100644 --- a/drivers/misc/habanalabs/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/habanalabs_ioctl.c @@ -140,7 +140,7 @@ static int debug_coresight(struct hl_device *hdev, struct hl_debug_args *args) params->op = args->op; if (args->input_ptr && args->input_size) { - input = memdup_user((const void __user *) args->input_ptr, + input = memdup_user(u64_to_user_ptr(args->input_ptr), args->input_size); if (IS_ERR(input)) { rc = PTR_ERR(input); diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c index 17f839dee976..d9fcfd3b5af0 100644 --- a/drivers/misc/lkdtm/bugs.c +++ b/drivers/misc/lkdtm/bugs.c @@ -236,7 +236,7 @@ void lkdtm_CORRUPT_USER_DS(void) set_fs(KERNEL_DS); /* Make sure we do not keep running with a KERNEL_DS! */ - force_sig(SIGKILL, current); + force_sig(SIGKILL); } /* Test that VMAP_STACK is actually allocating with a leading guard page */ diff --git a/drivers/misc/sram.h b/drivers/misc/sram.h index c181ce4c8fca..9c1d21ff7347 100644 --- a/drivers/misc/sram.h +++ b/drivers/misc/sram.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Defines for the SRAM driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __SRAM_H #define __SRAM_H diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index cc729f7ab32e..e6b40aa8fb42 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tifm_7xx1.c - TI FlashMedia driver * * Copyright (C) 2006 Alex Dubov <oakad@yahoo.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/tifm.h> diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index a511b2a713b3..667e574a7df2 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tifm_core.c - TI FlashMedia driver * * Copyright (C) 2006 Alex Dubov <oakad@yahoo.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/tifm.h> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index fc92c6c1c9a4..74de3f2dda38 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/core/bus.c * * Copyright (C) 2003 Russell King, All Rights Reserved. * Copyright (C) 2007 Pierre Ossman * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * MMC card bus driver model */ diff --git a/drivers/mmc/core/bus.h b/drivers/mmc/core/bus.h index 72b0ef03f10a..8105852c4b62 100644 --- a/drivers/mmc/core/bus.h +++ b/drivers/mmc/core/bus.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/mmc/core/bus.h * * Copyright (C) 2003 Russell King, All Rights Reserved. * Copyright 2007 Pierre Ossman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _MMC_CORE_BUS_H #define _MMC_CORE_BUS_H diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 6db36dc870b5..221127324709 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/core/core.c * @@ -5,10 +6,6 @@ * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/init.h> @@ -144,8 +141,9 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) int err = cmd->error; /* Flag re-tuning needed on CRC errors */ - if ((cmd->opcode != MMC_SEND_TUNING_BLOCK && - cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200) && + if (cmd->opcode != MMC_SEND_TUNING_BLOCK && + cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 && + !host->retune_crc_disable && (err == -EILSEQ || (mrq->sbc && mrq->sbc->error == -EILSEQ) || (mrq->data && mrq->data->error == -EILSEQ) || (mrq->stop && mrq->stop->error == -EILSEQ))) diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index b5083b13d594..328c78dbee66 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/mmc/core/core.h * * Copyright (C) 2003 Russell King, All Rights Reserved. * Copyright 2007 Pierre Ossman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _MMC_CORE_CORE_H #define _MMC_CORE_CORE_H diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index d2275c5a2311..2797771a5fa8 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Debugfs support for hosts and cards * * Copyright (C) 2008 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/moduleparam.h> #include <linux/export.h> diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 6a51f7a06ce7..105b7a7c0251 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/core/host.c * @@ -5,10 +6,6 @@ * Copyright (C) 2007-2008 Pierre Ossman * Copyright (C) 2010 Linus Walleij * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * MMC host class device management */ diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h index 4805438c02ff..5e3b9534ffb2 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/mmc/core/host.h * * Copyright (C) 2003 Russell King, All Rights Reserved. * Copyright 2007 Pierre Ossman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _MMC_CORE_HOST_H #define _MMC_CORE_HOST_H diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 3e786ba204c3..c8804895595f 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/core/mmc.c * * Copyright (C) 2003-2004 Russell King, All Rights Reserved. * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> @@ -1212,13 +1209,13 @@ static int mmc_select_hs400(struct mmc_card *card) mmc_set_timing(host, MMC_TIMING_MMC_HS400); mmc_set_bus_speed(card); + if (host->ops->hs400_complete) + host->ops->hs400_complete(host); + err = mmc_switch_status(card); if (err) goto out_err; - if (host->ops->hs400_complete) - host->ops->hs400_complete(host); - return 0; out_err: diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 92900a095796..3557d5c51141 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2003 Russell King, All Rights Reserved. * Copyright 2006-2007 Pierre Ossman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/slab.h> #include <linux/module.h> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index d3d32f9a2cb1..d681e8aaca83 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/core/sd.c * * Copyright (C) 2003-2004 Russell King, All Rights Reserved. * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index d1aa1c7577bb..712a7742765e 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -937,6 +937,10 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host) */ static int mmc_sdio_suspend(struct mmc_host *host) { + /* Prevent processing of SDIO IRQs in suspended state. */ + mmc_card_set_suspended(host->card); + cancel_delayed_work_sync(&host->sdio_irq_work); + mmc_claim_host(host); if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) @@ -985,13 +989,20 @@ static int mmc_sdio_resume(struct mmc_host *host) err = sdio_enable_4bit_bus(host->card); } - if (!err && host->sdio_irqs) { + if (err) + goto out; + + /* Allow SDIO IRQs to be processed again. */ + mmc_card_clr_suspended(host->card); + + if (host->sdio_irqs) { if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) wake_up_process(host->sdio_irq_thread); else if (host->caps & MMC_CAP_SDIO_IRQ) host->ops->enable_sdio_irq(host, 1); } +out: mmc_release_host(host); host->pm_flags &= ~MMC_PM_KEEP_POWER; diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index f79f0b0caab8..2ba00acf64e6 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -15,6 +15,7 @@ #include "sdio_ops.h" #include "core.h" #include "card.h" +#include "host.h" /** * sdio_claim_host - exclusively claim a bus for a certain SDIO function @@ -734,3 +735,79 @@ int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags) return 0; } EXPORT_SYMBOL_GPL(sdio_set_host_pm_flags); + +/** + * sdio_retune_crc_disable - temporarily disable retuning on CRC errors + * @func: SDIO function attached to host + * + * If the SDIO card is known to be in a state where it might produce + * CRC errors on the bus in response to commands (like if we know it is + * transitioning between power states), an SDIO function driver can + * call this function to temporarily disable the SD/MMC core behavior of + * triggering an automatic retuning. + * + * This function should be called while the host is claimed and the host + * should remain claimed until sdio_retune_crc_enable() is called. + * Specifically, the expected sequence of calls is: + * - sdio_claim_host() + * - sdio_retune_crc_disable() + * - some number of calls like sdio_writeb() and sdio_readb() + * - sdio_retune_crc_enable() + * - sdio_release_host() + */ +void sdio_retune_crc_disable(struct sdio_func *func) +{ + func->card->host->retune_crc_disable = true; +} +EXPORT_SYMBOL_GPL(sdio_retune_crc_disable); + +/** + * sdio_retune_crc_enable - re-enable retuning on CRC errors + * @func: SDIO function attached to host + * + * This is the compement to sdio_retune_crc_disable(). + */ +void sdio_retune_crc_enable(struct sdio_func *func) +{ + func->card->host->retune_crc_disable = false; +} +EXPORT_SYMBOL_GPL(sdio_retune_crc_enable); + +/** + * sdio_retune_hold_now - start deferring retuning requests till release + * @func: SDIO function attached to host + * + * This function can be called if it's currently a bad time to do + * a retune of the SDIO card. Retune requests made during this time + * will be held and we'll actually do the retune sometime after the + * release. + * + * This function could be useful if an SDIO card is in a power state + * where it can respond to a small subset of commands that doesn't + * include the retuning command. Care should be taken when using + * this function since (presumably) the retuning request we might be + * deferring was made for a good reason. + * + * This function should be called while the host is claimed. + */ +void sdio_retune_hold_now(struct sdio_func *func) +{ + mmc_retune_hold_now(func->card->host); +} +EXPORT_SYMBOL_GPL(sdio_retune_hold_now); + +/** + * sdio_retune_release - signal that it's OK to retune now + * @func: SDIO function attached to host + * + * This is the complement to sdio_retune_hold_now(). Calling this + * function won't make a retune happen right away but will allow + * them to be scheduled normally. + * + * This function should be called while the host is claimed. + */ +void sdio_retune_release(struct sdio_func *func) +{ + mmc_retune_release(func->card->host); +} +EXPORT_SYMBOL_GPL(sdio_retune_release); diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 931e6226c0b3..9f54a259a1b3 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -34,6 +34,10 @@ static int process_sdio_pending_irqs(struct mmc_host *host) unsigned char pending; struct sdio_func *func; + /* Don't process SDIO IRQs if the card is suspended. */ + if (mmc_card_suspended(card)) + return 0; + /* * Optimization, if there is only 1 function interrupt registered * and we know an IRQ was signaled then call irq handler directly. diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 4afc6b87b465..da2596c5fa28 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic GPIO card-detect helper * * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/mmc/host/android-goldfish.c b/drivers/mmc/host/android-goldfish.c index 61e4e2a213c9..11a208cfba04 100644 --- a/drivers/mmc/host/android-goldfish.c +++ b/drivers/mmc/host/android-goldfish.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2007, Google Inc. * Copyright 2012, Intel Inc. @@ -7,10 +8,6 @@ * Written by Tuukka Tikkanen and Juha Yrjölä <juha.yrjola@nokia.com> * Misc hacks here and there by Tony Lindgren <tony@atomide.com> * Other hacks (DMA, SD, etc) by David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 735aa5871358..392a1f87c638 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Atmel MultiMedia Card Interface driver * * Copyright (C) 2004-2008 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/blkdev.h> #include <linux/clk.h> diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 9b4be67330dd..bc8aeb47a7b4 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/host/au1xmmc.c - AU1XX0 MMC driver * @@ -16,9 +17,6 @@ * All Rights Reserved. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /* Why don't we use the SD controllers' carddetect feature? diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c index 4c477dcd2ada..e33270e40539 100644 --- a/drivers/mmc/host/cb710-mmc.c +++ b/drivers/mmc/host/cb710-mmc.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cb710/mmc.c * * Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/mmc/host/cb710-mmc.h b/drivers/mmc/host/cb710-mmc.h index 8ecd9e56636a..5e053077dbed 100644 --- a/drivers/mmc/host/cb710-mmc.h +++ b/drivers/mmc/host/cb710-mmc.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cb710/cb710-mmc.h * * Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef LINUX_CB710_MMC_H #define LINUX_CB710_MMC_H diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 5582561586b4..fb842255de49 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Amlogic SD/eMMC driver for the GX/S905 family SoCs * * Copyright (c) 2016 BayLibre, SAS. * Author: Kevin Hilman <khilman@baylibre.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * The full GNU General Public License is included in this distribution - * in the file called COPYING. */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 356833a606d5..b8554bf38f72 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver * * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. * Copyright (C) 2010 ST-Ericsson SA - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/moduleparam.h> diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 4f071bd34e59..833236ecb31e 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/mmc/host/mmci.h - ARM PrimeCell MMCI PL180/1 driver * * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define MMCIPOWER 0x000 #define MCI_PWR_OFF 0x00 diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 5a6d885994e6..33f4b6387ef7 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1023,6 +1023,8 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq) msdc_track_cmd_data(host, mrq->cmd, mrq->data); if (mrq->data) msdc_unprepare_data(host, mrq); + if (host->error) + msdc_reset_hw(host); mmc_request_done(host->mmc, mrq); } @@ -1375,24 +1377,25 @@ static void msdc_request_timeout(struct work_struct *work) } } -static void __msdc_enable_sdio_irq(struct mmc_host *mmc, int enb) +static void __msdc_enable_sdio_irq(struct msdc_host *host, int enb) { - unsigned long flags; - struct msdc_host *host = mmc_priv(mmc); - - spin_lock_irqsave(&host->lock, flags); - if (enb) + if (enb) { sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ); - else + sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); + } else { sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ); - spin_unlock_irqrestore(&host->lock, flags); + sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); + } } static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb) { + unsigned long flags; struct msdc_host *host = mmc_priv(mmc); - __msdc_enable_sdio_irq(mmc, enb); + spin_lock_irqsave(&host->lock, flags); + __msdc_enable_sdio_irq(host, enb); + spin_unlock_irqrestore(&host->lock, flags); if (enb) pm_runtime_get_noresume(host->dev); @@ -1414,6 +1417,8 @@ static irqreturn_t msdc_irq(int irq, void *dev_id) spin_lock_irqsave(&host->lock, flags); events = readl(host->base + MSDC_INT); event_mask = readl(host->base + MSDC_INTEN); + if ((events & event_mask) & MSDC_INT_SDIOIRQ) + __msdc_enable_sdio_irq(host, 0); /* clear interrupts */ writel(events & event_mask, host->base + MSDC_INT); @@ -1422,10 +1427,8 @@ static irqreturn_t msdc_irq(int irq, void *dev_id) data = host->data; spin_unlock_irqrestore(&host->lock, flags); - if ((events & event_mask) & MSDC_INT_SDIOIRQ) { - __msdc_enable_sdio_irq(host->mmc, 0); + if ((events & event_mask) & MSDC_INT_SDIOIRQ) sdio_signal_irq(host->mmc); - } if ((events & event_mask) & MSDC_INT_CDSC) { if (host->internal_cd) @@ -1564,10 +1567,7 @@ static void msdc_init_hw(struct msdc_host *host) sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO); /* Config SDIO device detect interrupt function */ - if (host->mmc->caps & MMC_CAP_SDIO_IRQ) - sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); - else - sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); + sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); /* Configure to default data timeout */ sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3); @@ -2095,7 +2095,12 @@ static void msdc_hw_reset(struct mmc_host *mmc) static void msdc_ack_sdio_irq(struct mmc_host *mmc) { - __msdc_enable_sdio_irq(mmc, 1); + unsigned long flags; + struct msdc_host *host = mmc_priv(mmc); + + spin_lock_irqsave(&host->lock, flags); + __msdc_enable_sdio_irq(host, 1); + spin_unlock_irqrestore(&host->lock, flags); } static int msdc_get_cd(struct mmc_host *mmc) diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 9cb93e15b197..74a0a7fbbf7f 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Marvell MMC/SD/SDIO driver * * Authors: Maen Suleiman, Nicolas Pitre * Copyright (C) 2008-2009 Marvell Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/mmc/host/mvsdio.h b/drivers/mmc/host/mvsdio.h index 7d9727b9f5aa..2f1458ac6cc3 100644 --- a/drivers/mmc/host/mvsdio.h +++ b/drivers/mmc/host/mvsdio.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2008 Marvell Semiconductors, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __MVSDIO_H diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 45f7b9b53d48..750604f7fac9 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/host/mxcmmc.c - Freescale i.MX MMCI driver * @@ -10,11 +11,6 @@ * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com> * * derived from pxamci.c by Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index b2873a2432b6..d74e73c95fdf 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/host/omap.c * @@ -5,10 +6,6 @@ * Written by Tuukka Tikkanen and Juha Yrjölä<juha.yrjola@nokia.com> * Misc hacks here and there by Tony Lindgren <tony@atomide.com> * Other hacks (DMA, SD, etc) by David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index e7d80c83da2c..024acc1b0a2e 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/host/pxa.c - PXA MMCI driver * * Copyright (C) 2003 Russell King, All Rights Reserved. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This hardware is really sick: * - No way to clear interrupts. * - Have to turn off the clock whenever we touch the device. diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 5e9e36ed2107..5f8d57ac084f 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -620,11 +620,16 @@ static const struct renesas_sdhi_quirks sdhi_quirks_h3_es2 = { .hs400_4taps = true, }; +static const struct renesas_sdhi_quirks sdhi_quirks_nohs400 = { + .hs400_disabled = true, +}; + static const struct soc_device_attribute sdhi_quirks_match[] = { { .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_h3_m3w_es1 }, { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_h3_es2 }, - { .soc_id = "r8a7796", .revision = "ES1.0", .data = &sdhi_quirks_h3_m3w_es1 }, - { .soc_id = "r8a7796", .revision = "ES1.1", .data = &sdhi_quirks_h3_m3w_es1 }, + { .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_h3_m3w_es1 }, + { .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_h3_m3w_es1 }, + { .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 }, { /* Sentinel. */ }, }; diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c index 669c6ab021c8..81d0dfe553a8 100644 --- a/drivers/mmc/host/rtsx_usb_sdmmc.c +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Realtek USB SD/MMC Card Interface driver * * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - * * Author: * Roger Tseng <rogerable@realtek.com> */ diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index f31333e831a7..b1d3f8288732 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver * @@ -5,10 +6,6 @@ * * Current driver maintained by Ben Dooks and Simtec Electronics * Copyright (C) 2008 Simtec Electronics <ben-linux@fluff.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h index 30c2c0dd1bc8..7ca1d9d639c4 100644 --- a/drivers/mmc/host/s3cmci.h +++ b/drivers/mmc/host/s3cmci.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver * * Copyright (C) 2004-2006 Thomas Kleffel, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ enum s3cmci_waitfor { diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c index bd286db7f9af..811eab1b8964 100644 --- a/drivers/mmc/host/sdhci-cns3xxx.c +++ b/drivers/mmc/host/sdhci-cns3xxx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SDHCI support for CNS3xxx SoC * @@ -6,10 +7,6 @@ * * Authors: Scott Shu * Anton Vorontsov <avorontsov@mvista.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c index b29bf4e7dcb4..dd21315922c8 100644 --- a/drivers/mmc/host/sdhci-pci-o2micro.c +++ b/drivers/mmc/host/sdhci-pci-o2micro.c @@ -115,6 +115,7 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode) */ if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) { current_bus_width = mmc->ios.bus_width; + mmc->ios.bus_width = MMC_BUS_WIDTH_4; sdhci_set_bus_width(host, MMC_BUS_WIDTH_4); } @@ -126,8 +127,10 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode) sdhci_end_tuning(host); - if (current_bus_width == MMC_BUS_WIDTH_8) + if (current_bus_width == MMC_BUS_WIDTH_8) { + mmc->ios.bus_width = MMC_BUS_WIDTH_8; sdhci_set_bus_width(host, current_bus_width); + } host->flags &= ~SDHCI_HS400_TUNING; return 0; diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index 6109987fc3b5..2af445b8c325 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2010 MontaVista Software, LLC. * * Author: Anton Vorontsov <avorontsov@ru.mvista.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _DRIVERS_MMC_SDHCI_PLTFM_H diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 9ef89d00970e..8e4a8ba33f05 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* linux/drivers/mmc/host/sdhci-s3c.c * * Copyright 2008 Openmoko Inc. @@ -6,10 +7,6 @@ * http://armlinux.simtec.co.uk/ * * SDHCI (HSMMC) support for Samsung SoC - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/spinlock.h> diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 35dd34b82a4d..54271b92ee59 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tifm_sd.c - TI FlashMedia driver * * Copyright (C) 2006 Alex Dubov <oakad@yahoo.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Special thanks to Brad Campbell for extensive testing of this driver. - * */ diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index 4fd6da29489e..2c4ba1fa4bbf 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * WM8505/WM8650 SD/MMC Host Controller * * Copyright (C) 2010 Tony Prisk * Copyright (C) 2008 WonderMedia Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation */ #include <linux/init.h> diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index fc424b185b08..6012a10f10c8 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * BCM47XX MTD partitioning * * Copyright © 2012 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/bcm47xx_nvram.h> diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index 815e2db87955..b41401852fb7 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Handle mapping of the NOR flash on implementa A7 boards * * Copyright 2002 SYSGO Real-Time Solutions GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index 77b1d8013295..67a1dbfdd72c 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -1,7 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. * * Copyright (C) 2004 Liu Peng Infineon IFAP DC COM CPE * Copyright (C) 2010 John Crispin <john@phrozen.org> diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index 7b3bb40aff72..9a49f8a06fb8 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mtd/maps/pci.c * * Copyright (C) 2001 Russell King, All rights reserved. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Generic PCI memory map driver. We support the following boards: * - Intel IQ80310 ATU. * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001 diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index 2cde28ed95c9..cebb346877a9 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Map driver for Intel XScale PXA2xx platforms. * * Author: Nicolas Pitre * Copyright: (C) 2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/mtd/maps/rbtx4939-flash.c b/drivers/mtd/maps/rbtx4939-flash.c index 80a187167c92..39c86c0b0ec1 100644 --- a/drivers/mtd/maps/rbtx4939-flash.c +++ b/drivers/mtd/maps/rbtx4939-flash.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rbtx4939-flash (based on physmap.c) * * This is a simplified physmap driver with map_init callback function. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Copyright (C) 2009 Atsushi Nemoto <anemo@mba.ocn.ne.jp> */ diff --git a/drivers/mtd/maps/vmu-flash.c b/drivers/mtd/maps/vmu-flash.c index c5d4b6589488..177bf134e189 100644 --- a/drivers/mtd/maps/vmu-flash.c +++ b/drivers/mtd/maps/vmu-flash.c @@ -1,11 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* vmu-flash.c * Driver for SEGA Dreamcast Visual Memory Unit * * Copyright (c) Adrian McMenamin 2002 - 2009 * Copyright (c) Paul Mundt 2001 - * - * Licensed under version 2 of the - * GNU General Public Licence */ #include <linux/init.h> #include <linux/slab.h> diff --git a/drivers/mtd/nand/onenand/generic.c b/drivers/mtd/nand/onenand/generic.c index acad17ec6581..8b6f4da5d720 100644 --- a/drivers/mtd/nand/onenand/generic.c +++ b/drivers/mtd/nand/onenand/generic.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005 Samsung Electronics * Kyungmin Park <kyungmin.park@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Overview: * This is a device driver for the OneNAND flash for generic boards. */ diff --git a/drivers/mtd/nand/onenand/onenand_base.c b/drivers/mtd/nand/onenand/onenand_base.c index f41d76248550..d759c02d9cb2 100644 --- a/drivers/mtd/nand/onenand/onenand_base.c +++ b/drivers/mtd/nand/onenand/onenand_base.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2005-2009 Samsung Electronics * Copyright © 2007 Nokia Corporation @@ -12,10 +13,6 @@ * Flex-OneNAND support * Amul Kumar Saha <amul.saha at samsung.com> * OTP support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/mtd/nand/onenand/samsung.c b/drivers/mtd/nand/onenand/samsung.c index e64d0fdf7eb5..55e5536a5850 100644 --- a/drivers/mtd/nand/onenand/samsung.c +++ b/drivers/mtd/nand/onenand/samsung.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung S3C64XX/S5PC1XX OneNAND driver * @@ -5,10 +6,6 @@ * Kyungmin Park <kyungmin.park@samsung.com> * Marek Szyprowski <m.szyprowski@samsung.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Implementation: * S3C64XX: emulate the pseudo BufferRAM * S5PC110: use DMA diff --git a/drivers/mtd/nand/onenand/samsung.h b/drivers/mtd/nand/onenand/samsung.h index 9016dc0136a8..892bbb6ca4fe 100644 --- a/drivers/mtd/nand/onenand/samsung.h +++ b/drivers/mtd/nand/onenand/samsung.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2008-2010 Samsung Electronics * Kyungmin Park <kyungmin.park@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __SAMSUNG_ONENAND_H__ #define __SAMSUNG_ONENAND_H__ diff --git a/drivers/mtd/nand/raw/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c index a963002663ed..97a97a9ccc36 100644 --- a/drivers/mtd/nand/raw/au1550nd.c +++ b/drivers/mtd/nand/raw/au1550nd.c @@ -1,10 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2004 Embedded Edge, LLC - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/slab.h> diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/main.c b/drivers/mtd/nand/raw/bcm47xxnflash/main.c index d79694160845..8dae97c1dbe7 100644 --- a/drivers/mtd/nand/raw/bcm47xxnflash/main.c +++ b/drivers/mtd/nand/raw/bcm47xxnflash/main.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * BCM47XX NAND flash driver * * Copyright (C) 2012 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include "bcm47xxnflash.h" diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c index a53ffb3d64b0..591775173034 100644 --- a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * BCM47XX NAND flash driver * * Copyright (C) 2012 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include "bcm47xxnflash.h" diff --git a/drivers/mtd/nand/raw/cmx270_nand.c b/drivers/mtd/nand/raw/cmx270_nand.c index 143e4acacaae..045b6175ae79 100644 --- a/drivers/mtd/nand/raw/cmx270_nand.c +++ b/drivers/mtd/nand/raw/cmx270_nand.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2006 Compulab, Ltd. * Mike Rapoport <mike@compulab.co.il> @@ -6,11 +7,6 @@ * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Overview: * This is a device driver for the NAND flash device found on the * CM-X270 board. diff --git a/drivers/mtd/nand/raw/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c index c6f578aff5d9..e2322cee3229 100644 --- a/drivers/mtd/nand/raw/cs553x_nand.c +++ b/drivers/mtd/nand/raw/cs553x_nand.c @@ -1,19 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * (C) 2005, 2006 Red Hat Inc. * * Author: David Woodhouse <dwmw2@infradead.org> * Tom Sylla <tom.sylla@amd.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Overview: * This is a device driver for the NAND flash controller found on * the AMD CS5535/CS5536 companion chipsets for the Geode processor. * mtd-id for command line partitioning is cs553x_nand_cs[0-3] * where 0-3 reflects the chip select for NAND. - * */ #include <linux/kernel.h> diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c index a6c9a824a7d4..f6b12354024f 100644 --- a/drivers/mtd/nand/raw/gpio.c +++ b/drivers/mtd/nand/raw/gpio.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Updated, and converted to generic GPIO based driver by Russell King. * @@ -9,11 +10,6 @@ * Device driver for NAND flash that uses a memory mapped interface to * read/write the NAND commands and data, and GPIO pins for control signals * (the DT binding refers to this as "GPIO assisted NAND flash") - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/mtd/nand/raw/ingenic/Kconfig b/drivers/mtd/nand/raw/ingenic/Kconfig index 19a96ce515c1..66b7cffdb0c2 100644 --- a/drivers/mtd/nand/raw/ingenic/Kconfig +++ b/drivers/mtd/nand/raw/ingenic/Kconfig @@ -16,7 +16,7 @@ config MTD_NAND_JZ4780 if MTD_NAND_JZ4780 config MTD_NAND_INGENIC_ECC - tristate + bool config MTD_NAND_JZ4740_ECC tristate "Hardware BCH support for JZ4740 SoC" diff --git a/drivers/mtd/nand/raw/ingenic/Makefile b/drivers/mtd/nand/raw/ingenic/Makefile index 1ac4f455baea..b63d36889263 100644 --- a/drivers/mtd/nand/raw/ingenic/Makefile +++ b/drivers/mtd/nand/raw/ingenic/Makefile @@ -2,7 +2,9 @@ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o obj-$(CONFIG_MTD_NAND_JZ4780) += ingenic_nand.o -obj-$(CONFIG_MTD_NAND_INGENIC_ECC) += ingenic_ecc.o +ingenic_nand-y += ingenic_nand_drv.o +ingenic_nand-$(CONFIG_MTD_NAND_INGENIC_ECC) += ingenic_ecc.o + obj-$(CONFIG_MTD_NAND_JZ4740_ECC) += jz4740_ecc.o obj-$(CONFIG_MTD_NAND_JZ4725B_BCH) += jz4725b_bch.o obj-$(CONFIG_MTD_NAND_JZ4780_BCH) += jz4780_bch.o diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c index d3e085c5685a..c954189606f6 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c @@ -30,7 +30,6 @@ int ingenic_ecc_calculate(struct ingenic_ecc *ecc, { return ecc->ops->calculate(ecc, params, buf, ecc_code); } -EXPORT_SYMBOL(ingenic_ecc_calculate); /** * ingenic_ecc_correct() - detect and correct bit errors @@ -51,7 +50,6 @@ int ingenic_ecc_correct(struct ingenic_ecc *ecc, { return ecc->ops->correct(ecc, params, buf, ecc_code); } -EXPORT_SYMBOL(ingenic_ecc_correct); /** * ingenic_ecc_get() - get the ECC controller device @@ -111,7 +109,6 @@ struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *of_node) } return ecc; } -EXPORT_SYMBOL(of_ingenic_ecc_get); /** * ingenic_ecc_release() - release the ECC controller device @@ -122,7 +119,6 @@ void ingenic_ecc_release(struct ingenic_ecc *ecc) clk_disable_unprepare(ecc->clk); put_device(ecc->dev); } -EXPORT_SYMBOL(ingenic_ecc_release); int ingenic_ecc_probe(struct platform_device *pdev) { @@ -159,8 +155,3 @@ int ingenic_ecc_probe(struct platform_device *pdev) return 0; } EXPORT_SYMBOL(ingenic_ecc_probe); - -MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>"); -MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>"); -MODULE_DESCRIPTION("Ingenic ECC common driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c index d7b7c0f13909..d7b7c0f13909 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c diff --git a/drivers/mtd/nand/raw/mtk_ecc.h b/drivers/mtd/nand/raw/mtk_ecc.h index a455df080952..aa52e94c771d 100644 --- a/drivers/mtd/nand/raw/mtk_ecc.h +++ b/drivers/mtd/nand/raw/mtk_ecc.h @@ -1,12 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * MTK SDG1 ECC controller * * Copyright (c) 2016 Mediatek * Authors: Xiaolei Li <xiaolei.li@mediatek.com> * Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org> - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__ diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 2cf71060d6f8..6eb131292eb2 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Overview: * This is the generic MTD driver for NAND flash devices. It should be @@ -20,11 +21,6 @@ * Check, if mtd->ecctype should be set to MTD_ECC_HW * if we have HW ECC support. * BBT table is not serialized, has to be fixed - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -4666,7 +4662,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) memorg = nanddev_get_memorg(&chip->base); memorg->planes_per_lun = 1; memorg->luns_per_target = 1; - memorg->ntargets = 1; /* * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) @@ -5031,6 +5026,8 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, if (ret) return ret; + memorg->ntargets = maxchips; + /* Read the flash type */ ret = nand_detect(chip, table); if (ret) { diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c index fd3c10216eda..2ef15ef94525 100644 --- a/drivers/mtd/nand/raw/nand_bbt.c +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Overview: * Bad block table support for the NAND driver * * Copyright © 2004 Thomas Gleixner (tglx@linutronix.de) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Description: * * When nand_scan_bbt is called, then it tries to find the bad block table @@ -54,7 +51,6 @@ * Following assumptions are made: * - bbts start at a page boundary, if autolocated on a block boundary * - the space necessary for a bbt in FLASH does not exceed a block boundary - * */ #include <linux/slab.h> diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c index ea5a342cd91e..ba27902fc54b 100644 --- a/drivers/mtd/nand/raw/nand_ids.c +++ b/drivers/mtd/nand/raw/nand_ids.c @@ -1,10 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/sizes.h> diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c index bea3062d71d6..f64b06a71dfa 100644 --- a/drivers/mtd/nand/raw/nand_timings.c +++ b/drivers/mtd/nand/raw/nand_timings.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Free Electrons * * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> #include <linux/err.h> diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index a9a275342a41..8d881a28140e 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2004 Texas Instruments, Jian Zhang <jzhang@ti.com> * Copyright © 2004 Micron Technology Inc. * Copyright © 2004 David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/platform_device.h> diff --git a/drivers/mtd/nand/raw/oxnas_nand.c b/drivers/mtd/nand/raw/oxnas_nand.c index 0e52dc29141c..30c51f772de6 100644 --- a/drivers/mtd/nand/raw/oxnas_nand.c +++ b/drivers/mtd/nand/raw/oxnas_nand.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Oxford Semiconductor OXNAS NAND driver @@ -6,11 +7,6 @@ * Author: Vitaly Wool <vitalywool@gmail.com> * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com> * Copyright (C) 2012 John Crispin <blogic@openwrt.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/err.h> diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c index a994b76daa50..dc0f3074ddbf 100644 --- a/drivers/mtd/nand/raw/plat_nand.c +++ b/drivers/mtd/nand/raw/plat_nand.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic NAND driver * * Author: Vitaly Wool <vitalywool@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/err.h> diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c index 7b99831aa046..dae0d235bb17 100644 --- a/drivers/mtd/nand/raw/r852.c +++ b/drivers/mtd/nand/raw/r852.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2009 - Maxim Levitsky * driver for Ricoh xD readers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define DRV_NAME "r852" diff --git a/drivers/mtd/nand/raw/r852.h b/drivers/mtd/nand/raw/r852.h index bc67f5bf67e8..e9ce299c499d 100644 --- a/drivers/mtd/nand/raw/r852.h +++ b/drivers/mtd/nand/raw/r852.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright © 2009 - Maxim Levitsky * driver for Ricoh xD readers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/pci.h> diff --git a/drivers/mtd/nand/raw/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c index c82f26c8b58c..b47a9eaff89b 100644 --- a/drivers/mtd/nand/raw/sharpsl.c +++ b/drivers/mtd/nand/raw/sharpsl.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2004 Richard Purdie * Copyright (C) 2008 Dmitry Baryshkov * * Based on Sharp's NAND driver sharp_sl.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/genhd.h> diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c index 409d036858dc..ba24cb36d0b9 100644 --- a/drivers/mtd/nand/raw/sm_common.c +++ b/drivers/mtd/nand/raw/sm_common.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2009 - Maxim Levitsky * Common routines & support for xD format - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/mtd/rawnand.h> diff --git a/drivers/mtd/nand/raw/sm_common.h b/drivers/mtd/nand/raw/sm_common.h index 1581671b05ae..57fc9f86f9ee 100644 --- a/drivers/mtd/nand/raw/sm_common.h +++ b/drivers/mtd/nand/raw/sm_common.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright © 2009 - Maxim Levitsky * Common routines & support for SmartMedia/xD format - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> #include <linux/mtd/mtd.h> diff --git a/drivers/mtd/nand/raw/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c index 8be9a50c7880..20f40c0e812c 100644 --- a/drivers/mtd/nand/raw/socrates_nand.c +++ b/drivers/mtd/nand/raw/socrates_nand.c @@ -1,11 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2008 Ilya Yanok, Emcraft Systems - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/slab.h> diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index b021a5720b42..89773293c64d 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -51,6 +51,7 @@ #define NFC_REG_USER_DATA(x) (0x0050 + ((x) * 4)) #define NFC_REG_SPARE_AREA 0x00A0 #define NFC_REG_PAT_ID 0x00A4 +#define NFC_REG_MDMA_CNT 0x00C4 #define NFC_RAM0_BASE 0x0400 #define NFC_RAM1_BASE 0x0800 @@ -69,6 +70,7 @@ #define NFC_PAGE_SHIFT(x) (((x) < 10 ? 0 : (x) - 10) << 8) #define NFC_SAM BIT(12) #define NFC_RAM_METHOD BIT(14) +#define NFC_DMA_TYPE_NORMAL BIT(15) #define NFC_DEBUG_CTL BIT(31) /* define bit use in NFC_ST */ @@ -205,14 +207,13 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand) * NAND Controller capabilities structure: stores NAND controller capabilities * for distinction between compatible strings. * - * @sram_through_ahb: On A23, we choose to access the internal RAM through AHB - * instead of MBUS (less configuration). A10, A10s, A13 and - * A20 use the MBUS but no extra configuration is needed. + * @extra_mbus_conf: Contrary to A10, A10s and A13, accessing internal RAM + * through MBUS on A23/A33 needs extra configuration. * @reg_io_data: I/O data register * @dma_maxburst: DMA maxburst */ struct sunxi_nfc_caps { - bool sram_through_ahb; + bool extra_mbus_conf; unsigned int reg_io_data; unsigned int dma_maxburst; }; @@ -368,28 +369,12 @@ static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf, goto err_unmap_buf; } - /* - * On A23, we suppose the "internal RAM" (p.12 of the NFC user manual) - * refers to the NAND controller's internal SRAM. This memory is mapped - * and so is accessible from the AHB. It seems that it can also be - * accessed by the MBUS. MBUS accesses are mandatory when using the - * internal DMA instead of the external DMA engine. - * - * During DMA I/O operation, either we access this memory from the AHB - * by clearing the NFC_RAM_METHOD bit, or we set the bit and use the - * MBUS. In this case, we should also configure the MBUS DMA length - * NFC_REG_MDMA_CNT(0xC4) to be chunksize * nchunks. NAND I/O over MBUS - * are also limited to 32kiB pages. - */ - if (nfc->caps->sram_through_ahb) - writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD, - nfc->regs + NFC_REG_CTL); - else - writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD, - nfc->regs + NFC_REG_CTL); - + writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD, + nfc->regs + NFC_REG_CTL); writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM); writel(chunksize, nfc->regs + NFC_REG_CNT); + if (nfc->caps->extra_mbus_conf) + writel(chunksize * nchunks, nfc->regs + NFC_REG_MDMA_CNT); dmat = dmaengine_submit(dmad); @@ -2151,6 +2136,11 @@ static int sunxi_nfc_probe(struct platform_device *pdev) dmac_cfg.src_maxburst = nfc->caps->dma_maxburst; dmac_cfg.dst_maxburst = nfc->caps->dma_maxburst; dmaengine_slave_config(nfc->dmac, &dmac_cfg); + + if (nfc->caps->extra_mbus_conf) + writel(readl(nfc->regs + NFC_REG_CTL) | + NFC_DMA_TYPE_NORMAL, nfc->regs + NFC_REG_CTL); + } else { dev_warn(dev, "failed to request rxtx DMA channel\n"); } @@ -2200,7 +2190,7 @@ static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = { }; static const struct sunxi_nfc_caps sunxi_nfc_a23_caps = { - .sram_through_ahb = true, + .extra_mbus_conf = true, .reg_io_data = NFC_REG_A23_IO_DATA, .dma_maxburst = 8, }; diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c index cb3beda88789..b3f2cabcc7c0 100644 --- a/drivers/mtd/nand/raw/tango_nand.c +++ b/drivers/mtd/nand/raw/tango_nand.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Sigma Designs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #include <linux/io.h> diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c index 97978227aa55..2642d5bb3241 100644 --- a/drivers/mtd/nand/raw/txx9ndfmc.c +++ b/drivers/mtd/nand/raw/txx9ndfmc.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TXx9 NAND flash memory controller driver * Based on RBTX49xx patch from CELF patch archive. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * (C) Copyright TOSHIBA CORPORATION 2004-2007 * All Rights Reserved. */ diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c index 4cb78106af14..834f794816a9 100644 --- a/drivers/mtd/nand/raw/xway_nand.c +++ b/drivers/mtd/nand/raw/xway_nand.c @@ -1,7 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. * * Copyright © 2012 John Crispin <john@phrozen.org> * Copyright © 2016 Hauke Mehrtens <hauke@hauke-m.de> diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c index e5586390026a..e6c646007cda 100644 --- a/drivers/mtd/nand/spi/gigadevice.c +++ b/drivers/mtd/nand/spi/gigadevice.c @@ -180,7 +180,7 @@ static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, gd5fxgq4xa_ecc_get_status)), SPINAND_INFO("GD5F4GQ4xA", 0xF4, - NAND_MEMORG(1, 2048, 64, 64, 4096, 40, 1, 1, 1), + NAND_MEMORG(1, 2048, 64, 64, 4096, 80, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c index 6502727049a8..21def3f8fb36 100644 --- a/drivers/mtd/nand/spi/macronix.c +++ b/drivers/mtd/nand/spi/macronix.c @@ -100,7 +100,7 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand, static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO("MX35LF1GE4AB", 0x12, - NAND_MEMORG(1, 2048, 64, 64, 1024, 40, 1, 1, 1), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(4, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, @@ -109,7 +109,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35LF2GE4AB", 0x22, - NAND_MEMORG(1, 2048, 64, 64, 2048, 20, 2, 1, 1), + NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1), NAND_ECCREQ(4, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, diff --git a/drivers/mtd/parsers/parser_trx.c b/drivers/mtd/parsers/parser_trx.c index 4a89a68622fe..8541182134d4 100644 --- a/drivers/mtd/parsers/parser_trx.c +++ b/drivers/mtd/parsers/parser_trx.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Parser for TRX format partitions * * Copyright (C) 2012 - 2017 RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index e0955a98a0f4..dfc47a444b90 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2009 - Maxim Levitsky * SmartMedia/xD translation layer - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/mtd/sm_ftl.h b/drivers/mtd/sm_ftl.h index 0a46d75cdc6a..6aed8b60de16 100644 --- a/drivers/mtd/sm_ftl.h +++ b/drivers/mtd/sm_ftl.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright © 2009 - Maxim Levitsky * SmartMedia/xD translation layer @@ -5,10 +6,6 @@ * Based loosly on ssfdc.c which is * © 2005 Eptar srl * Author: Claudio Lanconelli <lanconelli.claudio@eptar.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/mtd/blktrans.h> diff --git a/drivers/mtd/spi-nor/intel-spi-pci.c b/drivers/mtd/spi-nor/intel-spi-pci.c index bfbfc17ed6aa..5e2344768d53 100644 --- a/drivers/mtd/spi-nor/intel-spi-pci.c +++ b/drivers/mtd/spi-nor/intel-spi-pci.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Intel PCH/PCU SPI flash PCI driver. * * Copyright (C) 2016, Intel Corporation * Author: Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/ioport.h> diff --git a/drivers/mtd/spi-nor/intel-spi-platform.c b/drivers/mtd/spi-nor/intel-spi-platform.c index 5c943df9398f..f80f1086f928 100644 --- a/drivers/mtd/spi-nor/intel-spi-platform.c +++ b/drivers/mtd/spi-nor/intel-spi-platform.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Intel PCH/PCU SPI flash platform driver. * * Copyright (C) 2016, Intel Corporation * Author: Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/ioport.h> diff --git a/drivers/mtd/spi-nor/intel-spi.c b/drivers/mtd/spi-nor/intel-spi.c index d60cbf23d9aa..1ccf23fe7e4b 100644 --- a/drivers/mtd/spi-nor/intel-spi.c +++ b/drivers/mtd/spi-nor/intel-spi.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Intel PCH/PCU SPI flash driver. * * Copyright (C) 2016, Intel Corporation * Author: Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/mtd/spi-nor/intel-spi.h b/drivers/mtd/spi-nor/intel-spi.h index 5ab7dc250050..e2f41b8827bf 100644 --- a/drivers/mtd/spi-nor/intel-spi.h +++ b/drivers/mtd/spi-nor/intel-spi.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Intel PCH/PCU SPI flash driver. * * Copyright (C) 2016, Intel Corporation * Author: Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef INTEL_SPI_H diff --git a/drivers/mtd/spi-nor/nxp-spifi.c b/drivers/mtd/spi-nor/nxp-spifi.c index 0c9094ec5966..4a871587392b 100644 --- a/drivers/mtd/spi-nor/nxp-spifi.c +++ b/drivers/mtd/spi-nor/nxp-spifi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPI-NOR driver for NXP SPI Flash Interface (SPIFI) * @@ -5,11 +6,6 @@ * * Based on Freescale QuadSPI driver: * Copyright (C) 2013 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/clk.h> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 73172d7f512b..0c2ec1c21434 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1636,6 +1636,95 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor) return 0; } +/** + * spi_nor_clear_sr_bp() - clear the Status Register Block Protection bits. + * @nor: pointer to a 'struct spi_nor' + * + * Read-modify-write function that clears the Block Protection bits from the + * Status Register without affecting other bits. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_clear_sr_bp(struct spi_nor *nor) +{ + int ret; + u8 mask = SR_BP2 | SR_BP1 | SR_BP0; + + ret = read_sr(nor); + if (ret < 0) { + dev_err(nor->dev, "error while reading status register\n"); + return ret; + } + + write_enable(nor); + + ret = write_sr(nor, ret & ~mask); + if (ret) { + dev_err(nor->dev, "write to status register failed\n"); + return ret; + } + + ret = spi_nor_wait_till_ready(nor); + if (ret) + dev_err(nor->dev, "timeout while writing status register\n"); + return ret; +} + +/** + * spi_nor_spansion_clear_sr_bp() - clear the Status Register Block Protection + * bits on spansion flashes. + * @nor: pointer to a 'struct spi_nor' + * + * Read-modify-write function that clears the Block Protection bits from the + * Status Register without affecting other bits. The function is tightly + * coupled with the spansion_quad_enable() function. Both assume that the Write + * Register with 16 bits, together with the Read Configuration Register (35h) + * instructions are supported. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor) +{ + int ret; + u8 mask = SR_BP2 | SR_BP1 | SR_BP0; + u8 sr_cr[2] = {0}; + + /* Check current Quad Enable bit value. */ + ret = read_cr(nor); + if (ret < 0) { + dev_err(nor->dev, + "error while reading configuration register\n"); + return ret; + } + + /* + * When the configuration register Quad Enable bit is one, only the + * Write Status (01h) command with two data bytes may be used. + */ + if (ret & CR_QUAD_EN_SPAN) { + sr_cr[1] = ret; + + ret = read_sr(nor); + if (ret < 0) { + dev_err(nor->dev, + "error while reading status register\n"); + return ret; + } + sr_cr[0] = ret & ~mask; + + ret = write_sr_cr(nor, sr_cr); + if (ret) + dev_err(nor->dev, "16-bit write register failed\n"); + return ret; + } + + /* + * If the Quad Enable bit is zero, use the Write Status (01h) command + * with one data byte. + */ + return spi_nor_clear_sr_bp(nor); +} + /* Used when the "_ext_id" is two bytes at most */ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ .id = { \ @@ -3660,6 +3749,8 @@ static int spi_nor_init_params(struct spi_nor *nor, default: /* Kept only for backward compatibility purpose. */ params->quad_enable = spansion_quad_enable; + if (nor->clear_sr_bp) + nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp; break; } @@ -3912,17 +4003,13 @@ static int spi_nor_init(struct spi_nor *nor) { int err; - /* - * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up - * with the software protection bits set - */ - if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL || - JEDEC_MFR(nor->info) == SNOR_MFR_INTEL || - JEDEC_MFR(nor->info) == SNOR_MFR_SST || - nor->info->flags & SPI_NOR_HAS_LOCK) { - write_enable(nor); - write_sr(nor, 0); - spi_nor_wait_till_ready(nor); + if (nor->clear_sr_bp) { + err = nor->clear_sr_bp(nor); + if (err) { + dev_err(nor->dev, + "fail to clear block protection bits\n"); + return err; + } } if (nor->quad_enable) { @@ -4047,6 +4134,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (info->flags & SPI_S3AN) nor->flags |= SNOR_F_READY_XSR_RDY; + /* + * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up + * with the software protection bits set. + */ + if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL || + JEDEC_MFR(nor->info) == SNOR_MFR_INTEL || + JEDEC_MFR(nor->info) == SNOR_MFR_SST || + nor->info->flags & SPI_NOR_HAS_LOCK) + nor->clear_sr_bp = spi_nor_clear_sr_bp; + /* Parse the Serial Flash Discoverable Parameters table. */ ret = spi_nor_init_params(nor, ¶ms); if (ret) diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c index 13e9fc961d3b..33534f9e296b 100644 --- a/drivers/mtd/spi-nor/stm32-quadspi.c +++ b/drivers/mtd/spi-nor/stm32-quadspi.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for stm32 quadspi controller * * Copyright (C) 2017, STMicroelectronics - All Rights Reserved * Author(s): Ludovic Barre author <ludovic.barre@st.com>. - * - * License terms: GPL V2.0. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * This program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/clk.h> #include <linux/errno.h> diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index 7a1e54546f4a..1d05c121904c 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Linux driver for SSFDC Flash Translation Layer (Read only) * © 2005 Eptar srl * Author: Claudio Lanconelli <lanconelli.claudio@eptar.com> * * Based on NTFL and MTDBLOCK_RO drivers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 407f4095a37a..799fc38c5c34 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4320,12 +4320,12 @@ void bond_setup(struct net_device *bond_dev) bond_dev->features |= NETIF_F_NETNS_LOCAL; bond_dev->hw_features = BOND_VLAN_FEATURES | - NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER; bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4; bond_dev->features |= bond_dev->hw_features; + bond_dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; } /* Destroy a bonding device. diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c index da636a22c542..7cdc232cbfea 100644 --- a/drivers/net/can/cc770/cc770.c +++ b/drivers/net/can/cc770/cc770.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Core driver for the CC770 and AN82527 CAN controllers * * Copyright (C) 2009, 2011 Wolfgang Grandegger <wg@grandegger.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the version 2 of the GNU General Public License - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/net/can/cc770/cc770.h b/drivers/net/can/cc770/cc770.h index 95752e1d1283..948541491ab5 100644 --- a/drivers/net/can/cc770/cc770.h +++ b/drivers/net/can/cc770/cc770.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Core driver for the CC770 and AN82527 CAN controllers * * Copyright (C) 2009, 2011 Wolfgang Grandegger <wg@grandegger.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the version 2 of the GNU General Public License - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef CC770_DEV_H diff --git a/drivers/net/can/cc770/cc770_isa.c b/drivers/net/can/cc770/cc770_isa.c index fcd34698074f..b9047d8110d5 100644 --- a/drivers/net/can/cc770/cc770_isa.c +++ b/drivers/net/can/cc770/cc770_isa.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for CC770 and AN82527 CAN controllers on the legacy ISA bus * * Copyright (C) 2009, 2011 Wolfgang Grandegger <wg@grandegger.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the version 2 of the GNU General Public License - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ /* diff --git a/drivers/net/can/cc770/cc770_platform.c b/drivers/net/can/cc770/cc770_platform.c index 866e5e12fdd2..8d916e2ee6c2 100644 --- a/drivers/net/can/cc770/cc770_platform.c +++ b/drivers/net/can/cc770/cc770_platform.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for CC770 and AN82527 CAN controllers on the platform bus * * Copyright (C) 2009, 2011 Wolfgang Grandegger <wg@grandegger.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the version 2 of the GNU General Public License - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ /* diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 1c66fb2ad76b..f2fe344593d5 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -166,7 +166,7 @@ #define FLEXCAN_MB_CNT_LENGTH(x) (((x) & 0xf) << 16) #define FLEXCAN_MB_CNT_TIMESTAMP(x) ((x) & 0xffff) -#define FLEXCAN_TIMEOUT_US (50) +#define FLEXCAN_TIMEOUT_US (250) /* FLEXCAN hardware feature flags * @@ -1583,9 +1583,6 @@ static int flexcan_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "failed to setup stop-mode\n"); } - dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n", - priv->regs, dev->irq); - return 0; failed_register: diff --git a/drivers/net/can/led.c b/drivers/net/can/led.c index c1b667675fa1..db14897f8e16 100644 --- a/drivers/net/can/led.c +++ b/drivers/net/can/led.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com> * Copyright 2012, Kurt Van Dijck <kurt.van.dijck@eia.be> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 9b449400376b..deb274a19ba0 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -822,6 +822,27 @@ static int m_can_poll(struct napi_struct *napi, int quota) if (!irqstatus) goto end; + /* Errata workaround for issue "Needless activation of MRAF irq" + * During frame reception while the MCAN is in Error Passive state + * and the Receive Error Counter has the value MCAN_ECR.REC = 127, + * it may happen that MCAN_IR.MRAF is set although there was no + * Message RAM access failure. + * If MCAN_IR.MRAF is enabled, an interrupt to the Host CPU is generated + * The Message RAM Access Failure interrupt routine needs to check + * whether MCAN_ECR.RP = ’1’ and MCAN_ECR.REC = 127. + * In this case, reset MCAN_IR.MRAF. No further action is required. + */ + if ((priv->version <= 31) && (irqstatus & IR_MRAF) && + (m_can_read(priv, M_CAN_ECR) & ECR_RP)) { + struct can_berr_counter bec; + + __m_can_get_berr_counter(dev, &bec); + if (bec.rxerr == 127) { + m_can_write(priv, M_CAN_IR, IR_MRAF); + irqstatus &= ~IR_MRAF; + } + } + psr = m_can_read(priv, M_CAN_PSR); if (irqstatus & IR_ERR_STATE) work_done += m_can_handle_state_errors(dev, psr); diff --git a/drivers/net/can/peak_canfd/peak_canfd.c b/drivers/net/can/peak_canfd/peak_canfd.c index 5696d7e80751..6b0c6a99fc8d 100644 --- a/drivers/net/can/peak_canfd/peak_canfd.c +++ b/drivers/net/can/peak_canfd/peak_canfd.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com> * Copyright (C) 2012 Stephane Grosjean <s.grosjean@peak-system.com> * * Copyright (C) 2016 PEAK System-Technik GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the version 2 of the GNU General Public License - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/can.h> diff --git a/drivers/net/can/peak_canfd/peak_pciefd_main.c b/drivers/net/can/peak_canfd/peak_pciefd_main.c index c458d5fdc8d3..7f6a3b971da9 100644 --- a/drivers/net/can/peak_canfd/peak_pciefd_main.c +++ b/drivers/net/can/peak_canfd/peak_pciefd_main.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com> * Copyright (C) 2012 Stephane Grosjean <s.grosjean@peak-system.com> @@ -5,15 +6,6 @@ * Derived from the PCAN project file driver/src/pcan_pci.c: * * Copyright (C) 2001-2006 PEAK System-Technik GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the version 2 of the GNU General Public License - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/kernel.h> diff --git a/drivers/net/can/sja1000/ems_pcmcia.c b/drivers/net/can/sja1000/ems_pcmcia.c index 381de998d2f1..770304eaef95 100644 --- a/drivers/net/can/sja1000/ems_pcmcia.c +++ b/drivers/net/can/sja1000/ems_pcmcia.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2008 Sebastian Haas (initial chardev implementation) * Copyright (C) 2010 Markus Plessing <plessing@ems-wuensche.com> * Rework for mainline by Oliver Hartkopp <socketcan@hartkopp.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the version 2 of the GNU General Public License - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/kernel.h> diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c index a97b81d1d0da..68366d57916c 100644 --- a/drivers/net/can/sja1000/peak_pci.c +++ b/drivers/net/can/sja1000/peak_pci.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com> * Copyright (C) 2012 Stephane Grosjean <s.grosjean@peak-system.com> @@ -5,15 +6,6 @@ * Derived from the PCAN project file driver/src/pcan_pci.c: * * Copyright (C) 2001-2006 PEAK System-Technik GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the version 2 of the GNU General Public License - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/kernel.h> diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c index b8c39ede7cd5..185c7f7d38a4 100644 --- a/drivers/net/can/sja1000/peak_pcmcia.c +++ b/drivers/net/can/sja1000/peak_pcmcia.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com> * * CAN driver for PEAK-System PCAN-PC Card * Derived from the PCAN project file driver/src/pcan_pccard.c * Copyright (C) 2006-2010 PEAK System-Technik GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the version 2 of the GNU General Public License - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig index 2e7e535e9237..1c50788055cb 100644 --- a/drivers/net/can/spi/Kconfig +++ b/drivers/net/can/spi/Kconfig @@ -9,9 +9,10 @@ config CAN_HI311X Driver for the Holt HI311x SPI CAN controllers. config CAN_MCP251X - tristate "Microchip MCP251x SPI CAN controllers" + tristate "Microchip MCP251x and MCP25625 SPI CAN controllers" depends on HAS_DMA ---help--- - Driver for the Microchip MCP251x SPI CAN controllers. + Driver for the Microchip MCP251x and MCP25625 SPI CAN + controllers. endmenu diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c index ddaf46239e39..03a711c3221b 100644 --- a/drivers/net/can/spi/hi311x.c +++ b/drivers/net/can/spi/hi311x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* CAN bus driver for Holt HI3110 CAN Controller with SPI Interface * * Copyright(C) Timesys Corporation 2016 @@ -11,10 +12,6 @@ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix * - Simon Kallweit, intefo AG * Copyright 2007 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/can/core.h> diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index 78e29fa06fe6..44e99e3d7134 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * CAN bus driver for Microchip 251x CAN Controller with SPI Interface + * CAN bus driver for Microchip 251x/25625 CAN Controller with SPI Interface * * MCP2510 support and bug fixes by Christian Pellegrin * <chripell@evolware.org> @@ -28,7 +28,7 @@ * static struct spi_board_info spi_board_info[] = { * { * .modalias = "mcp2510", - * // or "mcp2515" depending on your controller + * // "mcp2515" or "mcp25625" depending on your controller * .platform_data = &mcp251x_info, * .irq = IRQ_EINT13, * .max_speed_hz = 2*1000*1000, @@ -224,6 +224,7 @@ static const struct can_bittiming_const mcp251x_bittiming_const = { enum mcp251x_model { CAN_MCP251X_MCP2510 = 0x2510, CAN_MCP251X_MCP2515 = 0x2515, + CAN_MCP251X_MCP25625 = 0x25625, }; struct mcp251x_priv { @@ -266,7 +267,6 @@ static inline int mcp251x_is_##_model(struct spi_device *spi) \ } MCP251X_IS(2510); -MCP251X_IS(2515); static void mcp251x_clean(struct net_device *net) { @@ -625,7 +625,7 @@ static int mcp251x_hw_reset(struct spi_device *spi) /* Wait for oscillator startup timer after reset */ mdelay(MCP251X_OST_DELAY_MS); - + reg = mcp251x_read_reg(spi, CANSTAT); if ((reg & CANCTRL_REQOP_MASK) != CANCTRL_REQOP_CONF) return -ENODEV; @@ -806,9 +806,8 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) /* receive buffer 0 */ if (intf & CANINTF_RX0IF) { mcp251x_hw_rx(spi, 0); - /* - * Free one buffer ASAP - * (The MCP2515 does this automatically.) + /* Free one buffer ASAP + * (The MCP2515/25625 does this automatically.) */ if (mcp251x_is_2510(spi)) mcp251x_write_bits(spi, CANINTF, CANINTF_RX0IF, 0x00); @@ -817,7 +816,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) /* receive buffer 1 */ if (intf & CANINTF_RX1IF) { mcp251x_hw_rx(spi, 1); - /* the MCP2515 does this automatically */ + /* The MCP2515/25625 does this automatically. */ if (mcp251x_is_2510(spi)) clear_intf |= CANINTF_RX1IF; } @@ -992,6 +991,10 @@ static const struct of_device_id mcp251x_of_match[] = { .compatible = "microchip,mcp2515", .data = (void *)CAN_MCP251X_MCP2515, }, + { + .compatible = "microchip,mcp25625", + .data = (void *)CAN_MCP251X_MCP25625, + }, { } }; MODULE_DEVICE_TABLE(of, mcp251x_of_match); @@ -1005,6 +1008,10 @@ static const struct spi_device_id mcp251x_id_table[] = { .name = "mcp2515", .driver_data = (kernel_ulong_t)CAN_MCP251X_MCP2515, }, + { + .name = "mcp25625", + .driver_data = (kernel_ulong_t)CAN_MCP251X_MCP25625, + }, { } }; MODULE_DEVICE_TABLE(spi, mcp251x_id_table); @@ -1245,5 +1252,5 @@ module_spi_driver(mcp251x_can_driver); MODULE_AUTHOR("Chris Elston <celston@katalix.com>, " "Christian Pellegrin <chripell@evolware.org>"); -MODULE_DESCRIPTION("Microchip 251x CAN driver"); +MODULE_DESCRIPTION("Microchip 251x/25625 CAN driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig index ac3522b77303..4b3d0ddcda79 100644 --- a/drivers/net/can/usb/Kconfig +++ b/drivers/net/can/usb/Kconfig @@ -102,12 +102,6 @@ config CAN_PEAK_USB (see also http://www.peak-system.com). -config CAN_MCBA_USB - tristate "Microchip CAN BUS Analyzer interface" - ---help--- - This driver supports the CAN BUS Analyzer interface - from Microchip (http://www.microchip.com/development-tools/). - config CAN_UCAN tristate "Theobroma Systems UCAN interface" ---help--- diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index f2024404b8d6..63203ff452b5 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -1435,7 +1435,7 @@ static const struct xcan_devtype_data xcan_canfd_data = { XCAN_FLAG_RXMNF | XCAN_FLAG_TX_MAILBOXES | XCAN_FLAG_RX_FIFO_MULTI, - .bittiming_const = &xcan_bittiming_const, + .bittiming_const = &xcan_bittiming_const_canfd, .btr_ts2_shift = XCAN_BTR_TS2_SHIFT_CANFD, .btr_sjw_shift = XCAN_BTR_SJW_SHIFT_CANFD, .bus_clk_name = "s_axi_aclk", diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index fefb6aaa82ba..d99dc6de0006 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -9,8 +9,8 @@ obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o -obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek.o -realtek-objs := realtek-smi.o rtl8366.o rtl8366rb.o +obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o +realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 39dace8e3512..db91b213eae1 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -83,6 +83,9 @@ static void ksz_mib_read_work(struct work_struct *work) int i; for (i = 0; i < dev->mib_port_cnt; i++) { + if (dsa_is_unused_port(dev->ds, i)) + continue; + p = &dev->ports[i]; mib = &p->mib; mutex_lock(&mib->cnt_mutex); @@ -433,9 +436,9 @@ int ksz_switch_register(struct ksz_device *dev, return PTR_ERR(dev->reset_gpio); if (dev->reset_gpio) { - gpiod_set_value(dev->reset_gpio, 1); + gpiod_set_value_cansleep(dev->reset_gpio, 1); mdelay(10); - gpiod_set_value(dev->reset_gpio, 0); + gpiod_set_value_cansleep(dev->reset_gpio, 0); } mutex_init(&dev->dev_mutex); @@ -484,7 +487,7 @@ void ksz_switch_remove(struct ksz_device *dev) dsa_unregister_switch(dev->ds); if (dev->reset_gpio) - gpiod_set_value(dev->reset_gpio, 1); + gpiod_set_value_cansleep(dev->reset_gpio, 1); } EXPORT_SYMBOL(ksz_switch_remove); diff --git a/drivers/net/dsa/mv88e6xxx/global1_vtu.c b/drivers/net/dsa/mv88e6xxx/global1_vtu.c index 3e9be3f51196..ecef69045a42 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_vtu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_vtu.c @@ -415,7 +415,7 @@ int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, * VTU DBNum[7:4] are located in VTU Operation 11:8 */ op |= entry->fid & 0x000f; - op |= (entry->fid & 0x00f0) << 8; + op |= (entry->fid & 0x00f0) << 4; } return mv88e6xxx_g1_vtu_op(chip, op); diff --git a/drivers/net/dsa/realtek-smi.c b/drivers/net/dsa/realtek-smi-core.c index ad41ec63cc9f..dc0509c02d29 100644 --- a/drivers/net/dsa/realtek-smi.c +++ b/drivers/net/dsa/realtek-smi-core.c @@ -40,7 +40,7 @@ #include <linux/bitops.h> #include <linux/if_bridge.h> -#include "realtek-smi.h" +#include "realtek-smi-core.h" #define REALTEK_SMI_ACK_RETRY_COUNT 5 #define REALTEK_SMI_HW_STOP_DELAY 25 /* msecs */ diff --git a/drivers/net/dsa/realtek-smi.h b/drivers/net/dsa/realtek-smi-core.h index 9a63b51e1d82..9a63b51e1d82 100644 --- a/drivers/net/dsa/realtek-smi.h +++ b/drivers/net/dsa/realtek-smi-core.h diff --git a/drivers/net/dsa/rtl8366.c b/drivers/net/dsa/rtl8366.c index 6dedd43442cc..ca3d17e43ed8 100644 --- a/drivers/net/dsa/rtl8366.c +++ b/drivers/net/dsa/rtl8366.c @@ -11,7 +11,7 @@ #include <linux/if_bridge.h> #include <net/dsa.h> -#include "realtek-smi.h" +#include "realtek-smi-core.h" int rtl8366_mc_is_used(struct realtek_smi *smi, int mc_index, int *used) { @@ -307,7 +307,8 @@ int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering) struct rtl8366_vlan_4k vlan4k; int ret; - if (!smi->ops->is_vlan_valid(smi, port)) + /* Use VLAN nr port + 1 since VLAN0 is not valid */ + if (!smi->ops->is_vlan_valid(smi, port + 1)) return -EINVAL; dev_info(smi->dev, "%s filtering on port %d\n", @@ -318,12 +319,12 @@ int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering) * The hardware support filter ID (FID) 0..7, I have no clue how to * support this in the driver when the callback only says on/off. */ - ret = smi->ops->get_vlan_4k(smi, port, &vlan4k); + ret = smi->ops->get_vlan_4k(smi, port + 1, &vlan4k); if (ret) return ret; /* Just set the filter to FID 1 for now then */ - ret = rtl8366_set_vlan(smi, port, + ret = rtl8366_set_vlan(smi, port + 1, vlan4k.member, vlan4k.untag, 1); diff --git a/drivers/net/dsa/rtl8366rb.c b/drivers/net/dsa/rtl8366rb.c index 40b3974970c6..a268085ffad2 100644 --- a/drivers/net/dsa/rtl8366rb.c +++ b/drivers/net/dsa/rtl8366rb.c @@ -20,7 +20,7 @@ #include <linux/of_irq.h> #include <linux/regmap.h> -#include "realtek-smi.h" +#include "realtek-smi-core.h" #define RTL8366RB_PORT_NUM_CPU 5 #define RTL8366RB_NUM_PORTS 6 diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig index bb09319feedf..2a3e2450968e 100644 --- a/drivers/net/ethernet/8390/Kconfig +++ b/drivers/net/ethernet/8390/Kconfig @@ -50,7 +50,7 @@ config XSURF100 tristate "Amiga XSurf 100 AX88796/NE2000 clone support" depends on ZORRO select AX88796 - select ASIX_PHY + select AX88796B_PHY help This driver is for the Individual Computers X-Surf 100 Ethernet card (based on the Asix AX88796 chip). If you have such a card, diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 3dcc61821ed5..172947fc051a 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/net/ethernet/8390/ax88796.c * * Copyright 2005,2007 Simtec Electronics @@ -5,10 +6,6 @@ * * Asix AX88796 10/100 Ethernet controller support * Based on ne.c, by Donald Becker, et-al. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/net/ethernet/8390/etherh.c b/drivers/net/ethernet/8390/etherh.c index 77191a281866..bd22a534b1c0 100644 --- a/drivers/net/ethernet/8390/etherh.c +++ b/drivers/net/ethernet/8390/etherh.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/net/etherh.c * * Copyright (C) 2000-2002 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * NS8390 I-cubed EtherH and ANT EtherM specific driver * Thanks to I-Cubed for information on their cards. * EtherM conversion (C) 1999 Chris Kemp and Tim Watterton diff --git a/drivers/net/ethernet/alacritech/slicoss.c b/drivers/net/ethernet/alacritech/slicoss.c index 4f7e792e50e9..80ef3e15bd22 100644 --- a/drivers/net/ethernet/alacritech/slicoss.c +++ b/drivers/net/ethernet/alacritech/slicoss.c @@ -1,19 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Gigabit Ethernet adapters based on the Session Layer * Interface (SLIC) technology by Alacritech. The driver does not * support the hardware acceleration features provided by these cards. * * Copyright (C) 2016 Lino Sanfilippo <LinoSanfilippo@gmx.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/kernel.h> diff --git a/drivers/net/ethernet/amd/am79c961a.c b/drivers/net/ethernet/amd/am79c961a.c index 265039c57023..0842da492a64 100644 --- a/drivers/net/ethernet/amd/am79c961a.c +++ b/drivers/net/ethernet/amd/am79c961a.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/net/ethernet/amd/am79c961a.c * * by Russell King <rmk@arm.linux.org.uk> 1995-2001. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Derived from various things including skeleton.c * * This is a special driver for the am79c961A Lance chip used in the diff --git a/drivers/net/ethernet/amd/am79c961a.h b/drivers/net/ethernet/amd/am79c961a.h index fc5088c70731..73679e053ceb 100644 --- a/drivers/net/ethernet/amd/am79c961a.h +++ b/drivers/net/ethernet/amd/am79c961a.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/net/ethernet/amd/am79c961a.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _LINUX_am79c961a_H diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c index 18bc035da850..1fff462a4175 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c @@ -843,9 +843,14 @@ int aq_filters_vlans_update(struct aq_nic_s *aq_nic) return err; if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) { - if (hweight < AQ_VLAN_MAX_FILTERS) - err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, true); + if (hweight < AQ_VLAN_MAX_FILTERS && hweight > 0) { + err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, + !(aq_nic->packet_filter & IFF_PROMISC)); + aq_nic->aq_nic_cfg.is_vlan_force_promisc = false; + } else { /* otherwise left in promiscue mode */ + aq_nic->aq_nic_cfg.is_vlan_force_promisc = true; + } } return err; @@ -866,6 +871,7 @@ int aq_filters_vlan_offload_off(struct aq_nic_s *aq_nic) if (unlikely(!aq_hw_ops->hw_filter_vlan_ctrl)) return -EOPNOTSUPP; + aq_nic->aq_nic_cfg.is_vlan_force_promisc = true; err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, false); if (err) return err; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 0da5e161ec5d..41172fbebddd 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -126,6 +126,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self) cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk; cfg->features = cfg->aq_hw_caps->hw_features; + cfg->is_vlan_force_promisc = true; } static int aq_nic_update_link_status(struct aq_nic_s *self) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index eb2e3c7c36f9..0f22f5d5691b 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -35,6 +35,7 @@ struct aq_nic_cfg_s { u32 flow_control; u32 link_speed_msk; u32 wol; + bool is_vlan_force_promisc; u16 is_mc_list_enabled; u16 mc_list_count; bool is_autoneg; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 1c7593d54035..13ac2661a473 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -778,8 +778,15 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self, unsigned int packet_filter) { unsigned int i = 0U; + struct aq_nic_cfg_s *cfg = self->aq_nic_cfg; + + hw_atl_rpfl2promiscuous_mode_en_set(self, + IS_FILTER_ENABLED(IFF_PROMISC)); + + hw_atl_rpf_vlan_prom_mode_en_set(self, + IS_FILTER_ENABLED(IFF_PROMISC) || + cfg->is_vlan_force_promisc); - hw_atl_rpfl2promiscuous_mode_en_set(self, IS_FILTER_ENABLED(IFF_PROMISC)); hw_atl_rpfl2multicast_flr_en_set(self, IS_FILTER_ENABLED(IFF_ALLMULTI), 0); @@ -788,13 +795,13 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self, hw_atl_rpfl2broadcast_en_set(self, IS_FILTER_ENABLED(IFF_BROADCAST)); - self->aq_nic_cfg->is_mc_list_enabled = IS_FILTER_ENABLED(IFF_MULTICAST); + cfg->is_mc_list_enabled = IS_FILTER_ENABLED(IFF_MULTICAST); for (i = HW_ATL_B0_MAC_MIN; i < HW_ATL_B0_MAC_MAX; ++i) hw_atl_rpfl2_uc_flr_en_set(self, - (self->aq_nic_cfg->is_mc_list_enabled && - (i <= self->aq_nic_cfg->mc_list_count)) ? - 1U : 0U, i); + (cfg->is_mc_list_enabled && + (i <= cfg->mc_list_count)) ? + 1U : 0U, i); return aq_hw_err_from_flags(self); } @@ -1086,7 +1093,7 @@ static int hw_atl_b0_hw_vlan_set(struct aq_hw_s *self, static int hw_atl_b0_hw_vlan_ctrl(struct aq_hw_s *self, bool enable) { /* set promisc in case of disabing the vland filter */ - hw_atl_rpf_vlan_prom_mode_en_set(self, !!!enable); + hw_atl_rpf_vlan_prom_mode_en_set(self, !enable); return aq_hw_err_from_flags(self); } diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index 13a1d99b29c6..6f2c867785fe 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2004-2013 Synopsys, Inc. (www.synopsys.com) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Driver for the ARC EMAC 10100 (hardware revision 5) * * Contributors: diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index c623896e3ccb..cae9b77ff44b 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Broadcom BCM7xxx System Port Ethernet MAC driver * * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h index 6f3141c86436..86193931203a 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.h +++ b/drivers/net/ethernet/broadcom/bcmsysport.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Broadcom BCM7xxx System Port Ethernet MAC driver * * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __BCM_SYSPORT_H diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 0745cccd416d..51fc845de31a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -1609,7 +1609,8 @@ static int bnx2x_get_module_info(struct net_device *dev, } if (!sff8472_comp || - (diag_type & SFP_EEPROM_DIAG_ADDR_CHANGE_REQ)) { + (diag_type & SFP_EEPROM_DIAG_ADDR_CHANGE_REQ) || + !(diag_type & SFP_EEPROM_DDM_IMPLEMENTED)) { modinfo->type = ETH_MODULE_SFF_8079; modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; } else { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h index b7d251108c19..7115f5025664 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h @@ -62,6 +62,7 @@ #define SFP_EEPROM_DIAG_TYPE_ADDR 0x5c #define SFP_EEPROM_DIAG_TYPE_SIZE 1 #define SFP_EEPROM_DIAG_ADDR_CHANGE_REQ (1<<2) +#define SFP_EEPROM_DDM_IMPLEMENTED (1<<6) #define SFP_EEPROM_SFF_8472_COMP_ADDR 0x5e #define SFP_EEPROM_SFF_8472_COMP_SIZE 1 diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 374b9ff05c88..41b50e6570ea 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Broadcom GENET (Gigabit Ethernet) controller driver * * Copyright (c) 2014-2017 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "bcmgenet: " fmt diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 14b49612aa86..9ad835aee1bc 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2014-2017 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __BCMGENET_H__ diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c index 57582efa362d..ea20d94bd050 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support * * Copyright (c) 2014-2017 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) "bcmgenet_wol: " fmt diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 51880d83131a..970e478a9017 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Broadcom GENET MDIO routines * * Copyright (c) 2014-2017 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 00ee5e8e0ff0..6ff123da6a14 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Atmel MACB Ethernet Controller driver * * Copyright (C) 2004-2006 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _MACB_H #define _MACB_H diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index f825e3960540..262a28ff81fc 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Cadence MACB/GEM Ethernet Controller driver * * Copyright (C) 2004-2006 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -4183,7 +4180,7 @@ static int macb_probe(struct platform_device *pdev) if (PTR_ERR(mac) == -EPROBE_DEFER) { err = -EPROBE_DEFER; goto err_out_free_netdev; - } else if (!IS_ERR(mac)) { + } else if (!IS_ERR_OR_NULL(mac)) { ether_addr_copy(bp->dev->dev_addr, mac); } else { macb_get_hwaddr(bp); diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c index 1c50c10b5a16..d7e805749a5b 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_core.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c @@ -964,7 +964,7 @@ static void liquidio_schedule_droq_pkt_handlers(struct octeon_device *oct) if (droq->ops.poll_mode) { droq->ops.napi_fn(droq); - oct_priv->napi_mask |= (1 << oq_no); + oct_priv->napi_mask |= BIT_ULL(oq_no); } else { tasklet_schedule(&oct_priv->droq_tasklet); } diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c index 79521e27f0d1..e24979010969 100644 --- a/drivers/net/ethernet/dnet.c +++ b/drivers/net/ethernet/dnet.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Dave DNET Ethernet Controller driver * * Copyright (C) 2008 Dave S.r.l. <www.dave.eu> * Copyright (C) 2009 Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/io.h> #include <linux/module.h> diff --git a/drivers/net/ethernet/dnet.h b/drivers/net/ethernet/dnet.h index d985080bbd5d..8af6c0705ab3 100644 --- a/drivers/net/ethernet/dnet.h +++ b/drivers/net/ethernet/dnet.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Dave DNET Ethernet Controller driver * * Copyright (C) 2008 Dave S.r.l. <www.dave.eu> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _DNET_H #define _DNET_H diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index fb308b330dc1..492f8769ac12 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -891,7 +891,7 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) { struct be_adapter *adapter = netdev_priv(netdev); - int status; + int status, cnt; u8 link_status = 0; if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) { @@ -902,6 +902,9 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test, memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM); + /* check link status before offline tests */ + link_status = netif_carrier_ok(netdev); + if (test->flags & ETH_TEST_FL_OFFLINE) { if (be_loopback_test(adapter, BE_MAC_LOOPBACK, &data[0]) != 0) test->flags |= ETH_TEST_FL_FAILED; @@ -922,13 +925,26 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test, test->flags |= ETH_TEST_FL_FAILED; } - status = be_cmd_link_status_query(adapter, NULL, &link_status, 0); - if (status) { - test->flags |= ETH_TEST_FL_FAILED; - data[4] = -1; - } else if (!link_status) { + /* link status was down prior to test */ + if (!link_status) { test->flags |= ETH_TEST_FL_FAILED; data[4] = 1; + return; + } + + for (cnt = 10; cnt; cnt--) { + status = be_cmd_link_status_query(adapter, NULL, &link_status, + 0); + if (status) { + test->flags |= ETH_TEST_FL_FAILED; + data[4] = -1; + break; + } + + if (link_status) + break; + + msleep_interruptible(500); } } @@ -1101,7 +1117,7 @@ static int be_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, cmd->data = be_get_rss_hash_opts(adapter, cmd->flow_type); break; case ETHTOOL_GRXRINGS: - cmd->data = adapter->num_rx_qs - 1; + cmd->data = adapter->num_rx_qs; break; default: return -EINVAL; diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 71da0490521b..ea4f17f5cce7 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/net/ethernet/ethoc.c * * Copyright (C) 2007-2008 Avionic Design Development GmbH * Copyright (C) 2008-2009 Avionic Design GmbH * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Written by Thierry Reding <thierry.reding@avionic-design.de> */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 196a3d780dcf..f326805543a4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -3803,7 +3803,7 @@ static int hns3_client_init(struct hnae3_handle *handle) ret = hns3_client_start(handle); if (ret) { dev_err(priv->dev, "hns3_client_start fail! ret=%d\n", ret); - goto out_client_start; + goto out_client_start; } hns3_dcbnl_setup(handle); diff --git a/drivers/net/ethernet/i825xx/ether1.c b/drivers/net/ethernet/i825xx/ether1.c index 35f6291a3672..bb3b8adbe4f0 100644 --- a/drivers/net/ethernet/i825xx/ether1.c +++ b/drivers/net/ethernet/i825xx/ether1.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/net/ether1.c * * Copyright (C) 1996-2000 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Acorn ether1 driver (82586 chip) for Acorn machines * * We basically keep two queues in the cards memory - one for transmit diff --git a/drivers/net/ethernet/i825xx/ether1.h b/drivers/net/ethernet/i825xx/ether1.h index 3a5830ab3dc7..3926e042fe2e 100644 --- a/drivers/net/ethernet/i825xx/ether1.h +++ b/drivers/net/ethernet/i825xx/ether1.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/acorn/net/ether1.h * * Copyright (C) 1996 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Network driver for Acorn Ether1 cards. */ diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 3da392bfd659..3da680073265 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -428,9 +428,10 @@ static int reset_rx_pools(struct ibmvnic_adapter *adapter) if (rx_pool->buff_size != be64_to_cpu(size_array[i])) { free_long_term_buff(adapter, &rx_pool->long_term_buff); rx_pool->buff_size = be64_to_cpu(size_array[i]); - alloc_long_term_buff(adapter, &rx_pool->long_term_buff, - rx_pool->size * - rx_pool->buff_size); + rc = alloc_long_term_buff(adapter, + &rx_pool->long_term_buff, + rx_pool->size * + rx_pool->buff_size); } else { rc = reset_long_term_buff(adapter, &rx_pool->long_term_buff); @@ -696,9 +697,9 @@ static int init_tx_pools(struct net_device *netdev) return rc; } - init_one_tx_pool(netdev, &adapter->tso_pool[i], - IBMVNIC_TSO_BUFS, - IBMVNIC_TSO_BUF_SZ); + rc = init_one_tx_pool(netdev, &adapter->tso_pool[i], + IBMVNIC_TSO_BUFS, + IBMVNIC_TSO_BUF_SZ); if (rc) { release_tx_pools(adapter); return rc; @@ -1745,7 +1746,8 @@ static int do_reset(struct ibmvnic_adapter *adapter, ibmvnic_cleanup(netdev); - if (adapter->reset_reason != VNIC_RESET_MOBILITY && + if (reset_state == VNIC_OPEN && + adapter->reset_reason != VNIC_RESET_MOBILITY && adapter->reset_reason != VNIC_RESET_FAILOVER) { rc = __ibmvnic_close(netdev); if (rc) @@ -1844,6 +1846,9 @@ static int do_reset(struct ibmvnic_adapter *adapter, return 0; } + /* refresh device's multicast list */ + ibmvnic_set_multi(netdev); + /* kick napi */ for (i = 0; i < adapter->req_rx_queues; i++) napi_schedule(&adapter->napi[i]); diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index f9bb890733b5..6e73ffe6f928 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -1,15 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. * * Copyright (C) 2011 John Crispin <blogic@openwrt.org> */ diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c index 0ee39ea47b6b..274fb07362cb 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c @@ -566,6 +566,9 @@ static int mvpp2_dbgfs_prs_entry_init(struct dentry *parent, debugfs_create_file("hits", 0444, prs_entry_dir, entry, &mvpp2_dbgfs_prs_hits_fops); + debugfs_create_file("pmap", 0444, prs_entry_dir, entry, + &mvpp2_dbgfs_prs_pmap_fops); + return 0; } diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c index 392fd895f278..ae2240074d8e 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c @@ -1905,8 +1905,7 @@ static int mvpp2_prs_ip6_init(struct mvpp2 *priv) } /* Find tcam entry with matched pair <vid,port> */ -static int mvpp2_prs_vid_range_find(struct mvpp2 *priv, int pmap, u16 vid, - u16 mask) +static int mvpp2_prs_vid_range_find(struct mvpp2_port *port, u16 vid, u16 mask) { unsigned char byte[2], enable[2]; struct mvpp2_prs_entry pe; @@ -1914,13 +1913,13 @@ static int mvpp2_prs_vid_range_find(struct mvpp2 *priv, int pmap, u16 vid, int tid; /* Go through the all entries with MVPP2_PRS_LU_VID */ - for (tid = MVPP2_PE_VID_FILT_RANGE_START; - tid <= MVPP2_PE_VID_FILT_RANGE_END; tid++) { - if (!priv->prs_shadow[tid].valid || - priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VID) + for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id); + tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) { + if (!port->priv->prs_shadow[tid].valid || + port->priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VID) continue; - mvpp2_prs_init_from_hw(priv, &pe, tid); + mvpp2_prs_init_from_hw(port->priv, &pe, tid); mvpp2_prs_tcam_data_byte_get(&pe, 2, &byte[0], &enable[0]); mvpp2_prs_tcam_data_byte_get(&pe, 3, &byte[1], &enable[1]); @@ -1950,7 +1949,7 @@ int mvpp2_prs_vid_entry_add(struct mvpp2_port *port, u16 vid) memset(&pe, 0, sizeof(pe)); /* Scan TCAM and see if entry with this <vid,port> already exist */ - tid = mvpp2_prs_vid_range_find(priv, (1 << port->id), vid, mask); + tid = mvpp2_prs_vid_range_find(port, vid, mask); reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id)); if (reg_val & MVPP2_DSA_EXTENDED) @@ -2008,7 +2007,7 @@ void mvpp2_prs_vid_entry_remove(struct mvpp2_port *port, u16 vid) int tid; /* Scan TCAM and see if entry with this <vid,port> already exist */ - tid = mvpp2_prs_vid_range_find(priv, (1 << port->id), vid, 0xfff); + tid = mvpp2_prs_vid_range_find(port, vid, 0xfff); /* No such entry */ if (tid < 0) @@ -2026,8 +2025,10 @@ void mvpp2_prs_vid_remove_all(struct mvpp2_port *port) for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id); tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) { - if (priv->prs_shadow[tid].valid) - mvpp2_prs_vid_entry_remove(port, tid); + if (priv->prs_shadow[tid].valid) { + mvpp2_prs_hw_inv(priv, tid); + priv->prs_shadow[tid].valid = false; + } } } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index d2ab8cd8ad9f..e94686c42000 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -441,6 +441,10 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op, case MLX5_CMD_OP_CREATE_GENERAL_OBJECT: case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT: case MLX5_CMD_OP_QUERY_GENERAL_OBJECT: + case MLX5_CMD_OP_CREATE_UCTX: + case MLX5_CMD_OP_DESTROY_UCTX: + case MLX5_CMD_OP_CREATE_UMEM: + case MLX5_CMD_OP_DESTROY_UMEM: case MLX5_CMD_OP_ALLOC_MEMIC: *status = MLX5_DRIVER_STATUS_ABORTED; *synd = MLX5_DRIVER_SYND; @@ -629,6 +633,10 @@ const char *mlx5_command_str(int command) MLX5_COMMAND_STR_CASE(ALLOC_MEMIC); MLX5_COMMAND_STR_CASE(DEALLOC_MEMIC); MLX5_COMMAND_STR_CASE(QUERY_HOST_PARAMS); + MLX5_COMMAND_STR_CASE(CREATE_UCTX); + MLX5_COMMAND_STR_CASE(DESTROY_UCTX); + MLX5_COMMAND_STR_CASE(CREATE_UMEM); + MLX5_COMMAND_STR_CASE(DESTROY_UMEM); default: return "unknown command opcode"; } } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c index ebc046fa97d3..f6b1da99e6c2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c @@ -248,11 +248,32 @@ void mlx5_unregister_interface(struct mlx5_interface *intf) } EXPORT_SYMBOL(mlx5_unregister_interface); +/* Must be called with intf_mutex held */ +static bool mlx5_has_added_dev_by_protocol(struct mlx5_core_dev *mdev, int protocol) +{ + struct mlx5_device_context *dev_ctx; + struct mlx5_interface *intf; + bool found = false; + + list_for_each_entry(intf, &intf_list, list) { + if (intf->protocol == protocol) { + dev_ctx = mlx5_get_device(intf, &mdev->priv); + if (dev_ctx && test_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state)) + found = true; + break; + } + } + + return found; +} + void mlx5_reload_interface(struct mlx5_core_dev *mdev, int protocol) { mutex_lock(&mlx5_intf_mutex); - mlx5_remove_dev_by_protocol(mdev, protocol); - mlx5_add_dev_by_protocol(mdev, protocol); + if (mlx5_has_added_dev_by_protocol(mdev, protocol)) { + mlx5_remove_dev_by_protocol(mdev, protocol); + mlx5_add_dev_by_protocol(mdev, protocol); + } mutex_unlock(&mlx5_intf_mutex); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 3a183d690e23..cc6797e24571 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -385,6 +385,7 @@ struct mlx5e_txqsq { /* control path */ struct mlx5_wq_ctrl wq_ctrl; struct mlx5e_channel *channel; + int ch_ix; int txq_ix; u32 rate_limit; struct work_struct recover_work; @@ -1112,6 +1113,7 @@ void mlx5e_del_vxlan_port(struct net_device *netdev, struct udp_tunnel_info *ti) netdev_features_t mlx5e_features_check(struct sk_buff *skb, struct net_device *netdev, netdev_features_t features); +int mlx5e_set_features(struct net_device *netdev, netdev_features_t features); #ifdef CONFIG_MLX5_ESWITCH int mlx5e_set_vf_mac(struct net_device *dev, int vf, u8 *mac); int mlx5e_set_vf_rate(struct net_device *dev, int vf, int min_tx_rate, int max_tx_rate); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c index fe5d4d7f15ed..231e7cdfc6f7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c @@ -11,24 +11,25 @@ static int get_route_and_out_devs(struct mlx5e_priv *priv, struct net_device **route_dev, struct net_device **out_dev) { + struct net_device *uplink_dev, *uplink_upper, *real_dev; struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; - struct net_device *uplink_dev, *uplink_upper; bool dst_is_lag_dev; + real_dev = is_vlan_dev(dev) ? vlan_dev_real_dev(dev) : dev; uplink_dev = mlx5_eswitch_uplink_get_proto_dev(esw, REP_ETH); uplink_upper = netdev_master_upper_dev_get(uplink_dev); dst_is_lag_dev = (uplink_upper && netif_is_lag_master(uplink_upper) && - dev == uplink_upper && + real_dev == uplink_upper && mlx5_lag_is_sriov(priv->mdev)); /* if the egress device isn't on the same HW e-switch or * it's a LAG device, use the uplink */ - if (!netdev_port_same_parent_id(priv->netdev, dev) || + if (!netdev_port_same_parent_id(priv->netdev, real_dev) || dst_is_lag_dev) { - *route_dev = uplink_dev; - *out_dev = *route_dev; + *route_dev = dev; + *out_dev = uplink_dev; } else { *route_dev = dev; if (is_vlan_dev(*route_dev)) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index c65cefd84eda..a8e8350b38aa 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1082,6 +1082,7 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c, sq->clock = &mdev->clock; sq->mkey_be = c->mkey_be; sq->channel = c; + sq->ch_ix = c->ix; sq->txq_ix = txq_ix; sq->uar_map = mdev->mlx5e_res.bfreg.map; sq->min_inline_mode = params->tx_min_inline_mode; @@ -3635,8 +3636,7 @@ static int mlx5e_handle_feature(struct net_device *netdev, return 0; } -static int mlx5e_set_features(struct net_device *netdev, - netdev_features_t features) +int mlx5e_set_features(struct net_device *netdev, netdev_features_t features) { netdev_features_t oper_features = netdev->features; int err = 0; @@ -5108,6 +5108,11 @@ static void mlx5e_detach(struct mlx5_core_dev *mdev, void *vpriv) struct mlx5e_priv *priv = vpriv; struct net_device *netdev = priv->netdev; +#ifdef CONFIG_MLX5_ESWITCH + if (MLX5_ESWITCH_MANAGER(mdev) && vpriv == mdev) + return; +#endif + if (!netif_device_present(netdev)) return; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 9aea9c5b2ce8..2f406b161bcf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1351,6 +1351,7 @@ static const struct net_device_ops mlx5e_netdev_ops_uplink_rep = { .ndo_get_vf_stats = mlx5e_get_vf_stats, .ndo_set_vf_vlan = mlx5e_uplink_rep_set_vf_vlan, .ndo_get_port_parent_id = mlx5e_rep_get_port_parent_id, + .ndo_set_features = mlx5e_set_features, }; bool mlx5e_eswitch_rep(struct net_device *netdev) @@ -1425,10 +1426,9 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev) netdev->watchdog_timeo = 15 * HZ; + netdev->features |= NETIF_F_NETNS_LOCAL; - netdev->features |= NETIF_F_HW_TC | NETIF_F_NETNS_LOCAL; - netdev->hw_features |= NETIF_F_HW_TC; - + netdev->hw_features |= NETIF_F_HW_TC; netdev->hw_features |= NETIF_F_SG; netdev->hw_features |= NETIF_F_IP_CSUM; netdev->hw_features |= NETIF_F_IPV6_CSUM; @@ -1437,7 +1437,9 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev) netdev->hw_features |= NETIF_F_TSO6; netdev->hw_features |= NETIF_F_RXCSUM; - if (rep->vport != MLX5_VPORT_UPLINK) + if (rep->vport == MLX5_VPORT_UPLINK) + netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX; + else netdev->features |= NETIF_F_VLAN_CHALLENGED; netdev->features |= netdev->hw_features; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 31cd02f11499..e40c60d1631f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -2812,9 +2812,6 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, if (!flow_action_has_entries(flow_action)) return -EINVAL; - attr->in_rep = rpriv->rep; - attr->in_mdev = priv->mdev; - flow_action_for_each(i, act, flow_action) { switch (act->id) { case FLOW_ACTION_DROP: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 195a7d903cec..701e5dc75bb0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -113,13 +113,13 @@ static inline int mlx5e_get_dscp_up(struct mlx5e_priv *priv, struct sk_buff *skb u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev) { - int channel_ix = netdev_pick_tx(dev, skb, NULL); + int txq_ix = netdev_pick_tx(dev, skb, NULL); struct mlx5e_priv *priv = netdev_priv(dev); u16 num_channels; int up = 0; if (!netdev_get_num_tc(dev)) - return channel_ix; + return txq_ix; #ifdef CONFIG_MLX5_CORE_EN_DCB if (priv->dcbx_dp.trust_state == MLX5_QPTS_TRUST_DSCP) @@ -129,14 +129,14 @@ u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb, if (skb_vlan_tag_present(skb)) up = skb_vlan_tag_get_prio(skb); - /* channel_ix can be larger than num_channels since + /* txq_ix can be larger than num_channels since * dev->num_real_tx_queues = num_channels * num_tc */ num_channels = priv->channels.params.num_channels; - if (channel_ix >= num_channels) - channel_ix = reciprocal_scale(channel_ix, num_channels); + if (txq_ix >= num_channels) + txq_ix = priv->txq2sq[txq_ix]->ch_ix; - return priv->channel_tc2txq[channel_ix][up]; + return priv->channel_tc2txq[txq_ix][up]; } static inline int mlx5e_skb_l2_header_offset(struct sk_buff *skb) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index e8002bfc1e8f..7ed63ed657c7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -997,7 +997,7 @@ static inline void mlxsw_reg_spaft_pack(char *payload, u8 local_port, MLXSW_REG_ZERO(spaft, payload); mlxsw_reg_spaft_local_port_set(payload, local_port); mlxsw_reg_spaft_allow_untagged_set(payload, allow_untagged); - mlxsw_reg_spaft_allow_prio_tagged_set(payload, true); + mlxsw_reg_spaft_allow_prio_tagged_set(payload, allow_untagged); mlxsw_reg_spaft_allow_tagged_set(payload, true); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index dfe6b44baf63..23204356ad88 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4280,13 +4280,16 @@ static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) } } +#define MLXSW_SP_LAG_SEED_INIT 0xcafecafe + static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) { char slcr_pl[MLXSW_REG_SLCR_LEN]; u32 seed; int err; - seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 0); + seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), + MLXSW_SP_LAG_SEED_INIT); mlxsw_reg_slcr_pack(slcr_pl, MLXSW_REG_SLCR_LAG_HASH_SMAC | MLXSW_REG_SLCR_LAG_HASH_DMAC | MLXSW_REG_SLCR_LAG_HASH_ETHERTYPE | diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index 8512dd49e420..1537f70bc26d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -437,8 +437,8 @@ static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = { MLXSW_SP1_SB_PR_CPU_SIZE, true, false), }; -#define MLXSW_SP2_SB_PR_INGRESS_SIZE 40960000 -#define MLXSW_SP2_SB_PR_EGRESS_SIZE 40960000 +#define MLXSW_SP2_SB_PR_INGRESS_SIZE 38128752 +#define MLXSW_SP2_SB_PR_EGRESS_SIZE 38128752 #define MLXSW_SP2_SB_PR_CPU_SIZE (256 * 1000) /* Order according to mlxsw_sp2_sb_pool_dess */ diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 15f804453cd6..96b23c856f4d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -247,8 +247,8 @@ static int mlxsw_sp_flower_parse_ip(struct mlxsw_sp *mlxsw_sp, match.mask->tos & 0x3); mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_IP_DSCP, - match.key->tos >> 6, - match.mask->tos >> 6); + match.key->tos >> 2, + match.mask->tos >> 2); return 0; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 1cda8a248b12..ef554739dd54 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2363,7 +2363,7 @@ static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work) static void mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_neigh_entry *neigh_entry, - bool removing); + bool removing, bool dead); static enum mlxsw_reg_rauht_op mlxsw_sp_rauht_op(bool adding) { @@ -2507,7 +2507,8 @@ static void mlxsw_sp_router_neigh_event_work(struct work_struct *work) memcpy(neigh_entry->ha, ha, ETH_ALEN); mlxsw_sp_neigh_entry_update(mlxsw_sp, neigh_entry, entry_connected); - mlxsw_sp_nexthop_neigh_update(mlxsw_sp, neigh_entry, !entry_connected); + mlxsw_sp_nexthop_neigh_update(mlxsw_sp, neigh_entry, !entry_connected, + dead); if (!neigh_entry->connected && list_empty(&neigh_entry->nexthop_list)) mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry); @@ -3472,13 +3473,79 @@ static void __mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop *nh, nh->update = 1; } +static int +mlxsw_sp_nexthop_dead_neigh_replace(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_neigh_entry *neigh_entry) +{ + struct neighbour *n, *old_n = neigh_entry->key.n; + struct mlxsw_sp_nexthop *nh; + bool entry_connected; + u8 nud_state, dead; + int err; + + nh = list_first_entry(&neigh_entry->nexthop_list, + struct mlxsw_sp_nexthop, neigh_list_node); + + n = neigh_lookup(nh->nh_grp->neigh_tbl, &nh->gw_addr, nh->rif->dev); + if (!n) { + n = neigh_create(nh->nh_grp->neigh_tbl, &nh->gw_addr, + nh->rif->dev); + if (IS_ERR(n)) + return PTR_ERR(n); + neigh_event_send(n, NULL); + } + + mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry); + neigh_entry->key.n = n; + err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry); + if (err) + goto err_neigh_entry_insert; + + read_lock_bh(&n->lock); + nud_state = n->nud_state; + dead = n->dead; + read_unlock_bh(&n->lock); + entry_connected = nud_state & NUD_VALID && !dead; + + list_for_each_entry(nh, &neigh_entry->nexthop_list, + neigh_list_node) { + neigh_release(old_n); + neigh_clone(n); + __mlxsw_sp_nexthop_neigh_update(nh, !entry_connected); + mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp); + } + + neigh_release(n); + + return 0; + +err_neigh_entry_insert: + neigh_entry->key.n = old_n; + mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry); + neigh_release(n); + return err; +} + static void mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_neigh_entry *neigh_entry, - bool removing) + bool removing, bool dead) { struct mlxsw_sp_nexthop *nh; + if (list_empty(&neigh_entry->nexthop_list)) + return; + + if (dead) { + int err; + + err = mlxsw_sp_nexthop_dead_neigh_replace(mlxsw_sp, + neigh_entry); + if (err) + dev_err(mlxsw_sp->bus_info->dev, "Failed to replace dead neigh\n"); + return; + } + list_for_each_entry(nh, &neigh_entry->nexthop_list, neigh_list_node) { __mlxsw_sp_nexthop_neigh_update(nh, removing); diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c index ba4fdf1b0dea..33305c9c5a62 100644 --- a/drivers/net/ethernet/micrel/ks8851.c +++ b/drivers/net/ethernet/micrel/ks8851.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/net/ethernet/micrel/ks8851.c * * Copyright 2009 Simtec Electronics * http://www.simtec.co.uk/ * Ben Dooks <ben@simtec.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/net/ethernet/micrel/ks8851.h b/drivers/net/ethernet/micrel/ks8851.h index 23da1e3ee429..8f834aef8e32 100644 --- a/drivers/net/ethernet/micrel/ks8851.h +++ b/drivers/net/ethernet/micrel/ks8851.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* drivers/net/ethernet/micrel/ks8851.h * * Copyright 2009 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * * KS8851 register definitions - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define KS_CCR 0x08 diff --git a/drivers/net/ethernet/microchip/encx24j600-regmap.c b/drivers/net/ethernet/microchip/encx24j600-regmap.c index 44bb04d4d21b..1f496fac7033 100644 --- a/drivers/net/ethernet/microchip/encx24j600-regmap.c +++ b/drivers/net/ethernet/microchip/encx24j600-regmap.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /** * Register map access API - ENCX24J600 support * * Copyright 2015 Gridpoint * * Author: Jon Ringle <jringle@gridpoint.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index b82b684f52ce..36a3bd30cfd9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -1867,6 +1867,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) napi_gro_receive(&rx_ring->r_vec->napi, skb); } else { skb->dev = netdev; + skb_reset_network_header(skb); __skb_push(skb, ETH_HLEN); dev_queue_xmit(skb); } diff --git a/drivers/net/ethernet/netx-eth.c b/drivers/net/ethernet/netx-eth.c index df4188cb43e0..cf6e7eb1b1e1 100644 --- a/drivers/net/ethernet/netx-eth.c +++ b/drivers/net/ethernet/netx-eth.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/net/ethernet/netx-eth.c * * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/init.h> diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.c b/drivers/net/ethernet/pasemi/pasemi_mac.c index 5ffaee9f53b1..bf5a7bca0298 100644 --- a/drivers/net/ethernet/pasemi/pasemi_mac.c +++ b/drivers/net/ethernet/pasemi/pasemi_mac.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2006-2007 PA Semi, Inc * * Driver for the PA Semi PWRficient onchip 1G/10G Ethernet MACs - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.h b/drivers/net/ethernet/pasemi/pasemi_mac.h index 7c47e263b8c1..d7d2068b6f1b 100644 --- a/drivers/net/ethernet/pasemi/pasemi_mac.h +++ b/drivers/net/ethernet/pasemi/pasemi_mac.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2006 PA Semi, Inc * * Driver for the PA6T-1682M onchip 1G/10G Ethernet MACs, soft state and * hardware register layouts. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #ifndef PASEMI_MAC_H diff --git a/drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c b/drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c index d0afc2b8f8e3..e1a304886a3c 100644 --- a/drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c +++ b/drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2006-2008 PA Semi, Inc * * Ethtool hooks for the PA Semi PWRficient onchip 1G/10G Ethernet MACs - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h index c61f260e18a4..049dc6cf4611 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* 10G controller driver for Samsung SoCs * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Siva Reddy Kallam <siva.kallam@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __SXGBE_COMMON_H__ diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c index 58c35692560e..e96e2bd295ef 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* 10G controller driver for Samsung SoCs * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Siva Reddy Kallam <siva.kallam@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c index 2686bb5b6765..b33ebf2dca47 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* 10G controller driver for Samsung SoCs * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Siva Reddy Kallam <siva.kallam@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h index 18609324db72..ede0827bf122 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* 10G controller driver for Samsung SoCs * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Siva Reddy Kallam <siva.kallam@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __SXGBE_DESC_H__ #define __SXGBE_DESC_H__ diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c index bb9b5b8afc5f..243db04b968c 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* 10G controller driver for Samsung SoCs * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Siva Reddy Kallam <siva.kallam@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> #include <linux/export.h> diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h index 1607b54c9bb0..e8f79a297278 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* 10G controller driver for Samsung SoCs * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Siva Reddy Kallam <siva.kallam@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __SXGBE_DMA_H__ #define __SXGBE_DMA_H__ diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c index c9aad0eda57f..0775b9464b4e 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* 10G controller driver for Samsung SoCs * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Siva Reddy Kallam <siva.kallam@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index 6d22dd500790..c56fcbb37066 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* 10G controller driver for Samsung SoCs * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Siva Reddy Kallam <siva.kallam@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c index 467ff7033606..b1e7f7ab281c 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* 10G controller driver for Samsung SoCs * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Siva Reddy Kallam <siva.kallam@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c index 324681c2bb74..298a7402e39c 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* 10G controller driver for Samsung SoCs * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Siva Reddy Kallam <siva.kallam@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h index 7e4810c4137e..e5634520700f 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* 10G controller driver for Samsung SoCs * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Siva Reddy Kallam <siva.kallam@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __SXGBE_MTL_H__ #define __SXGBE_MTL_H__ diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c index d2bc9412ba03..d2c48116f181 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* 10G controller driver for Samsung SoCs * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Siva Reddy Kallam <siva.kallam@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h index 81437d91df99..4def84ebf143 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* 10G controller driver for Samsung SoCs * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Siva Reddy Kallam <siva.kallam@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __SXGBE_REGMAP_H__ #define __SXGBE_REGMAP_H__ diff --git a/drivers/net/ethernet/seeq/ether3.c b/drivers/net/ethernet/seeq/ether3.c index d1bb73bf9914..632a7c85964d 100644 --- a/drivers/net/ethernet/seeq/ether3.c +++ b/drivers/net/ethernet/seeq/ether3.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/net/ether3.c * * Copyright (C) 1995-2000 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * SEEQ nq8005 ethernet driver for Acorn/ANT Ether3 card * for Acorn machines * diff --git a/drivers/net/ethernet/seeq/ether3.h b/drivers/net/ethernet/seeq/ether3.h index be19e5fa5cf2..585dd51be201 100644 --- a/drivers/net/ethernet/seeq/ether3.h +++ b/drivers/net/ethernet/seeq/ether3.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/acorn/net/ether3.h * * Copyright (C) 1995-2000 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * network driver for Acorn/ANT Ether3 cards */ diff --git a/drivers/net/ethernet/sfc/bitfield.h b/drivers/net/ethernet/sfc/bitfield.h index 41ad07d45144..1b59e9fe58b4 100644 --- a/drivers/net/ethernet/sfc/bitfield.h +++ b/drivers/net/ethernet/sfc/bitfield.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EFX_BITFIELD_H diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index e888b479c596..16d6952c312a 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2012-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include "net_driver.h" diff --git a/drivers/net/ethernet/sfc/ef10_regs.h b/drivers/net/ethernet/sfc/ef10_regs.h index 6a56778cf06c..154cfad95186 100644 --- a/drivers/net/ethernet/sfc/ef10_regs.h +++ b/drivers/net/ethernet/sfc/ef10_regs.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2012-2017 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EFX_EF10_REGS_H diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c index 3d76fd1504c2..52bd43f45761 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.c +++ b/drivers/net/ethernet/sfc/ef10_sriov.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2015 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/etherdevice.h> #include <linux/pci.h> diff --git a/drivers/net/ethernet/sfc/ef10_sriov.h b/drivers/net/ethernet/sfc/ef10_sriov.h index 2aa444ed42de..cfe556d17313 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.h +++ b/drivers/net/ethernet/sfc/ef10_sriov.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2015 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EF10_SRIOV_H diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index bc655ffc9e02..53b726bfe945 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2005-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/module.h> diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index 3f759ebdcf10..04fed7c06618 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EFX_EFX_H diff --git a/drivers/net/ethernet/sfc/enum.h b/drivers/net/ethernet/sfc/enum.h index 6fa824211d91..3332cdf2918a 100644 --- a/drivers/net/ethernet/sfc/enum.h +++ b/drivers/net/ethernet/sfc/enum.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2007-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EFX_ENUM_H diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 600d7b895cf2..86b965875540 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/netdevice.h> diff --git a/drivers/net/ethernet/sfc/falcon/bitfield.h b/drivers/net/ethernet/sfc/falcon/bitfield.h index 230fd77bd311..5eb178d0c149 100644 --- a/drivers/net/ethernet/sfc/falcon/bitfield.h +++ b/drivers/net/ethernet/sfc/falcon/bitfield.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EF4_BITFIELD_H diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c index 8b1f94d7a6c5..9b15c39ac670 100644 --- a/drivers/net/ethernet/sfc/falcon/efx.c +++ b/drivers/net/ethernet/sfc/falcon/efx.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2005-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/module.h> diff --git a/drivers/net/ethernet/sfc/falcon/efx.h b/drivers/net/ethernet/sfc/falcon/efx.h index a4e4d8ea4078..d3b4646545fa 100644 --- a/drivers/net/ethernet/sfc/falcon/efx.h +++ b/drivers/net/ethernet/sfc/falcon/efx.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EF4_EFX_H diff --git a/drivers/net/ethernet/sfc/falcon/enum.h b/drivers/net/ethernet/sfc/falcon/enum.h index 4824fcf5c3d4..7e6277fb47ec 100644 --- a/drivers/net/ethernet/sfc/falcon/enum.h +++ b/drivers/net/ethernet/sfc/falcon/enum.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2007-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EF4_ENUM_H diff --git a/drivers/net/ethernet/sfc/falcon/ethtool.c b/drivers/net/ethernet/sfc/falcon/ethtool.c index 72cedec945c1..08bd6a321918 100644 --- a/drivers/net/ethernet/sfc/falcon/ethtool.c +++ b/drivers/net/ethernet/sfc/falcon/ethtool.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/netdevice.h> diff --git a/drivers/net/ethernet/sfc/falcon/falcon.c b/drivers/net/ethernet/sfc/falcon/falcon.c index 6520d7bc8d21..3324a6219a09 100644 --- a/drivers/net/ethernet/sfc/falcon/falcon.c +++ b/drivers/net/ethernet/sfc/falcon/falcon.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/bitops.h> diff --git a/drivers/net/ethernet/sfc/falcon/falcon_boards.c b/drivers/net/ethernet/sfc/falcon/falcon_boards.c index dec83a217093..839189dab98e 100644 --- a/drivers/net/ethernet/sfc/falcon/falcon_boards.c +++ b/drivers/net/ethernet/sfc/falcon/falcon_boards.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2007-2012 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/rtnetlink.h> diff --git a/drivers/net/ethernet/sfc/falcon/farch.c b/drivers/net/ethernet/sfc/falcon/farch.c index 411a2f419447..332183280a45 100644 --- a/drivers/net/ethernet/sfc/falcon/farch.c +++ b/drivers/net/ethernet/sfc/falcon/farch.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/bitops.h> diff --git a/drivers/net/ethernet/sfc/falcon/farch_regs.h b/drivers/net/ethernet/sfc/falcon/farch_regs.h index 8095f273d574..5b01f3f3fde1 100644 --- a/drivers/net/ethernet/sfc/falcon/farch_regs.h +++ b/drivers/net/ethernet/sfc/falcon/farch_regs.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2012 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EF4_FARCH_REGS_H diff --git a/drivers/net/ethernet/sfc/falcon/filter.h b/drivers/net/ethernet/sfc/falcon/filter.h index 647f6b2725c5..bc6f5f563e70 100644 --- a/drivers/net/ethernet/sfc/falcon/filter.h +++ b/drivers/net/ethernet/sfc/falcon/filter.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EF4_FILTER_H diff --git a/drivers/net/ethernet/sfc/falcon/io.h b/drivers/net/ethernet/sfc/falcon/io.h index c3577643fbda..bc23c800a10f 100644 --- a/drivers/net/ethernet/sfc/falcon/io.h +++ b/drivers/net/ethernet/sfc/falcon/io.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EF4_IO_H diff --git a/drivers/net/ethernet/sfc/falcon/mdio_10g.c b/drivers/net/ethernet/sfc/falcon/mdio_10g.c index ee0713f03d01..540278161449 100644 --- a/drivers/net/ethernet/sfc/falcon/mdio_10g.c +++ b/drivers/net/ethernet/sfc/falcon/mdio_10g.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2006-2011 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ /* * Useful functions for working with MDIO clause 45 PHYs diff --git a/drivers/net/ethernet/sfc/falcon/mdio_10g.h b/drivers/net/ethernet/sfc/falcon/mdio_10g.h index 53cb5cc4ad37..de676bfa064d 100644 --- a/drivers/net/ethernet/sfc/falcon/mdio_10g.h +++ b/drivers/net/ethernet/sfc/falcon/mdio_10g.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2006-2011 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EF4_MDIO_10G_H diff --git a/drivers/net/ethernet/sfc/falcon/mtd.c b/drivers/net/ethernet/sfc/falcon/mtd.c index 2d67e4621a3d..15bd47bf9e8e 100644 --- a/drivers/net/ethernet/sfc/falcon/mtd.c +++ b/drivers/net/ethernet/sfc/falcon/mtd.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/module.h> diff --git a/drivers/net/ethernet/sfc/falcon/net_driver.h b/drivers/net/ethernet/sfc/falcon/net_driver.h index 37a8bdf32206..a49ea2e719b6 100644 --- a/drivers/net/ethernet/sfc/falcon/net_driver.h +++ b/drivers/net/ethernet/sfc/falcon/net_driver.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2005-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ /* Common definitions for all Efx net driver code */ diff --git a/drivers/net/ethernet/sfc/falcon/nic.c b/drivers/net/ethernet/sfc/falcon/nic.c index 9c07b5175581..156da315ec89 100644 --- a/drivers/net/ethernet/sfc/falcon/nic.c +++ b/drivers/net/ethernet/sfc/falcon/nic.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/bitops.h> diff --git a/drivers/net/ethernet/sfc/falcon/nic.h b/drivers/net/ethernet/sfc/falcon/nic.h index 07c62dc552cb..9f413474bd9f 100644 --- a/drivers/net/ethernet/sfc/falcon/nic.h +++ b/drivers/net/ethernet/sfc/falcon/nic.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EF4_NIC_H diff --git a/drivers/net/ethernet/sfc/falcon/phy.h b/drivers/net/ethernet/sfc/falcon/phy.h index 362141cee313..69bb548eae59 100644 --- a/drivers/net/ethernet/sfc/falcon/phy.h +++ b/drivers/net/ethernet/sfc/falcon/phy.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2007-2010 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EF4_PHY_H diff --git a/drivers/net/ethernet/sfc/falcon/qt202x_phy.c b/drivers/net/ethernet/sfc/falcon/qt202x_phy.c index f5e0f18d4ea8..21af67e42296 100644 --- a/drivers/net/ethernet/sfc/falcon/qt202x_phy.c +++ b/drivers/net/ethernet/sfc/falcon/qt202x_phy.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2006-2012 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ /* * Driver for AMCC QT202x SFP+ and XFP adapters; see www.amcc.com for details diff --git a/drivers/net/ethernet/sfc/falcon/rx.c b/drivers/net/ethernet/sfc/falcon/rx.c index 02456ed13a7d..fd850d3d8ec0 100644 --- a/drivers/net/ethernet/sfc/falcon/rx.c +++ b/drivers/net/ethernet/sfc/falcon/rx.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2005-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/socket.h> diff --git a/drivers/net/ethernet/sfc/falcon/selftest.c b/drivers/net/ethernet/sfc/falcon/selftest.c index 55c0fbbc4fb8..147677c7c72f 100644 --- a/drivers/net/ethernet/sfc/falcon/selftest.c +++ b/drivers/net/ethernet/sfc/falcon/selftest.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2012 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/netdevice.h> diff --git a/drivers/net/ethernet/sfc/falcon/selftest.h b/drivers/net/ethernet/sfc/falcon/selftest.h index be52a49c006a..c0dbc6394e0f 100644 --- a/drivers/net/ethernet/sfc/falcon/selftest.h +++ b/drivers/net/ethernet/sfc/falcon/selftest.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2012 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EF4_SELFTEST_H diff --git a/drivers/net/ethernet/sfc/falcon/tenxpress.c b/drivers/net/ethernet/sfc/falcon/tenxpress.c index ff9b4e2b590c..e27824ef121f 100644 --- a/drivers/net/ethernet/sfc/falcon/tenxpress.c +++ b/drivers/net/ethernet/sfc/falcon/tenxpress.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2007-2011 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/delay.h> diff --git a/drivers/net/ethernet/sfc/falcon/tx.c b/drivers/net/ethernet/sfc/falcon/tx.c index c5059f456f37..f7306e93a8b8 100644 --- a/drivers/net/ethernet/sfc/falcon/tx.c +++ b/drivers/net/ethernet/sfc/falcon/tx.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2005-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/pci.h> diff --git a/drivers/net/ethernet/sfc/falcon/tx.h b/drivers/net/ethernet/sfc/falcon/tx.h index a607eb0087a8..2a88c59cbbbe 100644 --- a/drivers/net/ethernet/sfc/falcon/tx.h +++ b/drivers/net/ethernet/sfc/falcon/tx.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2015 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EF4_TX_H diff --git a/drivers/net/ethernet/sfc/falcon/txc43128_phy.c b/drivers/net/ethernet/sfc/falcon/txc43128_phy.c index 3c55fd23c271..f3503965c52c 100644 --- a/drivers/net/ethernet/sfc/falcon/txc43128_phy.c +++ b/drivers/net/ethernet/sfc/falcon/txc43128_phy.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2006-2011 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ /* diff --git a/drivers/net/ethernet/sfc/falcon/workarounds.h b/drivers/net/ethernet/sfc/falcon/workarounds.h index 6af800bc9633..e28c67fc92a3 100644 --- a/drivers/net/ethernet/sfc/falcon/workarounds.h +++ b/drivers/net/ethernet/sfc/falcon/workarounds.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EF4_WORKAROUNDS_H diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c index e045a5d6b938..eedd32e2bfcb 100644 --- a/drivers/net/ethernet/sfc/farch.c +++ b/drivers/net/ethernet/sfc/farch.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/bitops.h> diff --git a/drivers/net/ethernet/sfc/farch_regs.h b/drivers/net/ethernet/sfc/farch_regs.h index 7019a712e799..d138be423e63 100644 --- a/drivers/net/ethernet/sfc/farch_regs.h +++ b/drivers/net/ethernet/sfc/farch_regs.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2012 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EFX_FARCH_REGS_H diff --git a/drivers/net/ethernet/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h index 59021ad6d98d..40b2af8bfb81 100644 --- a/drivers/net/ethernet/sfc/filter.h +++ b/drivers/net/ethernet/sfc/filter.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EFX_FILTER_H diff --git a/drivers/net/ethernet/sfc/io.h b/drivers/net/ethernet/sfc/io.h index 2774a10f44e9..c3c011bc6a68 100644 --- a/drivers/net/ethernet/sfc/io.h +++ b/drivers/net/ethernet/sfc/io.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EFX_IO_H diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 295ec1787b9f..2713300343c7 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2008-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/delay.h> diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h index ebd95972ae7b..9081f84a2604 100644 --- a/drivers/net/ethernet/sfc/mcdi.h +++ b/drivers/net/ethernet/sfc/mcdi.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2008-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EFX_MCDI_H diff --git a/drivers/net/ethernet/sfc/mcdi_mon.c b/drivers/net/ethernet/sfc/mcdi_mon.c index f17751559ccc..5954fcfee2b1 100644 --- a/drivers/net/ethernet/sfc/mcdi_mon.c +++ b/drivers/net/ethernet/sfc/mcdi_mon.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2011-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/bitops.h> diff --git a/drivers/net/ethernet/sfc/mcdi_pcol.h b/drivers/net/ethernet/sfc/mcdi_pcol.h index 20a5523bf9f3..79d834a4ae49 100644 --- a/drivers/net/ethernet/sfc/mcdi_pcol.h +++ b/drivers/net/ethernet/sfc/mcdi_pcol.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2009-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ diff --git a/drivers/net/ethernet/sfc/mcdi_port.c b/drivers/net/ethernet/sfc/mcdi_port.c index a4bbfebe3d64..fb7cde4980ed 100644 --- a/drivers/net/ethernet/sfc/mcdi_port.c +++ b/drivers/net/ethernet/sfc/mcdi_port.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2009-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ /* diff --git a/drivers/net/ethernet/sfc/mtd.c b/drivers/net/ethernet/sfc/mtd.c index 0d03e0577d85..273c08e5455f 100644 --- a/drivers/net/ethernet/sfc/mtd.c +++ b/drivers/net/ethernet/sfc/mtd.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/module.h> diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 961b92979640..284a1b047ac2 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2005-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ /* Common definitions for all Efx net driver code */ diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index c2d45a40eb48..b0baa70fbba7 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/bitops.h> diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index 5cca0556b47f..1f7c5717de75 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EFX_NIC_H diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c index f21661532ed3..02ed6d1b716c 100644 --- a/drivers/net/ethernet/sfc/ptp.c +++ b/drivers/net/ethernet/sfc/ptp.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2011-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ /* Theory of operation: diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index 8702ab44d80b..d5db045535d3 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2005-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/socket.h> diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index f6936949fc85..8474cf8ea7d3 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2012 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/netdevice.h> diff --git a/drivers/net/ethernet/sfc/selftest.h b/drivers/net/ethernet/sfc/selftest.h index 32a427253a03..a3553816d92c 100644 --- a/drivers/net/ethernet/sfc/selftest.h +++ b/drivers/net/ethernet/sfc/selftest.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2012 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EFX_SELFTEST_H diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index 65161f68265a..81499244a4b4 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/bitops.h> diff --git a/drivers/net/ethernet/sfc/siena_sriov.c b/drivers/net/ethernet/sfc/siena_sriov.c index da7b94f34604..dfbdf05dcf79 100644 --- a/drivers/net/ethernet/sfc/siena_sriov.c +++ b/drivers/net/ethernet/sfc/siena_sriov.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2010-2012 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/pci.h> #include <linux/module.h> diff --git a/drivers/net/ethernet/sfc/siena_sriov.h b/drivers/net/ethernet/sfc/siena_sriov.h index d88d4dab170a..e441c89c25ce 100644 --- a/drivers/net/ethernet/sfc/siena_sriov.h +++ b/drivers/net/ethernet/sfc/siena_sriov.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2015 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef SIENA_SRIOV_H diff --git a/drivers/net/ethernet/sfc/sriov.c b/drivers/net/ethernet/sfc/sriov.c index 0b766fdbcddb..3f241e6c881a 100644 --- a/drivers/net/ethernet/sfc/sriov.c +++ b/drivers/net/ethernet/sfc/sriov.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2014-2015 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/module.h> #include "net_driver.h" diff --git a/drivers/net/ethernet/sfc/sriov.h b/drivers/net/ethernet/sfc/sriov.h index 84c7984edcaf..747707bee483 100644 --- a/drivers/net/ethernet/sfc/sriov.h +++ b/drivers/net/ethernet/sfc/sriov.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2014-2015 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EFX_SRIOV_H diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index e182055ec2eb..31ec56091a5d 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2005-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/pci.h> diff --git a/drivers/net/ethernet/sfc/tx.h b/drivers/net/ethernet/sfc/tx.h index 1cccc97ec676..e04d5ddeb32c 100644 --- a/drivers/net/ethernet/sfc/tx.h +++ b/drivers/net/ethernet/sfc/tx.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2006-2015 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EFX_TX_H diff --git a/drivers/net/ethernet/sfc/tx_tso.c b/drivers/net/ethernet/sfc/tx_tso.c index e0cbda9ae859..898e5c61d908 100644 --- a/drivers/net/ethernet/sfc/tx_tso.c +++ b/drivers/net/ethernet/sfc/tx_tso.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. * Copyright 2005-2015 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/pci.h> diff --git a/drivers/net/ethernet/sfc/vfdi.h b/drivers/net/ethernet/sfc/vfdi.h index f62901d4cae0..480b872eb4d1 100644 --- a/drivers/net/ethernet/sfc/vfdi.h +++ b/drivers/net/ethernet/sfc/vfdi.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2010-2012 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef _VFDI_H #define _VFDI_H diff --git a/drivers/net/ethernet/sfc/workarounds.h b/drivers/net/ethernet/sfc/workarounds.h index c67fa18b8121..815be2d20c4b 100644 --- a/drivers/net/ethernet/sfc/workarounds.h +++ b/drivers/net/ethernet/sfc/workarounds.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2006-2013 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #ifndef EFX_WORKAROUNDS_H diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c index 67f9bb6e941b..9b036c857b1d 100644 --- a/drivers/net/ethernet/sis/sis900.c +++ b/drivers/net/ethernet/sis/sis900.c @@ -1057,7 +1057,7 @@ sis900_open(struct net_device *net_dev) sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED); /* Enable all known interrupts by setting the interrupt mask. */ - sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE); + sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC); sw32(cr, RxENA | sr32(cr)); sw32(ier, IE); @@ -1578,7 +1578,7 @@ static void sis900_tx_timeout(struct net_device *net_dev) sw32(txdp, sis_priv->tx_ring_dma); /* Enable all known interrupts by setting the interrupt mask. */ - sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE); + sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC); } /** @@ -1618,7 +1618,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) spin_unlock_irqrestore(&sis_priv->lock, flags); return NETDEV_TX_OK; } - sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len); + sis_priv->tx_ring[entry].cmdsts = (OWN | INTR | skb->len); sw32(cr, TxENA | sr32(cr)); sis_priv->cur_tx ++; @@ -1674,7 +1674,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance) do { status = sr32(isr); - if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0) + if ((status & (HIBERR|TxURN|TxERR|TxIDLE|TxDESC|RxORN|RxERR|RxOK)) == 0) /* nothing intresting happened */ break; handled = 1; @@ -1684,7 +1684,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance) /* Rx interrupt */ sis900_rx(net_dev); - if (status & (TxURN | TxERR | TxIDLE)) + if (status & (TxURN | TxERR | TxIDLE | TxDESC)) /* Tx interrupt */ sis900_finish_xmit(net_dev); @@ -1896,8 +1896,8 @@ static void sis900_finish_xmit (struct net_device *net_dev) if (tx_status & OWN) { /* The packet is not transmitted yet (owned by hardware) ! - * Note: the interrupt is generated only when Tx Machine - * is idle, so this is an almost impossible case */ + * Note: this is an almost impossible condition + * in case of TxDESC ('descriptor interrupt') */ break; } @@ -2473,7 +2473,7 @@ static int sis900_resume(struct pci_dev *pci_dev) sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED); /* Enable all known interrupts by setting the interrupt mask. */ - sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE); + sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC); sw32(cr, RxENA | sr32(cr)); sw32(ier, IE); diff --git a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c index 8b50afcdb52d..cd478d2cd871 100644 --- a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c +++ b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Copyright Altera Corporation (C) 2016. All rights reserved. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * * Author: Tien Hock Loh <thloh@altera.com> */ diff --git a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h index 2f5882450b06..442812c0a4bd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h +++ b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright Altera Corporation (C) 2016. All rights reserved. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * * Author: Tien Hock Loh <thloh@altera.com> */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index d466e33635b0..8bdbddeec117 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Copyright Altera Corporation (C) 2014. All rights reserved. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * * Adopted from dwmac-sti.c */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c index 2dcdf761d525..020159622559 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c @@ -112,7 +112,7 @@ static int adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec, * programmed with (2^32 – <new_sec_value>) */ if (gmac4) - sec = (100000000ULL - sec); + sec = -sec; value = readl(ioaddr + PTP_TCR); if (value & PTP_TCR_TSCTRLSSR) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 06dd51f47cfd..06358fe5b245 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2947,12 +2947,15 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) /* Manage tx mitigation */ tx_q->tx_count_frames += nfrags + 1; - if (priv->tx_coal_frames <= tx_q->tx_count_frames) { + if (likely(priv->tx_coal_frames > tx_q->tx_count_frames) && + !(priv->synopsys_id >= DWMAC_CORE_4_00 && + (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && + priv->hwts_tx_en)) { + stmmac_tx_timer_arm(priv, queue); + } else { + tx_q->tx_count_frames = 0; stmmac_set_tx_ic(priv, desc); priv->xstats.tx_set_ic_bit++; - tx_q->tx_count_frames = 0; - } else { - stmmac_tx_timer_arm(priv, queue); } skb_tx_timestamp(skb); @@ -3166,12 +3169,15 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) * element in case of no SG. */ tx_q->tx_count_frames += nfrags + 1; - if (priv->tx_coal_frames <= tx_q->tx_count_frames) { + if (likely(priv->tx_coal_frames > tx_q->tx_count_frames) && + !(priv->synopsys_id >= DWMAC_CORE_4_00 && + (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && + priv->hwts_tx_en)) { + stmmac_tx_timer_arm(priv, queue); + } else { + tx_q->tx_count_frames = 0; stmmac_set_tx_ic(priv, desc); priv->xstats.tx_set_ic_bit++; - tx_q->tx_count_frames = 0; - } else { - stmmac_tx_timer_arm(priv, queue); } skb_tx_timestamp(skb); diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 98d1a45c0606..cb2ea8facd8d 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * GENEVE: Generic Network Virtualization Encapsulation * * Copyright (c) 2015 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -395,7 +392,7 @@ static int geneve_udp_encap_err_lookup(struct sock *sk, struct sk_buff *skb) u8 zero_vni[3] = { 0 }; u8 *vni = zero_vni; - if (skb->len < GENEVE_BASE_HLEN) + if (!pskb_may_pull(skb, skb_transport_offset(skb) + GENEVE_BASE_HLEN)) return -EINVAL; geneveh = geneve_hdr(skb); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 03ea5a7ed3a4..afdcc5664ea6 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -2407,7 +2407,7 @@ static struct hv_driver netvsc_drv = { .probe = netvsc_probe, .remove = netvsc_remove, .driver = { - .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .probe_type = PROBE_FORCE_SYNCHRONOUS, }, }; diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index 077364cbf439..5e72cc55afbd 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * mdio.c: Generic support for MDIO-compatible transceivers * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. */ #include <linux/kernel.h> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index f99f27800fdb..1d406c6df790 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -254,7 +254,7 @@ config AQUANTIA_PHY ---help--- Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405 -config ASIX_PHY +config AX88796B_PHY tristate "Asix PHYs" help Currently supports the Asix Electronics PHY found in the X-Surf 100 diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 27d7f9f3b0de..5b5c8669499e 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -52,7 +52,7 @@ ifdef CONFIG_HWMON aquantia-objs += aquantia_hwmon.o endif obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o -obj-$(CONFIG_ASIX_PHY) += asix.o +obj-$(CONFIG_AX88796B_PHY) += ax88796b.o obj-$(CONFIG_AT803X_PHY) += at803x.o obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o diff --git a/drivers/net/phy/asix.c b/drivers/net/phy/ax88796b.c index 79bf7ef1fcfd..79bf7ef1fcfd 100644 --- a/drivers/net/phy/asix.c +++ b/drivers/net/phy/ax88796b.c diff --git a/drivers/net/ppp/Kconfig b/drivers/net/ppp/Kconfig index bf395df3bb37..1a2e2f7629f3 100644 --- a/drivers/net/ppp/Kconfig +++ b/drivers/net/ppp/Kconfig @@ -87,8 +87,7 @@ config PPP_MPPE depends on PPP select CRYPTO select CRYPTO_SHA1 - select CRYPTO_ARC4 - select CRYPTO_ECB + select CRYPTO_LIB_ARC4 ---help--- Support for the MPPE Encryption protocol, as employed by the Microsoft Point-to-Point Tunneling Protocol. diff --git a/drivers/net/ppp/ppp_deflate.c b/drivers/net/ppp/ppp_deflate.c index 685e875f5164..c457f849e553 100644 --- a/drivers/net/ppp/ppp_deflate.c +++ b/drivers/net/ppp/ppp_deflate.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ppp_deflate.c - interface the zlib procedures for Deflate compression * and decompression (as used by gzip) to the PPP code. * * Copyright 1994-1998 Paul Mackerras. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c index ff61dd8748de..bd3c80b0bc77 100644 --- a/drivers/net/ppp/ppp_mppe.c +++ b/drivers/net/ppp/ppp_mppe.c @@ -42,9 +42,10 @@ * deprecated in 2.6 */ +#include <crypto/arc4.h> #include <crypto/hash.h> -#include <crypto/skcipher.h> #include <linux/err.h> +#include <linux/fips.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -63,15 +64,9 @@ MODULE_AUTHOR("Frank Cusack <fcusack@fcusack.com>"); MODULE_DESCRIPTION("Point-to-Point Protocol Microsoft Point-to-Point Encryption support"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE)); +MODULE_SOFTDEP("pre: arc4"); MODULE_VERSION("1.0.2"); -static unsigned int -setup_sg(struct scatterlist *sg, const void *address, unsigned int length) -{ - sg_set_buf(sg, address, length); - return length; -} - #define SHA1_PAD_SIZE 40 /* @@ -95,7 +90,7 @@ static inline void sha_pad_init(struct sha_pad *shapad) * State for an MPPE (de)compressor. */ struct ppp_mppe_state { - struct crypto_sync_skcipher *arc4; + struct arc4_ctx arc4; struct shash_desc *sha1; unsigned char *sha1_digest; unsigned char master_key[MPPE_MAX_KEY_LEN]; @@ -154,24 +149,11 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state) */ static void mppe_rekey(struct ppp_mppe_state * state, int initial_key) { - struct scatterlist sg_in[1], sg_out[1]; - SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4); - - skcipher_request_set_sync_tfm(req, state->arc4); - skcipher_request_set_callback(req, 0, NULL, NULL); - get_new_key_from_sha(state); if (!initial_key) { - crypto_sync_skcipher_setkey(state->arc4, state->sha1_digest, - state->keylen); - sg_init_table(sg_in, 1); - sg_init_table(sg_out, 1); - setup_sg(sg_in, state->sha1_digest, state->keylen); - setup_sg(sg_out, state->session_key, state->keylen); - skcipher_request_set_crypt(req, sg_in, sg_out, state->keylen, - NULL); - if (crypto_skcipher_encrypt(req)) - printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n"); + arc4_setkey(&state->arc4, state->sha1_digest, state->keylen); + arc4_crypt(&state->arc4, state->session_key, state->sha1_digest, + state->keylen); } else { memcpy(state->session_key, state->sha1_digest, state->keylen); } @@ -181,9 +163,7 @@ static void mppe_rekey(struct ppp_mppe_state * state, int initial_key) state->session_key[1] = 0x26; state->session_key[2] = 0x9e; } - crypto_sync_skcipher_setkey(state->arc4, state->session_key, - state->keylen); - skcipher_request_zero(req); + arc4_setkey(&state->arc4, state->session_key, state->keylen); } /* @@ -196,7 +176,8 @@ static void *mppe_alloc(unsigned char *options, int optlen) unsigned int digestsize; if (optlen != CILEN_MPPE + sizeof(state->master_key) || - options[0] != CI_MPPE || options[1] != CILEN_MPPE) + options[0] != CI_MPPE || options[1] != CILEN_MPPE || + fips_enabled) goto out; state = kzalloc(sizeof(*state), GFP_KERNEL); @@ -204,12 +185,6 @@ static void *mppe_alloc(unsigned char *options, int optlen) goto out; - state->arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0); - if (IS_ERR(state->arc4)) { - state->arc4 = NULL; - goto out_free; - } - shash = crypto_alloc_shash("sha1", 0, 0); if (IS_ERR(shash)) goto out_free; @@ -250,7 +225,6 @@ out_free: crypto_free_shash(state->sha1->tfm); kzfree(state->sha1); } - crypto_free_sync_skcipher(state->arc4); kfree(state); out: return NULL; @@ -266,8 +240,7 @@ static void mppe_free(void *arg) kfree(state->sha1_digest); crypto_free_shash(state->sha1->tfm); kzfree(state->sha1); - crypto_free_sync_skcipher(state->arc4); - kfree(state); + kzfree(state); } } @@ -366,10 +339,7 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf, int isize, int osize) { struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; - SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4); int proto; - int err; - struct scatterlist sg_in[1], sg_out[1]; /* * Check that the protocol is in the range we handle. @@ -420,21 +390,7 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf, ibuf += 2; /* skip to proto field */ isize -= 2; - /* Encrypt packet */ - sg_init_table(sg_in, 1); - sg_init_table(sg_out, 1); - setup_sg(sg_in, ibuf, isize); - setup_sg(sg_out, obuf, osize); - - skcipher_request_set_sync_tfm(req, state->arc4); - skcipher_request_set_callback(req, 0, NULL, NULL); - skcipher_request_set_crypt(req, sg_in, sg_out, isize, NULL); - err = crypto_skcipher_encrypt(req); - skcipher_request_zero(req); - if (err) { - printk(KERN_DEBUG "crypto_cypher_encrypt failed\n"); - return -1; - } + arc4_crypt(&state->arc4, obuf, ibuf, isize); state->stats.unc_bytes += isize; state->stats.unc_packets++; @@ -480,10 +436,8 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf, int osize) { struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; - SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4); unsigned ccount; int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED; - struct scatterlist sg_in[1], sg_out[1]; if (isize <= PPP_HDRLEN + MPPE_OVHD) { if (state->debug) @@ -610,19 +564,7 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf, * Decrypt the first byte in order to check if it is * a compressed or uncompressed protocol field. */ - sg_init_table(sg_in, 1); - sg_init_table(sg_out, 1); - setup_sg(sg_in, ibuf, 1); - setup_sg(sg_out, obuf, 1); - - skcipher_request_set_sync_tfm(req, state->arc4); - skcipher_request_set_callback(req, 0, NULL, NULL); - skcipher_request_set_crypt(req, sg_in, sg_out, 1, NULL); - if (crypto_skcipher_decrypt(req)) { - printk(KERN_DEBUG "crypto_cypher_decrypt failed\n"); - osize = DECOMP_ERROR; - goto out_zap_req; - } + arc4_crypt(&state->arc4, obuf, ibuf, 1); /* * Do PFC decompression. @@ -637,14 +579,7 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf, } /* And finally, decrypt the rest of the packet. */ - setup_sg(sg_in, ibuf + 1, isize - 1); - setup_sg(sg_out, obuf + 1, osize - 1); - skcipher_request_set_crypt(req, sg_in, sg_out, isize - 1, NULL); - if (crypto_skcipher_decrypt(req)) { - printk(KERN_DEBUG "crypto_cypher_decrypt failed\n"); - osize = DECOMP_ERROR; - goto out_zap_req; - } + arc4_crypt(&state->arc4, obuf + 1, ibuf + 1, isize - 1); state->stats.unc_bytes += osize; state->stats.unc_packets++; @@ -654,8 +589,6 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf, /* good packet credit */ state->sanity_errors >>= 1; -out_zap_req: - skcipher_request_zero(req); return osize; sanity_error: @@ -728,8 +661,7 @@ static struct compressor ppp_mppe = { static int __init ppp_mppe_init(void) { int answer; - if (!(crypto_has_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC) && - crypto_has_ahash("sha1", 0, CRYPTO_ALG_ASYNC))) + if (fips_enabled || !crypto_has_ahash("sha1", 0, CRYPTO_ALG_ASYNC)) return -ENODEV; sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL); diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index b48006e7fa2f..36916bf51ee6 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -2128,12 +2128,12 @@ static void team_setup(struct net_device *dev) dev->features |= NETIF_F_NETNS_LOCAL; dev->hw_features = TEAM_VLAN_FEATURES | - NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER; dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4; dev->features |= dev->hw_features; + dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; } static int team_newlink(struct net *src_net, struct net_device *dev, diff --git a/drivers/net/tun.c b/drivers/net/tun.c index c452d6d831dd..d7c55e0fa8f4 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1014,18 +1014,8 @@ static void tun_net_uninit(struct net_device *dev) /* Net device open. */ static int tun_net_open(struct net_device *dev) { - struct tun_struct *tun = netdev_priv(dev); - int i; - netif_tx_start_all_queues(dev); - for (i = 0; i < tun->numqueues; i++) { - struct tun_file *tfile; - - tfile = rtnl_dereference(tun->tfiles[i]); - tfile->socket.sk->sk_write_space(tfile->socket.sk); - } - return 0; } @@ -3634,6 +3624,7 @@ static int tun_device_event(struct notifier_block *unused, { struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct tun_struct *tun = netdev_priv(dev); + int i; if (dev->rtnl_link_ops != &tun_link_ops) return NOTIFY_DONE; @@ -3643,6 +3634,14 @@ static int tun_device_event(struct notifier_block *unused, if (tun_queue_resize(tun)) return NOTIFY_BAD; break; + case NETDEV_UP: + for (i = 0; i < tun->numqueues; i++) { + struct tun_file *tfile; + + tfile = rtnl_dereference(tun->tfiles[i]); + tfile->socket.sk->sk_write_space(tfile->socket.sk); + } + break; default: break; } diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index 28321aca48fe..eb100eb33de3 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012 Smith Micro Software, Inc. * Copyright (c) 2012 Bjørn Mork <bjorn@mork.no> * * This driver is based on and reuse most of cdc_ncm, which is * Copyright (C) ST-Ericsson 2010-2012 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/net/usb/huawei_cdc_ncm.c b/drivers/net/usb/huawei_cdc_ncm.c index 63f28908afda..e15a472c6a54 100644 --- a/drivers/net/usb/huawei_cdc_ncm.c +++ b/drivers/net/usb/huawei_cdc_ncm.c @@ -1,8 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* huawei_cdc_ncm.c - handles Huawei devices using the CDC NCM protocol as * transport layer. * Copyright (C) 2013 Enrico Mioso <mrkiko.rs@gmail.com> * - * * ABSTRACT: * This driver handles devices resembling the CDC NCM standard, but * encapsulating another protocol inside it. An example are some Huawei 3G @@ -11,10 +11,6 @@ * This code has been heavily inspired by the cdc_mbim.c driver, which is * Copyright (c) 2012 Smith Micro Software, Inc. * Copyright (c) 2012 Bjørn Mork <bjorn@mork.no> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 63e44e746ccc..6d25dea5ad4b 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.com) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * ChangeLog: * .... Most of the time spent on reading sources & docs. * v0.2.x First official release for the Linux kernel. diff --git a/drivers/net/usb/pegasus.h b/drivers/net/usb/pegasus.h index 9b7ea9c9167d..a05b143155ba 100644 --- a/drivers/net/usb/pegasus.h +++ b/drivers/net/usb/pegasus.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index d9a6699abe59..8b4ad10cf940 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012 Bjørn Mork <bjorn@mork.no> * * The probing code is heavily inspired by cdc_ether, which is: * Copyright (C) 2003-2005 by David Brownell * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #include <linux/module.h> @@ -22,6 +19,7 @@ #include <linux/usb/cdc.h> #include <linux/usb/usbnet.h> #include <linux/usb/cdc-wdm.h> +#include <linux/u64_stats_sync.h> /* This driver supports wwan (3G/LTE/?) devices using a vendor * specific management protocol called Qualcomm MSM Interface (QMI) - @@ -75,6 +73,7 @@ struct qmimux_hdr { struct qmimux_priv { struct net_device *real_dev; u8 mux_id; + struct pcpu_sw_netstats __percpu *stats64; }; static int qmimux_open(struct net_device *dev) @@ -101,19 +100,65 @@ static netdev_tx_t qmimux_start_xmit(struct sk_buff *skb, struct net_device *dev struct qmimux_priv *priv = netdev_priv(dev); unsigned int len = skb->len; struct qmimux_hdr *hdr; + netdev_tx_t ret; hdr = skb_push(skb, sizeof(struct qmimux_hdr)); hdr->pad = 0; hdr->mux_id = priv->mux_id; hdr->pkt_len = cpu_to_be16(len); skb->dev = priv->real_dev; - return dev_queue_xmit(skb); + ret = dev_queue_xmit(skb); + + if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { + struct pcpu_sw_netstats *stats64 = this_cpu_ptr(priv->stats64); + + u64_stats_update_begin(&stats64->syncp); + stats64->tx_packets++; + stats64->tx_bytes += len; + u64_stats_update_end(&stats64->syncp); + } else { + dev->stats.tx_dropped++; + } + + return ret; +} + +static void qmimux_get_stats64(struct net_device *net, + struct rtnl_link_stats64 *stats) +{ + struct qmimux_priv *priv = netdev_priv(net); + unsigned int start; + int cpu; + + netdev_stats_to_stats64(stats, &net->stats); + + for_each_possible_cpu(cpu) { + struct pcpu_sw_netstats *stats64; + u64 rx_packets, rx_bytes; + u64 tx_packets, tx_bytes; + + stats64 = per_cpu_ptr(priv->stats64, cpu); + + do { + start = u64_stats_fetch_begin_irq(&stats64->syncp); + rx_packets = stats64->rx_packets; + rx_bytes = stats64->rx_bytes; + tx_packets = stats64->tx_packets; + tx_bytes = stats64->tx_bytes; + } while (u64_stats_fetch_retry_irq(&stats64->syncp, start)); + + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; + stats->tx_packets += tx_packets; + stats->tx_bytes += tx_bytes; + } } static const struct net_device_ops qmimux_netdev_ops = { - .ndo_open = qmimux_open, - .ndo_stop = qmimux_stop, - .ndo_start_xmit = qmimux_start_xmit, + .ndo_open = qmimux_open, + .ndo_stop = qmimux_stop, + .ndo_start_xmit = qmimux_start_xmit, + .ndo_get_stats64 = qmimux_get_stats64, }; static void qmimux_setup(struct net_device *dev) @@ -153,7 +198,7 @@ static bool qmimux_has_slaves(struct usbnet *dev) static int qmimux_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { - unsigned int len, offset = 0; + unsigned int len, offset = 0, pad_len, pkt_len; struct qmimux_hdr *hdr; struct net_device *net; struct sk_buff *skbn; @@ -171,10 +216,16 @@ static int qmimux_rx_fixup(struct usbnet *dev, struct sk_buff *skb) if (hdr->pad & 0x80) goto skip; + /* extract padding length and check for valid length info */ + pad_len = hdr->pad & 0x3f; + if (len == 0 || pad_len >= len) + goto skip; + pkt_len = len - pad_len; + net = qmimux_find_dev(dev, hdr->mux_id); if (!net) goto skip; - skbn = netdev_alloc_skb(net, len); + skbn = netdev_alloc_skb(net, pkt_len); if (!skbn) return 0; skbn->dev = net; @@ -191,9 +242,20 @@ static int qmimux_rx_fixup(struct usbnet *dev, struct sk_buff *skb) goto skip; } - skb_put_data(skbn, skb->data + offset + qmimux_hdr_sz, len); - if (netif_rx(skbn) != NET_RX_SUCCESS) + skb_put_data(skbn, skb->data + offset + qmimux_hdr_sz, pkt_len); + if (netif_rx(skbn) != NET_RX_SUCCESS) { + net->stats.rx_errors++; return 0; + } else { + struct pcpu_sw_netstats *stats64; + struct qmimux_priv *priv = netdev_priv(net); + + stats64 = this_cpu_ptr(priv->stats64); + u64_stats_update_begin(&stats64->syncp); + stats64->rx_packets++; + stats64->rx_bytes += pkt_len; + u64_stats_update_end(&stats64->syncp); + } skip: offset += len + qmimux_hdr_sz; @@ -217,6 +279,12 @@ static int qmimux_register_device(struct net_device *real_dev, u8 mux_id) priv->mux_id = mux_id; priv->real_dev = real_dev; + priv->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); + if (!priv->stats64) { + err = -ENOBUFS; + goto out_free_newdev; + } + err = register_netdevice(new_dev); if (err < 0) goto out_free_newdev; @@ -241,13 +309,15 @@ out_free_newdev: return err; } -static void qmimux_unregister_device(struct net_device *dev) +static void qmimux_unregister_device(struct net_device *dev, + struct list_head *head) { struct qmimux_priv *priv = netdev_priv(dev); struct net_device *real_dev = priv->real_dev; + free_percpu(priv->stats64); netdev_upper_dev_unlink(real_dev, dev); - unregister_netdevice(dev); + unregister_netdevice_queue(dev, head); /* Get rid of the reference to real_dev */ dev_put(real_dev); @@ -356,8 +426,8 @@ static ssize_t add_mux_store(struct device *d, struct device_attribute *attr, c if (kstrtou8(buf, 0, &mux_id)) return -EINVAL; - /* mux_id [1 - 0x7f] range empirically found */ - if (mux_id < 1 || mux_id > 0x7f) + /* mux_id [1 - 254] for compatibility with ip(8) and the rmnet driver */ + if (mux_id < 1 || mux_id > 254) return -EINVAL; if (!rtnl_trylock()) @@ -418,7 +488,7 @@ static ssize_t del_mux_store(struct device *d, struct device_attribute *attr, c ret = -EINVAL; goto err; } - qmimux_unregister_device(del_dev); + qmimux_unregister_device(del_dev, NULL); if (!qmimux_has_slaves(dev)) info->flags &= ~QMI_WWAN_FLAG_MUX; @@ -1412,7 +1482,7 @@ static int qmi_wwan_probe(struct usb_interface *intf, * different. Ignore the current interface if the number of endpoints * equals the number for the diag interface (two). */ - info = (void *)&id->driver_info; + info = (void *)id->driver_info; if (info->data & QMI_WWAN_QUIRK_QUECTEL_DYNCFG) { if (desc->bNumEndpoints == 2) @@ -1428,6 +1498,7 @@ static void qmi_wwan_disconnect(struct usb_interface *intf) struct qmi_wwan_state *info; struct list_head *iter; struct net_device *ldev; + LIST_HEAD(list); /* called twice if separate control and data intf */ if (!dev) @@ -1440,8 +1511,9 @@ static void qmi_wwan_disconnect(struct usb_interface *intf) } rcu_read_lock(); netdev_for_each_upper_dev_rcu(dev->net, ldev, iter) - qmimux_unregister_device(ldev); + qmimux_unregister_device(ldev, &list); rcu_read_unlock(); + unregister_netdevice_many(&list); rtnl_unlock(); info->flags &= ~QMI_WWAN_FLAG_MUX; } diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index b01bfa63860d..e0dcb681cfe5 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1,10 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 Realtek Semiconductor Corp. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * */ #include <linux/signal.h> diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 59dbdbb5feff..98f33e270af1 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #include <linux/signal.h> diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h index 258b030277e7..ea2b4de621c8 100644 --- a/drivers/net/usb/sr9700.h +++ b/drivers/net/usb/sr9700.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices * * Author : Liu Junliang <liujunliang_ljl@163.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #ifndef _SR9700_H diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 11b9525dff27..311b0cc6eb98 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -350,8 +350,8 @@ static int vrf_finish_output6(struct net *net, struct sock *sk, { struct dst_entry *dst = skb_dst(skb); struct net_device *dev = dst->dev; + const struct in6_addr *nexthop; struct neighbour *neigh; - struct in6_addr *nexthop; int ret; nf_reset(skb); diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 5994d5415a03..083f3f0bf37f 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * VXLAN: Virtual eXtensible Local Area Network * * Copyright (c) 2012-2013 Vyatta Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -1766,7 +1763,7 @@ static int vxlan_err_lookup(struct sock *sk, struct sk_buff *skb) struct vxlanhdr *hdr; __be32 vni; - if (skb->len < VXLAN_HLEN) + if (!pskb_may_pull(skb, skb_transport_offset(skb) + VXLAN_HLEN)) return -EINVAL; hdr = vxlan_hdr(skb); diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c index 3b0802fc5bf5..46f1427e6e9e 100644 --- a/drivers/net/wireless/admtek/adm8211.c +++ b/drivers/net/wireless/admtek/adm8211.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Linux device driver for ADMtek ADM8211 (IEEE 802.11b MAC/BBP) @@ -8,11 +9,6 @@ * and used with permission. * * Much thanks to Infineon-ADMtek for their support of this driver. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. */ #include <linux/interrupt.h> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 22b73da42822..9a51f1ba87c3 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -678,6 +678,12 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on) brcmf_dbg(TRACE, "Enter: on=%d\n", on); + sdio_retune_crc_disable(bus->sdiodev->func1); + + /* Cannot re-tune if device is asleep; defer till we're awake */ + if (on) + sdio_retune_hold_now(bus->sdiodev->func1); + wr_val = (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); /* 1st KSO write goes to AOS wake up core if device is asleep */ brcmf_sdiod_writeb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); @@ -738,6 +744,11 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on) if (try_cnt > MAX_KSO_ATTEMPTS) brcmf_err("max tries: rd_val=0x%x err=%d\n", rd_val, err); + if (on) + sdio_retune_release(bus->sdiodev->func1); + + sdio_retune_crc_enable(bus->sdiodev->func1); + return err; } @@ -3375,11 +3386,7 @@ err: static bool brcmf_sdio_aos_no_decode(struct brcmf_sdio *bus) { - if (bus->ci->chip == CY_CC_43012_CHIP_ID || - bus->ci->chip == CY_CC_4373_CHIP_ID || - bus->ci->chip == BRCM_CC_4339_CHIP_ID || - bus->ci->chip == BRCM_CC_4345_CHIP_ID || - bus->ci->chip == BRCM_CC_4354_CHIP_ID) + if (bus->ci->chip == CY_CC_43012_CHIP_ID) return true; else return false; diff --git a/drivers/net/wireless/intel/ipw2x00/ipw.h b/drivers/net/wireless/intel/ipw2x00/ipw.h index 4007bf5ed6f3..7b230a132daa 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw.h +++ b/drivers/net/wireless/intel/ipw2x00/ipw.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Intel Pro/Wireless 2100, 2200BG, 2915ABG network connection driver * * Copyright 2012 Stanislav Yakovlev <stas.yakovlev@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __IPW_H__ diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index 52e5ed2d3bc2..75c0c29d81f0 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -1,22 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. Contact Information: Intel Linux Wireless <ilw@linux.intel.com> diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.h b/drivers/net/wireless/intel/ipw2x00/ipw2100.h index 8c11c7fa2eef..b34085ade3aa 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.h +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.h @@ -1,22 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /****************************************************************************** Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. Contact Information: Intel Linux Wireless <ilw@linux.intel.com> diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index fa400f92d7e2..fa55d2ccbfab 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. @@ -8,21 +9,6 @@ By Gerald Combs <gerald@ethereal.com> Copyright 1998 Gerald Combs - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. Contact Information: Intel Linux Wireless <ilw@linux.intel.com> diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.h b/drivers/net/wireless/intel/ipw2x00/ipw2200.h index f98ab1f71edd..4346520545c4 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.h +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.h @@ -1,22 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /****************************************************************************** Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. Contact Information: Intel Linux Wireless <ilw@linux.intel.com> diff --git a/drivers/net/wireless/intel/ipw2x00/libipw.h b/drivers/net/wireless/intel/ipw2x00/libipw.h index b51355134e04..e4a6ab4e8391 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw.h +++ b/drivers/net/wireless/intel/ipw2x00/libipw.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 * remains copyright by the original authors @@ -13,11 +14,6 @@ * <jketreno@linux.intel.com> * Copyright (c) 2004-2005, Intel Corporation * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. - * * API Version History * 1.0.x -- Initial version * 1.1.x -- Added radiotap, QoS, TIM, libipw_geo APIs, diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_geo.c b/drivers/net/wireless/intel/ipw2x00/libipw_geo.c index ce7eda20a68f..f2ae3f8f2f5c 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_geo.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_geo.c @@ -1,22 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** Copyright(c) 2005 Intel Corporation. All rights reserved. - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. Contact Information: Intel Linux Wireless <ilw@linux.intel.com> diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_module.c b/drivers/net/wireless/intel/ipw2x00/libipw_module.c index f00d45f54c76..436b819aeb36 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_module.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /******************************************************************************* Copyright(c) 2004-2005 Intel Corporation. All rights reserved. @@ -8,21 +9,6 @@ <j@w1.fi> Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. Contact Information: Intel Linux Wireless <ilw@linux.intel.com> diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c index 6df19f03355a..34cfd8162855 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Original code based Host AP (software wireless LAN access point) driver * for Intersil Prism2/2.5/3 - hostap.o module, common routines @@ -6,11 +7,6 @@ * <j@w1.fi> * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> * Copyright (c) 2004-2005, Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. */ #include <linux/compiler.h> diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c index 84205aa508df..d9baa2fa603b 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c @@ -1,22 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved. - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. Contact Information: Intel Linux Wireless <ilw@linux.intel.com> diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c b/drivers/net/wireless/intel/ipw2x00/libipw_wx.c index d32d39fa2686..3d558b47168b 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_wx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** Copyright(c) 2004-2005 Intel Corporation. All rights reserved. @@ -8,21 +9,6 @@ <j@w1.fi> Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. Contact Information: Intel Linux Wireless <ilw@linux.intel.com> diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 5f52e40a2903..33d7bc5500db 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2747,3 +2747,42 @@ void iwl_fw_dbg_periodic_trig_handler(struct timer_list *t) jiffies + msecs_to_jiffies(collect_interval)); } } + +#define FSEQ_REG(x) { .addr = (x), .str = #x, } + +void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt) +{ + struct iwl_trans *trans = fwrt->trans; + unsigned long flags; + int i; + struct { + u32 addr; + const char *str; + } fseq_regs[] = { + FSEQ_REG(FSEQ_ERROR_CODE), + FSEQ_REG(FSEQ_TOP_INIT_VERSION), + FSEQ_REG(FSEQ_CNVIO_INIT_VERSION), + FSEQ_REG(FSEQ_OTP_VERSION), + FSEQ_REG(FSEQ_TOP_CONTENT_VERSION), + FSEQ_REG(FSEQ_ALIVE_TOKEN), + FSEQ_REG(FSEQ_CNVI_ID), + FSEQ_REG(FSEQ_CNVR_ID), + FSEQ_REG(CNVI_AUX_MISC_CHIP), + FSEQ_REG(CNVR_AUX_MISC_CHIP), + FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM), + FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR), + }; + + if (!iwl_trans_grab_nic_access(trans, &flags)) + return; + + IWL_ERR(fwrt, "Fseq Registers:\n"); + + for (i = 0; i < ARRAY_SIZE(fseq_regs); i++) + IWL_ERR(fwrt, "0x%08X | %s\n", + iwl_read_prph_no_grab(trans, fseq_regs[i].addr), + fseq_regs[i].str); + + iwl_trans_release_nic_access(trans, &flags); +} +IWL_EXPORT_SYMBOL(iwl_fw_error_print_fseq_regs); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 2a9e560a906b..fd0ad220e961 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -471,4 +471,6 @@ static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt) } void iwl_fw_dbg_periodic_trig_handler(struct timer_list *t); + +void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt); #endif /* __iwl_fw_dbg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 852d3cbfc719..fba242284507 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1597,7 +1597,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) goto free; out_free_fw: - iwl_dealloc_ucode(drv); release_firmware(ucode_raw); out_unbind: complete(&drv->request_firmware_complete); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 8e6a0c363c0d..8d930bfe0727 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -395,7 +395,11 @@ enum { WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK = 0x80000000, }; -#define AUX_MISC_REG 0xA200B0 +#define CNVI_AUX_MISC_CHIP 0xA200B0 +#define CNVR_AUX_MISC_CHIP 0xA2B800 +#define CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM 0xA29890 +#define CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR 0xA29938 + enum { HW_STEP_LOCATION_BITS = 24, }; @@ -408,7 +412,12 @@ enum aux_misc_master1_en { #define AUX_MISC_MASTER1_SMPHR_STATUS 0xA20800 #define RSA_ENABLE 0xA24B08 #define PREG_AUX_BUS_WPROT_0 0xA04CC0 -#define PREG_PRPH_WPROT_0 0xA04CE0 + +/* device family 9000 WPROT register */ +#define PREG_PRPH_WPROT_9000 0xA04CE0 +/* device family 22000 WPROT register */ +#define PREG_PRPH_WPROT_22000 0xA04D00 + #define SB_CPU_1_STATUS 0xA01E30 #define SB_CPU_2_STATUS 0xA01E34 #define UMAG_SB_CPU_1_STATUS 0xA038C0 @@ -442,4 +451,13 @@ enum { #define UREG_DOORBELL_TO_ISR6 0xA05C04 #define UREG_DOORBELL_TO_ISR6_NMI_BIT BIT(0) + +#define FSEQ_ERROR_CODE 0xA340C8 +#define FSEQ_TOP_INIT_VERSION 0xA34038 +#define FSEQ_CNVIO_INIT_VERSION 0xA3403C +#define FSEQ_OTP_VERSION 0xA340FC +#define FSEQ_TOP_CONTENT_VERSION 0xA340F4 +#define FSEQ_ALIVE_TOKEN 0xA340F0 +#define FSEQ_CNVI_ID 0xA3408C +#define FSEQ_CNVR_ID 0xA34090 #endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 60f5d337f16d..e7e68fb2bd29 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1972,26 +1972,6 @@ out: } } -static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) -{ -#ifdef CONFIG_IWLWIFI_DEBUGFS - const struct fw_img *img = &mvm->fw->img[IWL_UCODE_WOWLAN]; - u32 len = img->sec[IWL_UCODE_SECTION_DATA].len; - u32 offs = img->sec[IWL_UCODE_SECTION_DATA].offset; - - if (!mvm->store_d3_resume_sram) - return; - - if (!mvm->d3_resume_sram) { - mvm->d3_resume_sram = kzalloc(len, GFP_KERNEL); - if (!mvm->d3_resume_sram) - return; - } - - iwl_trans_read_mem_bytes(mvm->trans, offs, mvm->d3_resume_sram, len); -#endif -} - static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -2054,8 +2034,6 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) } iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt); - /* query SRAM first in case we want event logging */ - iwl_mvm_read_d3_sram(mvm); if (iwl_mvm_check_rt_status(mvm, vif)) { set_bit(STATUS_FW_ERROR, &mvm->trans->status); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index d4ff6b44de2c..5b1bb76c5d28 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1557,59 +1557,6 @@ static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm, } #endif -#ifdef CONFIG_PM_SLEEP -static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) -{ - int store; - - if (sscanf(buf, "%d", &store) != 1) - return -EINVAL; - - mvm->store_d3_resume_sram = store; - - return count; -} - -static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm *mvm = file->private_data; - const struct fw_img *img; - int ofs, len, pos = 0; - size_t bufsz, ret; - char *buf; - u8 *ptr = mvm->d3_resume_sram; - - img = &mvm->fw->img[IWL_UCODE_WOWLAN]; - len = img->sec[IWL_UCODE_SECTION_DATA].len; - - bufsz = len * 4 + 256; - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - pos += scnprintf(buf, bufsz, "D3 SRAM capture: %sabled\n", - mvm->store_d3_resume_sram ? "en" : "dis"); - - if (ptr) { - for (ofs = 0; ofs < len; ofs += 16) { - pos += scnprintf(buf + pos, bufsz - pos, - "0x%.4x %16ph\n", ofs, ptr + ofs); - } - } else { - pos += scnprintf(buf + pos, bufsz - pos, - "(no data captured)\n"); - } - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - - kfree(buf); - - return ret; -} -#endif - #define PRINT_MVM_REF(ref) do { \ if (mvm->refs[ref]) \ pos += scnprintf(buf + pos, bufsz - pos, \ @@ -1940,9 +1887,6 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); #endif -#ifdef CONFIG_PM_SLEEP -MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); -#endif #ifdef CONFIG_ACPI MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile); #endif @@ -2159,7 +2103,6 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) #endif #ifdef CONFIG_PM_SLEEP - MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, 0600); MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, 0400); debugfs_create_bool("d3_wake_sysassert", 0600, mvm->debugfs_dir, &mvm->d3_wake_sysassert); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index fec38a47696e..9f4b117db9d7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -93,7 +93,7 @@ void iwl_mvm_ftm_restart(struct iwl_mvm *mvm) struct cfg80211_pmsr_result result = { .status = NL80211_PMSR_STATUS_FAILURE, .final = 1, - .host_time = ktime_get_boot_ns(), + .host_time = ktime_get_boottime_ns(), .type = NL80211_PMSR_TYPE_FTM, }; int i; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index ab68b5d53ec9..153717587aeb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -311,6 +311,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, int ret; enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img; static const u16 alive_cmd[] = { MVM_ALIVE }; + bool run_in_rfkill = + ucode_type == IWL_UCODE_INIT || iwl_mvm_has_unified_ucode(mvm); if (ucode_type == IWL_UCODE_REGULAR && iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) && @@ -328,7 +330,12 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, alive_cmd, ARRAY_SIZE(alive_cmd), iwl_alive_fn, &alive_data); - ret = iwl_trans_start_fw(mvm->trans, fw, ucode_type == IWL_UCODE_INIT); + /* + * We want to load the INIT firmware even in RFKILL + * For the unified firmware case, the ucode_type is not + * INIT, but we still need to run it. + */ + ret = iwl_trans_start_fw(mvm->trans, fw, run_in_rfkill); if (ret) { iwl_fw_set_current_image(&mvm->fwrt, old_type); iwl_remove_notification(&mvm->notif_wait, &alive_wait); @@ -433,7 +440,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) * commands */ ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(SYSTEM_GROUP, - INIT_EXTENDED_CFG_CMD), 0, + INIT_EXTENDED_CFG_CMD), + CMD_SEND_IN_RFKILL, sizeof(init_cfg), &init_cfg); if (ret) { IWL_ERR(mvm, "Failed to run init config command: %d\n", @@ -457,7 +465,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) } ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP, - NVM_ACCESS_COMPLETE), 0, + NVM_ACCESS_COMPLETE), + CMD_SEND_IN_RFKILL, sizeof(nvm_complete), &nvm_complete); if (ret) { IWL_ERR(mvm, "Failed to run complete NVM access: %d\n", @@ -482,6 +491,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) } } + mvm->rfkill_safe_init_done = true; + return 0; error: @@ -526,7 +537,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) lockdep_assert_held(&mvm->mutex); - if (WARN_ON_ONCE(mvm->calibrating)) + if (WARN_ON_ONCE(mvm->rfkill_safe_init_done)) return 0; iwl_init_notification_wait(&mvm->notif_wait, @@ -576,7 +587,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) goto remove_notif; } - mvm->calibrating = true; + mvm->rfkill_safe_init_done = true; /* Send TX valid antennas before triggering calibrations */ ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); @@ -612,7 +623,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) remove_notif: iwl_remove_notification(&mvm->notif_wait, &calib_wait); out: - mvm->calibrating = false; + mvm->rfkill_safe_init_done = false; if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) { /* we want to debug INIT and we have no NVM - fake */ mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 5c52469288be..fdbabca0280e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1209,7 +1209,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) mvm->scan_status = 0; mvm->ps_disabled = false; - mvm->calibrating = false; + mvm->rfkill_safe_init_done = false; /* just in case one was running */ iwl_mvm_cleanup_roc_te(mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 8dc2a9850bc5..02efcf2189c4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -880,7 +880,7 @@ struct iwl_mvm { struct iwl_mvm_vif *bf_allowed_vif; bool hw_registered; - bool calibrating; + bool rfkill_safe_init_done; bool support_umac_log; u32 ampdu_ref; @@ -1039,8 +1039,6 @@ struct iwl_mvm { #ifdef CONFIG_IWLWIFI_DEBUGFS bool d3_wake_sysassert; bool d3_test_active; - bool store_d3_resume_sram; - void *d3_resume_sram; u32 d3_test_pme_ptr; struct ieee80211_vif *keep_vif; u32 last_netdetect_scans; /* no. of scans in the last net-detect wake */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index acd2fda12466..fad3bf563712 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -918,9 +918,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) kfree(mvm->error_recovery_buf); mvm->error_recovery_buf = NULL; -#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS) - kfree(mvm->d3_resume_sram); -#endif iwl_trans_op_mode_leave(mvm->trans); iwl_phy_db_free(mvm->phy_db); @@ -1212,7 +1209,8 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - bool calibrating = READ_ONCE(mvm->calibrating); + bool rfkill_safe_init_done = READ_ONCE(mvm->rfkill_safe_init_done); + bool unified = iwl_mvm_has_unified_ucode(mvm); if (state) set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); @@ -1221,15 +1219,23 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) iwl_mvm_set_rfkill_state(mvm); - /* iwl_run_init_mvm_ucode is waiting for results, abort it */ - if (calibrating) + /* iwl_run_init_mvm_ucode is waiting for results, abort it. */ + if (rfkill_safe_init_done) iwl_abort_notification_waits(&mvm->notif_wait); /* + * Don't ask the transport to stop the firmware. We'll do it + * after cfg80211 takes us down. + */ + if (unified) + return false; + + /* * Stop the device if we run OPERATIONAL firmware or if we are in the * middle of the calibrations. */ - return state && (mvm->fwrt.cur_fw_img != IWL_UCODE_INIT || calibrating); + return state && (mvm->fwrt.cur_fw_img != IWL_UCODE_INIT || + rfkill_safe_init_done); } static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 659e21b2d4e7..be62f499c595 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -441,7 +441,8 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, */ sta->max_amsdu_len = max_amsdu_len; - ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cfg_cmd), &cfg_cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_ASYNC, sizeof(cfg_cmd), + &cfg_cmd); if (ret) IWL_ERR(mvm, "Failed to send rate scale config (%d)\n", ret); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index fbd3014e8b82..160b0db27103 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -555,7 +555,7 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, if (unlikely(ieee80211_is_beacon(hdr->frame_control) || ieee80211_is_probe_resp(hdr->frame_control))) - rx_status->boottime_ns = ktime_get_boot_ns(); + rx_status->boottime_ns = ktime_get_boottime_ns(); /* Take a reference briefly to kick off a d0i3 entry delay so * we can handle bursts of RX packets without toggling the diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 1824566d08fc..64f950501287 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1684,7 +1684,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, if (unlikely(ieee80211_is_beacon(hdr->frame_control) || ieee80211_is_probe_resp(hdr->frame_control))) - rx_status->boottime_ns = ktime_get_boot_ns(); + rx_status->boottime_ns = ktime_get_boottime_ns(); } if (iwl_mvm_create_skb(mvm, skb, hdr, len, crypt_len, rxb)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index b9914efc55c4..72cd5b3f2d8d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -596,6 +596,8 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) iwl_mvm_dump_lmac_error_log(mvm, 1); iwl_mvm_dump_umac_error_log(mvm); + + iwl_fw_error_print_fseq_regs(&mvm->fwrt); } int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, @@ -1443,7 +1445,7 @@ void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime) } *gp2 = iwl_mvm_get_systime(mvm); - *boottime = ktime_get_boot_ns(); + *boottime = ktime_get_boottime_ns(); if (!ps_disabled) { mvm->ps_disabled = ps_disabled; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index b513037dc066..85973dd57234 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -928,7 +928,7 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) MSIX_HW_INT_CAUSES_REG_RF_KILL); } - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_9000) { + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_9000) { /* * On 9000-series devices this bit isn't enabled by default, so * when we power down the device we need set the bit to allow it diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 803fcbac4152..dfa1bed124aa 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1698,26 +1698,26 @@ static int iwl_pcie_init_msix_handler(struct pci_dev *pdev, return 0; } -static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) +static int iwl_trans_pcie_clear_persistence_bit(struct iwl_trans *trans) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u32 hpm; - int err; - - lockdep_assert_held(&trans_pcie->mutex); + u32 hpm, wprot; - err = iwl_pcie_prepare_card_hw(trans); - if (err) { - IWL_ERR(trans, "Error while preparing HW: %d\n", err); - return err; + switch (trans->cfg->device_family) { + case IWL_DEVICE_FAMILY_9000: + wprot = PREG_PRPH_WPROT_9000; + break; + case IWL_DEVICE_FAMILY_22000: + wprot = PREG_PRPH_WPROT_22000; + break; + default: + return 0; } hpm = iwl_read_umac_prph_no_grab(trans, HPM_DEBUG); if (hpm != 0xa5a5a5a0 && (hpm & PERSISTENCE_BIT)) { - int wfpm_val = iwl_read_umac_prph_no_grab(trans, - PREG_PRPH_WPROT_0); + u32 wprot_val = iwl_read_umac_prph_no_grab(trans, wprot); - if (wfpm_val & PREG_WFPM_ACCESS) { + if (wprot_val & PREG_WFPM_ACCESS) { IWL_ERR(trans, "Error, can not clear persistence bit\n"); return -EPERM; @@ -1726,6 +1726,26 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) hpm & ~PERSISTENCE_BIT); } + return 0; +} + +static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int err; + + lockdep_assert_held(&trans_pcie->mutex); + + err = iwl_pcie_prepare_card_hw(trans); + if (err) { + IWL_ERR(trans, "Error while preparing HW: %d\n", err); + return err; + } + + err = iwl_trans_pcie_clear_persistence_bit(trans); + if (err) + return err; + iwl_trans_pcie_sw_reset(trans); err = iwl_pcie_apm_init(trans); @@ -3526,7 +3546,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, hw_step |= ENABLE_WFPM; iwl_write_umac_prph_no_grab(trans, WFPM_CTRL_REG, hw_step); - hw_step = iwl_read_prph_no_grab(trans, AUX_MISC_REG); + hw_step = iwl_read_prph_no_grab(trans, + CNVI_AUX_MISC_CHIP); hw_step = (hw_step >> HW_STEP_LOCATION_BITS) & 0xF; if (hw_step == 0x3) trans->hw_rev = (trans->hw_rev & 0xFFFFFFF3) | @@ -3577,7 +3598,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, } } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) == CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR) && - (trans->cfg != &iwl_ax200_cfg_cc || + ((trans->cfg != &iwl_ax200_cfg_cc && + trans->cfg != &killer1650x_2ax_cfg && + trans->cfg != &killer1650w_2ax_cfg) || trans->hw_rev == CSR_HW_REV_TYPE_QNJ_B0)) { u32 hw_status; diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c index ad1aa65fee7f..158a3d762e55 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_hw.c +++ b/drivers/net/wireless/intersil/hostap/hostap_hw.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Host AP (software wireless LAN access point) driver for * Intersil Prism2/2.5/3. @@ -6,11 +7,6 @@ * <j@w1.fi> * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. - * * FIX: * - there is currently no way of associating TX packets to correct wds device * when TX Exc/OK event occurs, so all tx_packets and some diff --git a/drivers/net/wireless/intersil/hostap/hostap_main.c b/drivers/net/wireless/intersil/hostap/hostap_main.c index b0e7c0a0617e..05466281afb6 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_main.c +++ b/drivers/net/wireless/intersil/hostap/hostap_main.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Host AP (software wireless LAN access point) driver for * Intersil Prism2/2.5/3 - hostap.o module, common routines @@ -5,11 +6,6 @@ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen * <j@w1.fi> * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. */ #include <linux/module.h> diff --git a/drivers/net/wireless/intersil/p54/eeprom.c b/drivers/net/wireless/intersil/p54/eeprom.c index de2ef95c386c..5bd35c147e19 100644 --- a/drivers/net/wireless/intersil/p54/eeprom.c +++ b/drivers/net/wireless/intersil/p54/eeprom.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * EEPROM parser code for mac80211 Prism54 drivers * @@ -10,10 +11,6 @@ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. * - stlc45xx driver * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/firmware.h> diff --git a/drivers/net/wireless/intersil/p54/eeprom.h b/drivers/net/wireless/intersil/p54/eeprom.h index 20ebe39a3f4e..b8f46883a292 100644 --- a/drivers/net/wireless/intersil/p54/eeprom.h +++ b/drivers/net/wireless/intersil/p54/eeprom.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * eeprom specific definitions for mac80211 Prism54 drivers * @@ -13,10 +14,6 @@ * * - islmvc driver * Copyright (C) 2001 Intersil Americas Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef EEPROM_H diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c index 52c095c7765f..a5afcc865196 100644 --- a/drivers/net/wireless/intersil/p54/fwio.c +++ b/drivers/net/wireless/intersil/p54/fwio.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Firmware I/O code for mac80211 Prism54 drivers * @@ -10,10 +11,6 @@ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. * - stlc45xx driver * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/slab.h> diff --git a/drivers/net/wireless/intersil/p54/led.c b/drivers/net/wireless/intersil/p54/led.c index 9a8fedd3c0f5..4bc77010f9c1 100644 --- a/drivers/net/wireless/intersil/p54/led.c +++ b/drivers/net/wireless/intersil/p54/led.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Common code for mac80211 Prism54 drivers * @@ -10,10 +11,6 @@ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. * - stlc45xx driver * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/firmware.h> diff --git a/drivers/net/wireless/intersil/p54/lmac.h b/drivers/net/wireless/intersil/p54/lmac.h index de1d46bf97df..e00761536cfc 100644 --- a/drivers/net/wireless/intersil/p54/lmac.h +++ b/drivers/net/wireless/intersil/p54/lmac.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * LMAC Interface specific definitions for mac80211 Prism54 drivers * @@ -10,10 +11,6 @@ * * - LMAC API interface header file for STLC4560 (lmac_longbow.h) * Copyright (C) 2007 Conexant Systems, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef LMAC_H diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index 1c6d428515a4..ca2676f79bbb 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * mac80211 glue code for mac80211 Prism54 drivers * @@ -10,10 +11,6 @@ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. * - stlc45xx driver * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/slab.h> diff --git a/drivers/net/wireless/intersil/p54/p54.h b/drivers/net/wireless/intersil/p54/p54.h index 529939e611cd..0a9c1a19380f 100644 --- a/drivers/net/wireless/intersil/p54/p54.h +++ b/drivers/net/wireless/intersil/p54/p54.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Shared defines for all mac80211 Prism54 code * @@ -5,10 +6,6 @@ * * Based on the islsm (softmac prism54) driver, which is: * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef P54_H diff --git a/drivers/net/wireless/intersil/p54/p54pci.c b/drivers/net/wireless/intersil/p54/p54pci.c index 57ad56435dda..80ad0b7eaef4 100644 --- a/drivers/net/wireless/intersil/p54/p54pci.c +++ b/drivers/net/wireless/intersil/p54/p54pci.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Linux device driver for PCI based Prism54 @@ -7,10 +8,6 @@ * * Based on the islsm (softmac prism54) driver, which is: * Copyright 2004-2006 Jean-Baptiste Note <jean-baptiste.note@m4x.org>, et al. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/pci.h> diff --git a/drivers/net/wireless/intersil/p54/p54pci.h b/drivers/net/wireless/intersil/p54/p54pci.h index 68405c142f97..3867e5935ac4 100644 --- a/drivers/net/wireless/intersil/p54/p54pci.h +++ b/drivers/net/wireless/intersil/p54/p54pci.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef P54PCI_H #define P54PCI_H #include <linux/interrupt.h> @@ -9,10 +10,6 @@ * * Based on the islsm (softmac prism54) driver, which is: * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /* Device Interrupt register bits */ diff --git a/drivers/net/wireless/intersil/p54/p54usb.c b/drivers/net/wireless/intersil/p54/p54usb.c index b0b86f701061..f937815f0f2c 100644 --- a/drivers/net/wireless/intersil/p54/p54usb.c +++ b/drivers/net/wireless/intersil/p54/p54usb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Linux device driver for USB based Prism54 @@ -6,10 +7,6 @@ * * Based on the islsm (softmac prism54) driver, which is: * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/usb.h> diff --git a/drivers/net/wireless/intersil/p54/p54usb.h b/drivers/net/wireless/intersil/p54/p54usb.h index a5f5f0fea3bd..b2d1bce1b9e7 100644 --- a/drivers/net/wireless/intersil/p54/p54usb.h +++ b/drivers/net/wireless/intersil/p54/p54usb.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef P54USB_H #define P54USB_H @@ -8,10 +9,6 @@ * * Based on the islsm (softmac prism54) driver, which is: * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /* for isl3886 register definitions used on ver 1 devices */ diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c index 790784568ad2..ff9acd1563f4 100644 --- a/drivers/net/wireless/intersil/p54/txrx.c +++ b/drivers/net/wireless/intersil/p54/txrx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Common code for mac80211 Prism54 drivers * @@ -10,10 +11,6 @@ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. * - stlc45xx driver * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/export.h> diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 60ca13e0f15b..a7bf6519d7aa 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 * Copyright (c) 2008, Jouni Malinen <j@w1.fi> * Copyright (c) 2011, Javier Lopez <jlopex@gmail.com> * Copyright (c) 2016 - 2017 Intel Deutschland GmbH * Copyright (C) 2018 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /* @@ -1274,7 +1271,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, */ if (ieee80211_is_beacon(hdr->frame_control) || ieee80211_is_probe_resp(hdr->frame_control)) { - rx_status.boottime_ns = ktime_get_boot_ns(); + rx_status.boottime_ns = ktime_get_boottime_ns(); now = data->abs_bcn_ts; } else { now = mac80211_hwsim_get_tsf_raw(); @@ -3851,6 +3848,7 @@ static int __init init_mac80211_hwsim(void) break; case HWSIM_REGTEST_STRICT_ALL: param.reg_strict = true; + /* fall through */ case HWSIM_REGTEST_DRIVER_REG_ALL: param.reg_alpha2 = hwsim_alpha2s[0]; break; diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h index a1ef8457fad4..a85bc7c5c030 100644 --- a/drivers/net/wireless/mac80211_hwsim.h +++ b/drivers/net/wireless/mac80211_hwsim.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 * Copyright (c) 2008, Jouni Malinen <j@w1.fi> * Copyright (c) 2011, Javier Lopez <jlopex@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __MAC80211_HWSIM_H diff --git a/drivers/net/wireless/marvell/mwifiex/ie.c b/drivers/net/wireless/marvell/mwifiex/ie.c index 6845eb57b39a..653d347a9a19 100644 --- a/drivers/net/wireless/marvell/mwifiex/ie.c +++ b/drivers/net/wireless/marvell/mwifiex/ie.c @@ -329,6 +329,8 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv, struct ieee80211_vendor_ie *vendorhdr; u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0; int left_len, parsed_len = 0; + unsigned int token_len; + int err = 0; if (!info->tail || !info->tail_len) return 0; @@ -344,6 +346,12 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv, */ while (left_len > sizeof(struct ieee_types_header)) { hdr = (void *)(info->tail + parsed_len); + token_len = hdr->len + sizeof(struct ieee_types_header); + if (token_len > left_len) { + err = -EINVAL; + goto out; + } + switch (hdr->element_id) { case WLAN_EID_SSID: case WLAN_EID_SUPP_RATES: @@ -361,17 +369,20 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv, if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WMM, (const u8 *)hdr, - hdr->len + sizeof(struct ieee_types_header))) + token_len)) break; /* fall through */ default: - memcpy(gen_ie->ie_buffer + ie_len, hdr, - hdr->len + sizeof(struct ieee_types_header)); - ie_len += hdr->len + sizeof(struct ieee_types_header); + if (ie_len + token_len > IEEE_MAX_IE_SIZE) { + err = -EINVAL; + goto out; + } + memcpy(gen_ie->ie_buffer + ie_len, hdr, token_len); + ie_len += token_len; break; } - left_len -= hdr->len + sizeof(struct ieee_types_header); - parsed_len += hdr->len + sizeof(struct ieee_types_header); + left_len -= token_len; + parsed_len += token_len; } /* parse only WPA vendor IE from tail, WMM IE is configured by @@ -381,15 +392,17 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv, WLAN_OUI_TYPE_MICROSOFT_WPA, info->tail, info->tail_len); if (vendorhdr) { - memcpy(gen_ie->ie_buffer + ie_len, vendorhdr, - vendorhdr->len + sizeof(struct ieee_types_header)); - ie_len += vendorhdr->len + sizeof(struct ieee_types_header); + token_len = vendorhdr->len + sizeof(struct ieee_types_header); + if (ie_len + token_len > IEEE_MAX_IE_SIZE) { + err = -EINVAL; + goto out; + } + memcpy(gen_ie->ie_buffer + ie_len, vendorhdr, token_len); + ie_len += token_len; } - if (!ie_len) { - kfree(gen_ie); - return 0; - } + if (!ie_len) + goto out; gen_ie->ie_index = cpu_to_le16(gen_idx); gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON | @@ -399,13 +412,15 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv, if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, NULL, NULL, NULL)) { - kfree(gen_ie); - return -1; + err = -EINVAL; + goto out; } priv->gen_idx = gen_idx; + + out: kfree(gen_ie); - return 0; + return err; } /* This function parses different IEs-head & tail IEs, beacon IEs, diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index 935778ec9a1b..c269a0de9413 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -1247,6 +1247,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, } switch (element_id) { case WLAN_EID_SSID: + if (element_len > IEEE80211_MAX_SSID_LEN) + return -EINVAL; bss_entry->ssid.ssid_len = element_len; memcpy(bss_entry->ssid.ssid, (current_ptr + 2), element_len); @@ -1256,6 +1258,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_SUPP_RATES: + if (element_len > MWIFIEX_SUPPORTED_RATES) + return -EINVAL; memcpy(bss_entry->data_rates, current_ptr + 2, element_len); memcpy(bss_entry->supported_rates, current_ptr + 2, @@ -1265,6 +1269,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_FH_PARAMS: + if (element_len + 2 < sizeof(*fh_param_set)) + return -EINVAL; fh_param_set = (struct ieee_types_fh_param_set *) current_ptr; memcpy(&bss_entry->phy_param_set.fh_param_set, @@ -1273,6 +1279,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_DS_PARAMS: + if (element_len + 2 < sizeof(*ds_param_set)) + return -EINVAL; ds_param_set = (struct ieee_types_ds_param_set *) current_ptr; @@ -1284,6 +1292,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_CF_PARAMS: + if (element_len + 2 < sizeof(*cf_param_set)) + return -EINVAL; cf_param_set = (struct ieee_types_cf_param_set *) current_ptr; memcpy(&bss_entry->ss_param_set.cf_param_set, @@ -1292,6 +1302,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_IBSS_PARAMS: + if (element_len + 2 < sizeof(*ibss_param_set)) + return -EINVAL; ibss_param_set = (struct ieee_types_ibss_param_set *) current_ptr; @@ -1301,10 +1313,14 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_ERP_INFO: + if (!element_len) + return -EINVAL; bss_entry->erp_flags = *(current_ptr + 2); break; case WLAN_EID_PWR_CONSTRAINT: + if (!element_len) + return -EINVAL; bss_entry->local_constraint = *(current_ptr + 2); bss_entry->sensed_11h = true; break; @@ -1345,6 +1361,9 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_VENDOR_SPECIFIC: + if (element_len + 2 < sizeof(vendor_ie->vend_hdr)) + return -EINVAL; + vendor_ie = (struct ieee_types_vendor_specific *) current_ptr; diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.c index b1bfee738937..fda6ba796385 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Radio tuning for GCT GRF5101 on RTL8180 @@ -13,10 +14,6 @@ * A special Big Thanks also is for all people who donated me cards, * making possible the creation of the original rtl8180 driver * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/pci.h> diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.h b/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.h index 4d80a2785123..91ff3185cd1b 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.h +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef RTL8180_GRF5101_H #define RTL8180_GRF5101_H @@ -15,10 +16,6 @@ * A special Big Thanks also is for all people who donated me cards, * making possible the creation of the original rtl8180 driver * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define GRF5101_ANTENNA 0xA3 diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.c index eebf23976524..27d04fec3691 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Radio tuning for Maxim max2820 on RTL8180 * @@ -12,10 +13,6 @@ * A special Big Thanks also is for all people who donated me cards, * making possible the creation of the original rtl8180 driver * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/pci.h> diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.h b/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.h index 8e982b72b690..4cb800d2d3c8 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.h +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef RTL8180_MAX2820_H #define RTL8180_MAX2820_H @@ -15,10 +16,6 @@ * A special Big Thanks also is for all people who donated me cards, * making possible the creation of the original rtl8180 driver * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define MAXIM_ANTENNA 0xb3 diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225.c index 9bda5bc78eda..470a869e6658 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Radio tuning for RTL8225 on RTL8180 @@ -9,10 +10,6 @@ * Copyright 2005 Andrea Merello <andrea.merello@gmail.com>, et al. * * Thanks to Realtek for their support! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/pci.h> diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.c index 51e32df6120b..23cd4ff78e54 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Radio tuning for RTL8225 on RTL8187SE * @@ -10,10 +11,6 @@ * Also based on the rtl8187 driver, which is: * Copyright 2007 Michael Wu <flamingice@sourmilk.net> * Copyright 2007 Andrea Merello <andrea.merello@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <net/mac80211.h> diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.h b/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.h index 229400264088..f00972661888 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.h +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* Definitions for RTL8187SE hardware * @@ -10,10 +11,6 @@ * Also based on the rtl8187 driver, which is: * Copyright 2007 Michael Wu <flamingice@sourmilk.net> * Copyright 2007 Andrea Merello <andrea.merello@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef RTL8187SE_RTL8225_H diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.c index 959b049827de..dd12f5cdb19b 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Radio tuning for Philips SA2400 on RTL8180 @@ -13,10 +14,6 @@ * A special Big Thanks also is for all people who donated me cards, * making possible the creation of the original rtl8180 driver * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/pci.h> diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.h b/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.h index fb0093f35148..ef6565b20dbd 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.h +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef RTL8180_SA2400_H #define RTL8180_SA2400_H @@ -15,10 +16,6 @@ * A special Big Thanks also is for all people who donated me cards, * making possible the creation of the original rtl8180 driver * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define SA2400_ANTENNA 0x91 diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 1a2ea8b47714..eb68b2d3caa1 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Linux device driver for RTL8187 * @@ -14,10 +15,6 @@ * * Magic delays and register offsets below are taken from the original * r8187 driver sources. Thanks to Realtek for their support! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/usb.h> diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c index c089540116fa..49421d10e22b 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Linux LED driver for RTL8187 * @@ -7,10 +8,6 @@ * Copyright (c) Realtek Semiconductor Corp. All rights reserved. * * Thanks to Realtek for their support! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifdef CONFIG_RTL8187_LEDS diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.h b/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.h index d743c96d4a20..5565cbf92bbf 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.h +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Definitions for RTL8187 leds * @@ -5,10 +6,6 @@ * * Based on the LED handling in the r8187 driver, which is: * Copyright (c) Realtek Semiconductor Corp. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef RTL8187_LED_H diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/rfkill.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/rfkill.c index 34116719974a..c57a4742b03e 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/rfkill.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/rfkill.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Linux RFKILL support for RTL8187 * @@ -7,10 +8,6 @@ * Copyright (c) Realtek Semiconductor Corp. All rights reserved. * * Thanks to Realtek for their support! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/types.h> diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8187.h b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8187.h index 324451df97f7..36f3460cc6c6 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8187.h +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8187.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Definitions for RTL8187 hardware * @@ -6,10 +7,6 @@ * * Based on the r8187 driver, which is: * Copyright 2005 Andrea Merello <andrea.merello@gmail.com>, et al. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef RTL8187_H diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c index ff0971f1e2c8..b2616d61b66d 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Radio tuning for RTL8225 on RTL8187 * @@ -10,10 +11,6 @@ * Magic delays, register offsets, and phy value tables below are * taken from the original r8187 driver sources. Thanks to Realtek * for their support! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/usb.h> diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.h b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.h index 141afb09a5b4..b9475e6ead23 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.h +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Radio tuning definitions for RTL8225 on RTL8187 * @@ -6,10 +7,6 @@ * * Based on the r8187 driver, which is: * Copyright 2005 Andrea Merello <andrea.merello@gmail.com>, et al. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef RTL8187_RTL8225_H diff --git a/drivers/net/wireless/realtek/rtl818x/rtl818x.h b/drivers/net/wireless/realtek/rtl818x/rtl818x.h index 7abef95d278b..597f41af899a 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl818x.h +++ b/drivers/net/wireless/realtek/rtl818x/rtl818x.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Definitions for RTL818x hardware * @@ -6,10 +7,6 @@ * * Based on the r8187 driver, which is: * Copyright 2005 Andrea Merello <andrea.merello@gmail.com>, et al. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef RTL818X_H diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index cf4265cda224..628477971213 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -8,7 +8,8 @@ #include "reg.h" #include "debug.h" -void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev, struct sk_buff *skb) +static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev, + struct sk_buff *skb) { struct rtw_c2h_cmd *c2h; u8 sub_cmd_id; @@ -47,7 +48,8 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb) } } -void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev, u8 *h2c) +static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev, + u8 *h2c) { u8 box; u8 box_state; diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index f447361f7573..b2dac4609138 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -162,7 +162,8 @@ static void rtw_watch_dog_work(struct work_struct *work) rtwdev->stats.tx_cnt = 0; rtwdev->stats.rx_cnt = 0; - rtw_iterate_vifs(rtwdev, rtw_vif_watch_dog_iter, &data); + /* use atomic version to avoid taking local->iflist_mtx mutex */ + rtw_iterate_vifs_atomic(rtwdev, rtw_vif_watch_dog_iter, &data); /* fw supports only one station associated to enter lps, if there are * more than two stations associated to the AP, then we can not enter diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 4381b360b5b5..404d89432c96 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -144,10 +144,10 @@ static void rtw_phy_stat_rssi_iter(void *data, struct ieee80211_sta *sta) struct rtw_phy_stat_iter_data *iter_data = data; struct rtw_dev *rtwdev = iter_data->rtwdev; struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; - u8 rssi, rssi_level; + u8 rssi; rssi = ewma_rssi_read(&si->avg_rssi); - rssi_level = rtw_phy_get_rssi_level(si->rssi_level, rssi); + si->rssi_level = rtw_phy_get_rssi_level(si->rssi_level, rssi); rtw_fw_send_rssi_info(rtwdev, si); @@ -423,6 +423,11 @@ static u64 rtw_phy_db_2_linear(u8 power_db) u8 i, j; u64 linear; + if (power_db > 96) + power_db = 96; + else if (power_db < 1) + return 1; + /* 1dB ~ 96dB */ i = (power_db - 1) >> 3; j = (power_db - 1) - (i << 3); @@ -848,12 +853,13 @@ u8 rtw_vht_2s_rates[] = { DESC_RATEVHT2SS_MCS6, DESC_RATEVHT2SS_MCS7, DESC_RATEVHT2SS_MCS8, DESC_RATEVHT2SS_MCS9 }; -u8 rtw_cck_size = ARRAY_SIZE(rtw_cck_rates); -u8 rtw_ofdm_size = ARRAY_SIZE(rtw_ofdm_rates); -u8 rtw_ht_1s_size = ARRAY_SIZE(rtw_ht_1s_rates); -u8 rtw_ht_2s_size = ARRAY_SIZE(rtw_ht_2s_rates); -u8 rtw_vht_1s_size = ARRAY_SIZE(rtw_vht_1s_rates); -u8 rtw_vht_2s_size = ARRAY_SIZE(rtw_vht_2s_rates); + +static u8 rtw_cck_size = ARRAY_SIZE(rtw_cck_rates); +static u8 rtw_ofdm_size = ARRAY_SIZE(rtw_ofdm_rates); +static u8 rtw_ht_1s_size = ARRAY_SIZE(rtw_ht_1s_rates); +static u8 rtw_ht_2s_size = ARRAY_SIZE(rtw_ht_2s_rates); +static u8 rtw_vht_1s_size = ARRAY_SIZE(rtw_vht_1s_rates); +static u8 rtw_vht_2s_size = ARRAY_SIZE(rtw_vht_2s_rates); u8 *rtw_rate_section[RTW_RATE_SECTION_MAX] = { rtw_cck_rates, rtw_ofdm_rates, rtw_ht_1s_rates, rtw_ht_2s_rates, diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index f9c67ed473d1..b42cd50b837e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -929,11 +929,15 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter) u32 addr; u8 *data; + data = kzalloc(RSI_9116_REG_SIZE, GFP_KERNEL); + if (!data) + return -ENOMEM; + status = rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR); if (status < 0) { rsi_dbg(ERR_ZONE, "Unable to set ms word to common reg\n"); - return status; + goto err; } rsi_dbg(INIT_ZONE, "%s: Bring TA out of reset\n", __func__); @@ -944,7 +948,7 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter) RSI_9116_REG_SIZE); if (status < 0) { rsi_dbg(ERR_ZONE, "Unable to hold TA threads\n"); - return status; + goto err; } put_unaligned_le32(TA_SOFT_RST_CLR, data); @@ -954,7 +958,7 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter) RSI_9116_REG_SIZE); if (status < 0) { rsi_dbg(ERR_ZONE, "Unable to get TA out of reset\n"); - return status; + goto err; } put_unaligned_le32(TA_PC_ZERO, data); @@ -964,7 +968,8 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter) RSI_9116_REG_SIZE); if (status < 0) { rsi_dbg(ERR_ZONE, "Unable to Reset TA PC value\n"); - return -EINVAL; + status = -EINVAL; + goto err; } put_unaligned_le32(TA_RELEASE_THREAD_VALUE, data); @@ -974,17 +979,19 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter) RSI_9116_REG_SIZE); if (status < 0) { rsi_dbg(ERR_ZONE, "Unable to release TA threads\n"); - return status; + goto err; } status = rsi_sdio_master_access_msword(adapter, MISC_CFG_BASE_ADDR); if (status < 0) { rsi_dbg(ERR_ZONE, "Unable to set ms word to common reg\n"); - return status; + goto err; } rsi_dbg(INIT_ZONE, "***** TA Reset done *****\n"); - return 0; +err: + kfree(data); + return status; } static struct rsi_host_intf_ops sdio_host_intf_ops = { diff --git a/drivers/net/wireless/st/cw1200/bh.c b/drivers/net/wireless/st/cw1200/bh.c index 92d299aa257c..02efe8483cba 100644 --- a/drivers/net/wireless/st/cw1200/bh.c +++ b/drivers/net/wireless/st/cw1200/bh.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device handling thread implementation for mac80211 ST-Ericsson CW1200 drivers * @@ -8,10 +9,6 @@ * ST-Ericsson UMAC CW1200 driver, which is * Copyright (c) 2010, ST-Ericsson * Author: Ajitpal Singh <ajitpal.singh@stericsson.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/net/wireless/st/cw1200/bh.h b/drivers/net/wireless/st/cw1200/bh.h index af6a4853728f..a4ff6fd7624f 100644 --- a/drivers/net/wireless/st/cw1200/bh.h +++ b/drivers/net/wireless/st/cw1200/bh.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Device handling thread interface for mac80211 ST-Ericsson CW1200 drivers * * Copyright (c) 2010, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef CW1200_BH_H diff --git a/drivers/net/wireless/st/cw1200/cw1200.h b/drivers/net/wireless/st/cw1200/cw1200.h index 1ad7d3602520..48f808cdc1cb 100644 --- a/drivers/net/wireless/st/cw1200/cw1200.h +++ b/drivers/net/wireless/st/cw1200/cw1200.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Common private data for ST-Ericsson CW1200 drivers * @@ -9,10 +10,6 @@ * * Based on the islsm (softmac prism54) driver, which is: * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef CW1200_H diff --git a/drivers/net/wireless/st/cw1200/cw1200_sdio.c b/drivers/net/wireless/st/cw1200/cw1200_sdio.c index 1037ec62659d..43e012073dbf 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_sdio.c +++ b/drivers/net/wireless/st/cw1200/cw1200_sdio.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Mac80211 SDIO driver for ST-Ericsson CW1200 device * * Copyright (c) 2010, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/net/wireless/st/cw1200/cw1200_spi.c b/drivers/net/wireless/st/cw1200/cw1200_spi.c index 412fb6e49aed..ef01caac629c 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/st/cw1200/cw1200_spi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Mac80211 SPI driver for ST-Ericsson CW1200 device * @@ -7,10 +8,6 @@ * Based on cw1200_sdio.c * Copyright (c) 2010, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/net/wireless/st/cw1200/debug.c b/drivers/net/wireless/st/cw1200/debug.c index d94266d9d0b8..8686929c70df 100644 --- a/drivers/net/wireless/st/cw1200/debug.c +++ b/drivers/net/wireless/st/cw1200/debug.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers * DebugFS code * * Copyright (c) 2010, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/net/wireless/st/cw1200/debug.h b/drivers/net/wireless/st/cw1200/debug.h index b525aba53bfc..80bc1567533a 100644 --- a/drivers/net/wireless/st/cw1200/debug.h +++ b/drivers/net/wireless/st/cw1200/debug.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * DebugFS code for ST-Ericsson CW1200 mac80211 driver * * Copyright (c) 2011, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef CW1200_DEBUG_H_INCLUDED diff --git a/drivers/net/wireless/st/cw1200/fwio.c b/drivers/net/wireless/st/cw1200/fwio.c index b7881232499c..6574e78e05ea 100644 --- a/drivers/net/wireless/st/cw1200/fwio.c +++ b/drivers/net/wireless/st/cw1200/fwio.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Firmware I/O code for mac80211 ST-Ericsson CW1200 drivers * @@ -8,10 +9,6 @@ * ST-Ericsson UMAC CW1200 driver which is * Copyright (c) 2010, ST-Ericsson * Author: Ajitpal Singh <ajitpal.singh@stericsson.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/vmalloc.h> diff --git a/drivers/net/wireless/st/cw1200/fwio.h b/drivers/net/wireless/st/cw1200/fwio.h index ea3099362cdf..c287160a492e 100644 --- a/drivers/net/wireless/st/cw1200/fwio.h +++ b/drivers/net/wireless/st/cw1200/fwio.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Firmware API for mac80211 ST-Ericsson CW1200 drivers * @@ -8,10 +9,6 @@ * ST-Ericsson UMAC CW1200 driver which is * Copyright (c) 2010, ST-Ericsson * Author: Ajitpal Singh <ajitpal.singh@stericsson.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef FWIO_H_INCLUDED diff --git a/drivers/net/wireless/st/cw1200/hwbus.h b/drivers/net/wireless/st/cw1200/hwbus.h index 8b2fc831c3de..bc8802d37b7b 100644 --- a/drivers/net/wireless/st/cw1200/hwbus.h +++ b/drivers/net/wireless/st/cw1200/hwbus.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Common hwbus abstraction layer interface for cw1200 wireless driver * * Copyright (c) 2010, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef CW1200_HWBUS_H diff --git a/drivers/net/wireless/st/cw1200/hwio.c b/drivers/net/wireless/st/cw1200/hwio.c index ff230b7aeedd..3ba462de8e91 100644 --- a/drivers/net/wireless/st/cw1200/hwio.c +++ b/drivers/net/wireless/st/cw1200/hwio.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Low-level device IO routines for ST-Ericsson CW1200 drivers * @@ -8,10 +9,6 @@ * ST-Ericsson UMAC CW1200 driver, which is * Copyright (c) 2010, ST-Ericsson * Author: Ajitpal Singh <ajitpal.singh@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/types.h> diff --git a/drivers/net/wireless/st/cw1200/hwio.h b/drivers/net/wireless/st/cw1200/hwio.h index ddf52669dc5b..d1e629a566c2 100644 --- a/drivers/net/wireless/st/cw1200/hwio.h +++ b/drivers/net/wireless/st/cw1200/hwio.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Low-level API for mac80211 ST-Ericsson CW1200 drivers * @@ -8,10 +9,6 @@ * ST-Ericsson UMAC CW1200 driver which is * Copyright (c) 2010, ST-Ericsson * Author: Ajitpal Singh <ajitpal.singh@stericsson.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef CW1200_HWIO_H_INCLUDED diff --git a/drivers/net/wireless/st/cw1200/main.c b/drivers/net/wireless/st/cw1200/main.c index c1608f0bf6d0..f7fe56affbcd 100644 --- a/drivers/net/wireless/st/cw1200/main.c +++ b/drivers/net/wireless/st/cw1200/main.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers * @@ -14,10 +15,6 @@ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. * - stlc45xx driver * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/net/wireless/st/cw1200/pm.c b/drivers/net/wireless/st/cw1200/pm.c index ded23df1ac1d..a20ab577a364 100644 --- a/drivers/net/wireless/st/cw1200/pm.c +++ b/drivers/net/wireless/st/cw1200/pm.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Mac80211 power management API for ST-Ericsson CW1200 drivers * * Copyright (c) 2011, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/net/wireless/st/cw1200/pm.h b/drivers/net/wireless/st/cw1200/pm.h index 534548470ebc..f516eedfe03c 100644 --- a/drivers/net/wireless/st/cw1200/pm.h +++ b/drivers/net/wireless/st/cw1200/pm.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Mac80211 power management interface for ST-Ericsson CW1200 mac80211 drivers * * Copyright (c) 2011, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef PM_H_INCLUDED diff --git a/drivers/net/wireless/st/cw1200/queue.c b/drivers/net/wireless/st/cw1200/queue.c index 7895efefa95d..14133eedb3b6 100644 --- a/drivers/net/wireless/st/cw1200/queue.c +++ b/drivers/net/wireless/st/cw1200/queue.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * O(1) TX queue with built-in allocator for ST-Ericsson CW1200 drivers * * Copyright (c) 2010, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <net/mac80211.h> diff --git a/drivers/net/wireless/st/cw1200/queue.h b/drivers/net/wireless/st/cw1200/queue.h index 119f9c79c14e..96ac69ae97de 100644 --- a/drivers/net/wireless/st/cw1200/queue.h +++ b/drivers/net/wireless/st/cw1200/queue.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * O(1) TX queue with built-in allocator for ST-Ericsson CW1200 drivers * * Copyright (c) 2010, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef CW1200_QUEUE_H_INCLUDED diff --git a/drivers/net/wireless/st/cw1200/scan.c b/drivers/net/wireless/st/cw1200/scan.c index 71e9b91cf15b..c46b044b7f7b 100644 --- a/drivers/net/wireless/st/cw1200/scan.c +++ b/drivers/net/wireless/st/cw1200/scan.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Scan implementation for ST-Ericsson CW1200 mac80211 drivers * * Copyright (c) 2010, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/sched.h> diff --git a/drivers/net/wireless/st/cw1200/scan.h b/drivers/net/wireless/st/cw1200/scan.h index cc75459e5784..139a9f84c9bf 100644 --- a/drivers/net/wireless/st/cw1200/scan.h +++ b/drivers/net/wireless/st/cw1200/scan.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Scan interface for ST-Ericsson CW1200 mac80211 drivers * * Copyright (c) 2010, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef SCAN_H_INCLUDED diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c index 8dae92a79fe1..236022d4ae2a 100644 --- a/drivers/net/wireless/st/cw1200/sta.c +++ b/drivers/net/wireless/st/cw1200/sta.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Mac80211 STA API for ST-Ericsson CW1200 drivers * * Copyright (c) 2010, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/vmalloc.h> diff --git a/drivers/net/wireless/st/cw1200/sta.h b/drivers/net/wireless/st/cw1200/sta.h index 719de34dcbfe..706dab8e73bf 100644 --- a/drivers/net/wireless/st/cw1200/sta.h +++ b/drivers/net/wireless/st/cw1200/sta.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Mac80211 STA interface for ST-Ericsson CW1200 mac80211 drivers * * Copyright (c) 2010, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef STA_H_INCLUDED diff --git a/drivers/net/wireless/st/cw1200/txrx.c b/drivers/net/wireless/st/cw1200/txrx.c index 8c800ef23159..2dfcdb145944 100644 --- a/drivers/net/wireless/st/cw1200/txrx.c +++ b/drivers/net/wireless/st/cw1200/txrx.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Datapath implementation for ST-Ericsson CW1200 mac80211 drivers * * Copyright (c) 2010, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <net/mac80211.h> diff --git a/drivers/net/wireless/st/cw1200/txrx.h b/drivers/net/wireless/st/cw1200/txrx.h index 492a4e14213b..8b87e07465c7 100644 --- a/drivers/net/wireless/st/cw1200/txrx.h +++ b/drivers/net/wireless/st/cw1200/txrx.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Datapath interface for ST-Ericsson CW1200 mac80211 drivers * * Copyright (c) 2010, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef CW1200_TXRX_H diff --git a/drivers/net/wireless/st/cw1200/wsm.c b/drivers/net/wireless/st/cw1200/wsm.c index be4c22e0d902..c86f31dcc981 100644 --- a/drivers/net/wireless/st/cw1200/wsm.c +++ b/drivers/net/wireless/st/cw1200/wsm.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * WSM host interface (HI) implementation for * ST-Ericsson CW1200 mac80211 drivers. * * Copyright (c) 2010, ST-Ericsson * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/skbuff.h> diff --git a/drivers/net/wireless/st/cw1200/wsm.h b/drivers/net/wireless/st/cw1200/wsm.h index 48086e849515..ddea57f8c8ab 100644 --- a/drivers/net/wireless/st/cw1200/wsm.h +++ b/drivers/net/wireless/st/cw1200/wsm.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * WSM host interface (HI) interface for ST-Ericsson CW1200 mac80211 drivers * @@ -7,10 +8,6 @@ * Based on CW1200 UMAC WSM API, which is * Copyright (C) ST-Ericsson SA 2010 * Author: Stewart Mathers <stewart.mathers@stericsson.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef CW1200_WSM_H_INCLUDED diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index c9a485ecee7b..b74dc8bc9755 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -483,7 +483,7 @@ static int wlcore_fw_status(struct wl1271 *wl, struct wl_fw_status *status) } /* update the host-chipset time offset */ - wl->time_offset = (ktime_get_boot_ns() >> 10) - + wl->time_offset = (ktime_get_boottime_ns() >> 10) - (s64)(status->fw_localtime); wl->fw_fast_lnk_map = status->link_fast_bitmap; diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index d96bb602fae6..307fab21050b 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -93,7 +93,7 @@ static void wl1271_rx_status(struct wl1271 *wl, } if (beacon || probe_rsp) - status->boottime_ns = ktime_get_boot_ns(); + status->boottime_ns = ktime_get_boottime_ns(); if (beacon) wlcore_set_pending_regdomain_ch(wl, (u16)desc->channel, diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index 057c6be330e7..90e56d4c3df3 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c @@ -273,7 +273,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, } /* configure packet life time */ - hosttime = (ktime_get_boot_ns() >> 10); + hosttime = (ktime_get_boottime_ns() >> 10); desc->start_time = cpu_to_le32(hosttime - wl->time_offset); is_dummy = wl12xx_is_dummy_packet(wl, skb); diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.c b/drivers/net/wireless/ti/wlcore/vendor_cmd.c index 75756fb8e7b0..5cf0b32c413b 100644 --- a/drivers/net/wireless/ti/wlcore/vendor_cmd.c +++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * This file is part of wlcore * * Copyright (C) 2014 Texas Instruments. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #include <linux/pm_runtime.h> diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.h b/drivers/net/wireless/ti/wlcore/vendor_cmd.h index 6e0c15e30f03..ebe815ea0316 100644 --- a/drivers/net/wireless/ti/wlcore/vendor_cmd.h +++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * This file is part of wlcore * * Copyright (C) 2014 Texas Instruments. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #ifndef __WLCORE_VENDOR_H__ diff --git a/drivers/net/wireless/virt_wifi.c b/drivers/net/wireless/virt_wifi.c index 606999f102eb..be92e1220284 100644 --- a/drivers/net/wireless/virt_wifi.c +++ b/drivers/net/wireless/virt_wifi.c @@ -172,7 +172,7 @@ static void virt_wifi_scan_result(struct work_struct *work) informed_bss = cfg80211_inform_bss(wiphy, &channel_5ghz, CFG80211_BSS_FTYPE_PRESP, fake_router_bssid, - ktime_get_boot_ns(), + ktime_get_boottime_ns(), WLAN_CAPABILITY_ESS, 0, (void *)&ssid, sizeof(ssid), DBM_TO_MBM(-50), GFP_KERNEL); diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c index 22c70f1f568c..0db7362bedb4 100644 --- a/drivers/net/wireless/zydas/zd1201.c +++ b/drivers/net/wireless/zydas/zd1201.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for ZyDAS zd1201 based wireless USB devices. * * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * * Parts of this driver have been derived from a wlan-ng version * modified by ZyDAS. They also made documentation available, thanks! * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. diff --git a/drivers/net/wireless/zydas/zd1201.h b/drivers/net/wireless/zydas/zd1201.h index dd7ea1f35bef..c46ac87550d1 100644 --- a/drivers/net/wireless/zydas/zd1201.h +++ b/drivers/net/wireless/zydas/zd1201.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * * Parts of this driver have been derived from a wlan-ng version * modified by ZyDAS. * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c index a570f2263a42..99a5708b37e3 100644 --- a/drivers/nvdimm/security.c +++ b/drivers/nvdimm/security.c @@ -55,7 +55,7 @@ static struct key *nvdimm_request_key(struct nvdimm *nvdimm) struct device *dev = &nvdimm->dev; sprintf(desc, "%s%s", NVDIMM_PREFIX, nvdimm->dimm_id); - key = request_key(&key_type_encrypted, desc, ""); + key = request_key(&key_type_encrypted, desc, "", NULL); if (IS_ERR(key)) { if (PTR_ERR(key) == -ENOKEY) dev_dbg(dev, "request_key() found no key\n"); diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 120fb593d1da..b2dd4e391f5c 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1113,15 +1113,15 @@ static struct nvme_id_ns *nvme_identify_ns(struct nvme_ctrl *ctrl, return id; } -static int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11, - void *buffer, size_t buflen, u32 *result) +static int nvme_features(struct nvme_ctrl *dev, u8 op, unsigned int fid, + unsigned int dword11, void *buffer, size_t buflen, u32 *result) { struct nvme_command c; union nvme_result res; int ret; memset(&c, 0, sizeof(c)); - c.features.opcode = nvme_admin_set_features; + c.features.opcode = op; c.features.fid = cpu_to_le32(fid); c.features.dword11 = cpu_to_le32(dword11); @@ -1132,6 +1132,24 @@ static int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword return ret; } +int nvme_set_features(struct nvme_ctrl *dev, unsigned int fid, + unsigned int dword11, void *buffer, size_t buflen, + u32 *result) +{ + return nvme_features(dev, nvme_admin_set_features, fid, dword11, buffer, + buflen, result); +} +EXPORT_SYMBOL_GPL(nvme_set_features); + +int nvme_get_features(struct nvme_ctrl *dev, unsigned int fid, + unsigned int dword11, void *buffer, size_t buflen, + u32 *result) +{ + return nvme_features(dev, nvme_admin_get_features, fid, dword11, buffer, + buflen, result); +} +EXPORT_SYMBOL_GPL(nvme_get_features); + int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count) { u32 q_count = (*count - 1) | ((*count - 1) << 16); @@ -3318,7 +3336,7 @@ static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) device_add_disk(ctrl->device, ns->disk, nvme_ns_id_attr_groups); nvme_mpath_add_disk(ns, id); - nvme_fault_inject_init(ns); + nvme_fault_inject_init(&ns->fault_inject, ns->disk->disk_name); kfree(id); return 0; @@ -3343,7 +3361,15 @@ static void nvme_ns_remove(struct nvme_ns *ns) if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags)) return; - nvme_fault_inject_fini(ns); + nvme_fault_inject_fini(&ns->fault_inject); + + mutex_lock(&ns->ctrl->subsys->lock); + list_del_rcu(&ns->siblings); + mutex_unlock(&ns->ctrl->subsys->lock); + synchronize_rcu(); /* guarantee not available in head->list */ + nvme_mpath_clear_current_path(ns); + synchronize_srcu(&ns->head->srcu); /* wait for concurrent submissions */ + if (ns->disk && ns->disk->flags & GENHD_FL_UP) { del_gendisk(ns->disk); blk_cleanup_queue(ns->queue); @@ -3351,16 +3377,10 @@ static void nvme_ns_remove(struct nvme_ns *ns) blk_integrity_unregister(ns->disk); } - mutex_lock(&ns->ctrl->subsys->lock); - list_del_rcu(&ns->siblings); - nvme_mpath_clear_current_path(ns); - mutex_unlock(&ns->ctrl->subsys->lock); - down_write(&ns->ctrl->namespaces_rwsem); list_del_init(&ns->list); up_write(&ns->ctrl->namespaces_rwsem); - synchronize_srcu(&ns->head->srcu); nvme_mpath_check_last_path(ns); nvme_put_ns(ns); } @@ -3702,6 +3722,7 @@ EXPORT_SYMBOL_GPL(nvme_start_ctrl); void nvme_uninit_ctrl(struct nvme_ctrl *ctrl) { + nvme_fault_inject_fini(&ctrl->fault_inject); dev_pm_qos_hide_latency_tolerance(ctrl->device); cdev_device_del(&ctrl->cdev, ctrl->device); } @@ -3797,6 +3818,8 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev, dev_pm_qos_update_user_latency_tolerance(ctrl->device, min(default_ps_max_latency_us, (unsigned long)S32_MAX)); + nvme_fault_inject_init(&ctrl->fault_inject, dev_name(ctrl->device)); + return 0; out_free_name: kfree_const(ctrl->device->kobj.name); diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 5838f7cd53ac..1994d5b42f94 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -578,7 +578,7 @@ bool __nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq, switch (ctrl->state) { case NVME_CTRL_NEW: case NVME_CTRL_CONNECTING: - if (req->cmd->common.opcode == nvme_fabrics_command && + if (nvme_is_fabrics(req->cmd) && req->cmd->fabrics.fctype == nvme_fabrics_type_connect) return true; break; diff --git a/drivers/nvme/host/fault_inject.c b/drivers/nvme/host/fault_inject.c index 4cfd2c9222d4..1352159733b0 100644 --- a/drivers/nvme/host/fault_inject.c +++ b/drivers/nvme/host/fault_inject.c @@ -15,11 +15,10 @@ static DECLARE_FAULT_ATTR(fail_default_attr); static char *fail_request; module_param(fail_request, charp, 0000); -void nvme_fault_inject_init(struct nvme_ns *ns) +void nvme_fault_inject_init(struct nvme_fault_inject *fault_inj, + const char *dev_name) { struct dentry *dir, *parent; - char *name = ns->disk->disk_name; - struct nvme_fault_inject *fault_inj = &ns->fault_inject; struct fault_attr *attr = &fault_inj->attr; /* set default fault injection attribute */ @@ -27,20 +26,20 @@ void nvme_fault_inject_init(struct nvme_ns *ns) setup_fault_attr(&fail_default_attr, fail_request); /* create debugfs directory and attribute */ - parent = debugfs_create_dir(name, NULL); + parent = debugfs_create_dir(dev_name, NULL); if (!parent) { - pr_warn("%s: failed to create debugfs directory\n", name); + pr_warn("%s: failed to create debugfs directory\n", dev_name); return; } *attr = fail_default_attr; dir = fault_create_debugfs_attr("fault_inject", parent, attr); if (IS_ERR(dir)) { - pr_warn("%s: failed to create debugfs attr\n", name); + pr_warn("%s: failed to create debugfs attr\n", dev_name); debugfs_remove_recursive(parent); return; } - ns->fault_inject.parent = parent; + fault_inj->parent = parent; /* create debugfs for status code and dont_retry */ fault_inj->status = NVME_SC_INVALID_OPCODE; @@ -49,29 +48,33 @@ void nvme_fault_inject_init(struct nvme_ns *ns) debugfs_create_bool("dont_retry", 0600, dir, &fault_inj->dont_retry); } -void nvme_fault_inject_fini(struct nvme_ns *ns) +void nvme_fault_inject_fini(struct nvme_fault_inject *fault_inject) { /* remove debugfs directories */ - debugfs_remove_recursive(ns->fault_inject.parent); + debugfs_remove_recursive(fault_inject->parent); } void nvme_should_fail(struct request *req) { struct gendisk *disk = req->rq_disk; - struct nvme_ns *ns = NULL; + struct nvme_fault_inject *fault_inject = NULL; u16 status; - /* - * make sure this request is coming from a valid namespace - */ - if (!disk) - return; + if (disk) { + struct nvme_ns *ns = disk->private_data; + + if (ns) + fault_inject = &ns->fault_inject; + else + WARN_ONCE(1, "No namespace found for request\n"); + } else { + fault_inject = &nvme_req(req)->ctrl->fault_inject; + } - ns = disk->private_data; - if (ns && should_fail(&ns->fault_inject.attr, 1)) { + if (fault_inject && should_fail(&fault_inject->attr, 1)) { /* inject status code and DNR bit */ - status = ns->fault_inject.status; - if (ns->fault_inject.dont_retry) + status = fault_inject->status; + if (fault_inject->dont_retry) status |= NVME_SC_DNR; nvme_req(req)->status = status; } diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index dd8169bbf0d2..9b497d785ed7 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -2607,6 +2607,12 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) if (nvme_fc_ctlr_active_on_rport(ctrl)) return -ENOTUNIQ; + dev_info(ctrl->ctrl.device, + "NVME-FC{%d}: create association : host wwpn 0x%016llx " + " rport wwpn 0x%016llx: NQN \"%s\"\n", + ctrl->cnum, ctrl->lport->localport.port_name, + ctrl->rport->remoteport.port_name, ctrl->ctrl.opts->subsysnqn); + /* * Create the admin queue */ diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index 4f20a10b39d3..ba009d4c9dfa 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -660,7 +660,7 @@ static struct request *nvme_nvm_alloc_request(struct request_queue *q, rq->cmd_flags &= ~REQ_FAILFAST_DRIVER; if (rqd->bio) - blk_init_request_from_bio(rq, rqd->bio); + blk_rq_append_bio(rq, &rqd->bio); else rq->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, IOPRIO_NORM); diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 55553d293a98..ea45d7d393ad 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -146,6 +146,15 @@ enum nvme_ctrl_state { NVME_CTRL_DEAD, }; +struct nvme_fault_inject { +#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS + struct fault_attr attr; + struct dentry *parent; + bool dont_retry; /* DNR, do not retry */ + u16 status; /* status code */ +#endif +}; + struct nvme_ctrl { bool comp_seen; enum nvme_ctrl_state state; @@ -247,6 +256,8 @@ struct nvme_ctrl { struct page *discard_page; unsigned long discard_page_busy; + + struct nvme_fault_inject fault_inject; }; enum nvme_iopolicy { @@ -313,15 +324,6 @@ struct nvme_ns_head { #endif }; -#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS -struct nvme_fault_inject { - struct fault_attr attr; - struct dentry *parent; - bool dont_retry; /* DNR, do not retry */ - u16 status; /* status code */ -}; -#endif - struct nvme_ns { struct list_head list; @@ -349,9 +351,7 @@ struct nvme_ns { #define NVME_NS_ANA_PENDING 2 u16 noiob; -#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS struct nvme_fault_inject fault_inject; -#endif }; @@ -372,12 +372,18 @@ struct nvme_ctrl_ops { }; #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS -void nvme_fault_inject_init(struct nvme_ns *ns); -void nvme_fault_inject_fini(struct nvme_ns *ns); +void nvme_fault_inject_init(struct nvme_fault_inject *fault_inj, + const char *dev_name); +void nvme_fault_inject_fini(struct nvme_fault_inject *fault_inject); void nvme_should_fail(struct request *req); #else -static inline void nvme_fault_inject_init(struct nvme_ns *ns) {} -static inline void nvme_fault_inject_fini(struct nvme_ns *ns) {} +static inline void nvme_fault_inject_init(struct nvme_fault_inject *fault_inj, + const char *dev_name) +{ +} +static inline void nvme_fault_inject_fini(struct nvme_fault_inject *fault_inj) +{ +} static inline void nvme_should_fail(struct request *req) {} #endif @@ -459,6 +465,12 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd, union nvme_result *result, void *buffer, unsigned bufflen, unsigned timeout, int qid, int at_head, blk_mq_req_flags_t flags, bool poll); +int nvme_set_features(struct nvme_ctrl *dev, unsigned int fid, + unsigned int dword11, void *buffer, size_t buflen, + u32 *result); +int nvme_get_features(struct nvme_ctrl *dev, unsigned int fid, + unsigned int dword11, void *buffer, size_t buflen, + u32 *result); int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count); void nvme_stop_keep_alive(struct nvme_ctrl *ctrl); int nvme_reset_ctrl(struct nvme_ctrl *ctrl); diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 524d6bd6d095..189352081994 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -18,6 +18,7 @@ #include <linux/mutex.h> #include <linux/once.h> #include <linux/pci.h> +#include <linux/suspend.h> #include <linux/t10-pi.h> #include <linux/types.h> #include <linux/io-64-nonatomic-lo-hi.h> @@ -67,20 +68,14 @@ static int io_queue_depth = 1024; module_param_cb(io_queue_depth, &io_queue_depth_ops, &io_queue_depth, 0644); MODULE_PARM_DESC(io_queue_depth, "set io queue depth, should >= 2"); -static int queue_count_set(const char *val, const struct kernel_param *kp); -static const struct kernel_param_ops queue_count_ops = { - .set = queue_count_set, - .get = param_get_int, -}; - static int write_queues; -module_param_cb(write_queues, &queue_count_ops, &write_queues, 0644); +module_param(write_queues, int, 0644); MODULE_PARM_DESC(write_queues, "Number of queues to use for writes. If not set, reads and writes " "will share a queue set."); -static int poll_queues = 0; -module_param_cb(poll_queues, &queue_count_ops, &poll_queues, 0644); +static int poll_queues; +module_param(poll_queues, int, 0644); MODULE_PARM_DESC(poll_queues, "Number of queues to use for polled IO."); struct nvme_dev; @@ -116,6 +111,7 @@ struct nvme_dev { u32 cmbsz; u32 cmbloc; struct nvme_ctrl ctrl; + u32 last_ps; mempool_t *iod_mempool; @@ -144,19 +140,6 @@ static int io_queue_depth_set(const char *val, const struct kernel_param *kp) return param_set_int(val, kp); } -static int queue_count_set(const char *val, const struct kernel_param *kp) -{ - int n, ret; - - ret = kstrtoint(val, 10, &n); - if (ret) - return ret; - if (n > num_possible_cpus()) - n = num_possible_cpus(); - - return param_set_int(val, kp); -} - static inline unsigned int sq_idx(unsigned int qid, u32 stride) { return qid * 2 * stride; @@ -2068,6 +2051,7 @@ static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues) .priv = dev, }; unsigned int irq_queues, this_p_queues; + unsigned int nr_cpus = num_possible_cpus(); /* * Poll queues don't need interrupts, but we need at least one IO @@ -2078,7 +2062,10 @@ static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues) this_p_queues = nr_io_queues - 1; irq_queues = 1; } else { - irq_queues = nr_io_queues - this_p_queues + 1; + if (nr_cpus < nr_io_queues - this_p_queues) + irq_queues = nr_cpus + 1; + else + irq_queues = nr_io_queues - this_p_queues + 1; } dev->io_queues[HCTX_TYPE_POLL] = this_p_queues; @@ -2464,10 +2451,8 @@ static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl) kfree(dev); } -static void nvme_remove_dead_ctrl(struct nvme_dev *dev, int status) +static void nvme_remove_dead_ctrl(struct nvme_dev *dev) { - dev_warn(dev->ctrl.device, "Removing after probe failure status: %d\n", status); - nvme_get_ctrl(&dev->ctrl); nvme_dev_disable(dev, false); nvme_kill_queues(&dev->ctrl); @@ -2480,11 +2465,13 @@ static void nvme_reset_work(struct work_struct *work) struct nvme_dev *dev = container_of(work, struct nvme_dev, ctrl.reset_work); bool was_suspend = !!(dev->ctrl.ctrl_config & NVME_CC_SHN_NORMAL); - int result = -ENODEV; + int result; enum nvme_ctrl_state new_state = NVME_CTRL_LIVE; - if (WARN_ON(dev->ctrl.state != NVME_CTRL_RESETTING)) + if (WARN_ON(dev->ctrl.state != NVME_CTRL_RESETTING)) { + result = -ENODEV; goto out; + } /* * If we're called to reset a live controller first shut it down before @@ -2528,6 +2515,7 @@ static void nvme_reset_work(struct work_struct *work) if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_CONNECTING)) { dev_warn(dev->ctrl.device, "failed to mark controller CONNECTING\n"); + result = -EBUSY; goto out; } @@ -2588,6 +2576,7 @@ static void nvme_reset_work(struct work_struct *work) if (!nvme_change_ctrl_state(&dev->ctrl, new_state)) { dev_warn(dev->ctrl.device, "failed to mark controller state %d\n", new_state); + result = -ENODEV; goto out; } @@ -2597,7 +2586,10 @@ static void nvme_reset_work(struct work_struct *work) out_unlock: mutex_unlock(&dev->shutdown_lock); out: - nvme_remove_dead_ctrl(dev, result); + if (result) + dev_warn(dev->ctrl.device, + "Removing after probe failure status: %d\n", result); + nvme_remove_dead_ctrl(dev); } static void nvme_remove_dead_ctrl_work(struct work_struct *work) @@ -2835,16 +2827,94 @@ static void nvme_remove(struct pci_dev *pdev) } #ifdef CONFIG_PM_SLEEP +static int nvme_get_power_state(struct nvme_ctrl *ctrl, u32 *ps) +{ + return nvme_get_features(ctrl, NVME_FEAT_POWER_MGMT, 0, NULL, 0, ps); +} + +static int nvme_set_power_state(struct nvme_ctrl *ctrl, u32 ps) +{ + return nvme_set_features(ctrl, NVME_FEAT_POWER_MGMT, ps, NULL, 0, NULL); +} + +static int nvme_resume(struct device *dev) +{ + struct nvme_dev *ndev = pci_get_drvdata(to_pci_dev(dev)); + struct nvme_ctrl *ctrl = &ndev->ctrl; + + if (pm_resume_via_firmware() || !ctrl->npss || + nvme_set_power_state(ctrl, ndev->last_ps) != 0) + nvme_reset_ctrl(ctrl); + return 0; +} + static int nvme_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct nvme_dev *ndev = pci_get_drvdata(pdev); + struct nvme_ctrl *ctrl = &ndev->ctrl; + int ret = -EBUSY; + + /* + * The platform does not remove power for a kernel managed suspend so + * use host managed nvme power settings for lowest idle power if + * possible. This should have quicker resume latency than a full device + * shutdown. But if the firmware is involved after the suspend or the + * device does not support any non-default power states, shut down the + * device fully. + */ + if (pm_suspend_via_firmware() || !ctrl->npss) { + nvme_dev_disable(ndev, true); + return 0; + } + + nvme_start_freeze(ctrl); + nvme_wait_freeze(ctrl); + nvme_sync_queues(ctrl); + + if (ctrl->state != NVME_CTRL_LIVE && + ctrl->state != NVME_CTRL_ADMIN_ONLY) + goto unfreeze; + + ndev->last_ps = 0; + ret = nvme_get_power_state(ctrl, &ndev->last_ps); + if (ret < 0) + goto unfreeze; + + ret = nvme_set_power_state(ctrl, ctrl->npss); + if (ret < 0) + goto unfreeze; + + if (ret) { + /* + * Clearing npss forces a controller reset on resume. The + * correct value will be resdicovered then. + */ + nvme_dev_disable(ndev, true); + ctrl->npss = 0; + ret = 0; + goto unfreeze; + } + /* + * A saved state prevents pci pm from generically controlling the + * device's power. If we're using protocol specific settings, we don't + * want pci interfering. + */ + pci_save_state(pdev); +unfreeze: + nvme_unfreeze(ctrl); + return ret; +} + +static int nvme_simple_suspend(struct device *dev) +{ + struct nvme_dev *ndev = pci_get_drvdata(to_pci_dev(dev)); nvme_dev_disable(ndev, true); return 0; } -static int nvme_resume(struct device *dev) +static int nvme_simple_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct nvme_dev *ndev = pci_get_drvdata(pdev); @@ -2852,9 +2922,16 @@ static int nvme_resume(struct device *dev) nvme_reset_ctrl(&ndev->ctrl); return 0; } -#endif -static SIMPLE_DEV_PM_OPS(nvme_dev_pm_ops, nvme_suspend, nvme_resume); +const struct dev_pm_ops nvme_dev_pm_ops = { + .suspend = nvme_suspend, + .resume = nvme_resume, + .freeze = nvme_simple_suspend, + .thaw = nvme_simple_resume, + .poweroff = nvme_simple_suspend, + .restore = nvme_simple_resume, +}; +#endif /* CONFIG_PM_SLEEP */ static pci_ers_result_t nvme_error_detected(struct pci_dev *pdev, pci_channel_state_t state) @@ -2959,9 +3036,11 @@ static struct pci_driver nvme_driver = { .probe = nvme_probe, .remove = nvme_remove, .shutdown = nvme_shutdown, +#ifdef CONFIG_PM_SLEEP .driver = { .pm = &nvme_dev_pm_ops, }, +#endif .sriov_configure = pci_sriov_configure_simple, .err_handler = &nvme_err_handler, }; diff --git a/drivers/nvme/host/trace.c b/drivers/nvme/host/trace.c index 5f24ea7a28eb..f01ad0fd60bb 100644 --- a/drivers/nvme/host/trace.c +++ b/drivers/nvme/host/trace.c @@ -135,6 +135,69 @@ const char *nvme_trace_parse_nvm_cmd(struct trace_seq *p, } } +static const char *nvme_trace_fabrics_property_set(struct trace_seq *p, u8 *spc) +{ + const char *ret = trace_seq_buffer_ptr(p); + u8 attrib = spc[0]; + u32 ofst = get_unaligned_le32(spc + 4); + u64 value = get_unaligned_le64(spc + 8); + + trace_seq_printf(p, "attrib=%u, ofst=0x%x, value=0x%llx", + attrib, ofst, value); + trace_seq_putc(p, 0); + return ret; +} + +static const char *nvme_trace_fabrics_connect(struct trace_seq *p, u8 *spc) +{ + const char *ret = trace_seq_buffer_ptr(p); + u16 recfmt = get_unaligned_le16(spc); + u16 qid = get_unaligned_le16(spc + 2); + u16 sqsize = get_unaligned_le16(spc + 4); + u8 cattr = spc[6]; + u32 kato = get_unaligned_le32(spc + 8); + + trace_seq_printf(p, "recfmt=%u, qid=%u, sqsize=%u, cattr=%u, kato=%u", + recfmt, qid, sqsize, cattr, kato); + trace_seq_putc(p, 0); + return ret; +} + +static const char *nvme_trace_fabrics_property_get(struct trace_seq *p, u8 *spc) +{ + const char *ret = trace_seq_buffer_ptr(p); + u8 attrib = spc[0]; + u32 ofst = get_unaligned_le32(spc + 4); + + trace_seq_printf(p, "attrib=%u, ofst=0x%x", attrib, ofst); + trace_seq_putc(p, 0); + return ret; +} + +static const char *nvme_trace_fabrics_common(struct trace_seq *p, u8 *spc) +{ + const char *ret = trace_seq_buffer_ptr(p); + + trace_seq_printf(p, "spcecific=%*ph", 24, spc); + trace_seq_putc(p, 0); + return ret; +} + +const char *nvme_trace_parse_fabrics_cmd(struct trace_seq *p, + u8 fctype, u8 *spc) +{ + switch (fctype) { + case nvme_fabrics_type_property_set: + return nvme_trace_fabrics_property_set(p, spc); + case nvme_fabrics_type_connect: + return nvme_trace_fabrics_connect(p, spc); + case nvme_fabrics_type_property_get: + return nvme_trace_fabrics_property_get(p, spc); + default: + return nvme_trace_fabrics_common(p, spc); + } +} + const char *nvme_trace_disk_name(struct trace_seq *p, char *name) { const char *ret = trace_seq_buffer_ptr(p); @@ -145,6 +208,5 @@ const char *nvme_trace_disk_name(struct trace_seq *p, char *name) return ret; } -EXPORT_SYMBOL_GPL(nvme_trace_disk_name); EXPORT_TRACEPOINT_SYMBOL_GPL(nvme_sq); diff --git a/drivers/nvme/host/trace.h b/drivers/nvme/host/trace.h index e71502d141ed..daaf700eae79 100644 --- a/drivers/nvme/host/trace.h +++ b/drivers/nvme/host/trace.h @@ -16,59 +16,19 @@ #include "nvme.h" -#define nvme_admin_opcode_name(opcode) { opcode, #opcode } -#define show_admin_opcode_name(val) \ - __print_symbolic(val, \ - nvme_admin_opcode_name(nvme_admin_delete_sq), \ - nvme_admin_opcode_name(nvme_admin_create_sq), \ - nvme_admin_opcode_name(nvme_admin_get_log_page), \ - nvme_admin_opcode_name(nvme_admin_delete_cq), \ - nvme_admin_opcode_name(nvme_admin_create_cq), \ - nvme_admin_opcode_name(nvme_admin_identify), \ - nvme_admin_opcode_name(nvme_admin_abort_cmd), \ - nvme_admin_opcode_name(nvme_admin_set_features), \ - nvme_admin_opcode_name(nvme_admin_get_features), \ - nvme_admin_opcode_name(nvme_admin_async_event), \ - nvme_admin_opcode_name(nvme_admin_ns_mgmt), \ - nvme_admin_opcode_name(nvme_admin_activate_fw), \ - nvme_admin_opcode_name(nvme_admin_download_fw), \ - nvme_admin_opcode_name(nvme_admin_ns_attach), \ - nvme_admin_opcode_name(nvme_admin_keep_alive), \ - nvme_admin_opcode_name(nvme_admin_directive_send), \ - nvme_admin_opcode_name(nvme_admin_directive_recv), \ - nvme_admin_opcode_name(nvme_admin_dbbuf), \ - nvme_admin_opcode_name(nvme_admin_format_nvm), \ - nvme_admin_opcode_name(nvme_admin_security_send), \ - nvme_admin_opcode_name(nvme_admin_security_recv), \ - nvme_admin_opcode_name(nvme_admin_sanitize_nvm)) - -#define nvme_opcode_name(opcode) { opcode, #opcode } -#define show_nvm_opcode_name(val) \ - __print_symbolic(val, \ - nvme_opcode_name(nvme_cmd_flush), \ - nvme_opcode_name(nvme_cmd_write), \ - nvme_opcode_name(nvme_cmd_read), \ - nvme_opcode_name(nvme_cmd_write_uncor), \ - nvme_opcode_name(nvme_cmd_compare), \ - nvme_opcode_name(nvme_cmd_write_zeroes), \ - nvme_opcode_name(nvme_cmd_dsm), \ - nvme_opcode_name(nvme_cmd_resv_register), \ - nvme_opcode_name(nvme_cmd_resv_report), \ - nvme_opcode_name(nvme_cmd_resv_acquire), \ - nvme_opcode_name(nvme_cmd_resv_release)) - -#define show_opcode_name(qid, opcode) \ - (qid ? show_nvm_opcode_name(opcode) : show_admin_opcode_name(opcode)) - const char *nvme_trace_parse_admin_cmd(struct trace_seq *p, u8 opcode, u8 *cdw10); const char *nvme_trace_parse_nvm_cmd(struct trace_seq *p, u8 opcode, u8 *cdw10); +const char *nvme_trace_parse_fabrics_cmd(struct trace_seq *p, u8 fctype, + u8 *spc); -#define parse_nvme_cmd(qid, opcode, cdw10) \ - (qid ? \ - nvme_trace_parse_nvm_cmd(p, opcode, cdw10) : \ - nvme_trace_parse_admin_cmd(p, opcode, cdw10)) +#define parse_nvme_cmd(qid, opcode, fctype, cdw10) \ + ((opcode) == nvme_fabrics_command ? \ + nvme_trace_parse_fabrics_cmd(p, fctype, cdw10) : \ + ((qid) ? \ + nvme_trace_parse_nvm_cmd(p, opcode, cdw10) : \ + nvme_trace_parse_admin_cmd(p, opcode, cdw10))) const char *nvme_trace_disk_name(struct trace_seq *p, char *name); #define __print_disk_name(name) \ @@ -93,6 +53,7 @@ TRACE_EVENT(nvme_setup_cmd, __field(int, qid) __field(u8, opcode) __field(u8, flags) + __field(u8, fctype) __field(u16, cid) __field(u32, nsid) __field(u64, metadata) @@ -106,6 +67,7 @@ TRACE_EVENT(nvme_setup_cmd, __entry->cid = cmd->common.command_id; __entry->nsid = le32_to_cpu(cmd->common.nsid); __entry->metadata = le64_to_cpu(cmd->common.metadata); + __entry->fctype = cmd->fabrics.fctype; __assign_disk_name(__entry->disk, req->rq_disk); memcpy(__entry->cdw10, &cmd->common.cdw10, sizeof(__entry->cdw10)); @@ -114,8 +76,10 @@ TRACE_EVENT(nvme_setup_cmd, __entry->ctrl_id, __print_disk_name(__entry->disk), __entry->qid, __entry->cid, __entry->nsid, __entry->flags, __entry->metadata, - show_opcode_name(__entry->qid, __entry->opcode), - parse_nvme_cmd(__entry->qid, __entry->opcode, __entry->cdw10)) + show_opcode_name(__entry->qid, __entry->opcode, + __entry->fctype), + parse_nvme_cmd(__entry->qid, __entry->opcode, + __entry->fctype, __entry->cdw10)) ); TRACE_EVENT(nvme_complete_rq, @@ -141,7 +105,7 @@ TRACE_EVENT(nvme_complete_rq, __entry->status = nvme_req(req)->status; __assign_disk_name(__entry->disk, req->rq_disk); ), - TP_printk("nvme%d: %sqid=%d, cmdid=%u, res=%llu, retries=%u, flags=0x%x, status=%u", + TP_printk("nvme%d: %sqid=%d, cmdid=%u, res=%#llx, retries=%u, flags=0x%x, status=%#x", __entry->ctrl_id, __print_disk_name(__entry->disk), __entry->qid, __entry->cid, __entry->result, __entry->retries, __entry->flags, __entry->status) diff --git a/drivers/nvme/target/Makefile b/drivers/nvme/target/Makefile index 8c3ad0fb6860..2b33836f3d3e 100644 --- a/drivers/nvme/target/Makefile +++ b/drivers/nvme/target/Makefile @@ -1,5 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 +ccflags-y += -I$(src) + obj-$(CONFIG_NVME_TARGET) += nvmet.o obj-$(CONFIG_NVME_TARGET_LOOP) += nvme-loop.o obj-$(CONFIG_NVME_TARGET_RDMA) += nvmet-rdma.o @@ -14,3 +16,4 @@ nvmet-rdma-y += rdma.o nvmet-fc-y += fc.o nvme-fcloop-y += fcloop.o nvmet-tcp-y += tcp.o +nvmet-$(CONFIG_TRACING) += trace.o diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 7734a6acff85..dad0243c7c96 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -10,6 +10,9 @@ #include <linux/pci-p2pdma.h> #include <linux/scatterlist.h> +#define CREATE_TRACE_POINTS +#include "trace.h" + #include "nvmet.h" struct workqueue_struct *buffered_io_wq; @@ -311,6 +314,7 @@ int nvmet_enable_port(struct nvmet_port *port) port->inline_data_size = 0; port->enabled = true; + port->tr_ops = ops; return 0; } @@ -321,6 +325,7 @@ void nvmet_disable_port(struct nvmet_port *port) lockdep_assert_held(&nvmet_config_sem); port->enabled = false; + port->tr_ops = NULL; ops = nvmet_transports[port->disc_addr.trtype]; ops->remove_port(port); @@ -689,6 +694,9 @@ static void __nvmet_req_complete(struct nvmet_req *req, u16 status) if (unlikely(status)) nvmet_set_error(req, status); + + trace_nvmet_req_complete(req); + if (req->ns) nvmet_put_namespace(req->ns); req->ops->queue_response(req); @@ -848,6 +856,8 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, req->error_loc = NVMET_NO_ERROR_LOC; req->error_slba = 0; + trace_nvmet_req_init(req, req->cmd); + /* no support for fused commands yet */ if (unlikely(flags & (NVME_CMD_FUSE_FIRST | NVME_CMD_FUSE_SECOND))) { req->error_loc = offsetof(struct nvme_common_command, flags); @@ -871,7 +881,7 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, status = nvmet_parse_connect_cmd(req); else if (likely(req->sq->qid != 0)) status = nvmet_parse_io_cmd(req); - else if (req->cmd->common.opcode == nvme_fabrics_command) + else if (nvme_is_fabrics(req->cmd)) status = nvmet_parse_fabrics_cmd(req); else if (req->sq->ctrl->subsys->type == NVME_NQN_DISC) status = nvmet_parse_discovery_cmd(req); diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c index 5baf269f3f8a..8efca26b4776 100644 --- a/drivers/nvme/target/discovery.c +++ b/drivers/nvme/target/discovery.c @@ -41,6 +41,10 @@ void nvmet_port_disc_changed(struct nvmet_port *port, __nvmet_disc_changed(port, ctrl); } mutex_unlock(&nvmet_disc_subsys->lock); + + /* If transport can signal change, notify transport */ + if (port->tr_ops && port->tr_ops->discovery_chg) + port->tr_ops->discovery_chg(port); } static void __nvmet_subsys_disc_changed(struct nvmet_port *port, diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c index 3b9f79aba98f..d16b55ffe79f 100644 --- a/drivers/nvme/target/fabrics-cmd.c +++ b/drivers/nvme/target/fabrics-cmd.c @@ -268,7 +268,7 @@ u16 nvmet_parse_connect_cmd(struct nvmet_req *req) { struct nvme_command *cmd = req->cmd; - if (cmd->common.opcode != nvme_fabrics_command) { + if (!nvme_is_fabrics(cmd)) { pr_err("invalid command 0x%x on unconnected queue.\n", cmd->fabrics.opcode); req->error_loc = offsetof(struct nvme_common_command, opcode); diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c index 508661af0f50..ce8d819f86cc 100644 --- a/drivers/nvme/target/fc.c +++ b/drivers/nvme/target/fc.c @@ -1806,7 +1806,7 @@ nvmet_fc_prep_fcp_rsp(struct nvmet_fc_tgtport *tgtport, */ rspcnt = atomic_inc_return(&fod->queue->zrspcnt); if (!(rspcnt % fod->queue->ersp_ratio) || - sqe->opcode == nvme_fabrics_command || + nvme_is_fabrics((struct nvme_command *) sqe) || xfr_length != fod->req.transfer_len || (le16_to_cpu(cqe->status) & 0xFFFE) || cqewd[0] || cqewd[1] || (sqe->flags & (NVME_CMD_FUSE_FIRST | NVME_CMD_FUSE_SECOND)) || @@ -2549,6 +2549,16 @@ nvmet_fc_remove_port(struct nvmet_port *port) kfree(pe); } +static void +nvmet_fc_discovery_chg(struct nvmet_port *port) +{ + struct nvmet_fc_port_entry *pe = port->priv; + struct nvmet_fc_tgtport *tgtport = pe->tgtport; + + if (tgtport && tgtport->ops->discovery_event) + tgtport->ops->discovery_event(&tgtport->fc_target_port); +} + static const struct nvmet_fabrics_ops nvmet_fc_tgt_fcp_ops = { .owner = THIS_MODULE, .type = NVMF_TRTYPE_FC, @@ -2557,6 +2567,7 @@ static const struct nvmet_fabrics_ops nvmet_fc_tgt_fcp_ops = { .remove_port = nvmet_fc_remove_port, .queue_response = nvmet_fc_fcp_nvme_cmd_done, .delete_ctrl = nvmet_fc_delete_ctrl, + .discovery_chg = nvmet_fc_discovery_chg, }; static int __init nvmet_fc_init_module(void) diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c index 381b5a90c48b..b8c1cc54a0db 100644 --- a/drivers/nvme/target/fcloop.c +++ b/drivers/nvme/target/fcloop.c @@ -231,6 +231,11 @@ struct fcloop_lsreq { int status; }; +struct fcloop_rscn { + struct fcloop_tport *tport; + struct work_struct work; +}; + enum { INI_IO_START = 0, INI_IO_ACTIVE = 1, @@ -348,6 +353,37 @@ fcloop_xmt_ls_rsp(struct nvmet_fc_target_port *tport, return 0; } +/* + * Simulate reception of RSCN and converting it to a initiator transport + * call to rescan a remote port. + */ +static void +fcloop_tgt_rscn_work(struct work_struct *work) +{ + struct fcloop_rscn *tgt_rscn = + container_of(work, struct fcloop_rscn, work); + struct fcloop_tport *tport = tgt_rscn->tport; + + if (tport->remoteport) + nvme_fc_rescan_remoteport(tport->remoteport); + kfree(tgt_rscn); +} + +static void +fcloop_tgt_discovery_evt(struct nvmet_fc_target_port *tgtport) +{ + struct fcloop_rscn *tgt_rscn; + + tgt_rscn = kzalloc(sizeof(*tgt_rscn), GFP_KERNEL); + if (!tgt_rscn) + return; + + tgt_rscn->tport = tgtport->private; + INIT_WORK(&tgt_rscn->work, fcloop_tgt_rscn_work); + + schedule_work(&tgt_rscn->work); +} + static void fcloop_tfcp_req_free(struct kref *ref) { @@ -839,6 +875,7 @@ static struct nvmet_fc_target_template tgttemplate = { .fcp_op = fcloop_fcp_op, .fcp_abort = fcloop_tgt_fcp_abort, .fcp_req_release = fcloop_fcp_req_release, + .discovery_event = fcloop_tgt_discovery_evt, .max_hw_queues = FCLOOP_HW_QUEUES, .max_sgl_segments = FCLOOP_SGL_SEGS, .max_dif_sgl_segments = FCLOOP_SGL_SEGS, diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index c25d88fc9dec..dc270944bb25 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -140,6 +140,7 @@ struct nvmet_port { void *priv; bool enabled; int inline_data_size; + const struct nvmet_fabrics_ops *tr_ops; }; static inline struct nvmet_port *to_nvmet_port(struct config_item *item) @@ -277,6 +278,7 @@ struct nvmet_fabrics_ops { void (*disc_traddr)(struct nvmet_req *req, struct nvmet_port *port, char *traddr); u16 (*install_queue)(struct nvmet_sq *nvme_sq); + void (*discovery_chg)(struct nvmet_port *port); }; #define NVMET_MAX_INLINE_BIOVEC 8 diff --git a/drivers/nvme/target/trace.c b/drivers/nvme/target/trace.c new file mode 100644 index 000000000000..cdcdd14c6408 --- /dev/null +++ b/drivers/nvme/target/trace.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NVM Express target device driver tracepoints + * Copyright (c) 2018 Johannes Thumshirn, SUSE Linux GmbH + */ + +#include <asm/unaligned.h> +#include "trace.h" + +static const char *nvmet_trace_admin_identify(struct trace_seq *p, u8 *cdw10) +{ + const char *ret = trace_seq_buffer_ptr(p); + u8 cns = cdw10[0]; + u16 ctrlid = get_unaligned_le16(cdw10 + 2); + + trace_seq_printf(p, "cns=%u, ctrlid=%u", cns, ctrlid); + trace_seq_putc(p, 0); + + return ret; +} + +static const char *nvmet_trace_admin_get_features(struct trace_seq *p, + u8 *cdw10) +{ + const char *ret = trace_seq_buffer_ptr(p); + u8 fid = cdw10[0]; + u8 sel = cdw10[1] & 0x7; + u32 cdw11 = get_unaligned_le32(cdw10 + 4); + + trace_seq_printf(p, "fid=0x%x sel=0x%x cdw11=0x%x", fid, sel, cdw11); + trace_seq_putc(p, 0); + + return ret; +} + +static const char *nvmet_trace_read_write(struct trace_seq *p, u8 *cdw10) +{ + const char *ret = trace_seq_buffer_ptr(p); + u64 slba = get_unaligned_le64(cdw10); + u16 length = get_unaligned_le16(cdw10 + 8); + u16 control = get_unaligned_le16(cdw10 + 10); + u32 dsmgmt = get_unaligned_le32(cdw10 + 12); + u32 reftag = get_unaligned_le32(cdw10 + 16); + + trace_seq_printf(p, + "slba=%llu, len=%u, ctrl=0x%x, dsmgmt=%u, reftag=%u", + slba, length, control, dsmgmt, reftag); + trace_seq_putc(p, 0); + + return ret; +} + +static const char *nvmet_trace_dsm(struct trace_seq *p, u8 *cdw10) +{ + const char *ret = trace_seq_buffer_ptr(p); + + trace_seq_printf(p, "nr=%u, attributes=%u", + get_unaligned_le32(cdw10), + get_unaligned_le32(cdw10 + 4)); + trace_seq_putc(p, 0); + + return ret; +} + +static const char *nvmet_trace_common(struct trace_seq *p, u8 *cdw10) +{ + const char *ret = trace_seq_buffer_ptr(p); + + trace_seq_printf(p, "cdw10=%*ph", 24, cdw10); + trace_seq_putc(p, 0); + + return ret; +} + +const char *nvmet_trace_parse_admin_cmd(struct trace_seq *p, + u8 opcode, u8 *cdw10) +{ + switch (opcode) { + case nvme_admin_identify: + return nvmet_trace_admin_identify(p, cdw10); + case nvme_admin_get_features: + return nvmet_trace_admin_get_features(p, cdw10); + default: + return nvmet_trace_common(p, cdw10); + } +} + +const char *nvmet_trace_parse_nvm_cmd(struct trace_seq *p, + u8 opcode, u8 *cdw10) +{ + switch (opcode) { + case nvme_cmd_read: + case nvme_cmd_write: + case nvme_cmd_write_zeroes: + return nvmet_trace_read_write(p, cdw10); + case nvme_cmd_dsm: + return nvmet_trace_dsm(p, cdw10); + default: + return nvmet_trace_common(p, cdw10); + } +} + +static const char *nvmet_trace_fabrics_property_set(struct trace_seq *p, + u8 *spc) +{ + const char *ret = trace_seq_buffer_ptr(p); + u8 attrib = spc[0]; + u32 ofst = get_unaligned_le32(spc + 4); + u64 value = get_unaligned_le64(spc + 8); + + trace_seq_printf(p, "attrib=%u, ofst=0x%x, value=0x%llx", + attrib, ofst, value); + trace_seq_putc(p, 0); + return ret; +} + +static const char *nvmet_trace_fabrics_connect(struct trace_seq *p, + u8 *spc) +{ + const char *ret = trace_seq_buffer_ptr(p); + u16 recfmt = get_unaligned_le16(spc); + u16 qid = get_unaligned_le16(spc + 2); + u16 sqsize = get_unaligned_le16(spc + 4); + u8 cattr = spc[6]; + u32 kato = get_unaligned_le32(spc + 8); + + trace_seq_printf(p, "recfmt=%u, qid=%u, sqsize=%u, cattr=%u, kato=%u", + recfmt, qid, sqsize, cattr, kato); + trace_seq_putc(p, 0); + return ret; +} + +static const char *nvmet_trace_fabrics_property_get(struct trace_seq *p, + u8 *spc) +{ + const char *ret = trace_seq_buffer_ptr(p); + u8 attrib = spc[0]; + u32 ofst = get_unaligned_le32(spc + 4); + + trace_seq_printf(p, "attrib=%u, ofst=0x%x", attrib, ofst); + trace_seq_putc(p, 0); + return ret; +} + +static const char *nvmet_trace_fabrics_common(struct trace_seq *p, u8 *spc) +{ + const char *ret = trace_seq_buffer_ptr(p); + + trace_seq_printf(p, "spcecific=%*ph", 24, spc); + trace_seq_putc(p, 0); + return ret; +} + +const char *nvmet_trace_parse_fabrics_cmd(struct trace_seq *p, + u8 fctype, u8 *spc) +{ + switch (fctype) { + case nvme_fabrics_type_property_set: + return nvmet_trace_fabrics_property_set(p, spc); + case nvme_fabrics_type_connect: + return nvmet_trace_fabrics_connect(p, spc); + case nvme_fabrics_type_property_get: + return nvmet_trace_fabrics_property_get(p, spc); + default: + return nvmet_trace_fabrics_common(p, spc); + } +} + +const char *nvmet_trace_disk_name(struct trace_seq *p, char *name) +{ + const char *ret = trace_seq_buffer_ptr(p); + + if (*name) + trace_seq_printf(p, "disk=%s, ", name); + trace_seq_putc(p, 0); + + return ret; +} + +const char *nvmet_trace_ctrl_name(struct trace_seq *p, struct nvmet_ctrl *ctrl) +{ + const char *ret = trace_seq_buffer_ptr(p); + + /* + * XXX: We don't know the controller instance before executing the + * connect command itself because the connect command for the admin + * queue will not provide the cntlid which will be allocated in this + * command. In case of io queues, the controller instance will be + * mapped by the extra data of the connect command. + * If we can know the extra data of the connect command in this stage, + * we can update this print statement later. + */ + if (ctrl) + trace_seq_printf(p, "%d", ctrl->cntlid); + else + trace_seq_printf(p, "_"); + trace_seq_putc(p, 0); + + return ret; +} + diff --git a/drivers/nvme/target/trace.h b/drivers/nvme/target/trace.h new file mode 100644 index 000000000000..e645caa882dd --- /dev/null +++ b/drivers/nvme/target/trace.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * NVM Express target device driver tracepoints + * Copyright (c) 2018 Johannes Thumshirn, SUSE Linux GmbH + * + * This is entirely based on drivers/nvme/host/trace.h + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM nvmet + +#if !defined(_TRACE_NVMET_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_NVMET_H + +#include <linux/nvme.h> +#include <linux/tracepoint.h> +#include <linux/trace_seq.h> + +#include "nvmet.h" + +const char *nvmet_trace_parse_admin_cmd(struct trace_seq *p, u8 opcode, + u8 *cdw10); +const char *nvmet_trace_parse_nvm_cmd(struct trace_seq *p, u8 opcode, + u8 *cdw10); +const char *nvmet_trace_parse_fabrics_cmd(struct trace_seq *p, u8 fctype, + u8 *spc); + +#define parse_nvme_cmd(qid, opcode, fctype, cdw10) \ + ((opcode) == nvme_fabrics_command ? \ + nvmet_trace_parse_fabrics_cmd(p, fctype, cdw10) : \ + (qid ? \ + nvmet_trace_parse_nvm_cmd(p, opcode, cdw10) : \ + nvmet_trace_parse_admin_cmd(p, opcode, cdw10))) + +const char *nvmet_trace_ctrl_name(struct trace_seq *p, struct nvmet_ctrl *ctrl); +#define __print_ctrl_name(ctrl) \ + nvmet_trace_ctrl_name(p, ctrl) + +const char *nvmet_trace_disk_name(struct trace_seq *p, char *name); +#define __print_disk_name(name) \ + nvmet_trace_disk_name(p, name) + +#ifndef TRACE_HEADER_MULTI_READ +static inline struct nvmet_ctrl *nvmet_req_to_ctrl(struct nvmet_req *req) +{ + return req->sq->ctrl; +} + +static inline void __assign_disk_name(char *name, struct nvmet_req *req, + bool init) +{ + struct nvmet_ctrl *ctrl = nvmet_req_to_ctrl(req); + struct nvmet_ns *ns; + + if ((init && req->sq->qid) || (!init && req->cq->qid)) { + ns = nvmet_find_namespace(ctrl, req->cmd->rw.nsid); + strncpy(name, ns->device_path, DISK_NAME_LEN); + return; + } + + memset(name, 0, DISK_NAME_LEN); +} +#endif + +TRACE_EVENT(nvmet_req_init, + TP_PROTO(struct nvmet_req *req, struct nvme_command *cmd), + TP_ARGS(req, cmd), + TP_STRUCT__entry( + __field(struct nvme_command *, cmd) + __field(struct nvmet_ctrl *, ctrl) + __array(char, disk, DISK_NAME_LEN) + __field(int, qid) + __field(u16, cid) + __field(u8, opcode) + __field(u8, fctype) + __field(u8, flags) + __field(u32, nsid) + __field(u64, metadata) + __array(u8, cdw10, 24) + ), + TP_fast_assign( + __entry->cmd = cmd; + __entry->ctrl = nvmet_req_to_ctrl(req); + __assign_disk_name(__entry->disk, req, true); + __entry->qid = req->sq->qid; + __entry->cid = cmd->common.command_id; + __entry->opcode = cmd->common.opcode; + __entry->fctype = cmd->fabrics.fctype; + __entry->flags = cmd->common.flags; + __entry->nsid = le32_to_cpu(cmd->common.nsid); + __entry->metadata = le64_to_cpu(cmd->common.metadata); + memcpy(__entry->cdw10, &cmd->common.cdw10, + sizeof(__entry->cdw10)); + ), + TP_printk("nvmet%s: %sqid=%d, cmdid=%u, nsid=%u, flags=%#x, " + "meta=%#llx, cmd=(%s, %s)", + __print_ctrl_name(__entry->ctrl), + __print_disk_name(__entry->disk), + __entry->qid, __entry->cid, __entry->nsid, + __entry->flags, __entry->metadata, + show_opcode_name(__entry->qid, __entry->opcode, + __entry->fctype), + parse_nvme_cmd(__entry->qid, __entry->opcode, + __entry->fctype, __entry->cdw10)) +); + +TRACE_EVENT(nvmet_req_complete, + TP_PROTO(struct nvmet_req *req), + TP_ARGS(req), + TP_STRUCT__entry( + __field(struct nvmet_ctrl *, ctrl) + __array(char, disk, DISK_NAME_LEN) + __field(int, qid) + __field(int, cid) + __field(u64, result) + __field(u16, status) + ), + TP_fast_assign( + __entry->ctrl = nvmet_req_to_ctrl(req); + __entry->qid = req->cq->qid; + __entry->cid = req->cqe->command_id; + __entry->result = le64_to_cpu(req->cqe->result.u64); + __entry->status = le16_to_cpu(req->cqe->status) >> 1; + __assign_disk_name(__entry->disk, req, false); + ), + TP_printk("nvmet%s: %sqid=%d, cmdid=%u, res=%#llx, status=%#x", + __print_ctrl_name(__entry->ctrl), + __print_disk_name(__entry->disk), + __entry->qid, __entry->cid, __entry->result, __entry->status) + +); + +#endif /* _TRACE_NVMET_H */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +/* This part must be outside protection */ +#include <trace/define_trace.h> diff --git a/drivers/nvmem/imx-iim.c b/drivers/nvmem/imx-iim.c index 34582293b985..701704b87dc9 100644 --- a/drivers/nvmem/imx-iim.c +++ b/drivers/nvmem/imx-iim.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * i.MX IIM driver * @@ -6,13 +7,6 @@ * Based on the barebox iim driver, * Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>, * Orex Computed Radiography - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html */ #include <linux/device.h> diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c index 4cf7b61e4bf5..bd016b928589 100644 --- a/drivers/nvmem/imx-ocotp.c +++ b/drivers/nvmem/imx-ocotp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * i.MX6 OCOTP fusebox driver * @@ -9,13 +10,6 @@ * * Write support based on the fsl_otp driver, * Copyright (C) 2010-2013 Freescale Semiconductor, Inc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html */ #include <linux/clk.h> diff --git a/drivers/nvmem/lpc18xx_eeprom.c b/drivers/nvmem/lpc18xx_eeprom.c index 66cff1e2147a..a0275b29afd5 100644 --- a/drivers/nvmem/lpc18xx_eeprom.c +++ b/drivers/nvmem/lpc18xx_eeprom.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP LPC18xx/LPC43xx EEPROM memory NVMEM driver * * Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/nvmem/lpc18xx_otp.c b/drivers/nvmem/lpc18xx_otp.c index 549b5298ac4c..16c92ea85d49 100644 --- a/drivers/nvmem/lpc18xx_otp.c +++ b/drivers/nvmem/lpc18xx_otp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP LPC18xx/43xx OTP memory NVMEM driver * @@ -6,10 +7,6 @@ * Based on the imx ocotp driver, * Copyright (c) 2015 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * * TODO: add support for writing OTP register via API in boot ROM. */ diff --git a/drivers/nvmem/snvs_lpgpr.c b/drivers/nvmem/snvs_lpgpr.c index c050a23a9f2b..c527d26ca6ac 100644 --- a/drivers/nvmem/snvs_lpgpr.c +++ b/drivers/nvmem/snvs_lpgpr.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. */ #include <linux/mfd/syscon.h> diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 0e7703fe733f..c094d5d20fd7 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic OPP Interface * @@ -5,10 +6,6 @@ * Nishanth Menon * Romit Dasgupta * Kevin Hilman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -685,7 +682,7 @@ static int _set_opp_custom(const struct opp_table *opp_table, data->old_opp.rate = old_freq; size = sizeof(*old_supply) * opp_table->regulator_count; - if (IS_ERR(old_supply)) + if (!old_supply) memset(data->old_opp.supplies, 0, size); else memcpy(data->old_opp.supplies, old_supply, size); @@ -711,7 +708,7 @@ static int _set_required_opps(struct device *dev, /* Single genpd case */ if (!genpd_virt_devs) { - pstate = opp->required_opps[0]->pstate; + pstate = likely(opp) ? opp->required_opps[0]->pstate : 0; ret = dev_pm_genpd_set_performance_state(dev, pstate); if (ret) { dev_err(dev, "Failed to set performance state of %s: %d (%d)\n", @@ -729,7 +726,7 @@ static int _set_required_opps(struct device *dev, mutex_lock(&opp_table->genpd_virt_dev_lock); for (i = 0; i < opp_table->required_opp_count; i++) { - pstate = opp->required_opps[i]->pstate; + pstate = likely(opp) ? opp->required_opps[i]->pstate : 0; if (!genpd_virt_devs[i]) continue; @@ -751,29 +748,37 @@ static int _set_required_opps(struct device *dev, * @dev: device for which we do this operation * @target_freq: frequency to achieve * - * This configures the power-supplies and clock source to the levels specified - * by the OPP corresponding to the target_freq. + * This configures the power-supplies to the levels specified by the OPP + * corresponding to the target_freq, and programs the clock to a value <= + * target_freq, as rounded by clk_round_rate(). Device wanting to run at fmax + * provided by the opp, should have already rounded to the target OPP's + * frequency. */ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) { struct opp_table *opp_table; - unsigned long freq, old_freq; + unsigned long freq, old_freq, temp_freq; struct dev_pm_opp *old_opp, *opp; struct clk *clk; int ret; - if (unlikely(!target_freq)) { - dev_err(dev, "%s: Invalid target frequency %lu\n", __func__, - target_freq); - return -EINVAL; - } - opp_table = _find_opp_table(dev); if (IS_ERR(opp_table)) { dev_err(dev, "%s: device opp doesn't exist\n", __func__); return PTR_ERR(opp_table); } + if (unlikely(!target_freq)) { + if (opp_table->required_opp_tables) { + ret = _set_required_opps(dev, opp_table, NULL); + } else { + dev_err(dev, "target frequency can't be 0\n"); + ret = -EINVAL; + } + + goto put_opp_table; + } + clk = opp_table->clk; if (IS_ERR(clk)) { dev_err(dev, "%s: No clock available for the device\n", @@ -796,13 +801,15 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) goto put_opp_table; } - old_opp = _find_freq_ceil(opp_table, &old_freq); + temp_freq = old_freq; + old_opp = _find_freq_ceil(opp_table, &temp_freq); if (IS_ERR(old_opp)) { dev_err(dev, "%s: failed to find current OPP for freq %lu (%ld)\n", __func__, old_freq, PTR_ERR(old_opp)); } - opp = _find_freq_ceil(opp_table, &freq); + temp_freq = freq; + opp = _find_freq_ceil(opp_table, &temp_freq); if (IS_ERR(opp)) { ret = PTR_ERR(opp); dev_err(dev, "%s: failed to find OPP for freq %lu (%d)\n", @@ -1744,91 +1751,137 @@ void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) } EXPORT_SYMBOL_GPL(dev_pm_opp_unregister_set_opp_helper); +static void _opp_detach_genpd(struct opp_table *opp_table) +{ + int index; + + for (index = 0; index < opp_table->required_opp_count; index++) { + if (!opp_table->genpd_virt_devs[index]) + continue; + + dev_pm_domain_detach(opp_table->genpd_virt_devs[index], false); + opp_table->genpd_virt_devs[index] = NULL; + } + + kfree(opp_table->genpd_virt_devs); + opp_table->genpd_virt_devs = NULL; +} + /** - * dev_pm_opp_set_genpd_virt_dev - Set virtual genpd device for an index - * @dev: Consumer device for which the genpd device is getting set. - * @virt_dev: virtual genpd device. - * @index: index. + * dev_pm_opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer + * @dev: Consumer device for which the genpd is getting attached. + * @names: Null terminated array of pointers containing names of genpd to attach. * * Multiple generic power domains for a device are supported with the help of * virtual genpd devices, which are created for each consumer device - genpd * pair. These are the device structures which are attached to the power domain * and are required by the OPP core to set the performance state of the genpd. + * The same API also works for the case where single genpd is available and so + * we don't need to support that separately. * * This helper will normally be called by the consumer driver of the device - * "dev", as only that has details of the genpd devices. + * "dev", as only that has details of the genpd names. * - * This helper needs to be called once for each of those virtual devices, but - * only if multiple domains are available for a device. Otherwise the original - * device structure will be used instead by the OPP core. + * This helper needs to be called once with a list of all genpd to attach. + * Otherwise the original device structure will be used instead by the OPP core. */ -struct opp_table *dev_pm_opp_set_genpd_virt_dev(struct device *dev, - struct device *virt_dev, - int index) +struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names) { struct opp_table *opp_table; + struct device *virt_dev; + int index, ret = -EINVAL; + const char **name = names; opp_table = dev_pm_opp_get_opp_table(dev); if (!opp_table) return ERR_PTR(-ENOMEM); + /* + * If the genpd's OPP table isn't already initialized, parsing of the + * required-opps fail for dev. We should retry this after genpd's OPP + * table is added. + */ + if (!opp_table->required_opp_count) { + ret = -EPROBE_DEFER; + goto put_table; + } + mutex_lock(&opp_table->genpd_virt_dev_lock); - if (unlikely(!opp_table->genpd_virt_devs || - index >= opp_table->required_opp_count || - opp_table->genpd_virt_devs[index])) { + opp_table->genpd_virt_devs = kcalloc(opp_table->required_opp_count, + sizeof(*opp_table->genpd_virt_devs), + GFP_KERNEL); + if (!opp_table->genpd_virt_devs) + goto unlock; - dev_err(dev, "Invalid request to set required device\n"); - dev_pm_opp_put_opp_table(opp_table); - mutex_unlock(&opp_table->genpd_virt_dev_lock); + while (*name) { + index = of_property_match_string(dev->of_node, + "power-domain-names", *name); + if (index < 0) { + dev_err(dev, "Failed to find power domain: %s (%d)\n", + *name, index); + goto err; + } - return ERR_PTR(-EINVAL); + if (index >= opp_table->required_opp_count) { + dev_err(dev, "Index can't be greater than required-opp-count - 1, %s (%d : %d)\n", + *name, opp_table->required_opp_count, index); + goto err; + } + + if (opp_table->genpd_virt_devs[index]) { + dev_err(dev, "Genpd virtual device already set %s\n", + *name); + goto err; + } + + virt_dev = dev_pm_domain_attach_by_name(dev, *name); + if (IS_ERR(virt_dev)) { + ret = PTR_ERR(virt_dev); + dev_err(dev, "Couldn't attach to pm_domain: %d\n", ret); + goto err; + } + + opp_table->genpd_virt_devs[index] = virt_dev; + name++; } - opp_table->genpd_virt_devs[index] = virt_dev; mutex_unlock(&opp_table->genpd_virt_dev_lock); return opp_table; + +err: + _opp_detach_genpd(opp_table); +unlock: + mutex_unlock(&opp_table->genpd_virt_dev_lock); + +put_table: + dev_pm_opp_put_opp_table(opp_table); + + return ERR_PTR(ret); } +EXPORT_SYMBOL_GPL(dev_pm_opp_attach_genpd); /** - * dev_pm_opp_put_genpd_virt_dev() - Releases resources blocked for genpd device. - * @opp_table: OPP table returned by dev_pm_opp_set_genpd_virt_dev(). - * @virt_dev: virtual genpd device. + * dev_pm_opp_detach_genpd() - Detach genpd(s) from the device. + * @opp_table: OPP table returned by dev_pm_opp_attach_genpd(). * - * This releases the resource previously acquired with a call to - * dev_pm_opp_set_genpd_virt_dev(). The consumer driver shall call this helper - * if it doesn't want OPP core to update performance state of a power domain - * anymore. + * This detaches the genpd(s), resets the virtual device pointers, and puts the + * OPP table. */ -void dev_pm_opp_put_genpd_virt_dev(struct opp_table *opp_table, - struct device *virt_dev) +void dev_pm_opp_detach_genpd(struct opp_table *opp_table) { - int i; - /* * Acquire genpd_virt_dev_lock to make sure virt_dev isn't getting * used in parallel. */ mutex_lock(&opp_table->genpd_virt_dev_lock); - - for (i = 0; i < opp_table->required_opp_count; i++) { - if (opp_table->genpd_virt_devs[i] != virt_dev) - continue; - - opp_table->genpd_virt_devs[i] = NULL; - dev_pm_opp_put_opp_table(opp_table); - - /* Drop the vote */ - dev_pm_genpd_set_performance_state(virt_dev, 0); - break; - } - + _opp_detach_genpd(opp_table); mutex_unlock(&opp_table->genpd_virt_dev_lock); - if (unlikely(i == opp_table->required_opp_count)) - dev_err(virt_dev, "Failed to find required device entry\n"); + dev_pm_opp_put_opp_table(opp_table); } +EXPORT_SYMBOL_GPL(dev_pm_opp_detach_genpd); /** * dev_pm_opp_xlate_performance_state() - Find required OPP's pstate for src_table. diff --git a/drivers/opp/cpu.c b/drivers/opp/cpu.c index ab6d07e78945..b5055cc886ef 100644 --- a/drivers/opp/cpu.c +++ b/drivers/opp/cpu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic OPP helper interface for CPU device * @@ -5,10 +6,6 @@ * Nishanth Menon * Romit Dasgupta * Kevin Hilman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/opp/debugfs.c b/drivers/opp/debugfs.c index a1c57fe14de4..609665e339b6 100644 --- a/drivers/opp/debugfs.c +++ b/drivers/opp/debugfs.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic OPP debugfs interface * * Copyright (C) 2015-2016 Viresh Kumar <viresh.kumar@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/opp/of.c b/drivers/opp/of.c index c10c782d15aa..b313aca9894f 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic OPP OF helpers * @@ -5,10 +6,6 @@ * Nishanth Menon * Romit Dasgupta * Kevin Hilman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -141,7 +138,6 @@ err: static void _opp_table_free_required_tables(struct opp_table *opp_table) { struct opp_table **required_opp_tables = opp_table->required_opp_tables; - struct device **genpd_virt_devs = opp_table->genpd_virt_devs; int i; if (!required_opp_tables) @@ -155,10 +151,8 @@ static void _opp_table_free_required_tables(struct opp_table *opp_table) } kfree(required_opp_tables); - kfree(genpd_virt_devs); opp_table->required_opp_count = 0; - opp_table->genpd_virt_devs = NULL; opp_table->required_opp_tables = NULL; } @@ -171,9 +165,8 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table, struct device_node *opp_np) { struct opp_table **required_opp_tables; - struct device **genpd_virt_devs = NULL; struct device_node *required_np, *np; - int count, count_pd, i; + int count, i; /* Traversing the first OPP node is all we need */ np = of_get_next_available_child(opp_np, NULL); @@ -186,33 +179,11 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table, if (!count) goto put_np; - /* - * Check the number of power-domains to know if we need to deal - * with virtual devices. In some cases we have devices with multiple - * power domains but with only one of them being scalable, hence - * 'count' could be 1, but we still have to deal with multiple genpds - * and virtual devices. - */ - count_pd = of_count_phandle_with_args(dev->of_node, "power-domains", - "#power-domain-cells"); - if (!count_pd) - goto put_np; - - if (count_pd > 1) { - genpd_virt_devs = kcalloc(count, sizeof(*genpd_virt_devs), - GFP_KERNEL); - if (!genpd_virt_devs) - goto put_np; - } - required_opp_tables = kcalloc(count, sizeof(*required_opp_tables), GFP_KERNEL); - if (!required_opp_tables) { - kfree(genpd_virt_devs); + if (!required_opp_tables) goto put_np; - } - opp_table->genpd_virt_devs = genpd_virt_devs; opp_table->required_opp_tables = required_opp_tables; opp_table->required_opp_count = count; diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h index 569b3525aa67..01a500e2c40a 100644 --- a/drivers/opp/opp.h +++ b/drivers/opp/opp.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Generic OPP Interface * @@ -5,10 +6,6 @@ * Nishanth Menon * Romit Dasgupta * Kevin Hilman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __DRIVER_OPP_H__ diff --git a/drivers/parport/parport_ax88796.c b/drivers/parport/parport_ax88796.c index bfe97c2a8d4c..54b539809673 100644 --- a/drivers/parport/parport_ax88796.c +++ b/drivers/parport/parport_ax88796.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* linux/drivers/parport/parport_ax88796.c * * (c) 2005,2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index a98126ad9c3a..a4994aa3acc0 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -18,6 +18,7 @@ #include <linux/percpu-refcount.h> #include <linux/random.h> #include <linux/seq_buf.h> +#include <linux/iommu.h> struct pci_p2pdma { struct gen_pool *pool; @@ -299,6 +300,9 @@ static bool root_complex_whitelist(struct pci_dev *dev) struct pci_dev *root = pci_get_slot(host->bus, PCI_DEVFN(0, 0)); unsigned short vendor, device; + if (iommu_present(dev->dev.bus)) + return false; + if (!root) return false; diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 1897847ceb0c..45049f558860 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -685,12 +685,21 @@ static pci_power_t acpi_pci_get_power_state(struct pci_dev *dev) if (!adev || !acpi_device_power_manageable(adev)) return PCI_UNKNOWN; - if (acpi_device_get_power(adev, &state) || state == ACPI_STATE_UNKNOWN) + state = adev->power.state; + if (state == ACPI_STATE_UNKNOWN) return PCI_UNKNOWN; return state_conv[state]; } +static void acpi_pci_refresh_power_state(struct pci_dev *dev) +{ + struct acpi_device *adev = ACPI_COMPANION(&dev->dev); + + if (adev && acpi_device_power_manageable(adev)) + acpi_device_update_power(adev, NULL); +} + static int acpi_pci_propagate_wakeup(struct pci_bus *bus, bool enable) { while (bus->parent) { @@ -748,6 +757,7 @@ static const struct pci_platform_pm_ops acpi_pci_platform_pm = { .is_manageable = acpi_pci_power_manageable, .set_state = acpi_pci_set_power_state, .get_state = acpi_pci_get_power_state, + .refresh_state = acpi_pci_refresh_power_state, .choose_state = acpi_pci_choose_state, .set_wakeup = acpi_pci_wakeup, .need_resume = acpi_pci_need_resume, @@ -901,6 +911,7 @@ static void pci_acpi_setup(struct device *dev) device_wakeup_enable(dev); acpi_pci_wakeup(pci_dev, false); + acpi_device_power_add_dependent(adev, dev); } static void pci_acpi_cleanup(struct device *dev) @@ -913,6 +924,7 @@ static void pci_acpi_cleanup(struct device *dev) pci_acpi_remove_pm_notifier(adev); if (adev->wakeup.flags.valid) { + acpi_device_power_remove_dependent(adev, dev); if (pci_dev->bridge_d3) device_wakeup_disable(dev); diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 5eadbc3d0969..36dbe960306b 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -524,7 +524,6 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev) pci_power_up(pci_dev); pci_restore_state(pci_dev); pci_pme_restore(pci_dev); - pci_fixup_device(pci_fixup_resume_early, pci_dev); } /* @@ -679,6 +678,7 @@ static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) static int pci_pm_prepare(struct device *dev) { struct device_driver *drv = dev->driver; + struct pci_dev *pci_dev = to_pci_dev(dev); if (drv && drv->pm && drv->pm->prepare) { int error = drv->pm->prepare(dev); @@ -688,7 +688,15 @@ static int pci_pm_prepare(struct device *dev) if (!error && dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_PREPARE)) return 0; } - return pci_dev_keep_suspended(to_pci_dev(dev)); + if (pci_dev_need_resume(pci_dev)) + return 0; + + /* + * The PME setting needs to be adjusted here in case the direct-complete + * optimization is used with respect to this device. + */ + pci_dev_adjust_pme(pci_dev); + return 1; } static void pci_pm_complete(struct device *dev) @@ -702,7 +710,14 @@ static void pci_pm_complete(struct device *dev) if (pm_runtime_suspended(dev) && pm_resume_via_firmware()) { pci_power_t pre_sleep_state = pci_dev->current_state; - pci_update_current_state(pci_dev, pci_dev->current_state); + pci_refresh_power_state(pci_dev); + /* + * On platforms with ACPI this check may also trigger for + * devices sharing power resources if one of those power + * resources has been activated as a result of a change of the + * power state of another device sharing it. However, in that + * case it is also better to resume the device, in general. + */ if (pci_dev->current_state < pre_sleep_state) pm_request_resume(dev); } @@ -758,9 +773,11 @@ static int pci_pm_suspend(struct device *dev) * better to resume the device from runtime suspend here. */ if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) || - !pci_dev_keep_suspended(pci_dev)) { + pci_dev_need_resume(pci_dev)) { pm_runtime_resume(dev); pci_dev->state_saved = false; + } else { + pci_dev_adjust_pme(pci_dev); } if (pm->suspend) { @@ -831,18 +848,16 @@ static int pci_pm_suspend_noirq(struct device *dev) if (pci_dev->skip_bus_pm) { /* - * The function is running for the second time in a row without + * Either the device is a bridge with a child in D0 below it, or + * the function is running for the second time in a row without * going through full resume, which is possible only during - * suspend-to-idle in a spurious wakeup case. Moreover, the - * device was originally left in D0, so its power state should - * not be changed here and the device register values saved - * originally should be restored on resume again. + * suspend-to-idle in a spurious wakeup case. The device should + * be in D0 at this point, but if it is a bridge, it may be + * necessary to save its state. */ - pci_dev->state_saved = true; - } else if (pci_dev->state_saved) { - if (pci_dev->current_state == PCI_D0) - pci_dev->skip_bus_pm = true; - } else { + if (!pci_dev->state_saved) + pci_save_state(pci_dev); + } else if (!pci_dev->state_saved) { pci_save_state(pci_dev); if (pci_power_manageable(pci_dev)) pci_prepare_to_sleep(pci_dev); @@ -851,6 +866,22 @@ static int pci_pm_suspend_noirq(struct device *dev) dev_dbg(dev, "PCI PM: Suspend power state: %s\n", pci_power_name(pci_dev->current_state)); + if (pci_dev->current_state == PCI_D0) { + pci_dev->skip_bus_pm = true; + /* + * Per PCI PM r1.2, table 6-1, a bridge must be in D0 if any + * downstream device is in D0, so avoid changing the power state + * of the parent bridge by setting the skip_bus_pm flag for it. + */ + if (pci_dev->bus->self) + pci_dev->bus->self->skip_bus_pm = true; + } + + if (pci_dev->skip_bus_pm && pm_suspend_no_platform()) { + dev_dbg(dev, "PCI PM: Skipped\n"); + goto Fixup; + } + pci_pm_set_unknown_state(pci_dev); /* @@ -898,7 +929,16 @@ static int pci_pm_resume_noirq(struct device *dev) if (dev_pm_smart_suspend_and_suspended(dev)) pm_runtime_set_active(dev); - pci_pm_default_resume_early(pci_dev); + /* + * In the suspend-to-idle case, devices left in D0 during suspend will + * stay in D0, so it is not necessary to restore or update their + * configuration here and attempting to put them into D0 again is + * pointless, so avoid doing that. + */ + if (!(pci_dev->skip_bus_pm && pm_suspend_no_platform())) + pci_pm_default_resume_early(pci_dev); + + pci_fixup_device(pci_fixup_resume_early, pci_dev); if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_resume_early(dev); @@ -972,15 +1012,15 @@ static int pci_pm_freeze(struct device *dev) } /* - * This used to be done in pci_pm_prepare() for all devices and some - * drivers may depend on it, so do it here. Ideally, runtime-suspended - * devices should not be touched during freeze/thaw transitions, - * however. + * Resume all runtime-suspended devices before creating a snapshot + * image of system memory, because the restore kernel generally cannot + * be expected to always handle them consistently and they need to be + * put into the runtime-active metastate during system resume anyway, + * so it is better to ensure that the state saved in the image will be + * always consistent with that. */ - if (!dev_pm_smart_suspend_and_suspended(dev)) { - pm_runtime_resume(dev); - pci_dev->state_saved = false; - } + pm_runtime_resume(dev); + pci_dev->state_saved = false; if (pm->freeze) { int error; @@ -994,22 +1034,11 @@ static int pci_pm_freeze(struct device *dev) return 0; } -static int pci_pm_freeze_late(struct device *dev) -{ - if (dev_pm_smart_suspend_and_suspended(dev)) - return 0; - - return pm_generic_freeze_late(dev); -} - static int pci_pm_freeze_noirq(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); struct device_driver *drv = dev->driver; - if (dev_pm_smart_suspend_and_suspended(dev)) - return 0; - if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_suspend_late(dev, PMSG_FREEZE); @@ -1039,16 +1068,6 @@ static int pci_pm_thaw_noirq(struct device *dev) struct device_driver *drv = dev->driver; int error = 0; - /* - * If the device is in runtime suspend, the code below may not work - * correctly with it, so skip that code and make the PM core skip all of - * the subsequent "thaw" callbacks for the device. - */ - if (dev_pm_smart_suspend_and_suspended(dev)) { - dev_pm_skip_next_resume_phases(dev); - return 0; - } - if (pcibios_pm_ops.thaw_noirq) { error = pcibios_pm_ops.thaw_noirq(dev); if (error) @@ -1108,10 +1127,13 @@ static int pci_pm_poweroff(struct device *dev) /* The reason to do that is the same as in pci_pm_suspend(). */ if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) || - !pci_dev_keep_suspended(pci_dev)) + pci_dev_need_resume(pci_dev)) { pm_runtime_resume(dev); + pci_dev->state_saved = false; + } else { + pci_dev_adjust_pme(pci_dev); + } - pci_dev->state_saved = false; if (pm->poweroff) { int error; @@ -1183,10 +1205,6 @@ static int pci_pm_restore_noirq(struct device *dev) struct device_driver *drv = dev->driver; int error = 0; - /* This is analogous to the pci_pm_resume_noirq() case. */ - if (dev_pm_smart_suspend_and_suspended(dev)) - pm_runtime_set_active(dev); - if (pcibios_pm_ops.restore_noirq) { error = pcibios_pm_ops.restore_noirq(dev); if (error) @@ -1194,6 +1212,7 @@ static int pci_pm_restore_noirq(struct device *dev) } pci_pm_default_resume_early(pci_dev); + pci_fixup_device(pci_fixup_resume_early, pci_dev); if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_resume_early(dev); @@ -1235,7 +1254,6 @@ static int pci_pm_restore(struct device *dev) #else /* !CONFIG_HIBERNATE_CALLBACKS */ #define pci_pm_freeze NULL -#define pci_pm_freeze_late NULL #define pci_pm_freeze_noirq NULL #define pci_pm_thaw NULL #define pci_pm_thaw_noirq NULL @@ -1361,7 +1379,6 @@ static const struct dev_pm_ops pci_dev_pm_ops = { .suspend_late = pci_pm_suspend_late, .resume = pci_pm_resume, .freeze = pci_pm_freeze, - .freeze_late = pci_pm_freeze_late, .thaw = pci_pm_thaw, .poweroff = pci_pm_poweroff, .poweroff_late = pci_pm_poweroff_late, diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8abc843b1615..b1f563916036 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -777,6 +777,12 @@ static inline pci_power_t platform_pci_get_power_state(struct pci_dev *dev) return pci_platform_pm ? pci_platform_pm->get_state(dev) : PCI_UNKNOWN; } +static inline void platform_pci_refresh_power_state(struct pci_dev *dev) +{ + if (pci_platform_pm && pci_platform_pm->refresh_state) + pci_platform_pm->refresh_state(dev); +} + static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev) { return pci_platform_pm ? @@ -938,6 +944,21 @@ void pci_update_current_state(struct pci_dev *dev, pci_power_t state) } /** + * pci_refresh_power_state - Refresh the given device's power state data + * @dev: Target PCI device. + * + * Ask the platform to refresh the devices power state information and invoke + * pci_update_current_state() to update its current PCI power state. + */ +void pci_refresh_power_state(struct pci_dev *dev) +{ + if (platform_pci_power_manageable(dev)) + platform_pci_refresh_power_state(dev); + + pci_update_current_state(dev, dev->current_state); +} + +/** * pci_power_up - Put the given device into D0 forcibly * @dev: PCI device to power up */ @@ -1004,15 +1025,10 @@ static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state) if (state == PCI_D0) { pci_platform_power_transition(dev, PCI_D0); /* - * Mandatory power management transition delays, see - * PCI Express Base Specification Revision 2.0 Section - * 6.6.1: Conventional Reset. Do not delay for - * devices powered on/off by corresponding bridge, - * because have already delayed for the bridge. + * Mandatory power management transition delays are + * handled in the PCIe portdrv resume hooks. */ if (dev->runtime_d3cold) { - if (dev->d3cold_delay && !dev->imm_ready) - msleep(dev->d3cold_delay); /* * When powering on a bridge from D3cold, the * whole hierarchy may be powered on into @@ -2065,6 +2081,13 @@ static void pci_pme_list_scan(struct work_struct *work) */ if (bridge && bridge->current_state != PCI_D0) continue; + /* + * If the device is in D3cold it should not be + * polled either. + */ + if (pme_dev->dev->current_state == PCI_D3cold) + continue; + pci_pme_wakeup(pme_dev->dev, NULL); } else { list_del(&pme_dev->list); @@ -2459,45 +2482,56 @@ bool pci_dev_run_wake(struct pci_dev *dev) EXPORT_SYMBOL_GPL(pci_dev_run_wake); /** - * pci_dev_keep_suspended - Check if the device can stay in the suspended state. + * pci_dev_need_resume - Check if it is necessary to resume the device. * @pci_dev: Device to check. * - * Return 'true' if the device is runtime-suspended, it doesn't have to be + * Return 'true' if the device is not runtime-suspended or it has to be * reconfigured due to wakeup settings difference between system and runtime - * suspend and the current power state of it is suitable for the upcoming - * (system) transition. - * - * If the device is not configured for system wakeup, disable PME for it before - * returning 'true' to prevent it from waking up the system unnecessarily. + * suspend, or the current power state of it is not suitable for the upcoming + * (system-wide) transition. */ -bool pci_dev_keep_suspended(struct pci_dev *pci_dev) +bool pci_dev_need_resume(struct pci_dev *pci_dev) { struct device *dev = &pci_dev->dev; - bool wakeup = device_may_wakeup(dev); + pci_power_t target_state; - if (!pm_runtime_suspended(dev) - || pci_target_state(pci_dev, wakeup) != pci_dev->current_state - || platform_pci_need_resume(pci_dev)) - return false; + if (!pm_runtime_suspended(dev) || platform_pci_need_resume(pci_dev)) + return true; + + target_state = pci_target_state(pci_dev, device_may_wakeup(dev)); /* - * At this point the device is good to go unless it's been configured - * to generate PME at the runtime suspend time, but it is not supposed - * to wake up the system. In that case, simply disable PME for it - * (it will have to be re-enabled on exit from system resume). - * - * If the device's power state is D3cold and the platform check above - * hasn't triggered, the device's configuration is suitable and we don't - * need to manipulate it at all. + * If the earlier platform check has not triggered, D3cold is just power + * removal on top of D3hot, so no need to resume the device in that + * case. */ + return target_state != pci_dev->current_state && + target_state != PCI_D3cold && + pci_dev->current_state != PCI_D3hot; +} + +/** + * pci_dev_adjust_pme - Adjust PME setting for a suspended device. + * @pci_dev: Device to check. + * + * If the device is suspended and it is not configured for system wakeup, + * disable PME for it to prevent it from waking up the system unnecessarily. + * + * Note that if the device's power state is D3cold and the platform check in + * pci_dev_need_resume() has not triggered, the device's configuration need not + * be changed. + */ +void pci_dev_adjust_pme(struct pci_dev *pci_dev) +{ + struct device *dev = &pci_dev->dev; + spin_lock_irq(&dev->power.lock); - if (pm_runtime_suspended(dev) && pci_dev->current_state < PCI_D3cold && - !wakeup) + if (pm_runtime_suspended(dev) && !device_may_wakeup(dev) && + pci_dev->current_state < PCI_D3cold) __pci_pme_active(pci_dev, false); spin_unlock_irq(&dev->power.lock); - return true; } /** @@ -4568,14 +4602,16 @@ static int pci_pm_reset(struct pci_dev *dev, int probe) return pci_dev_wait(dev, "PM D3->D0", PCIE_RESET_READY_POLL_MS); } + /** - * pcie_wait_for_link - Wait until link is active or inactive + * pcie_wait_for_link_delay - Wait until link is active or inactive * @pdev: Bridge device * @active: waiting for active or inactive? + * @delay: Delay to wait after link has become active (in ms) * * Use this to wait till link becomes active or inactive. */ -bool pcie_wait_for_link(struct pci_dev *pdev, bool active) +bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active, int delay) { int timeout = 1000; bool ret; @@ -4612,13 +4648,25 @@ bool pcie_wait_for_link(struct pci_dev *pdev, bool active) timeout -= 10; } if (active && ret) - msleep(100); + msleep(delay); else if (ret != active) pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n", active ? "set" : "cleared"); return ret == active; } +/** + * pcie_wait_for_link - Wait until link is active or inactive + * @pdev: Bridge device + * @active: waiting for active or inactive? + * + * Use this to wait till link becomes active or inactive. + */ +bool pcie_wait_for_link(struct pci_dev *pdev, bool active) +{ + return pcie_wait_for_link_delay(pdev, active, 100); +} + void pci_reset_secondary_bus(struct pci_dev *dev) { u16 ctrl; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 9cb99380c61e..5db6f985f16d 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -51,6 +51,8 @@ int pci_bus_error_reset(struct pci_dev *dev); * * @get_state: queries the platform firmware for a device's current power state * + * @refresh_state: asks the platform to refresh the device's power state data + * * @choose_state: returns PCI power state of given device preferred by the * platform; to be used during system-wide transitions from a * sleeping state to the working state and vice versa @@ -69,6 +71,7 @@ struct pci_platform_pm_ops { bool (*is_manageable)(struct pci_dev *dev); int (*set_state)(struct pci_dev *dev, pci_power_t state); pci_power_t (*get_state)(struct pci_dev *dev); + void (*refresh_state)(struct pci_dev *dev); pci_power_t (*choose_state)(struct pci_dev *dev); int (*set_wakeup)(struct pci_dev *dev, bool enable); bool (*need_resume)(struct pci_dev *dev); @@ -76,13 +79,15 @@ struct pci_platform_pm_ops { int pci_set_platform_pm(const struct pci_platform_pm_ops *ops); void pci_update_current_state(struct pci_dev *dev, pci_power_t state); +void pci_refresh_power_state(struct pci_dev *dev); void pci_power_up(struct pci_dev *dev); void pci_disable_enabled_device(struct pci_dev *dev); int pci_finish_runtime_suspend(struct pci_dev *dev); void pcie_clear_root_pme_status(struct pci_dev *dev); int __pci_pme_wakeup(struct pci_dev *dev, void *ign); void pci_pme_restore(struct pci_dev *dev); -bool pci_dev_keep_suspended(struct pci_dev *dev); +bool pci_dev_need_resume(struct pci_dev *dev); +void pci_dev_adjust_pme(struct pci_dev *dev); void pci_dev_complete_resume(struct pci_dev *pci_dev); void pci_config_pm_runtime_get(struct pci_dev *dev); void pci_config_pm_runtime_put(struct pci_dev *dev); @@ -493,6 +498,7 @@ static inline int pci_dev_specific_disable_acs_redir(struct pci_dev *dev) void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state, u32 service); +bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active, int delay); bool pcie_wait_for_link(struct pci_dev *pdev, bool active); #ifdef CONFIG_PCIEASPM void pcie_aspm_init_link_state(struct pci_dev *pdev); diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 1b330129089f..308c3e0c4a34 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/kernel.h> +#include <linux/delay.h> #include <linux/errno.h> #include <linux/pm.h> #include <linux/pm_runtime.h> @@ -378,6 +379,67 @@ static int pm_iter(struct device *dev, void *data) return 0; } +static int get_downstream_delay(struct pci_bus *bus) +{ + struct pci_dev *pdev; + int min_delay = 100; + int max_delay = 0; + + list_for_each_entry(pdev, &bus->devices, bus_list) { + if (!pdev->imm_ready) + min_delay = 0; + else if (pdev->d3cold_delay < min_delay) + min_delay = pdev->d3cold_delay; + if (pdev->d3cold_delay > max_delay) + max_delay = pdev->d3cold_delay; + } + + return max(min_delay, max_delay); +} + +/* + * wait_for_downstream_link - Wait for downstream link to establish + * @pdev: PCIe port whose downstream link is waited + * + * Handle delays according to PCIe 4.0 section 6.6.1 before configuration + * access to the downstream component is permitted. + * + * This blocks PCI core resume of the hierarchy below this port until the + * link is trained. Should be called before resuming port services to + * prevent pciehp from starting to tear-down the hierarchy too soon. + */ +static void wait_for_downstream_link(struct pci_dev *pdev) +{ + int delay; + + if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT && + pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM) + return; + + if (pci_dev_is_disconnected(pdev)) + return; + + if (!pdev->subordinate || list_empty(&pdev->subordinate->devices) || + !pdev->bridge_d3) + return; + + delay = get_downstream_delay(pdev->subordinate); + if (!delay) + return; + + dev_dbg(&pdev->dev, "waiting downstream link for %d ms\n", delay); + + /* + * If downstream port does not support speeds greater than 5 GT/s + * need to wait 100ms. For higher speeds (gen3) we need to wait + * first for the data link layer to become active. + */ + if (pcie_get_speed_cap(pdev) <= PCIE_SPEED_5_0GT) + msleep(delay); + else + pcie_wait_for_link_delay(pdev, true, delay); +} + /** * pcie_port_device_suspend - suspend port services associated with a PCIe port * @dev: PCI Express port to handle @@ -391,6 +453,8 @@ int pcie_port_device_suspend(struct device *dev) int pcie_port_device_resume_noirq(struct device *dev) { size_t off = offsetof(struct pcie_port_service_driver, resume_noirq); + + wait_for_downstream_link(to_pci_dev(dev)); return device_for_each_child(dev, &off, pm_iter); } @@ -421,6 +485,8 @@ int pcie_port_device_runtime_suspend(struct device *dev) int pcie_port_device_runtime_resume(struct device *dev) { size_t off = offsetof(struct pcie_port_service_driver, runtime_resume); + + wait_for_downstream_link(to_pci_dev(dev)); return device_for_each_child(dev, &off, pm_iter); } #endif /* PM */ diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index 5c0170597037..c502dfbf66e3 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cardbus.c -- 16-bit PCMCIA core support * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The initial developer of the original code is David A. Hinds * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index ac0672b8dfca..abd029945cc8 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cistpl.c -- 16-bit PCMCIA Card Information Structure parser * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The initial developer of the original code is David A. Hinds * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 8c8caec3a72c..e211e2619680 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cs.c -- Kernel Card Services - core services * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The initial developer of the original code is David A. Hinds * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 03ec43802909..33c9b6ea7364 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cs_internal.h -- definitions internal to the PCMCIA core modules * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The initial developer of the original code is David A. Hinds * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. @@ -12,7 +9,6 @@ * (C) 1999 David A. Hinds * (C) 2003 - 2010 Dominik Brodowski * - * * This file contains definitions _only_ needed by the PCMCIA core modules. * It must not be included by PCMCIA socket drivers or by PCMCIA device * drivers. diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index a9258f641cee..552bda167e7d 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ds.c -- 16-bit PCMCIA core support * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The initial developer of the original code is David A. Hinds * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. diff --git a/drivers/pcmcia/pcmcia_cis.c b/drivers/pcmcia/pcmcia_cis.c index 1c05d74e850d..b553f7ab532f 100644 --- a/drivers/pcmcia/pcmcia_cis.c +++ b/drivers/pcmcia/pcmcia_cis.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PCMCIA high-level CIS access functions * @@ -7,11 +8,6 @@ * * Copyright (C) 1999 David A. Hinds * Copyright (C) 2004-2010 Dominik Brodowski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/slab.h> diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 41ce410f7f97..e3a6b6c8a5b0 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PCMCIA 16-bit resource management functions * @@ -7,11 +8,6 @@ * * Copyright (C) 1999 David A. Hinds * Copyright (C) 2004-2010 Dominik Brodowski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/pcmcia/pxa2xx_balloon3.c b/drivers/pcmcia/pxa2xx_balloon3.c index 2ef576c5b69d..5fe1da7a50e4 100644 --- a/drivers/pcmcia/pxa2xx_balloon3.c +++ b/drivers/pcmcia/pxa2xx_balloon3.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pcmcia/pxa2xx_balloon3.c * @@ -9,10 +10,6 @@ * Derived from pxa2xx_mainstone.c, by Nico Pitre * * Various modification by Marek Vasut <marek.vasut@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/pcmcia/pxa2xx_cm_x255.c b/drivers/pcmcia/pxa2xx_cm_x255.c index da40908b29dd..c0b6b846fbaa 100644 --- a/drivers/pcmcia/pxa2xx_cm_x255.c +++ b/drivers/pcmcia/pxa2xx_cm_x255.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pcmcia/pxa/pxa_cm_x255.c * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Compulab Ltd., 2003, 2007, 2008 * Mike Rapoport <mike@compulab.co.il> - * */ #include <linux/platform_device.h> diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c index f59223f2307d..36e35da5f887 100644 --- a/drivers/pcmcia/pxa2xx_cm_x270.c +++ b/drivers/pcmcia/pxa2xx_cm_x270.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pcmcia/pxa/pxa_cm_x270.c * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Compulab Ltd., 2003, 2007, 2008 * Mike Rapoport <mike@compulab.co.il> - * */ #include <linux/platform_device.h> diff --git a/drivers/pcmcia/pxa2xx_cm_x2xx.c b/drivers/pcmcia/pxa2xx_cm_x2xx.c index 6e7dcfd22ede..14eae238131d 100644 --- a/drivers/pcmcia/pxa2xx_cm_x2xx.c +++ b/drivers/pcmcia/pxa2xx_cm_x2xx.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pcmcia/pxa/pxa_cm_x2xx.c * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Compulab Ltd., 2003, 2007, 2008 * Mike Rapoport <mike@compulab.co.il> - * */ #include <linux/module.h> diff --git a/drivers/pcmcia/pxa2xx_colibri.c b/drivers/pcmcia/pxa2xx_colibri.c index 4dee7b2a8032..f0f725e99604 100644 --- a/drivers/pcmcia/pxa2xx_colibri.c +++ b/drivers/pcmcia/pxa2xx_colibri.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pcmcia/pxa2xx_colibri.c * * Driver for Toradex Colibri PXA270 CF socket * * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/pcmcia/pxa2xx_e740.c b/drivers/pcmcia/pxa2xx_e740.c index 8751a323b448..72caa6d05ab9 100644 --- a/drivers/pcmcia/pxa2xx_e740.c +++ b/drivers/pcmcia/pxa2xx_e740.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Toshiba e740 PCMCIA specific routines. * * (c) 2004 Ian Molton <spyro@f2s.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> diff --git a/drivers/pcmcia/pxa2xx_hx4700.c b/drivers/pcmcia/pxa2xx_hx4700.c index 7dfef3ee5b53..87b6a1639d94 100644 --- a/drivers/pcmcia/pxa2xx_hx4700.c +++ b/drivers/pcmcia/pxa2xx_hx4700.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index 770c7bf0171d..a076e4108452 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pcmcia/pxa2xx_mainstone.c * @@ -6,10 +7,6 @@ * Created: May 12, 2004 * Author: Nicolas Pitre * Copyright: MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/gpio/consumer.h> #include <linux/module.h> diff --git a/drivers/pcmcia/pxa2xx_palmld.c b/drivers/pcmcia/pxa2xx_palmld.c index ed7d4dbc39fa..cfff41ac9ca2 100644 --- a/drivers/pcmcia/pxa2xx_palmld.c +++ b/drivers/pcmcia/pxa2xx_palmld.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pcmcia/pxa2xx_palmld.c * @@ -5,11 +6,6 @@ * * Copyright (C) 2006 Alex Osborne <ato@meshy.org> * Copyright (C) 2007-2011 Marek Vasut <marek.vasut@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/pcmcia/pxa2xx_palmtc.c b/drivers/pcmcia/pxa2xx_palmtc.c index 81225a7a8cbb..8fe05613ed04 100644 --- a/drivers/pcmcia/pxa2xx_palmtc.c +++ b/drivers/pcmcia/pxa2xx_palmtc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pcmcia/pxa2xx_palmtc.c * @@ -5,11 +6,6 @@ * * Copyright (C) 2008 Alex Osborne <ato@meshy.org> * Copyright (C) 2009-2011 Marek Vasut <marek.vasut@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/pcmcia/pxa2xx_palmtx.c b/drivers/pcmcia/pxa2xx_palmtx.c index 069b6bbcf319..c449ca72cb87 100644 --- a/drivers/pcmcia/pxa2xx_palmtx.c +++ b/drivers/pcmcia/pxa2xx_palmtx.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pcmcia/pxa2xx_palmtx.c * * Driver for Palm T|X PCMCIA * * Copyright (C) 2007-2011 Marek Vasut <marek.vasut@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index 89ebd8c76636..5fdd25a9e28e 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Sharp SL-C7xx Series PCMCIA routines * * Copyright (c) 2004-2005 Richard Purdie * * Based on Sharp's 2.4 kernel patches and pxa2xx_mainstone.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/pcmcia/pxa2xx_stargate2.c b/drivers/pcmcia/pxa2xx_stargate2.c index 1d73c4401fdd..6efb7f814b4a 100644 --- a/drivers/pcmcia/pxa2xx_stargate2.c +++ b/drivers/pcmcia/pxa2xx_stargate2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pcmcia/pxa2xx_stargate2.c * @@ -7,10 +8,6 @@ * Author: Ed C. Epp * Copyright: Intel Corp 2005 * Jonathan Cameron <jic23@cam.ac.uk> 2009 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/pcmcia/pxa2xx_trizeps4.c b/drivers/pcmcia/pxa2xx_trizeps4.c index d326ba1fa1ce..6db8fe880ed4 100644 --- a/drivers/pcmcia/pxa2xx_trizeps4.c +++ b/drivers/pcmcia/pxa2xx_trizeps4.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pcmcia/pxa2xx_trizeps4.c * @@ -6,10 +7,6 @@ * Author: Jürgen Schindele * Created: 20 02, 2006 * Copyright: Jürgen Schindele - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/pcmcia/pxa2xx_vpac270.c b/drivers/pcmcia/pxa2xx_vpac270.c index 33c5b8823367..3565add03a5e 100644 --- a/drivers/pcmcia/pxa2xx_vpac270.c +++ b/drivers/pcmcia/pxa2xx_vpac270.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pcmcia/pxa2xx_vpac270.c * * Driver for Voipac PXA270 PCMCIA and CF sockets * * Copyright (C) 2010-2011 Marek Vasut <marek.vasut@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/gpio.h> diff --git a/drivers/pcmcia/rsrc_iodyn.c b/drivers/pcmcia/rsrc_iodyn.c index f53c237bda2f..b04b16496b0c 100644 --- a/drivers/pcmcia/rsrc_iodyn.c +++ b/drivers/pcmcia/rsrc_iodyn.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rsrc_iodyn.c -- Resource management routines for MEM-static sockets. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The initial developer of the original code is David A. Hinds * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index df2cb70aef5b..252893216e50 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rsrc_mgr.c -- Resource management routines and/or wrappers * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The initial developer of the original code is David A. Hinds * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 49377d502b74..9e6922c08ef6 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rsrc_nonstatic.c -- Resource management routines for !SS_CAP_STATIC_MAP sockets * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The initial developer of the original code is David A. Hinds * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. diff --git a/drivers/pcmcia/sa1111_badge4.c b/drivers/pcmcia/sa1111_badge4.c index 93a5c7423d80..e76d5ba921dd 100644 --- a/drivers/pcmcia/sa1111_badge4.c +++ b/drivers/pcmcia/sa1111_badge4.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pcmcia/sa1100_badge4.c * @@ -6,11 +7,6 @@ * Christopher Hoover <ch@hpl.hp.com> * * Copyright (C) 2002 Hewlett-Packard Company - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> #include <linux/kernel.h> diff --git a/drivers/pcmcia/sa1111_lubbock.c b/drivers/pcmcia/sa1111_lubbock.c index e3fc14cfb42b..7feb8d61c639 100644 --- a/drivers/pcmcia/sa1111_lubbock.c +++ b/drivers/pcmcia/sa1111_lubbock.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pcmcia/pxa2xx_lubbock.c * @@ -5,14 +6,9 @@ * Created: Jan 10, 2002 * Copyright: MontaVista Software Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c * * Lubbock PCMCIA specific routines. - * */ #include <linux/module.h> #include <linux/kernel.h> diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index d6881514d38e..d1b220a1e1ab 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * socket_sysfs.c -- most of socket-related sysfs output * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * (C) 2003 - 2004 Dominik Brodowski */ diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig index e4221a107dca..09ae8a970880 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig @@ -71,6 +71,14 @@ config ARM_DSU_PMU system, control logic. The PMU allows counting various events related to DSU. +config FSL_IMX8_DDR_PMU + tristate "Freescale i.MX8 DDR perf monitor" + depends on ARCH_MXC + help + Provides support for the DDR performance monitor in i.MX8, which + can give information about memory throughput and other related + events. + config HISI_PMU bool "HiSilicon SoC PMU" depends on ARM64 && ACPI diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile index 30489941f3d6..2ebb4de17815 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_ARM_DSU_PMU) += arm_dsu_pmu.o obj-$(CONFIG_ARM_PMU) += arm_pmu.o arm_pmu_platform.o obj-$(CONFIG_ARM_PMU_ACPI) += arm_pmu_acpi.o obj-$(CONFIG_ARM_SMMU_V3_PMU) += arm_smmuv3_pmu.o +obj-$(CONFIG_FSL_IMX8_DDR_PMU) += fsl_imx8_ddr_perf.o obj-$(CONFIG_HISI_PMU) += hisilicon/ obj-$(CONFIG_QCOM_L2_PMU) += qcom_l2_pmu.o obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c index 5851de56bbd0..70968c8c09d7 100644 --- a/drivers/perf/arm_dsu_pmu.c +++ b/drivers/perf/arm_dsu_pmu.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ARM DynamIQ Shared Unit (DSU) PMU driver * * Copyright (C) ARM Limited, 2017. * * Based on ARM CCI-PMU, ARMv8 PMU-v3 drivers. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #define PMUNAME "arm_dsu" diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c index 0f197516d708..acce8781c456 100644 --- a/drivers/perf/arm_pmu_acpi.c +++ b/drivers/perf/arm_pmu_acpi.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ACPI probing code for ARM performance counters. * * Copyright (C) 2017 ARM Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> @@ -74,6 +71,76 @@ static void arm_pmu_acpi_unregister_irq(int cpu) acpi_unregister_gsi(gsi); } +#if IS_ENABLED(CONFIG_ARM_SPE_PMU) +static struct resource spe_resources[] = { + { + /* irq */ + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device spe_dev = { + .name = ARMV8_SPE_PDEV_NAME, + .id = -1, + .resource = spe_resources, + .num_resources = ARRAY_SIZE(spe_resources) +}; + +/* + * For lack of a better place, hook the normal PMU MADT walk + * and create a SPE device if we detect a recent MADT with + * a homogeneous PPI mapping. + */ +static void arm_spe_acpi_register_device(void) +{ + int cpu, hetid, irq, ret; + bool first = true; + u16 gsi = 0; + + /* + * Sanity check all the GICC tables for the same interrupt number. + * For now, we only support homogeneous ACPI/SPE machines. + */ + for_each_possible_cpu(cpu) { + struct acpi_madt_generic_interrupt *gicc; + + gicc = acpi_cpu_get_madt_gicc(cpu); + if (gicc->header.length < ACPI_MADT_GICC_SPE) + return; + + if (first) { + gsi = gicc->spe_interrupt; + if (!gsi) + return; + hetid = find_acpi_cpu_topology_hetero_id(cpu); + first = false; + } else if ((gsi != gicc->spe_interrupt) || + (hetid != find_acpi_cpu_topology_hetero_id(cpu))) { + pr_warn("ACPI: SPE must be homogeneous\n"); + return; + } + } + + irq = acpi_register_gsi(NULL, gsi, ACPI_LEVEL_SENSITIVE, + ACPI_ACTIVE_HIGH); + if (irq < 0) { + pr_warn("ACPI: SPE Unable to register interrupt: %d\n", gsi); + return; + } + + spe_resources[0].start = irq; + ret = platform_device_register(&spe_dev); + if (ret < 0) { + pr_warn("ACPI: SPE: Unable to register device\n"); + acpi_unregister_gsi(gsi); + } +} +#else +static inline void arm_spe_acpi_register_device(void) +{ +} +#endif /* CONFIG_ARM_SPE_PMU */ + static int arm_pmu_acpi_parse_irqs(void) { int irq, cpu, irq_cpu, err; @@ -279,6 +346,8 @@ static int arm_pmu_acpi_init(void) if (acpi_disabled) return 0; + arm_spe_acpi_register_device(); + ret = arm_pmu_acpi_parse_irqs(); if (ret) return ret; diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c index e120f933412a..4e4984a55cd1 100644 --- a/drivers/perf/arm_spe_pmu.c +++ b/drivers/perf/arm_spe_pmu.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Perf support for the Statistical Profiling Extension, introduced as * part of ARMv8.2. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * * Copyright (C) 2016 ARM Limited * * Author: Will Deacon <will.deacon@arm.com> @@ -38,6 +27,7 @@ #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/perf_event.h> +#include <linux/perf/arm_pmu.h> #include <linux/platform_device.h> #include <linux/printk.h> #include <linux/slab.h> @@ -1168,7 +1158,13 @@ static const struct of_device_id arm_spe_pmu_of_match[] = { }; MODULE_DEVICE_TABLE(of, arm_spe_pmu_of_match); -static int arm_spe_pmu_device_dt_probe(struct platform_device *pdev) +static const struct platform_device_id arm_spe_match[] = { + { ARMV8_SPE_PDEV_NAME, 0}, + { } +}; +MODULE_DEVICE_TABLE(platform, arm_spe_match); + +static int arm_spe_pmu_device_probe(struct platform_device *pdev) { int ret; struct arm_spe_pmu *spe_pmu; @@ -1228,11 +1224,12 @@ static int arm_spe_pmu_device_remove(struct platform_device *pdev) } static struct platform_driver arm_spe_pmu_driver = { + .id_table = arm_spe_match, .driver = { .name = DRVNAME, .of_match_table = of_match_ptr(arm_spe_pmu_of_match), }, - .probe = arm_spe_pmu_device_dt_probe, + .probe = arm_spe_pmu_device_probe, .remove = arm_spe_pmu_device_remove, }; diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c new file mode 100644 index 000000000000..63fe21600072 --- /dev/null +++ b/drivers/perf/fsl_imx8_ddr_perf.c @@ -0,0 +1,554 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2017 NXP + * Copyright 2016 Freescale Semiconductor, Inc. + */ + +#include <linux/bitfield.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> +#include <linux/perf_event.h> +#include <linux/slab.h> + +#define COUNTER_CNTL 0x0 +#define COUNTER_READ 0x20 + +#define COUNTER_DPCR1 0x30 + +#define CNTL_OVER 0x1 +#define CNTL_CLEAR 0x2 +#define CNTL_EN 0x4 +#define CNTL_EN_MASK 0xFFFFFFFB +#define CNTL_CLEAR_MASK 0xFFFFFFFD +#define CNTL_OVER_MASK 0xFFFFFFFE + +#define CNTL_CSV_SHIFT 24 +#define CNTL_CSV_MASK (0xFF << CNTL_CSV_SHIFT) + +#define EVENT_CYCLES_ID 0 +#define EVENT_CYCLES_COUNTER 0 +#define NUM_COUNTERS 4 + +#define to_ddr_pmu(p) container_of(p, struct ddr_pmu, pmu) + +#define DDR_PERF_DEV_NAME "imx8_ddr" +#define DDR_CPUHP_CB_NAME DDR_PERF_DEV_NAME "_perf_pmu" + +static DEFINE_IDA(ddr_ida); + +static const struct of_device_id imx_ddr_pmu_dt_ids[] = { + { .compatible = "fsl,imx8-ddr-pmu",}, + { .compatible = "fsl,imx8m-ddr-pmu",}, + { /* sentinel */ } +}; + +struct ddr_pmu { + struct pmu pmu; + void __iomem *base; + unsigned int cpu; + struct hlist_node node; + struct device *dev; + struct perf_event *events[NUM_COUNTERS]; + int active_events; + enum cpuhp_state cpuhp_state; + int irq; + int id; +}; + +static ssize_t ddr_perf_cpumask_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ddr_pmu *pmu = dev_get_drvdata(dev); + + return cpumap_print_to_pagebuf(true, buf, cpumask_of(pmu->cpu)); +} + +static struct device_attribute ddr_perf_cpumask_attr = + __ATTR(cpumask, 0444, ddr_perf_cpumask_show, NULL); + +static struct attribute *ddr_perf_cpumask_attrs[] = { + &ddr_perf_cpumask_attr.attr, + NULL, +}; + +static struct attribute_group ddr_perf_cpumask_attr_group = { + .attrs = ddr_perf_cpumask_attrs, +}; + +static ssize_t +ddr_pmu_event_show(struct device *dev, struct device_attribute *attr, + char *page) +{ + struct perf_pmu_events_attr *pmu_attr; + + pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); + return sprintf(page, "event=0x%02llx\n", pmu_attr->id); +} + +#define IMX8_DDR_PMU_EVENT_ATTR(_name, _id) \ + (&((struct perf_pmu_events_attr[]) { \ + { .attr = __ATTR(_name, 0444, ddr_pmu_event_show, NULL),\ + .id = _id, } \ + })[0].attr.attr) + +static struct attribute *ddr_perf_events_attrs[] = { + IMX8_DDR_PMU_EVENT_ATTR(cycles, EVENT_CYCLES_ID), + IMX8_DDR_PMU_EVENT_ATTR(selfresh, 0x01), + IMX8_DDR_PMU_EVENT_ATTR(read-accesses, 0x04), + IMX8_DDR_PMU_EVENT_ATTR(write-accesses, 0x05), + IMX8_DDR_PMU_EVENT_ATTR(read-queue-depth, 0x08), + IMX8_DDR_PMU_EVENT_ATTR(write-queue-depth, 0x09), + IMX8_DDR_PMU_EVENT_ATTR(lp-read-credit-cnt, 0x10), + IMX8_DDR_PMU_EVENT_ATTR(hp-read-credit-cnt, 0x11), + IMX8_DDR_PMU_EVENT_ATTR(write-credit-cnt, 0x12), + IMX8_DDR_PMU_EVENT_ATTR(read-command, 0x20), + IMX8_DDR_PMU_EVENT_ATTR(write-command, 0x21), + IMX8_DDR_PMU_EVENT_ATTR(read-modify-write-command, 0x22), + IMX8_DDR_PMU_EVENT_ATTR(hp-read, 0x23), + IMX8_DDR_PMU_EVENT_ATTR(hp-req-nocredit, 0x24), + IMX8_DDR_PMU_EVENT_ATTR(hp-xact-credit, 0x25), + IMX8_DDR_PMU_EVENT_ATTR(lp-req-nocredit, 0x26), + IMX8_DDR_PMU_EVENT_ATTR(lp-xact-credit, 0x27), + IMX8_DDR_PMU_EVENT_ATTR(wr-xact-credit, 0x29), + IMX8_DDR_PMU_EVENT_ATTR(read-cycles, 0x2a), + IMX8_DDR_PMU_EVENT_ATTR(write-cycles, 0x2b), + IMX8_DDR_PMU_EVENT_ATTR(read-write-transition, 0x30), + IMX8_DDR_PMU_EVENT_ATTR(precharge, 0x31), + IMX8_DDR_PMU_EVENT_ATTR(activate, 0x32), + IMX8_DDR_PMU_EVENT_ATTR(load-mode, 0x33), + IMX8_DDR_PMU_EVENT_ATTR(perf-mwr, 0x34), + IMX8_DDR_PMU_EVENT_ATTR(read, 0x35), + IMX8_DDR_PMU_EVENT_ATTR(read-activate, 0x36), + IMX8_DDR_PMU_EVENT_ATTR(refresh, 0x37), + IMX8_DDR_PMU_EVENT_ATTR(write, 0x38), + IMX8_DDR_PMU_EVENT_ATTR(raw-hazard, 0x39), + NULL, +}; + +static struct attribute_group ddr_perf_events_attr_group = { + .name = "events", + .attrs = ddr_perf_events_attrs, +}; + +PMU_FORMAT_ATTR(event, "config:0-7"); + +static struct attribute *ddr_perf_format_attrs[] = { + &format_attr_event.attr, + NULL, +}; + +static struct attribute_group ddr_perf_format_attr_group = { + .name = "format", + .attrs = ddr_perf_format_attrs, +}; + +static const struct attribute_group *attr_groups[] = { + &ddr_perf_events_attr_group, + &ddr_perf_format_attr_group, + &ddr_perf_cpumask_attr_group, + NULL, +}; + +static u32 ddr_perf_alloc_counter(struct ddr_pmu *pmu, int event) +{ + int i; + + /* + * Always map cycle event to counter 0 + * Cycles counter is dedicated for cycle event + * can't used for the other events + */ + if (event == EVENT_CYCLES_ID) { + if (pmu->events[EVENT_CYCLES_COUNTER] == NULL) + return EVENT_CYCLES_COUNTER; + else + return -ENOENT; + } + + for (i = 1; i < NUM_COUNTERS; i++) { + if (pmu->events[i] == NULL) + return i; + } + + return -ENOENT; +} + +static void ddr_perf_free_counter(struct ddr_pmu *pmu, int counter) +{ + pmu->events[counter] = NULL; +} + +static u32 ddr_perf_read_counter(struct ddr_pmu *pmu, int counter) +{ + return readl_relaxed(pmu->base + COUNTER_READ + counter * 4); +} + +static int ddr_perf_event_init(struct perf_event *event) +{ + struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + struct perf_event *sibling; + + if (event->attr.type != event->pmu->type) + return -ENOENT; + + if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) + return -EOPNOTSUPP; + + if (event->cpu < 0) { + dev_warn(pmu->dev, "Can't provide per-task data!\n"); + return -EOPNOTSUPP; + } + + /* + * We must NOT create groups containing mixed PMUs, although software + * events are acceptable (for example to create a CCN group + * periodically read when a hrtimer aka cpu-clock leader triggers). + */ + if (event->group_leader->pmu != event->pmu && + !is_software_event(event->group_leader)) + return -EINVAL; + + for_each_sibling_event(sibling, event->group_leader) { + if (sibling->pmu != event->pmu && + !is_software_event(sibling)) + return -EINVAL; + } + + event->cpu = pmu->cpu; + hwc->idx = -1; + + return 0; +} + + +static void ddr_perf_event_update(struct perf_event *event) +{ + struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + u64 delta, prev_raw_count, new_raw_count; + int counter = hwc->idx; + + do { + prev_raw_count = local64_read(&hwc->prev_count); + new_raw_count = ddr_perf_read_counter(pmu, counter); + } while (local64_cmpxchg(&hwc->prev_count, prev_raw_count, + new_raw_count) != prev_raw_count); + + delta = (new_raw_count - prev_raw_count) & 0xFFFFFFFF; + + local64_add(delta, &event->count); +} + +static void ddr_perf_counter_enable(struct ddr_pmu *pmu, int config, + int counter, bool enable) +{ + u8 reg = counter * 4 + COUNTER_CNTL; + int val; + + if (enable) { + /* + * must disable first, then enable again + * otherwise, cycle counter will not work + * if previous state is enabled. + */ + writel(0, pmu->base + reg); + val = CNTL_EN | CNTL_CLEAR; + val |= FIELD_PREP(CNTL_CSV_MASK, config); + writel(val, pmu->base + reg); + } else { + /* Disable counter */ + writel(0, pmu->base + reg); + } +} + +static void ddr_perf_event_start(struct perf_event *event, int flags) +{ + struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + int counter = hwc->idx; + + local64_set(&hwc->prev_count, 0); + + ddr_perf_counter_enable(pmu, event->attr.config, counter, true); + + hwc->state = 0; +} + +static int ddr_perf_event_add(struct perf_event *event, int flags) +{ + struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + int counter; + int cfg = event->attr.config; + + counter = ddr_perf_alloc_counter(pmu, cfg); + if (counter < 0) { + dev_dbg(pmu->dev, "There are not enough counters\n"); + return -EOPNOTSUPP; + } + + pmu->events[counter] = event; + pmu->active_events++; + hwc->idx = counter; + + hwc->state |= PERF_HES_STOPPED; + + if (flags & PERF_EF_START) + ddr_perf_event_start(event, flags); + + return 0; +} + +static void ddr_perf_event_stop(struct perf_event *event, int flags) +{ + struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + int counter = hwc->idx; + + ddr_perf_counter_enable(pmu, event->attr.config, counter, false); + ddr_perf_event_update(event); + + hwc->state |= PERF_HES_STOPPED; +} + +static void ddr_perf_event_del(struct perf_event *event, int flags) +{ + struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + int counter = hwc->idx; + + ddr_perf_event_stop(event, PERF_EF_UPDATE); + + ddr_perf_free_counter(pmu, counter); + pmu->active_events--; + hwc->idx = -1; +} + +static void ddr_perf_pmu_enable(struct pmu *pmu) +{ + struct ddr_pmu *ddr_pmu = to_ddr_pmu(pmu); + + /* enable cycle counter if cycle is not active event list */ + if (ddr_pmu->events[EVENT_CYCLES_COUNTER] == NULL) + ddr_perf_counter_enable(ddr_pmu, + EVENT_CYCLES_ID, + EVENT_CYCLES_COUNTER, + true); +} + +static void ddr_perf_pmu_disable(struct pmu *pmu) +{ + struct ddr_pmu *ddr_pmu = to_ddr_pmu(pmu); + + if (ddr_pmu->events[EVENT_CYCLES_COUNTER] == NULL) + ddr_perf_counter_enable(ddr_pmu, + EVENT_CYCLES_ID, + EVENT_CYCLES_COUNTER, + false); +} + +static int ddr_perf_init(struct ddr_pmu *pmu, void __iomem *base, + struct device *dev) +{ + *pmu = (struct ddr_pmu) { + .pmu = (struct pmu) { + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, + .task_ctx_nr = perf_invalid_context, + .attr_groups = attr_groups, + .event_init = ddr_perf_event_init, + .add = ddr_perf_event_add, + .del = ddr_perf_event_del, + .start = ddr_perf_event_start, + .stop = ddr_perf_event_stop, + .read = ddr_perf_event_update, + .pmu_enable = ddr_perf_pmu_enable, + .pmu_disable = ddr_perf_pmu_disable, + }, + .base = base, + .dev = dev, + }; + + pmu->id = ida_simple_get(&ddr_ida, 0, 0, GFP_KERNEL); + return pmu->id; +} + +static irqreturn_t ddr_perf_irq_handler(int irq, void *p) +{ + int i; + struct ddr_pmu *pmu = (struct ddr_pmu *) p; + struct perf_event *event, *cycle_event = NULL; + + /* all counter will stop if cycle counter disabled */ + ddr_perf_counter_enable(pmu, + EVENT_CYCLES_ID, + EVENT_CYCLES_COUNTER, + false); + /* + * When the cycle counter overflows, all counters are stopped, + * and an IRQ is raised. If any other counter overflows, it + * continues counting, and no IRQ is raised. + * + * Cycles occur at least 4 times as often as other events, so we + * can update all events on a cycle counter overflow and not + * lose events. + * + */ + for (i = 0; i < NUM_COUNTERS; i++) { + + if (!pmu->events[i]) + continue; + + event = pmu->events[i]; + + ddr_perf_event_update(event); + + if (event->hw.idx == EVENT_CYCLES_COUNTER) + cycle_event = event; + } + + ddr_perf_counter_enable(pmu, + EVENT_CYCLES_ID, + EVENT_CYCLES_COUNTER, + true); + if (cycle_event) + ddr_perf_event_update(cycle_event); + + return IRQ_HANDLED; +} + +static int ddr_perf_offline_cpu(unsigned int cpu, struct hlist_node *node) +{ + struct ddr_pmu *pmu = hlist_entry_safe(node, struct ddr_pmu, node); + int target; + + if (cpu != pmu->cpu) + return 0; + + target = cpumask_any_but(cpu_online_mask, cpu); + if (target >= nr_cpu_ids) + return 0; + + perf_pmu_migrate_context(&pmu->pmu, cpu, target); + pmu->cpu = target; + + WARN_ON(irq_set_affinity_hint(pmu->irq, cpumask_of(pmu->cpu))); + + return 0; +} + +static int ddr_perf_probe(struct platform_device *pdev) +{ + struct ddr_pmu *pmu; + struct device_node *np; + void __iomem *base; + char *name; + int num; + int ret; + int irq; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + np = pdev->dev.of_node; + + pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL); + if (!pmu) + return -ENOMEM; + + num = ddr_perf_init(pmu, base, &pdev->dev); + + platform_set_drvdata(pdev, pmu); + + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, DDR_PERF_DEV_NAME "%d", + num); + if (!name) + return -ENOMEM; + + pmu->cpu = raw_smp_processor_id(); + ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, + DDR_CPUHP_CB_NAME, + NULL, + ddr_perf_offline_cpu); + + if (ret < 0) { + dev_err(&pdev->dev, "cpuhp_setup_state_multi failed\n"); + goto ddr_perf_err; + } + + pmu->cpuhp_state = ret; + + /* Register the pmu instance for cpu hotplug */ + cpuhp_state_add_instance_nocalls(pmu->cpuhp_state, &pmu->node); + + /* Request irq */ + irq = of_irq_get(np, 0); + if (irq < 0) { + dev_err(&pdev->dev, "Failed to get irq: %d", irq); + ret = irq; + goto ddr_perf_err; + } + + ret = devm_request_irq(&pdev->dev, irq, + ddr_perf_irq_handler, + IRQF_NOBALANCING | IRQF_NO_THREAD, + DDR_CPUHP_CB_NAME, + pmu); + if (ret < 0) { + dev_err(&pdev->dev, "Request irq failed: %d", ret); + goto ddr_perf_err; + } + + pmu->irq = irq; + ret = irq_set_affinity_hint(pmu->irq, cpumask_of(pmu->cpu)); + if (ret) { + dev_err(pmu->dev, "Failed to set interrupt affinity!\n"); + goto ddr_perf_err; + } + + ret = perf_pmu_register(&pmu->pmu, name, -1); + if (ret) + goto ddr_perf_err; + + return 0; + +ddr_perf_err: + if (pmu->cpuhp_state) + cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node); + + ida_simple_remove(&ddr_ida, pmu->id); + dev_warn(&pdev->dev, "i.MX8 DDR Perf PMU failed (%d), disabled\n", ret); + return ret; +} + +static int ddr_perf_remove(struct platform_device *pdev) +{ + struct ddr_pmu *pmu = platform_get_drvdata(pdev); + + cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node); + irq_set_affinity_hint(pmu->irq, NULL); + + perf_pmu_unregister(&pmu->pmu); + + ida_simple_remove(&ddr_ida, pmu->id); + return 0; +} + +static struct platform_driver imx_ddr_pmu_driver = { + .driver = { + .name = "imx-ddr-pmu", + .of_match_table = imx_ddr_pmu_dt_ids, + }, + .probe = ddr_perf_probe, + .remove = ddr_perf_remove, +}; + +module_platform_driver(imx_ddr_pmu_driver); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c index 0eba947c2ee9..6ad0823bcf23 100644 --- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HiSilicon SoC DDRC uncore Hardware event counters support * @@ -6,10 +7,6 @@ * Anurup M <anurup.m@huawei.com> * * This code is based on the uncore PMUs like arm-cci and arm-ccn. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> #include <linux/bug.h> diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c index 2553a844ebf6..4f2917f3e25e 100644 --- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HiSilicon SoC HHA uncore Hardware event counters support * @@ -6,10 +7,6 @@ * Anurup M <anurup.m@huawei.com> * * This code is based on the uncore PMUs like arm-cci and arm-ccn. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> #include <linux/bug.h> diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c index cf1cc34f402a..9153e093f9df 100644 --- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HiSilicon SoC L3C uncore Hardware event counters support * @@ -6,10 +7,6 @@ * Shaokun Zhang <zhangshaokun@hisilicon.com> * * This code is based on the uncore PMUs like arm-cci and arm-ccn. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> #include <linux/bug.h> diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c index f028cbc3443c..79f76f8dda8e 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HiSilicon SoC Hardware event counters support * @@ -6,10 +7,6 @@ * Shaokun Zhang <zhangshaokun@hisilicon.com> * * This code is based on the uncore PMUs like arm-cci and arm-ccn. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitmap.h> #include <linux/bitops.h> diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h index f21226a0e9c6..25b0c97b3eb0 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pmu.h +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * HiSilicon SoC Hardware event counters support * @@ -6,10 +7,6 @@ * Shaokun Zhang <zhangshaokun@hisilicon.com> * * This code is based on the uncore PMUs like arm-cci and arm-ccn. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __HISI_UNCORE_PMU_H__ #define __HISI_UNCORE_PMU_H__ diff --git a/drivers/phy/broadcom/phy-bcm-ns-usb2.c b/drivers/phy/broadcom/phy-bcm-ns-usb2.c index 58dff80e9386..9f2f84d65dcd 100644 --- a/drivers/phy/broadcom/phy-bcm-ns-usb2.c +++ b/drivers/phy/broadcom/phy-bcm-ns-usb2.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Broadcom Northstar USB 2.0 PHY Driver * * Copyright (C) 2016 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/bcma/bcma.h> diff --git a/drivers/phy/broadcom/phy-bcm-ns-usb3.c b/drivers/phy/broadcom/phy-bcm-ns-usb3.c index a53ae128eadf..14f45bc35cc5 100644 --- a/drivers/phy/broadcom/phy-bcm-ns-usb3.c +++ b/drivers/phy/broadcom/phy-bcm-ns-usb3.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Broadcom Northstar USB 3.0 PHY Driver * @@ -7,10 +8,6 @@ * All magic values used for initialization (and related comments) were obtained * from Broadcom's SDK: * Copyright (c) Broadcom Corp, 2012 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bcma/bcma.h> diff --git a/drivers/phy/hisilicon/phy-histb-combphy.c b/drivers/phy/hisilicon/phy-histb-combphy.c index 5777b3120017..62d10ef20296 100644 --- a/drivers/phy/hisilicon/phy-histb-combphy.c +++ b/drivers/phy/hisilicon/phy-histb-combphy.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * COMBPHY driver for HiSilicon STB SoCs * * Copyright (C) 2016-2017 HiSilicon Co., Ltd. http://www.hisilicon.com * * Authors: Jianguo Sun <sunjianguo1@huawei.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c b/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c index f9e0dd19ff26..be09b1530ae6 100644 --- a/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c +++ b/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Lantiq XWAY SoC RCU module based USB 1.1/2.0 PHY driver * * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com> * Copyright (C) 2017 Hauke Mehrtens <hauke@hauke-m.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/phy/phy-lpc18xx-usb-otg.c b/drivers/phy/phy-lpc18xx-usb-otg.c index 7de280a45421..f905d3c64584 100644 --- a/drivers/phy/phy-lpc18xx-usb-otg.c +++ b/drivers/phy/phy-lpc18xx-usb-otg.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PHY driver for NXP LPC18xx/43xx internal USB OTG PHY * * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/clk.h> diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs.c b/drivers/phy/qualcomm/phy-qcom-usb-hs.c index 04934f8dac91..b163b3a1558d 100644 --- a/drivers/phy/qualcomm/phy-qcom-usb-hs.c +++ b/drivers/phy/qualcomm/phy-qcom-usb-hs.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /** * Copyright (C) 2016 Linaro Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/ulpi/driver.h> diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hsic.c b/drivers/phy/qualcomm/phy-qcom-usb-hsic.c index c110563a73cb..04d18d52f700 100644 --- a/drivers/phy/qualcomm/phy-qcom-usb-hsic.c +++ b/drivers/phy/qualcomm/phy-qcom-usb-hsic.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /** * Copyright (C) 2016 Linaro Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/ulpi/driver.h> diff --git a/drivers/phy/rockchip/phy-rockchip-emmc.c b/drivers/phy/rockchip/phy-rockchip-emmc.c index b804c6bf4b55..2dc19ddd120f 100644 --- a/drivers/phy/rockchip/phy-rockchip-emmc.c +++ b/drivers/phy/rockchip/phy-rockchip-emmc.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Rockchip emmc PHY driver * * Copyright (C) 2016 Shawn Lin <shawn.lin@rock-chips.com> * Copyright (C) 2016 ROCKCHIP, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/clk.h> diff --git a/drivers/phy/rockchip/phy-rockchip-pcie.c b/drivers/phy/rockchip/phy-rockchip-pcie.c index 7cbdde029c0a..75216091d901 100644 --- a/drivers/phy/rockchip/phy-rockchip-pcie.c +++ b/drivers/phy/rockchip/phy-rockchip-pcie.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Rockchip PCIe PHY driver * * Copyright (C) 2016 Shawn Lin <shawn.lin@rock-chips.com> * Copyright (C) 2016 ROCKCHIP, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/clk.h> diff --git a/drivers/phy/rockchip/phy-rockchip-usb.c b/drivers/phy/rockchip/phy-rockchip-usb.c index b2899c744ad9..8454285977eb 100644 --- a/drivers/phy/rockchip/phy-rockchip-usb.c +++ b/drivers/phy/rockchip/phy-rockchip-usb.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Rockchip usb PHY driver * * Copyright (C) 2014 Yunzhi Li <lyz@rock-chips.com> * Copyright (C) 2014 ROCKCHIP, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/clk.h> diff --git a/drivers/phy/samsung/phy-exynos-dp-video.c b/drivers/phy/samsung/phy-exynos-dp-video.c index 2dd6dd1f37a8..aebd216dcf2f 100644 --- a/drivers/phy/samsung/phy-exynos-dp-video.c +++ b/drivers/phy/samsung/phy-exynos-dp-video.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung EXYNOS SoC series Display Port PHY driver * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Author: Jingoo Han <jg1.han@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/phy/samsung/phy-exynos-mipi-video.c b/drivers/phy/samsung/phy-exynos-mipi-video.c index 00d89599c67d..3784bf100b95 100644 --- a/drivers/phy/samsung/phy-exynos-mipi-video.c +++ b/drivers/phy/samsung/phy-exynos-mipi-video.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver * * Copyright (C) 2013,2016 Samsung Electronics Co., Ltd. * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/phy/samsung/phy-exynos-pcie.c b/drivers/phy/samsung/phy-exynos-pcie.c index a89c12faff39..1b4ba8bdb43c 100644 --- a/drivers/phy/samsung/phy-exynos-pcie.c +++ b/drivers/phy/samsung/phy-exynos-pcie.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung EXYNOS SoC series PCIe PHY driver * @@ -5,10 +6,6 @@ * * Copyright (C) 2017 Samsung Electronics Co., Ltd. * Jaehoon Chung <jh80.chung@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/phy/samsung/phy-exynos4210-usb2.c b/drivers/phy/samsung/phy-exynos4210-usb2.c index 1f50e1004828..3898a7f58217 100644 --- a/drivers/phy/samsung/phy-exynos4210-usb2.c +++ b/drivers/phy/samsung/phy-exynos4210-usb2.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Author: Kamil Debski <k.debski@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/phy/samsung/phy-exynos4x12-usb2.c b/drivers/phy/samsung/phy-exynos4x12-usb2.c index 7f27a91acf87..b528a5d037fe 100644 --- a/drivers/phy/samsung/phy-exynos4x12-usb2.c +++ b/drivers/phy/samsung/phy-exynos4x12-usb2.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4x12 support * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Author: Kamil Debski <k.debski@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c index b8b226a20014..646259bee909 100644 --- a/drivers/phy/samsung/phy-exynos5-usbdrd.c +++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung EXYNOS5 SoC series USB DRD PHY driver * @@ -5,10 +6,6 @@ * * Copyright (C) 2014 Samsung Electronics Co., Ltd. * Author: Vivek Gautam <gautam.vivek@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/phy/samsung/phy-exynos5250-sata.c b/drivers/phy/samsung/phy-exynos5250-sata.c index 60e13afcd9b8..9e5fc126032c 100644 --- a/drivers/phy/samsung/phy-exynos5250-sata.c +++ b/drivers/phy/samsung/phy-exynos5250-sata.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung SATA SerDes(PHY) driver * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Authors: Girish K S <ks.giri@samsung.com> * Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/phy/samsung/phy-exynos5250-usb2.c b/drivers/phy/samsung/phy-exynos5250-usb2.c index aad806272305..4f53b711fd6f 100644 --- a/drivers/phy/samsung/phy-exynos5250-usb2.c +++ b/drivers/phy/samsung/phy-exynos5250-usb2.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 5250 support * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Author: Kamil Debski <k.debski@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/phy/samsung/phy-s5pv210-usb2.c b/drivers/phy/samsung/phy-s5pv210-usb2.c index f6f72339bbc3..56a5083fe6f9 100644 --- a/drivers/phy/samsung/phy-s5pv210-usb2.c +++ b/drivers/phy/samsung/phy-s5pv210-usb2.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung SoC USB 1.1/2.0 PHY driver - S5PV210 support * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Authors: Kamil Debski <k.debski@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/phy/samsung/phy-samsung-usb2.c b/drivers/phy/samsung/phy-samsung-usb2.c index ea818866985a..e51d45eeda60 100644 --- a/drivers/phy/samsung/phy-samsung-usb2.c +++ b/drivers/phy/samsung/phy-samsung-usb2.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung SoC USB 1.1/2.0 PHY driver * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Author: Kamil Debski <k.debski@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/phy/samsung/phy-samsung-usb2.h b/drivers/phy/samsung/phy-samsung-usb2.h index 6563e7ca0ac4..2c1a7d71142b 100644 --- a/drivers/phy/samsung/phy-samsung-usb2.h +++ b/drivers/phy/samsung/phy-samsung-usb2.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Samsung SoC USB 1.1/2.0 PHY driver * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Author: Kamil Debski <k.debski@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _PHY_EXYNOS_USB2_H diff --git a/drivers/phy/st/phy-miphy28lp.c b/drivers/phy/st/phy-miphy28lp.c index 213e2e15339c..068160a34f5c 100644 --- a/drivers/phy/st/phy-miphy28lp.c +++ b/drivers/phy/st/phy-miphy28lp.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 STMicroelectronics * * STMicroelectronics PHY driver MiPHY28lp (for SoC STiH407). * * Author: Alexandre Torgue <alexandre.torgue@st.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * */ #include <linux/platform_device.h> diff --git a/drivers/phy/st/phy-spear1310-miphy.c b/drivers/phy/st/phy-spear1310-miphy.c index ed67e98e54ca..8871cd186304 100644 --- a/drivers/phy/st/phy-spear1310-miphy.c +++ b/drivers/phy/st/phy-spear1310-miphy.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ST SPEAr1310-miphy driver * * Copyright (C) 2014 ST Microelectronics * Pratyush Anand <pratyush.anand@gmail.com> * Mohit Kumar <mohit.kumar.dhaka@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/bitops.h> diff --git a/drivers/phy/st/phy-spear1340-miphy.c b/drivers/phy/st/phy-spear1340-miphy.c index 97280c0cf612..ed4d0e2df053 100644 --- a/drivers/phy/st/phy-spear1340-miphy.c +++ b/drivers/phy/st/phy-spear1340-miphy.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ST spear1340-miphy driver * * Copyright (C) 2014 ST Microelectronics * Pratyush Anand <pratyush.anand@gmail.com> * Mohit Kumar <mohit.kumar.dhaka@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/bitops.h> diff --git a/drivers/phy/st/phy-stih407-usb.c b/drivers/phy/st/phy-stih407-usb.c index b1f44ab669fb..a4ae2cca7f63 100644 --- a/drivers/phy/st/phy-stih407-usb.c +++ b/drivers/phy/st/phy-stih407-usb.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 STMicroelectronics * * STMicroelectronics Generic PHY driver for STiH407 USB2. * * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * */ #include <linux/platform_device.h> #include <linux/io.h> diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c index 329fb938099a..d8d0cc11d187 100644 --- a/drivers/phy/ti/phy-tusb1210.c +++ b/drivers/phy/ti/phy-tusb1210.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /** * tusb1210.c - TUSB1210 USB ULPI PHY driver * * Copyright (C) 2015 Intel Corporation * * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/ulpi/driver.h> diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c index f464f8cd274b..7e526bcf5e0b 100644 --- a/drivers/pinctrl/mediatek/mtk-eint.c +++ b/drivers/pinctrl/mediatek/mtk-eint.c @@ -113,6 +113,8 @@ static void mtk_eint_mask(struct irq_data *d) void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->mask_set); + eint->cur_mask[d->hwirq >> 5] &= ~mask; + writel(mask, reg); } @@ -123,6 +125,8 @@ static void mtk_eint_unmask(struct irq_data *d) void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->mask_clr); + eint->cur_mask[d->hwirq >> 5] |= mask; + writel(mask, reg); if (eint->dual_edge[d->hwirq]) @@ -217,19 +221,6 @@ static void mtk_eint_chip_write_mask(const struct mtk_eint *eint, } } -static void mtk_eint_chip_read_mask(const struct mtk_eint *eint, - void __iomem *base, u32 *buf) -{ - int port; - void __iomem *reg; - - for (port = 0; port < eint->hw->ports; port++) { - reg = base + eint->regs->mask + (port << 2); - buf[port] = ~readl_relaxed(reg); - /* Mask is 0 when irq is enabled, and 1 when disabled. */ - } -} - static int mtk_eint_irq_request_resources(struct irq_data *d) { struct mtk_eint *eint = irq_data_get_irq_chip_data(d); @@ -318,7 +309,7 @@ static void mtk_eint_irq_handler(struct irq_desc *desc) struct irq_chip *chip = irq_desc_get_chip(desc); struct mtk_eint *eint = irq_desc_get_handler_data(desc); unsigned int status, eint_num; - int offset, index, virq; + int offset, mask_offset, index, virq; void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat); int dual_edge, start_level, curr_level; @@ -328,10 +319,24 @@ static void mtk_eint_irq_handler(struct irq_desc *desc) status = readl(reg); while (status) { offset = __ffs(status); + mask_offset = eint_num >> 5; index = eint_num + offset; virq = irq_find_mapping(eint->domain, index); status &= ~BIT(offset); + /* + * If we get an interrupt on pin that was only required + * for wake (but no real interrupt requested), mask the + * interrupt (as would mtk_eint_resume do anyway later + * in the resume sequence). + */ + if (eint->wake_mask[mask_offset] & BIT(offset) && + !(eint->cur_mask[mask_offset] & BIT(offset))) { + writel_relaxed(BIT(offset), reg - + eint->regs->stat + + eint->regs->mask_set); + } + dual_edge = eint->dual_edge[index]; if (dual_edge) { /* @@ -370,7 +375,6 @@ static void mtk_eint_irq_handler(struct irq_desc *desc) int mtk_eint_do_suspend(struct mtk_eint *eint) { - mtk_eint_chip_read_mask(eint, eint->base, eint->cur_mask); mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask); return 0; diff --git a/drivers/pinctrl/nomadik/pinctrl-ab8500.c b/drivers/pinctrl/nomadik/pinctrl-ab8500.c index 0723627c7bc2..3106a21cd277 100644 --- a/drivers/pinctrl/nomadik/pinctrl-ab8500.c +++ b/drivers/pinctrl/nomadik/pinctrl-ab8500.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) ST-Ericsson SA 2012 * * Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/pinctrl/nomadik/pinctrl-ab8505.c b/drivers/pinctrl/nomadik/pinctrl-ab8505.c index 2683509c1410..5e6e7d28390a 100644 --- a/drivers/pinctrl/nomadik/pinctrl-ab8505.c +++ b/drivers/pinctrl/nomadik/pinctrl-ab8505.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) ST-Ericsson SA 2012 * * Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index ec02739bd21b..ddd1f466d302 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic GPIO driver for logic cells found in the Nomadik SoC * @@ -5,10 +6,6 @@ * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it> * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com> * Copyright (C) 2011-2013 Linus Walleij <linus.walleij@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/init.h> diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c index 4d032e637f5c..ef133a82e612 100644 --- a/drivers/pinctrl/pinctrl-falcon.c +++ b/drivers/pinctrl/pinctrl-falcon.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/pinctrl/pinmux-falcon.c * based on linux/drivers/pinctrl/pinmux-pxa910.c * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com> * Copyright (C) 2012 John Crispin <john@phrozen.org> */ diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index 568ca96cdb6d..3a235487e38d 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -771,6 +771,10 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, if (ret < 0) goto fail; + ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp); + if (ret < 0) + goto fail; + mcp->irq_controller = device_property_read_bool(dev, "interrupt-controller"); if (mcp->irq && mcp->irq_controller) { @@ -812,10 +816,6 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, goto fail; } - ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp); - if (ret < 0) - goto fail; - if (one_regmap_config) { mcp->pinctrl_desc.name = devm_kasprintf(dev, GFP_KERNEL, "mcp23xxx-pinctrl.%d", raw_chip_address); diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c index 3b4ca52d2456..fb76fb2e9ea5 100644 --- a/drivers/pinctrl/pinctrl-ocelot.c +++ b/drivers/pinctrl/pinctrl-ocelot.c @@ -396,7 +396,7 @@ static int ocelot_pin_function_idx(struct ocelot_pinctrl *info, return -1; } -#define REG(r, info, p) ((r) * (info)->stride + (4 * ((p) / 32))) +#define REG_ALT(msb, info, p) (OCELOT_GPIO_ALT0 * (info)->stride + 4 * ((msb) + ((info)->stride * ((p) / 32)))) static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int selector, unsigned int group) @@ -412,19 +412,21 @@ static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev, /* * f is encoded on two bits. - * bit 0 of f goes in BIT(pin) of ALT0, bit 1 of f goes in BIT(pin) of - * ALT1 + * bit 0 of f goes in BIT(pin) of ALT[0], bit 1 of f goes in BIT(pin) of + * ALT[1] * This is racy because both registers can't be updated at the same time * but it doesn't matter much for now. */ - regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT0, info, pin->pin), + regmap_update_bits(info->map, REG_ALT(0, info, pin->pin), BIT(p), f << p); - regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT1, info, pin->pin), + regmap_update_bits(info->map, REG_ALT(1, info, pin->pin), BIT(p), f << (p - 1)); return 0; } +#define REG(r, info, p) ((r) * (info)->stride + (4 * ((p) / 32))) + static int ocelot_gpio_set_direction(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned int pin, bool input) @@ -432,7 +434,7 @@ static int ocelot_gpio_set_direction(struct pinctrl_dev *pctldev, struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); unsigned int p = pin % 32; - regmap_update_bits(info->map, REG(OCELOT_GPIO_OE, info, p), BIT(p), + regmap_update_bits(info->map, REG(OCELOT_GPIO_OE, info, pin), BIT(p), input ? 0 : BIT(p)); return 0; @@ -445,9 +447,9 @@ static int ocelot_gpio_request_enable(struct pinctrl_dev *pctldev, struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); unsigned int p = offset % 32; - regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT0, info, offset), + regmap_update_bits(info->map, REG_ALT(0, info, offset), BIT(p), 0); - regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT1, info, offset), + regmap_update_bits(info->map, REG_ALT(1, info, offset), BIT(p), 0); return 0; diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c index 195b442a2343..b9688ea548da 100644 --- a/drivers/pinctrl/pinctrl-st.c +++ b/drivers/pinctrl/pinctrl-st.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 STMicroelectronics (R&D) Limited. * Authors: * Srinivas Kandagatla <srinivas.kandagatla@st.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> diff --git a/drivers/pinctrl/zte/pinctrl-zx.c b/drivers/pinctrl/zte/pinctrl-zx.c index 3cb69309912b..9512045420ec 100644 --- a/drivers/pinctrl/zte/pinctrl-zx.c +++ b/drivers/pinctrl/zte/pinctrl-zx.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 Sanechips Technology Co., Ltd. * Copyright 2017 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/io.h> diff --git a/drivers/pinctrl/zte/pinctrl-zx.h b/drivers/pinctrl/zte/pinctrl-zx.h index bc67e2be0503..a0692e2e9012 100644 --- a/drivers/pinctrl/zte/pinctrl-zx.h +++ b/drivers/pinctrl/zte/pinctrl-zx.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2017 Sanechips Technology Co., Ltd. * Copyright 2017 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __PINCTRL_ZX_H diff --git a/drivers/pinctrl/zte/pinctrl-zx296718.c b/drivers/pinctrl/zte/pinctrl-zx296718.c index 71efec17ee7e..c980aecb6f2f 100644 --- a/drivers/pinctrl/zte/pinctrl-zx296718.c +++ b/drivers/pinctrl/zte/pinctrl-zx296718.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 Sanechips Technology Co., Ltd. * Copyright 2017 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/platform/x86/acer-wireless.c b/drivers/platform/x86/acer-wireless.c index 858037987b33..e0976180532a 100644 --- a/drivers/platform/x86/acer-wireless.c +++ b/drivers/platform/x86/acer-wireless.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Acer Wireless Radio Control Driver * * Copyright (C) 2017 Endless Mobile, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index fd2ffebc868f..7e3083deb1c5 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Gmux driver for Apple laptops * * Copyright (C) Canonical Ltd. <seth.forshee@canonical.com> * Copyright (C) 2010-2012 Andreas Heider <andreas@meetr.de> * Copyright (C) 2015 Lukas Wunner <lukas@wunner.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c index 7458f7602d5e..d3e7171928e5 100644 --- a/drivers/platform/x86/asus-wireless.c +++ b/drivers/platform/x86/asus-wireless.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Asus Wireless Radio Control Driver * * Copyright (C) 2015-2016 Endless Mobile, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index a561f653cf13..4e2f76aa98de 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Dell laptop extras * @@ -7,10 +8,6 @@ * * Based on documentation in the libsmbios package: * Copyright (C) 2005-2014 Dell Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c index 0537d44d45a6..fe59b0ebff31 100644 --- a/drivers/platform/x86/dell-smbios-base.c +++ b/drivers/platform/x86/dell-smbios-base.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Common functions for kernel modules using Dell SMBIOS * @@ -7,10 +8,6 @@ * * Based on documentation in the libsmbios package: * Copyright (C) 2005-2014 Dell Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/platform/x86/dell-smbios-smm.c b/drivers/platform/x86/dell-smbios-smm.c index ab9b822a6dfe..d6854d1c4119 100644 --- a/drivers/platform/x86/dell-smbios-smm.c +++ b/drivers/platform/x86/dell-smbios-smm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SMI methods for use with dell-smbios * @@ -5,10 +6,6 @@ * Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com> * Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com> * Copyright (c) 2017 Dell Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c index c3ed3c8c17b9..942b5b77883a 100644 --- a/drivers/platform/x86/dell-smbios-wmi.c +++ b/drivers/platform/x86/dell-smbios-wmi.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * WMI methods for use with dell-smbios * * Copyright (c) 2017 Dell Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index d8adaf959740..a7ff9803f41a 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Common functions for kernel modules using Dell SMBIOS * @@ -7,10 +8,6 @@ * * Based on documentation in the libsmbios package: * Copyright (C) 2005-2014 Dell Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _DELL_SMBIOS_H_ diff --git a/drivers/platform/x86/dell-wmi-descriptor.h b/drivers/platform/x86/dell-wmi-descriptor.h index a6123a4d06a7..1f469fef1535 100644 --- a/drivers/platform/x86/dell-wmi-descriptor.h +++ b/drivers/platform/x86/dell-wmi-descriptor.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Dell WMI descriptor driver * * Copyright (c) 2017 Dell Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _DELL_WMI_DESCRIPTOR_H_ diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index 6fa3cced6f8e..4fbdff48a4b5 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -21,18 +21,55 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/module.h> +#include <linux/pci.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> +#include <linux/usb/pd.h> #define EXPECTED_PTYPE 4 +enum { + INT33FE_NODE_FUSB302, + INT33FE_NODE_MAX17047, + INT33FE_NODE_PI3USB30532, + INT33FE_NODE_DISPLAYPORT, + INT33FE_NODE_ROLE_SWITCH, + INT33FE_NODE_USB_CONNECTOR, + INT33FE_NODE_MAX, +}; + struct cht_int33fe_data { struct i2c_client *max17047; struct i2c_client *fusb302; struct i2c_client *pi3usb30532; - /* Contain a list-head must be per device */ - struct device_connection connections[4]; + + struct fwnode_handle *dp; + struct fwnode_handle *mux; +}; + +static const struct software_node nodes[]; + +static const struct software_node_ref_args pi3usb30532_ref = { + &nodes[INT33FE_NODE_PI3USB30532] +}; + +static const struct software_node_ref_args dp_ref = { + &nodes[INT33FE_NODE_DISPLAYPORT] +}; + +static struct software_node_ref_args mux_ref; + +static const struct software_node_reference usb_connector_refs[] = { + { "orientation-switch", 1, &pi3usb30532_ref}, + { "mode-switch", 1, &pi3usb30532_ref}, + { "displayport", 1, &dp_ref}, + { } +}; + +static const struct software_node_reference fusb302_refs[] = { + { "usb-role-switch", 1, &mux_ref}, + { } }; /* @@ -63,14 +100,6 @@ static int cht_int33fe_check_for_max17047(struct device *dev, void *data) return 1; } -static struct i2c_client *cht_int33fe_find_max17047(void) -{ - struct i2c_client *max17047 = NULL; - - i2c_for_each_dev(&max17047, cht_int33fe_check_for_max17047); - return max17047; -} - static const char * const max17047_suppliers[] = { "bq24190-charger" }; static const struct property_entry max17047_props[] = { @@ -80,18 +109,196 @@ static const struct property_entry max17047_props[] = { static const struct property_entry fusb302_props[] = { PROPERTY_ENTRY_STRING("linux,extcon-name", "cht_wcove_pwrsrc"), - PROPERTY_ENTRY_U32("fcs,max-sink-microvolt", 12000000), - PROPERTY_ENTRY_U32("fcs,max-sink-microamp", 3000000), - PROPERTY_ENTRY_U32("fcs,max-sink-microwatt", 36000000), { } }; +#define PDO_FIXED_FLAGS \ + (PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP | PDO_FIXED_USB_COMM) + +static const u32 src_pdo[] = { + PDO_FIXED(5000, 1500, PDO_FIXED_FLAGS), +}; + +static const u32 snk_pdo[] = { + PDO_FIXED(5000, 400, PDO_FIXED_FLAGS), + PDO_VAR(5000, 12000, 3000), +}; + +static const struct property_entry usb_connector_props[] = { + PROPERTY_ENTRY_STRING("data-role", "dual"), + PROPERTY_ENTRY_STRING("power-role", "dual"), + PROPERTY_ENTRY_STRING("try-power-role", "sink"), + PROPERTY_ENTRY_U32_ARRAY("source-pdos", src_pdo), + PROPERTY_ENTRY_U32_ARRAY("sink-pdos", snk_pdo), + PROPERTY_ENTRY_U32("op-sink-microwatt", 2500000), + { } +}; + +static const struct software_node nodes[] = { + { "fusb302", NULL, fusb302_props, fusb302_refs }, + { "max17047", NULL, max17047_props }, + { "pi3usb30532" }, + { "displayport" }, + { "usb-role-switch" }, + { "connector", &nodes[0], usb_connector_props, usb_connector_refs }, + { } +}; + +static int cht_int33fe_setup_mux(struct cht_int33fe_data *data) +{ + struct fwnode_handle *fwnode; + struct device *dev; + struct device *p; + + fwnode = software_node_fwnode(&nodes[INT33FE_NODE_ROLE_SWITCH]); + if (!fwnode) + return -ENODEV; + + /* First finding the platform device */ + p = bus_find_device_by_name(&platform_bus_type, NULL, + "intel_xhci_usb_sw"); + if (!p) + return -EPROBE_DEFER; + + /* Then the mux child device */ + dev = device_find_child_by_name(p, "intel_xhci_usb_sw-role-switch"); + put_device(p); + if (!dev) + return -EPROBE_DEFER; + + /* If there already is a node for the mux, using that one. */ + if (dev->fwnode) + fwnode_remove_software_node(fwnode); + else + dev->fwnode = fwnode; + + data->mux = fwnode_handle_get(dev->fwnode); + put_device(dev); + mux_ref.node = to_software_node(data->mux); + + return 0; +} + +static int cht_int33fe_setup_dp(struct cht_int33fe_data *data) +{ + struct fwnode_handle *fwnode; + struct pci_dev *pdev; + + fwnode = software_node_fwnode(&nodes[INT33FE_NODE_DISPLAYPORT]); + if (!fwnode) + return -ENODEV; + + /* First let's find the GPU PCI device */ + pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); + if (!pdev || pdev->vendor != PCI_VENDOR_ID_INTEL) { + pci_dev_put(pdev); + return -ENODEV; + } + + /* Then the DP child device node */ + data->dp = device_get_named_child_node(&pdev->dev, "DD02"); + pci_dev_put(pdev); + if (!data->dp) + return -ENODEV; + + fwnode->secondary = ERR_PTR(-ENODEV); + data->dp->secondary = fwnode; + + return 0; +} + +static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data) +{ + software_node_unregister_nodes(nodes); + + if (data->mux) { + fwnode_handle_put(data->mux); + mux_ref.node = NULL; + data->mux = NULL; + } + + if (data->dp) { + data->dp->secondary = NULL; + fwnode_handle_put(data->dp); + data->dp = NULL; + } +} + +static int cht_int33fe_add_nodes(struct cht_int33fe_data *data) +{ + int ret; + + ret = software_node_register_nodes(nodes); + if (ret) + return ret; + + /* The devices that are not created in this driver need extra steps. */ + + /* + * There is no ACPI device node for the USB role mux, so we need to find + * the mux device and assign our node directly to it. That means we + * depend on the mux driver. This function will return -PROBE_DEFER + * until the mux device is registered. + */ + ret = cht_int33fe_setup_mux(data); + if (ret) + goto err_remove_nodes; + + /* + * The DP connector does have ACPI device node. In this case we can just + * find that ACPI node and assign our node as the secondary node to it. + */ + ret = cht_int33fe_setup_dp(data); + if (ret) + goto err_remove_nodes; + + return 0; + +err_remove_nodes: + cht_int33fe_remove_nodes(data); + + return ret; +} + +static int +cht_int33fe_register_max17047(struct device *dev, struct cht_int33fe_data *data) +{ + struct i2c_client *max17047 = NULL; + struct i2c_board_info board_info; + struct fwnode_handle *fwnode; + int ret; + + fwnode = software_node_fwnode(&nodes[INT33FE_NODE_MAX17047]); + if (!fwnode) + return -ENODEV; + + i2c_for_each_dev(&max17047, cht_int33fe_check_for_max17047); + if (max17047) { + /* Pre-existing i2c-client for the max17047, add device-props */ + fwnode->secondary = ERR_PTR(-ENODEV); + max17047->dev.fwnode->secondary = fwnode; + /* And re-probe to get the new device-props applied. */ + ret = device_reprobe(&max17047->dev); + if (ret) + dev_warn(dev, "Reprobing max17047 error: %d\n", ret); + return 0; + } + + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "max17047", I2C_NAME_SIZE); + board_info.dev_name = "max17047"; + board_info.fwnode = fwnode; + data->max17047 = i2c_acpi_new_device(dev, 1, &board_info); + + return PTR_ERR_OR_ZERO(data->max17047); +} + static int cht_int33fe_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct i2c_board_info board_info; struct cht_int33fe_data *data; - struct i2c_client *max17047; + struct fwnode_handle *fwnode; struct regulator *regulator; unsigned long long ptyp; acpi_status status; @@ -151,43 +358,25 @@ static int cht_int33fe_probe(struct platform_device *pdev) if (!data) return -ENOMEM; - /* Work around BIOS bug, see comment on cht_int33fe_find_max17047 */ - max17047 = cht_int33fe_find_max17047(); - if (max17047) { - /* Pre-existing i2c-client for the max17047, add device-props */ - ret = device_add_properties(&max17047->dev, max17047_props); - if (ret) - return ret; - /* And re-probe to get the new device-props applied. */ - ret = device_reprobe(&max17047->dev); - if (ret) - dev_warn(dev, "Reprobing max17047 error: %d\n", ret); - } else { - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "max17047", I2C_NAME_SIZE); - board_info.dev_name = "max17047"; - board_info.properties = max17047_props; - data->max17047 = i2c_acpi_new_device(dev, 1, &board_info); - if (IS_ERR(data->max17047)) - return PTR_ERR(data->max17047); - } + ret = cht_int33fe_add_nodes(data); + if (ret) + return ret; - data->connections[0].endpoint[0] = "port0"; - data->connections[0].endpoint[1] = "i2c-pi3usb30532"; - data->connections[0].id = "orientation-switch"; - data->connections[1].endpoint[0] = "port0"; - data->connections[1].endpoint[1] = "i2c-pi3usb30532"; - data->connections[1].id = "mode-switch"; - data->connections[2].endpoint[0] = "i2c-fusb302"; - data->connections[2].endpoint[1] = "intel_xhci_usb_sw-role-switch"; - data->connections[2].id = "usb-role-switch"; + /* Work around BIOS bug, see comment on cht_int33fe_check_for_max17047 */ + ret = cht_int33fe_register_max17047(dev, data); + if (ret) + goto out_remove_nodes; - device_connections_add(data->connections); + fwnode = software_node_fwnode(&nodes[INT33FE_NODE_FUSB302]); + if (!fwnode) { + ret = -ENODEV; + goto out_unregister_max17047; + } memset(&board_info, 0, sizeof(board_info)); strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE); board_info.dev_name = "fusb302"; - board_info.properties = fusb302_props; + board_info.fwnode = fwnode; board_info.irq = fusb302_irq; data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info); @@ -196,8 +385,15 @@ static int cht_int33fe_probe(struct platform_device *pdev) goto out_unregister_max17047; } + fwnode = software_node_fwnode(&nodes[INT33FE_NODE_PI3USB30532]); + if (!fwnode) { + ret = -ENODEV; + goto out_unregister_fusb302; + } + memset(&board_info, 0, sizeof(board_info)); board_info.dev_name = "pi3usb30532"; + board_info.fwnode = fwnode; strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE); data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info); @@ -216,7 +412,8 @@ out_unregister_fusb302: out_unregister_max17047: i2c_unregister_device(data->max17047); - device_connections_remove(data->connections); +out_remove_nodes: + cht_int33fe_remove_nodes(data); return ret; } @@ -229,7 +426,7 @@ static int cht_int33fe_remove(struct platform_device *pdev) i2c_unregister_device(data->fusb302); i2c_unregister_device(data->max17047); - device_connections_remove(data->connections); + cht_int33fe_remove_nodes(data); return 0; } diff --git a/drivers/platform/x86/peaq-wmi.c b/drivers/platform/x86/peaq-wmi.c index 9b9e1f39bbfb..fdeb3624c529 100644 --- a/drivers/platform/x86/peaq-wmi.c +++ b/drivers/platform/x86/peaq-wmi.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PEAQ 2-in-1 WMI hotkey driver * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 7b160ee98115..123e52c73c86 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung Laptop driver * * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de) * Copyright (C) 2009,2011 Novell Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/platform/x86/samsung-q10.c b/drivers/platform/x86/samsung-q10.c index a2fb7fbc3273..6eb08b539311 100644 --- a/drivers/platform/x86/samsung-q10.c +++ b/drivers/platform/x86/samsung-q10.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Samsung Q10 and related laptops: controls the backlight * * Copyright (c) 2011 Frederick van der Wyck <fvanderwyck@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c index be1d137c6079..57a5dc60c58a 100644 --- a/drivers/platform/x86/toshiba_bluetooth.c +++ b/drivers/platform/x86/toshiba_bluetooth.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Toshiba Bluetooth Enable Driver * @@ -6,10 +7,6 @@ * * Thanks to Matthew Garrett for background info on ACPI innards which * normal people aren't meant to understand :-) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/power/avs/smartreflex.c b/drivers/power/avs/smartreflex.c index c96c01e09740..4684e7df833a 100644 --- a/drivers/power/avs/smartreflex.c +++ b/drivers/power/avs/smartreflex.c @@ -899,38 +899,19 @@ static int omap_sr_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__); - if (!sr_dbg_dir) { + if (!sr_dbg_dir) sr_dbg_dir = debugfs_create_dir("smartreflex", NULL); - if (IS_ERR_OR_NULL(sr_dbg_dir)) { - ret = PTR_ERR(sr_dbg_dir); - pr_err("%s:sr debugfs dir creation failed(%d)\n", - __func__, ret); - goto err_list_del; - } - } sr_info->dbg_dir = debugfs_create_dir(sr_info->name, sr_dbg_dir); - if (IS_ERR_OR_NULL(sr_info->dbg_dir)) { - dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n", - __func__); - ret = PTR_ERR(sr_info->dbg_dir); - goto err_debugfs; - } - (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, - sr_info->dbg_dir, (void *)sr_info, &pm_sr_fops); - (void) debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir, - &sr_info->err_weight); - (void) debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir, - &sr_info->err_maxlimit); + debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, sr_info->dbg_dir, + (void *)sr_info, &pm_sr_fops); + debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir, + &sr_info->err_weight); + debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir, + &sr_info->err_maxlimit); nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir); - if (IS_ERR_OR_NULL(nvalue_dir)) { - dev_err(&pdev->dev, "%s: Unable to create debugfs directory for n-values\n", - __func__); - ret = PTR_ERR(nvalue_dir); - goto err_debugfs; - } if (sr_info->nvalue_count == 0 || !sr_info->nvalue_table) { dev_warn(&pdev->dev, "%s: %s: No Voltage table for the corresponding vdd. Cannot create debugfs entries for n-values\n", @@ -945,12 +926,12 @@ static int omap_sr_probe(struct platform_device *pdev) snprintf(name, sizeof(name), "volt_%lu", sr_info->nvalue_table[i].volt_nominal); - (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir, - &(sr_info->nvalue_table[i].nvalue)); + debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir, + &(sr_info->nvalue_table[i].nvalue)); snprintf(name, sizeof(name), "errminlimit_%lu", sr_info->nvalue_table[i].volt_nominal); - (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir, - &(sr_info->nvalue_table[i].errminlimit)); + debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir, + &(sr_info->nvalue_table[i].errminlimit)); } diff --git a/drivers/power/reset/arm-versatile-reboot.c b/drivers/power/reset/arm-versatile-reboot.c index 06d34ab47df5..08d0a07b58ef 100644 --- a/drivers/power/reset/arm-versatile-reboot.c +++ b/drivers/power/reset/arm-versatile-reboot.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Linaro Ltd. * * Author: Linus Walleij <linus.walleij@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * */ #include <linux/init.h> #include <linux/mfd/syscon.h> diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c index 52525b6c18db..6a4bbb506551 100644 --- a/drivers/power/reset/gpio-poweroff.c +++ b/drivers/power/reset/gpio-poweroff.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Toggles a GPIO pin to power down a device * @@ -5,11 +6,6 @@ * Andrew Lunn <andrew@lunn.ch> * * Copyright (C) 2012 Jamie Lentin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> #include <linux/init.h> diff --git a/drivers/power/reset/hisi-reboot.c b/drivers/power/reset/hisi-reboot.c index f69387e12c1e..0ba5fdce186f 100644 --- a/drivers/power/reset/hisi-reboot.c +++ b/drivers/power/reset/hisi-reboot.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Hisilicon SoC reset code * @@ -5,10 +6,6 @@ * Copyright (c) 2014 Linaro Ltd. * * Author: Haojian Zhuang <haojian.zhuang@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/power/reset/keystone-reset.c b/drivers/power/reset/keystone-reset.c index 09380857a1c5..ad11faae19c5 100644 --- a/drivers/power/reset/keystone-reset.c +++ b/drivers/power/reset/keystone-reset.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI keystone reboot driver * * Copyright (C) 2014 Texas Instruments Incorporated. http://www.ti.com/ * * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/io.h> diff --git a/drivers/power/reset/restart-poweroff.c b/drivers/power/reset/restart-poweroff.c index 41b22c4d5236..d233daa5835b 100644 --- a/drivers/power/reset/restart-poweroff.c +++ b/drivers/power/reset/restart-poweroff.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Power off by restarting and let u-boot keep hold of the machine * until the user presses a button for example. @@ -5,10 +6,6 @@ * Andrew Lunn <andrew@lunn.ch> * * Copyright (C) 2012 Andrew Lunn - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/init.h> diff --git a/drivers/power/reset/st-poweroff.c b/drivers/power/reset/st-poweroff.c index 2046b31232f7..5ccaacffab54 100644 --- a/drivers/power/reset/st-poweroff.c +++ b/drivers/power/reset/st-poweroff.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 STMicroelectronics * * Power off Restart driver, used in STMicroelectronics devices. * * Author: Christophe Kerello <christophe.kerello@st.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/power/reset/zx-reboot.c b/drivers/power/reset/zx-reboot.c index 186901c96c01..457950833dba 100644 --- a/drivers/power/reset/zx-reboot.c +++ b/drivers/power/reset/zx-reboot.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ZTE zx296702 SoC reset code * * Copyright (c) 2015 Linaro Ltd. * * Author: Jun Nie <jun.nie@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/power/supply/88pm860x_battery.c b/drivers/power/supply/88pm860x_battery.c index 63c57dc82ac1..5ca047b3f58f 100644 --- a/drivers/power/supply/88pm860x_battery.c +++ b/drivers/power/supply/88pm860x_battery.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Battery driver for Marvell 88PM860x PMIC * * Copyright (c) 2012 Marvell International Ltd. * Author: Jett Zhou <jtzhou@marvell.com> * Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/power/supply/88pm860x_charger.c b/drivers/power/supply/88pm860x_charger.c index 2b82e44d9027..f21ce52fbc04 100644 --- a/drivers/power/supply/88pm860x_charger.c +++ b/drivers/power/supply/88pm860x_charger.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Battery driver for Marvell 88PM860x PMIC * * Copyright (c) 2012 Marvell International Ltd. * Author: Jett Zhou <jtzhou@marvell.com> * Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index 8e117b31ba79..5f3eb6941d05 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Power supply driver for the Active-semi ACT8945A PMIC * * Copyright (C) 2015 Atmel Corporation * * Author: Wenyou Yang <wenyou.yang@atmel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/interrupt.h> #include <linux/module.h> diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index cc0dfdc9e85a..a3dd1cfcfa8b 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for the TI bq24190 battery charger. * * Author: Mark A. Greer <mgreer@animalcreek.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c index a6900aa0d2ed..a21e1a2673f8 100644 --- a/drivers/power/supply/charger-manager.c +++ b/drivers/power/supply/charger-manager.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Samsung Electronics Co., Ltd. * MyungJoo Ham <myungjoo.ham@samsung.com> @@ -7,9 +8,6 @@ * Charger manager depends on other devices. Register this later than * the depending devices. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. **/ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/power/supply/collie_battery.c b/drivers/power/supply/collie_battery.c index 3a0bc608d4b5..cbd588e9e233 100644 --- a/drivers/power/supply/collie_battery.c +++ b/drivers/power/supply/collie_battery.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Battery and Power Management code for the Sharp SL-5x00 * * Copyright (C) 2009 Thomas Kunze * * based on tosa_battery.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/power/supply/da9030_battery.c b/drivers/power/supply/da9030_battery.c index 5ca0f4d90792..88582423b87d 100644 --- a/drivers/power/supply/da9030_battery.c +++ b/drivers/power/supply/da9030_battery.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Battery charger driver for Dialog Semiconductor DA9030 * * Copyright (C) 2008 Compulab, Ltd. * Mike Rapoport <mike@compulab.co.il> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/power/supply/ds2780_battery.c b/drivers/power/supply/ds2780_battery.c index 5bf7c714a6ee..db3a25404c9f 100644 --- a/drivers/power/supply/ds2780_battery.c +++ b/drivers/power/supply/ds2780_battery.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 1-wire client/driver for the Maxim/Dallas DS2780 Stand-Alone Fuel Gauge IC * @@ -6,11 +7,6 @@ * Author: Clifton Barnes <cabarnes@indesign-llc.com> * * Based on ds2760_battery and ds2782_battery drivers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/power/supply/ds2781_battery.c b/drivers/power/supply/ds2781_battery.c index 166a8bd58811..130cbdfc14eb 100644 --- a/drivers/power/supply/ds2781_battery.c +++ b/drivers/power/supply/ds2781_battery.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 1-wire client/driver for the Maxim/Dallas DS2781 Stand-Alone Fuel Gauge IC * * Author: Renata Sayakhova <renata@oktetlabs.ru> * * Based on ds2780_battery drivers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/power/supply/ds2782_battery.c b/drivers/power/supply/ds2782_battery.c index 04b0fe7d7d62..9ae273fde7a2 100644 --- a/drivers/power/supply/ds2782_battery.c +++ b/drivers/power/supply/ds2782_battery.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C client/driver for the Maxim/Dallas DS2782 Stand-Alone Fuel Gauge IC * @@ -8,11 +9,6 @@ * DS2786 added by Yulia Vilensky <vilensky@compulab.co.il> * * UEvent sending added by Evgeny Romanov <romanov@neurosoft.ru> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/power/supply/ipaq_micro_battery.c b/drivers/power/supply/ipaq_micro_battery.c index 2fa6edd6e8b1..03592ceaca88 100644 --- a/drivers/power/supply/ipaq_micro_battery.c +++ b/drivers/power/supply/ipaq_micro_battery.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. * * h3xxx atmel micro companion support, battery subdevice * based on previous kernel 2.4 version * Author : Alessandro Gardich <gremlin@gremlin.it> * Author : Linus Walleij <linus.walleij@linaro.org> - * */ #include <linux/module.h> diff --git a/drivers/power/supply/jz4740-battery.c b/drivers/power/supply/jz4740-battery.c index 88f04f4d1a70..6366bd61ea9f 100644 --- a/drivers/power/supply/jz4740-battery.c +++ b/drivers/power/supply/jz4740-battery.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Battery measurement code for Ingenic JZ SOC. * @@ -7,11 +8,6 @@ * based on tosa_battery.c * * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com> -* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/interrupt.h> diff --git a/drivers/power/supply/lp8727_charger.c b/drivers/power/supply/lp8727_charger.c index 042fb3dacb46..9ee54e397754 100644 --- a/drivers/power/supply/lp8727_charger.c +++ b/drivers/power/supply/lp8727_charger.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for LP8727 Micro/Mini USB IC with integrated charger * * Copyright (C) 2011 Texas Instruments * Copyright (C) 2011 National Semiconductor - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/power/supply/lp8788-charger.c b/drivers/power/supply/lp8788-charger.c index 309e6efbb8ef..84a206f42a8e 100644 --- a/drivers/power/supply/lp8788-charger.c +++ b/drivers/power/supply/lp8788-charger.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LP8788 MFD - battery charger driver * * Copyright 2012 Texas Instruments * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/err.h> diff --git a/drivers/power/supply/max14656_charger_detector.c b/drivers/power/supply/max14656_charger_detector.c index 9e6472834e37..68cfde4be632 100644 --- a/drivers/power/supply/max14656_charger_detector.c +++ b/drivers/power/supply/max14656_charger_detector.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Maxim MAX14656 / AL32 USB Charger Detector driver * @@ -7,11 +8,6 @@ * Components from Maxim AL32 Charger detection Driver for MX50 Yoshi Board * Copyright (C) Amazon Technologies Inc. All rights reserved. * Manish Lachwani (lachwani@lab126.com) - * - * This package is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * */ #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/power/supply/max8925_power.c b/drivers/power/supply/max8925_power.c index 39b4d5b6ac39..5fca4960f440 100644 --- a/drivers/power/supply/max8925_power.c +++ b/drivers/power/supply/max8925_power.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Battery driver for Maxim MAX8925 * * Copyright (c) 2009-2010 Marvell International Ltd. * Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/power/supply/olpc_battery.c b/drivers/power/supply/olpc_battery.c index 7720e4c2ac0b..9f9430ac8887 100644 --- a/drivers/power/supply/olpc_battery.c +++ b/drivers/power/supply/olpc_battery.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Battery driver for One Laptop Per Child board. * * Copyright © 2006-2010 David Woodhouse <dwmw2@infradead.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/power/supply/pda_power.c b/drivers/power/supply/pda_power.c index 922a86787c5c..3ae5707d39fa 100644 --- a/drivers/power/supply/pda_power.c +++ b/drivers/power/supply/pda_power.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Common power driver for PDAs and phones with one or two external * power supplies (AC/USB) connected to main and backup batteries, * and optional builtin charger. * * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/power/supply/pm2301_charger.c b/drivers/power/supply/pm2301_charger.c index 78561b6884fc..17749fc90e16 100644 --- a/drivers/power/supply/pm2301_charger.c +++ b/drivers/power/supply/pm2301_charger.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2012 ST Ericsson. * * Power supply driver for ST Ericsson pm2xxx_charger charger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> diff --git a/drivers/power/supply/pmu_battery.c b/drivers/power/supply/pmu_battery.c index 9c8d5253812c..eaab7500d99b 100644 --- a/drivers/power/supply/pmu_battery.c +++ b/drivers/power/supply/pmu_battery.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Battery class driver for Apple PMU * * Copyright © 2006 David Woodhouse <dwmw2@infradead.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c index cb6e8f66c7a2..63173068a1ab 100644 --- a/drivers/power/supply/sbs-manager.c +++ b/drivers/power/supply/sbs-manager.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for SBS compliant Smart Battery System Managers * @@ -10,10 +11,6 @@ * Datasheet LTC1760: http://cds.linear.com/docs/en/datasheet/1760fb.pdf * * Karl-Heinz Schneider <karl-heinz@schneider-inet.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/gpio.h> diff --git a/drivers/power/supply/smb347-charger.c b/drivers/power/supply/smb347-charger.c index 072c5189bd6d..c1d124b8be0c 100644 --- a/drivers/power/supply/smb347-charger.c +++ b/drivers/power/supply/smb347-charger.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Summit Microelectronics SMB347 Battery Charger Driver * @@ -5,10 +6,6 @@ * * Authors: Bruce E. Robertson <bruce.e.robertson@intel.com> * Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/power/supply/test_power.c b/drivers/power/supply/test_power.c index 57246cdbd042..c3cad2b6daba 100644 --- a/drivers/power/supply/test_power.c +++ b/drivers/power/supply/test_power.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Power supply driver for testing. * @@ -8,10 +9,6 @@ * By: Masashi YOKOTA <yokota@pylone.jp> * Originally found here: * http://downloads.pylone.jp/src/virtual_battery/virtual_battery-0.0.1.tar.bz2 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/power/supply/tosa_battery.c b/drivers/power/supply/tosa_battery.c index 6e88c1b37945..32cc31cd4761 100644 --- a/drivers/power/supply/tosa_battery.c +++ b/drivers/power/supply/tosa_battery.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Battery and Power Management code for the Sharp SL-6000x * * Copyright (c) 2005 Dirk Opfer * Copyright (c) 2008 Dmitry Baryshkov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/power/supply/wm831x_backup.c b/drivers/power/supply/wm831x_backup.c index 2e33109ca8c7..ffb265b8526d 100644 --- a/drivers/power/supply/wm831x_backup.c +++ b/drivers/power/supply/wm831x_backup.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Backup battery driver for Wolfson Microelectronics wm831x PMICs * * Copyright 2009 Wolfson Microelectronics PLC. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/power/supply/wm831x_power.c b/drivers/power/supply/wm831x_power.c index 927050d4444d..65832bc229f6 100644 --- a/drivers/power/supply/wm831x_power.c +++ b/drivers/power/supply/wm831x_power.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PMU driver for Wolfson Microelectronics wm831x PMICs * * Copyright 2009 Wolfson Microelectronics PLC. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/power/supply/wm8350_power.c b/drivers/power/supply/wm8350_power.c index 15c0ca15e2aa..26923af574f4 100644 --- a/drivers/power/supply/wm8350_power.c +++ b/drivers/power/supply/wm8350_power.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Battery driver for wm8350 PMIC * @@ -6,10 +7,6 @@ * Based on OLPC Battery Driver * * Copyright 2006 David Woodhouse <dwmw2@infradead.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c index 6754e761778a..58f01659daa5 100644 --- a/drivers/power/supply/wm97xx_battery.c +++ b/drivers/power/supply/wm97xx_battery.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Battery measurement code for WM97xx * * based on tosa_battery.c * * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/init.h> diff --git a/drivers/power/supply/z2_battery.c b/drivers/power/supply/z2_battery.c index bcc2d1a9b0a7..ebd2e42a4457 100644 --- a/drivers/power/supply/z2_battery.c +++ b/drivers/power/supply/z2_battery.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Battery measurement code for Zipit Z2 * * Copyright (C) 2009 Peter Edwards <sweetlilmre@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index f888117b0efc..8692f6b79f93 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c @@ -166,12 +166,15 @@ struct rapl_domain { #define power_zone_to_rapl_domain(_zone) \ container_of(_zone, struct rapl_domain, power_zone) +/* maximum rapl package domain name: package-%d-die-%d */ +#define PACKAGE_DOMAIN_NAME_LENGTH 30 -/* Each physical package contains multiple domains, these are the common + +/* Each rapl package contains multiple domains, these are the common * data across RAPL domains within a package. */ struct rapl_package { - unsigned int id; /* physical package/socket id */ + unsigned int id; /* logical die id, equals physical 1-die systems */ unsigned int nr_domains; unsigned long domain_map; /* bit map of active domains */ unsigned int power_unit; @@ -186,6 +189,7 @@ struct rapl_package { int lead_cpu; /* one active cpu per package for access */ /* Track active cpus */ struct cpumask cpumask; + char name[PACKAGE_DOMAIN_NAME_LENGTH]; }; struct rapl_defaults { @@ -252,8 +256,9 @@ static struct powercap_control_type *control_type; /* PowerCap Controller */ static struct rapl_domain *platform_rapl_domain; /* Platform (PSys) domain */ /* caller to ensure CPU hotplug lock is held */ -static struct rapl_package *find_package_by_id(int id) +static struct rapl_package *rapl_find_package_domain(int cpu) { + int id = topology_logical_die_id(cpu); struct rapl_package *rp; list_for_each_entry(rp, &rapl_packages, plist) { @@ -913,8 +918,8 @@ static int rapl_check_unit_core(struct rapl_package *rp, int cpu) value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET; rp->time_unit = 1000000 / (1 << value); - pr_debug("Core CPU package %d energy=%dpJ, time=%dus, power=%duW\n", - rp->id, rp->energy_unit, rp->time_unit, rp->power_unit); + pr_debug("Core CPU %s energy=%dpJ, time=%dus, power=%duW\n", + rp->name, rp->energy_unit, rp->time_unit, rp->power_unit); return 0; } @@ -938,8 +943,8 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu) value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET; rp->time_unit = 1000000 / (1 << value); - pr_debug("Atom package %d energy=%dpJ, time=%dus, power=%duW\n", - rp->id, rp->energy_unit, rp->time_unit, rp->power_unit); + pr_debug("Atom %s energy=%dpJ, time=%dus, power=%duW\n", + rp->name, rp->energy_unit, rp->time_unit, rp->power_unit); return 0; } @@ -1168,7 +1173,7 @@ static void rapl_update_domain_data(struct rapl_package *rp) u64 val; for (dmn = 0; dmn < rp->nr_domains; dmn++) { - pr_debug("update package %d domain %s data\n", rp->id, + pr_debug("update %s domain %s data\n", rp->name, rp->domains[dmn].name); /* exclude non-raw primitives */ for (prim = 0; prim < NR_RAW_PRIMITIVES; prim++) { @@ -1193,7 +1198,6 @@ static void rapl_unregister_powercap(void) static int rapl_package_register_powercap(struct rapl_package *rp) { struct rapl_domain *rd; - char dev_name[17]; /* max domain name = 7 + 1 + 8 for int + 1 for null*/ struct powercap_zone *power_zone = NULL; int nr_pl, ret; @@ -1204,20 +1208,16 @@ static int rapl_package_register_powercap(struct rapl_package *rp) for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) { if (rd->id == RAPL_DOMAIN_PACKAGE) { nr_pl = find_nr_power_limit(rd); - pr_debug("register socket %d package domain %s\n", - rp->id, rd->name); - memset(dev_name, 0, sizeof(dev_name)); - snprintf(dev_name, sizeof(dev_name), "%s-%d", - rd->name, rp->id); + pr_debug("register package domain %s\n", rp->name); power_zone = powercap_register_zone(&rd->power_zone, control_type, - dev_name, NULL, + rp->name, NULL, &zone_ops[rd->id], nr_pl, &constraint_ops); if (IS_ERR(power_zone)) { - pr_debug("failed to register package, %d\n", - rp->id); + pr_debug("failed to register power zone %s\n", + rp->name); return PTR_ERR(power_zone); } /* track parent zone in per package/socket data */ @@ -1243,8 +1243,8 @@ static int rapl_package_register_powercap(struct rapl_package *rp) &constraint_ops); if (IS_ERR(power_zone)) { - pr_debug("failed to register power_zone, %d:%s:%s\n", - rp->id, rd->name, dev_name); + pr_debug("failed to register power_zone, %s:%s\n", + rp->name, rd->name); ret = PTR_ERR(power_zone); goto err_cleanup; } @@ -1257,7 +1257,7 @@ err_cleanup: * failed after the first domain setup. */ while (--rd >= rp->domains) { - pr_debug("unregister package %d domain %s\n", rp->id, rd->name); + pr_debug("unregister %s domain %s\n", rp->name, rd->name); powercap_unregister_zone(control_type, &rd->power_zone); } @@ -1288,7 +1288,7 @@ static int __init rapl_register_psys(void) rd->rpl[0].name = pl1_name; rd->rpl[1].prim_id = PL2_ENABLE; rd->rpl[1].name = pl2_name; - rd->rp = find_package_by_id(0); + rd->rp = rapl_find_package_domain(0); power_zone = powercap_register_zone(&rd->power_zone, control_type, "psys", NULL, @@ -1367,8 +1367,8 @@ static void rapl_detect_powerlimit(struct rapl_domain *rd) /* check if the domain is locked by BIOS, ignore if MSR doesn't exist */ if (!rapl_read_data_raw(rd, FW_LOCK, false, &val64)) { if (val64) { - pr_info("RAPL package %d domain %s locked by BIOS\n", - rd->rp->id, rd->name); + pr_info("RAPL %s domain %s locked by BIOS\n", + rd->rp->name, rd->name); rd->state |= DOMAIN_STATE_BIOS_LOCKED; } } @@ -1397,10 +1397,10 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu) } rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX); if (!rp->nr_domains) { - pr_debug("no valid rapl domains found in package %d\n", rp->id); + pr_debug("no valid rapl domains found in %s\n", rp->name); return -ENODEV; } - pr_debug("found %d domains on package %d\n", rp->nr_domains, rp->id); + pr_debug("found %d domains on %s\n", rp->nr_domains, rp->name); rp->domains = kcalloc(rp->nr_domains + 1, sizeof(struct rapl_domain), GFP_KERNEL); @@ -1433,8 +1433,8 @@ static void rapl_remove_package(struct rapl_package *rp) rd_package = rd; continue; } - pr_debug("remove package, undo power limit on %d: %s\n", - rp->id, rd->name); + pr_debug("remove package, undo power limit on %s: %s\n", + rp->name, rd->name); powercap_unregister_zone(control_type, &rd->power_zone); } /* do parent zone last */ @@ -1444,9 +1444,11 @@ static void rapl_remove_package(struct rapl_package *rp) } /* called from CPU hotplug notifier, hotplug lock held */ -static struct rapl_package *rapl_add_package(int cpu, int pkgid) +static struct rapl_package *rapl_add_package(int cpu) { + int id = topology_logical_die_id(cpu); struct rapl_package *rp; + struct cpuinfo_x86 *c = &cpu_data(cpu); int ret; rp = kzalloc(sizeof(struct rapl_package), GFP_KERNEL); @@ -1454,9 +1456,16 @@ static struct rapl_package *rapl_add_package(int cpu, int pkgid) return ERR_PTR(-ENOMEM); /* add the new package to the list */ - rp->id = pkgid; + rp->id = id; rp->lead_cpu = cpu; + if (topology_max_die_per_package() > 1) + snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH, + "package-%d-die-%d", c->phys_proc_id, c->cpu_die_id); + else + snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH, "package-%d", + c->phys_proc_id); + /* check if the package contains valid domains */ if (rapl_detect_domains(rp, cpu) || rapl_defaults->check_unit(rp, cpu)) { @@ -1485,12 +1494,11 @@ err_free_package: */ static int rapl_cpu_online(unsigned int cpu) { - int pkgid = topology_physical_package_id(cpu); struct rapl_package *rp; - rp = find_package_by_id(pkgid); + rp = rapl_find_package_domain(cpu); if (!rp) { - rp = rapl_add_package(cpu, pkgid); + rp = rapl_add_package(cpu); if (IS_ERR(rp)) return PTR_ERR(rp); } @@ -1500,11 +1508,10 @@ static int rapl_cpu_online(unsigned int cpu) static int rapl_cpu_down_prep(unsigned int cpu) { - int pkgid = topology_physical_package_id(cpu); struct rapl_package *rp; int lead_cpu; - rp = find_package_by_id(pkgid); + rp = rapl_find_package_domain(cpu); if (!rp) return 0; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index dff5a93f7daa..a7e57516959e 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -401,6 +401,17 @@ config PWM_SAMSUNG To compile this driver as a module, choose M here: the module will be called pwm-samsung. +config PWM_SIFIVE + tristate "SiFive PWM support" + depends on OF + depends on COMMON_CLK + depends on RISCV || COMPILE_TEST + help + Generic PWM framework driver for SiFive SoCs. + + To compile this driver as a module, choose M here: the module + will be called pwm-sifive. + config PWM_SPEAR tristate "STMicroelectronics SPEAr PWM support" depends on PLAT_SPEAR diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index c368599d36c0..76b555b51887 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o +obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o obj-$(CONFIG_PWM_STI) += pwm-sti.o obj-$(CONFIG_PWM_STM32) += pwm-stm32.o diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 275b5f399a1a..c3ab07ab31a9 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -6,6 +6,7 @@ * Copyright (C) 2011-2012 Avionic Design GmbH */ +#include <linux/acpi.h> #include <linux/module.h> #include <linux/pwm.h> #include <linux/radix-tree.h> @@ -626,8 +627,35 @@ static struct pwm_chip *of_node_to_pwmchip(struct device_node *np) return ERR_PTR(-EPROBE_DEFER); } +static struct device_link *pwm_device_link_add(struct device *dev, + struct pwm_device *pwm) +{ + struct device_link *dl; + + if (!dev) { + /* + * No device for the PWM consumer has been provided. It may + * impact the PM sequence ordering: the PWM supplier may get + * suspended before the consumer. + */ + dev_warn(pwm->chip->dev, + "No consumer device specified to create a link to\n"); + return NULL; + } + + dl = device_link_add(dev, pwm->chip->dev, DL_FLAG_AUTOREMOVE_CONSUMER); + if (!dl) { + dev_err(dev, "failed to create device link to %s\n", + dev_name(pwm->chip->dev)); + return ERR_PTR(-EINVAL); + } + + return dl; +} + /** * of_pwm_get() - request a PWM via the PWM framework + * @dev: device for PWM consumer * @np: device node to get the PWM from * @con_id: consumer name * @@ -645,10 +673,12 @@ static struct pwm_chip *of_node_to_pwmchip(struct device_node *np) * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded * error code on failure. */ -struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id) +struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np, + const char *con_id) { struct pwm_device *pwm = NULL; struct of_phandle_args args; + struct device_link *dl; struct pwm_chip *pc; int index = 0; int err; @@ -679,6 +709,14 @@ struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id) if (IS_ERR(pwm)) goto put; + dl = pwm_device_link_add(dev, pwm); + if (IS_ERR(dl)) { + /* of_xlate ended up calling pwm_request_from_chip() */ + pwm_free(pwm); + pwm = ERR_CAST(dl); + goto put; + } + /* * If a consumer name was not given, try to look it up from the * "pwm-names" property if it exists. Otherwise use the name of @@ -700,6 +738,85 @@ put: } EXPORT_SYMBOL_GPL(of_pwm_get); +#if IS_ENABLED(CONFIG_ACPI) +static struct pwm_chip *device_to_pwmchip(struct device *dev) +{ + struct pwm_chip *chip; + + mutex_lock(&pwm_lock); + + list_for_each_entry(chip, &pwm_chips, list) { + struct acpi_device *adev = ACPI_COMPANION(chip->dev); + + if ((chip->dev == dev) || (adev && &adev->dev == dev)) { + mutex_unlock(&pwm_lock); + return chip; + } + } + + mutex_unlock(&pwm_lock); + + return ERR_PTR(-EPROBE_DEFER); +} +#endif + +/** + * acpi_pwm_get() - request a PWM via parsing "pwms" property in ACPI + * @fwnode: firmware node to get the "pwm" property from + * + * Returns the PWM device parsed from the fwnode and index specified in the + * "pwms" property or a negative error-code on failure. + * Values parsed from the device tree are stored in the returned PWM device + * object. + * + * This is analogous to of_pwm_get() except con_id is not yet supported. + * ACPI entries must look like + * Package () {"pwms", Package () + * { <PWM device reference>, <PWM index>, <PWM period> [, <PWM flags>]}} + * + * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded + * error code on failure. + */ +static struct pwm_device *acpi_pwm_get(struct fwnode_handle *fwnode) +{ + struct pwm_device *pwm = ERR_PTR(-ENODEV); +#if IS_ENABLED(CONFIG_ACPI) + struct fwnode_reference_args args; + struct acpi_device *acpi; + struct pwm_chip *chip; + int ret; + + memset(&args, 0, sizeof(args)); + + ret = __acpi_node_get_property_reference(fwnode, "pwms", 0, 3, &args); + if (ret < 0) + return ERR_PTR(ret); + + acpi = to_acpi_device_node(args.fwnode); + if (!acpi) + return ERR_PTR(-EINVAL); + + if (args.nargs < 2) + return ERR_PTR(-EPROTO); + + chip = device_to_pwmchip(&acpi->dev); + if (IS_ERR(chip)) + return ERR_CAST(chip); + + pwm = pwm_request_from_chip(chip, args.args[0], NULL); + if (IS_ERR(pwm)) + return pwm; + + pwm->args.period = args.args[1]; + pwm->args.polarity = PWM_POLARITY_NORMAL; + + if (args.nargs > 2 && args.args[2] & PWM_POLARITY_INVERTED) + pwm->args.polarity = PWM_POLARITY_INVERSED; +#endif + + return pwm; +} + /** * pwm_add_table() - register PWM device consumers * @table: array of consumers to register @@ -754,6 +871,7 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) const char *dev_id = dev ? dev_name(dev) : NULL; struct pwm_device *pwm; struct pwm_chip *chip; + struct device_link *dl; unsigned int best = 0; struct pwm_lookup *p, *chosen = NULL; unsigned int match; @@ -761,7 +879,11 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) /* look up via DT first */ if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) - return of_pwm_get(dev->of_node, con_id); + return of_pwm_get(dev, dev->of_node, con_id); + + /* then lookup via ACPI */ + if (dev && is_acpi_node(dev->fwnode)) + return acpi_pwm_get(dev->fwnode); /* * We look up the provider in the static table typically provided by @@ -838,6 +960,12 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) if (IS_ERR(pwm)) return pwm; + dl = pwm_device_link_add(dev, pwm); + if (IS_ERR(dl)) { + pwm_free(pwm); + return ERR_CAST(dl); + } + pwm->args.period = chosen->period; pwm->args.polarity = chosen->polarity; @@ -930,7 +1058,7 @@ struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np, if (!ptr) return ERR_PTR(-ENOMEM); - pwm = of_pwm_get(np, con_id); + pwm = of_pwm_get(dev, np, con_id); if (!IS_ERR(pwm)) { *ptr = pwm; devres_add(dev, ptr); @@ -942,6 +1070,44 @@ struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np, } EXPORT_SYMBOL_GPL(devm_of_pwm_get); +/** + * devm_fwnode_pwm_get() - request a resource managed PWM from firmware node + * @dev: device for PWM consumer + * @fwnode: firmware node to get the PWM from + * @con_id: consumer name + * + * Returns the PWM device parsed from the firmware node. See of_pwm_get() and + * acpi_pwm_get() for a detailed description. + * + * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded + * error code on failure. + */ +struct pwm_device *devm_fwnode_pwm_get(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id) +{ + struct pwm_device **ptr, *pwm = ERR_PTR(-ENODEV); + + ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + if (is_of_node(fwnode)) + pwm = of_pwm_get(dev, to_of_node(fwnode), con_id); + else if (is_acpi_node(fwnode)) + pwm = acpi_pwm_get(fwnode); + + if (!IS_ERR(pwm)) { + *ptr = pwm; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return pwm; +} +EXPORT_SYMBOL_GPL(devm_fwnode_pwm_get); + static int devm_pwm_match(struct device *dev, void *res, void *data) { struct pwm_device **p = res; diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index 54c6633d9b5d..d13a83f430ac 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Free Electrons * Copyright (C) 2014 Atmel * * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/clk.h> @@ -246,6 +235,7 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = { .compatible = "atmel,sama5d4-hlcdc", .data = &atmel_hlcdc_pwm_sama5d3_errata, }, + { .compatible = "microchip,sam9x60-hlcdc", }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, atmel_hlcdc_dt_ids); diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index 5652f461d994..f6fe0b922e1e 100644 --- a/drivers/pwm/pwm-bcm2835.c +++ b/drivers/pwm/pwm-bcm2835.c @@ -70,7 +70,7 @@ static int bcm2835_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, return -EINVAL; } - scaler = NSEC_PER_SEC / rate; + scaler = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate); if (period_ns <= MIN_PERIOD) { dev_err(pc->dev, "period %d not supported, minimum %d\n", @@ -78,8 +78,10 @@ static int bcm2835_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, return -EINVAL; } - writel(duty_ns / scaler, pc->base + DUTY(pwm->hwpwm)); - writel(period_ns / scaler, pc->base + PERIOD(pwm->hwpwm)); + writel(DIV_ROUND_CLOSEST(duty_ns, scaler), + pc->base + DUTY(pwm->hwpwm)); + writel(DIV_ROUND_CLOSEST(period_ns, scaler), + pc->base + PERIOD(pwm->hwpwm)); return 0; } diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index a39b48839df7..9d31a217111d 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -34,17 +34,19 @@ struct fsl_ftm_soc { bool has_enable_bits; }; +struct fsl_pwm_periodcfg { + enum fsl_pwm_clk clk_select; + unsigned int clk_ps; + unsigned int mod_period; +}; + struct fsl_pwm_chip { struct pwm_chip chip; - struct mutex lock; - - unsigned int cnt_select; - unsigned int clk_ps; - struct regmap *regmap; - int period_ns; + /* This value is valid iff a pwm is running */ + struct fsl_pwm_periodcfg period; struct clk *ipg_clk; struct clk *clk[FSL_PWM_CLK_MAX]; @@ -57,6 +59,33 @@ static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip) return container_of(chip, struct fsl_pwm_chip, chip); } +static void ftm_clear_write_protection(struct fsl_pwm_chip *fpc) +{ + u32 val; + + regmap_read(fpc->regmap, FTM_FMS, &val); + if (val & FTM_FMS_WPEN) + regmap_update_bits(fpc->regmap, FTM_MODE, FTM_MODE_WPDIS, + FTM_MODE_WPDIS); +} + +static void ftm_set_write_protection(struct fsl_pwm_chip *fpc) +{ + regmap_update_bits(fpc->regmap, FTM_FMS, FTM_FMS_WPEN, FTM_FMS_WPEN); +} + +static bool fsl_pwm_periodcfg_are_equal(const struct fsl_pwm_periodcfg *a, + const struct fsl_pwm_periodcfg *b) +{ + if (a->clk_select != b->clk_select) + return false; + if (a->clk_ps != b->clk_ps) + return false; + if (a->mod_period != b->mod_period) + return false; + return true; +} + static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) { int ret; @@ -87,89 +116,58 @@ static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) clk_disable_unprepare(fpc->ipg_clk); } -static int fsl_pwm_calculate_default_ps(struct fsl_pwm_chip *fpc, - enum fsl_pwm_clk index) +static unsigned int fsl_pwm_ticks_to_ns(struct fsl_pwm_chip *fpc, + unsigned int ticks) { - unsigned long sys_rate, cnt_rate; - unsigned long long ratio; - - sys_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_SYS]); - if (!sys_rate) - return -EINVAL; - - cnt_rate = clk_get_rate(fpc->clk[fpc->cnt_select]); - if (!cnt_rate) - return -EINVAL; - - switch (index) { - case FSL_PWM_CLK_SYS: - fpc->clk_ps = 1; - break; - case FSL_PWM_CLK_FIX: - ratio = 2 * cnt_rate - 1; - do_div(ratio, sys_rate); - fpc->clk_ps = ratio; - break; - case FSL_PWM_CLK_EXT: - ratio = 4 * cnt_rate - 1; - do_div(ratio, sys_rate); - fpc->clk_ps = ratio; - break; - default: - return -EINVAL; - } - - return 0; + unsigned long rate; + unsigned long long exval; + + rate = clk_get_rate(fpc->clk[fpc->period.clk_select]); + exval = ticks; + exval *= 1000000000UL; + do_div(exval, rate >> fpc->period.clk_ps); + return exval; } -static unsigned long fsl_pwm_calculate_cycles(struct fsl_pwm_chip *fpc, - unsigned long period_ns) +static bool fsl_pwm_calculate_period_clk(struct fsl_pwm_chip *fpc, + unsigned int period_ns, + enum fsl_pwm_clk index, + struct fsl_pwm_periodcfg *periodcfg + ) { - unsigned long long c, c0; + unsigned long long c; + unsigned int ps; - c = clk_get_rate(fpc->clk[fpc->cnt_select]); + c = clk_get_rate(fpc->clk[index]); c = c * period_ns; do_div(c, 1000000000UL); - do { - c0 = c; - do_div(c0, (1 << fpc->clk_ps)); - if (c0 <= 0xFFFF) - return (unsigned long)c0; - } while (++fpc->clk_ps < 8); - - return 0; -} - -static unsigned long fsl_pwm_calculate_period_cycles(struct fsl_pwm_chip *fpc, - unsigned long period_ns, - enum fsl_pwm_clk index) -{ - int ret; + if (c == 0) + return false; - ret = fsl_pwm_calculate_default_ps(fpc, index); - if (ret) { - dev_err(fpc->chip.dev, - "failed to calculate default prescaler: %d\n", - ret); - return 0; + for (ps = 0; ps < 8 ; ++ps, c >>= 1) { + if (c <= 0x10000) { + periodcfg->clk_select = index; + periodcfg->clk_ps = ps; + periodcfg->mod_period = c - 1; + return true; + } } - - return fsl_pwm_calculate_cycles(fpc, period_ns); + return false; } -static unsigned long fsl_pwm_calculate_period(struct fsl_pwm_chip *fpc, - unsigned long period_ns) +static bool fsl_pwm_calculate_period(struct fsl_pwm_chip *fpc, + unsigned int period_ns, + struct fsl_pwm_periodcfg *periodcfg) { enum fsl_pwm_clk m0, m1; - unsigned long fix_rate, ext_rate, cycles; + unsigned long fix_rate, ext_rate; + bool ret; - cycles = fsl_pwm_calculate_period_cycles(fpc, period_ns, - FSL_PWM_CLK_SYS); - if (cycles) { - fpc->cnt_select = FSL_PWM_CLK_SYS; - return cycles; - } + ret = fsl_pwm_calculate_period_clk(fpc, period_ns, FSL_PWM_CLK_SYS, + periodcfg); + if (ret) + return true; fix_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_FIX]); ext_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_EXT]); @@ -182,158 +180,185 @@ static unsigned long fsl_pwm_calculate_period(struct fsl_pwm_chip *fpc, m1 = FSL_PWM_CLK_FIX; } - cycles = fsl_pwm_calculate_period_cycles(fpc, period_ns, m0); - if (cycles) { - fpc->cnt_select = m0; - return cycles; - } - - fpc->cnt_select = m1; + ret = fsl_pwm_calculate_period_clk(fpc, period_ns, m0, periodcfg); + if (ret) + return true; - return fsl_pwm_calculate_period_cycles(fpc, period_ns, m1); + return fsl_pwm_calculate_period_clk(fpc, period_ns, m1, periodcfg); } -static unsigned long fsl_pwm_calculate_duty(struct fsl_pwm_chip *fpc, - unsigned long period_ns, - unsigned long duty_ns) +static unsigned int fsl_pwm_calculate_duty(struct fsl_pwm_chip *fpc, + unsigned int duty_ns) { unsigned long long duty; - u32 val; - regmap_read(fpc->regmap, FTM_MOD, &val); - duty = (unsigned long long)duty_ns * (val + 1); + unsigned int period = fpc->period.mod_period + 1; + unsigned int period_ns = fsl_pwm_ticks_to_ns(fpc, period); + + duty = (unsigned long long)duty_ns * period; do_div(duty, period_ns); - return (unsigned long)duty; + return (unsigned int)duty; } -static int fsl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) +static bool fsl_pwm_is_any_pwm_enabled(struct fsl_pwm_chip *fpc, + struct pwm_device *pwm) { - struct fsl_pwm_chip *fpc = to_fsl_chip(chip); - u32 period, duty; + u32 val; - mutex_lock(&fpc->lock); + regmap_read(fpc->regmap, FTM_OUTMASK, &val); + if (~val & 0xFF) + return true; + else + return false; +} + +static bool fsl_pwm_is_other_pwm_enabled(struct fsl_pwm_chip *fpc, + struct pwm_device *pwm) +{ + u32 val; + regmap_read(fpc->regmap, FTM_OUTMASK, &val); + if (~(val | BIT(pwm->hwpwm)) & 0xFF) + return true; + else + return false; +} + +static int fsl_pwm_apply_config(struct fsl_pwm_chip *fpc, + struct pwm_device *pwm, + struct pwm_state *newstate) +{ + unsigned int duty; + u32 reg_polarity; + + struct fsl_pwm_periodcfg periodcfg; + bool do_write_period = false; + + if (!fsl_pwm_calculate_period(fpc, newstate->period, &periodcfg)) { + dev_err(fpc->chip.dev, "failed to calculate new period\n"); + return -EINVAL; + } + + if (!fsl_pwm_is_any_pwm_enabled(fpc, pwm)) + do_write_period = true; /* * The Freescale FTM controller supports only a single period for - * all PWM channels, therefore incompatible changes need to be - * refused. + * all PWM channels, therefore verify if the newly computed period + * is different than the current period being used. In such case + * we allow to change the period only if no other pwm is running. */ - if (fpc->period_ns && fpc->period_ns != period_ns) { - dev_err(fpc->chip.dev, - "conflicting period requested for PWM %u\n", - pwm->hwpwm); - mutex_unlock(&fpc->lock); - return -EBUSY; + else if (!fsl_pwm_periodcfg_are_equal(&fpc->period, &periodcfg)) { + if (fsl_pwm_is_other_pwm_enabled(fpc, pwm)) { + dev_err(fpc->chip.dev, + "Cannot change period for PWM %u, disable other PWMs first\n", + pwm->hwpwm); + return -EBUSY; + } + if (fpc->period.clk_select != periodcfg.clk_select) { + int ret; + enum fsl_pwm_clk oldclk = fpc->period.clk_select; + enum fsl_pwm_clk newclk = periodcfg.clk_select; + + ret = clk_prepare_enable(fpc->clk[newclk]); + if (ret) + return ret; + clk_disable_unprepare(fpc->clk[oldclk]); + } + do_write_period = true; } - if (!fpc->period_ns && duty_ns) { - period = fsl_pwm_calculate_period(fpc, period_ns); - if (!period) { - dev_err(fpc->chip.dev, "failed to calculate period\n"); - mutex_unlock(&fpc->lock); - return -EINVAL; - } + ftm_clear_write_protection(fpc); + if (do_write_period) { + regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK, + FTM_SC_CLK(periodcfg.clk_select)); regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_PS_MASK, - fpc->clk_ps); - regmap_write(fpc->regmap, FTM_MOD, period - 1); + periodcfg.clk_ps); + regmap_write(fpc->regmap, FTM_MOD, periodcfg.mod_period); - fpc->period_ns = period_ns; + fpc->period = periodcfg; } - mutex_unlock(&fpc->lock); - - duty = fsl_pwm_calculate_duty(fpc, period_ns, duty_ns); + duty = fsl_pwm_calculate_duty(fpc, newstate->duty_cycle); regmap_write(fpc->regmap, FTM_CSC(pwm->hwpwm), FTM_CSC_MSB | FTM_CSC_ELSB); regmap_write(fpc->regmap, FTM_CV(pwm->hwpwm), duty); - return 0; -} - -static int fsl_pwm_set_polarity(struct pwm_chip *chip, - struct pwm_device *pwm, - enum pwm_polarity polarity) -{ - struct fsl_pwm_chip *fpc = to_fsl_chip(chip); - u32 val; + reg_polarity = 0; + if (newstate->polarity == PWM_POLARITY_INVERSED) + reg_polarity = BIT(pwm->hwpwm); - regmap_read(fpc->regmap, FTM_POL, &val); + regmap_update_bits(fpc->regmap, FTM_POL, BIT(pwm->hwpwm), reg_polarity); - if (polarity == PWM_POLARITY_INVERSED) - val |= BIT(pwm->hwpwm); - else - val &= ~BIT(pwm->hwpwm); + newstate->period = fsl_pwm_ticks_to_ns(fpc, + fpc->period.mod_period + 1); + newstate->duty_cycle = fsl_pwm_ticks_to_ns(fpc, duty); - regmap_write(fpc->regmap, FTM_POL, val); + ftm_set_write_protection(fpc); return 0; } -static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc) -{ - int ret; - - /* select counter clock source */ - regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK, - FTM_SC_CLK(fpc->cnt_select)); - - ret = clk_prepare_enable(fpc->clk[fpc->cnt_select]); - if (ret) - return ret; - - ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]); - if (ret) { - clk_disable_unprepare(fpc->clk[fpc->cnt_select]); - return ret; - } - - return 0; -} - -static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +static int fsl_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *newstate) { struct fsl_pwm_chip *fpc = to_fsl_chip(chip); - int ret; - - mutex_lock(&fpc->lock); - regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm), 0); + struct pwm_state *oldstate = &pwm->state; + int ret = 0; - ret = fsl_counter_clock_enable(fpc); - mutex_unlock(&fpc->lock); + /* + * oldstate to newstate : action + * + * disabled to disabled : ignore + * enabled to disabled : disable + * enabled to enabled : update settings + * disabled to enabled : update settings + enable + */ - return ret; -} + mutex_lock(&fpc->lock); -static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct fsl_pwm_chip *fpc = to_fsl_chip(chip); - u32 val; + if (!newstate->enabled) { + if (oldstate->enabled) { + regmap_update_bits(fpc->regmap, FTM_OUTMASK, + BIT(pwm->hwpwm), BIT(pwm->hwpwm)); + clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); + clk_disable_unprepare(fpc->clk[fpc->period.clk_select]); + } - mutex_lock(&fpc->lock); - regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm), - BIT(pwm->hwpwm)); + goto end_mutex; + } - clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); - clk_disable_unprepare(fpc->clk[fpc->cnt_select]); + ret = fsl_pwm_apply_config(fpc, pwm, newstate); + if (ret) + goto end_mutex; + + /* check if need to enable */ + if (!oldstate->enabled) { + ret = clk_prepare_enable(fpc->clk[fpc->period.clk_select]); + if (ret) + goto end_mutex; + + ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]); + if (ret) { + clk_disable_unprepare(fpc->clk[fpc->period.clk_select]); + goto end_mutex; + } - regmap_read(fpc->regmap, FTM_OUTMASK, &val); - if ((val & 0xFF) == 0xFF) - fpc->period_ns = 0; + regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm), + 0); + } +end_mutex: mutex_unlock(&fpc->lock); + return ret; } static const struct pwm_ops fsl_pwm_ops = { .request = fsl_pwm_request, .free = fsl_pwm_free, - .config = fsl_pwm_config, - .set_polarity = fsl_pwm_set_polarity, - .enable = fsl_pwm_enable, - .disable = fsl_pwm_disable, + .apply = fsl_pwm_apply, .owner = THIS_MODULE, }; @@ -357,6 +382,8 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc) static bool fsl_pwm_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { + case FTM_FMS: + case FTM_MODE: case FTM_CNT: return true; } @@ -474,7 +501,7 @@ static int fsl_pwm_suspend(struct device *dev) continue; clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); - clk_disable_unprepare(fpc->clk[fpc->cnt_select]); + clk_disable_unprepare(fpc->clk[fpc->period.clk_select]); } return 0; @@ -496,7 +523,7 @@ static int fsl_pwm_resume(struct device *dev) if (!pwm_is_enabled(pwm)) continue; - clk_prepare_enable(fpc->clk[fpc->cnt_select]); + clk_prepare_enable(fpc->clk[fpc->period.clk_select]); clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]); } diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index 88a51a40e695..f901e8a0d33d 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -63,7 +63,15 @@ static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { uint32_t ctrl = jz4740_timer_get_ctrl(pwm->hwpwm); - /* Disable PWM output. + /* + * Set duty > period. This trick allows the TCU channels in TCU2 mode to + * properly return to their init level. + */ + jz4740_timer_set_duty(pwm->hwpwm, 0xffff); + jz4740_timer_set_period(pwm->hwpwm, 0x0); + + /* + * Disable PWM output. * In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the * counter is stopped, while in TCU1 mode the order does not matter. */ @@ -74,17 +82,16 @@ static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) jz4740_timer_disable(pwm->hwpwm); } -static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) +static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) { struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip); unsigned long long tmp; unsigned long period, duty; unsigned int prescaler = 0; uint16_t ctrl; - bool is_enabled; - tmp = (unsigned long long)clk_get_rate(jz4740->clk) * period_ns; + tmp = (unsigned long long)clk_get_rate(jz4740->clk) * state->period; do_div(tmp, 1000000000); period = tmp; @@ -96,16 +103,14 @@ static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, if (prescaler == 6) return -EINVAL; - tmp = (unsigned long long)period * duty_ns; - do_div(tmp, period_ns); + tmp = (unsigned long long)period * state->duty_cycle; + do_div(tmp, state->period); duty = period - tmp; if (duty >= period) duty = period - 1; - is_enabled = jz4740_timer_is_enabled(pwm->hwpwm); - if (is_enabled) - jz4740_pwm_disable(chip, pwm); + jz4740_pwm_disable(chip, pwm); jz4740_timer_set_count(pwm->hwpwm, 0); jz4740_timer_set_duty(pwm->hwpwm, duty); @@ -116,18 +121,7 @@ static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, jz4740_timer_set_ctrl(pwm->hwpwm, ctrl); - if (is_enabled) - jz4740_pwm_enable(chip, pwm); - - return 0; -} - -static int jz4740_pwm_set_polarity(struct pwm_chip *chip, - struct pwm_device *pwm, enum pwm_polarity polarity) -{ - uint32_t ctrl = jz4740_timer_get_ctrl(pwm->pwm); - - switch (polarity) { + switch (state->polarity) { case PWM_POLARITY_NORMAL: ctrl &= ~JZ_TIMER_CTRL_PWM_ACTIVE_LOW; break; @@ -137,16 +131,17 @@ static int jz4740_pwm_set_polarity(struct pwm_chip *chip, } jz4740_timer_set_ctrl(pwm->hwpwm, ctrl); + + if (state->enabled) + jz4740_pwm_enable(chip, pwm); + return 0; } static const struct pwm_ops jz4740_pwm_ops = { .request = jz4740_pwm_request, .free = jz4740_pwm_free, - .config = jz4740_pwm_config, - .set_polarity = jz4740_pwm_set_polarity, - .enable = jz4740_pwm_enable, - .disable = jz4740_pwm_disable, + .apply = jz4740_pwm_apply, .owner = THIS_MODULE, }; @@ -184,8 +179,6 @@ static int jz4740_pwm_remove(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id jz4740_pwm_dt_ids[] = { { .compatible = "ingenic,jz4740-pwm", }, - { .compatible = "ingenic,jz4770-pwm", }, - { .compatible = "ingenic,jz4780-pwm", }, {}, }; MODULE_DEVICE_TABLE(of, jz4740_pwm_dt_ids); diff --git a/drivers/pwm/pwm-lpss-pci.c b/drivers/pwm/pwm-lpss-pci.c index c1527cb645be..cf749ea0de9f 100644 --- a/drivers/pwm/pwm-lpss-pci.c +++ b/drivers/pwm/pwm-lpss-pci.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Intel Low Power Subsystem PWM controller PCI driver * * Copyright (C) 2014, Intel Corporation * * Derived from the original pwm-lpss.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c index 757230e1f575..48f34d20aecd 100644 --- a/drivers/pwm/pwm-lpss-platform.c +++ b/drivers/pwm/pwm-lpss-platform.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Intel Low Power Subsystem PWM controller driver * * Copyright (C) 2014, Intel Corporation * * Derived from the original pwm-lpss.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 2ac3a2aa9e53..4098a4601691 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Intel Low Power Subsystem PWM controller driver * @@ -7,10 +8,6 @@ * Author: Chang Rebecca Swee Fun <rebecca.swee.fun.chang@intel.com> * Author: Chew Chiau Ee <chiau.ee.chew@intel.com> * Author: Alan Cox <alan@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h index 3236be835bd9..7909fa12fca2 100644 --- a/drivers/pwm/pwm-lpss.h +++ b/drivers/pwm/pwm-lpss.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Intel Low Power Subsystem PWM controller driver * * Copyright (C) 2014, Intel Corporation * * Derived from the original pwm-lpss.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __PWM_LPSS_H diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index fb5a369b1a8d..3cbff5cbb789 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -1,65 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. + * PWM controller driver for Amlogic Meson SoCs. * - * GPL LICENSE SUMMARY + * This PWM is only a set of Gates, Dividers and Counters: + * PWM output is achieved by calculating a clock that permits calculating + * two periods (low and high). The counter then has to be set to switch after + * N cycles for the first half period. + * The hardware has no "polarity" setting. This driver reverses the period + * cycles (the low length is inverted with the high length) for + * PWM_POLARITY_INVERSED. This means that .get_state cannot read the polarity + * from the hardware. + * Setting the duty cycle will disable and re-enable the PWM output. + * Disabling the PWM stops the output immediately (without waiting for the + * current period to complete first). * - * Copyright (c) 2016 BayLibre, SAS. - * Author: Neil Armstrong <narmstrong@baylibre.com> - * Copyright (C) 2014 Amlogic, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * BSD LICENSE + * The public S912 (GXM) datasheet contains some documentation for this PWM + * controller starting on page 543: + * https://dl.khadas.com/Hardware/VIM2/Datasheet/S912_Datasheet_V0.220170314publicversion-Wesion.pdf + * An updated version of this IP block is found in S922X (G12B) SoCs. The + * datasheet contains the description for this IP block revision starting at + * page 1084: + * https://dn.odroid.com/S922X/ODROID-N2/Datasheet/S922X_Public_Datasheet_V0.2.pdf * * Copyright (c) 2016 BayLibre, SAS. * Author: Neil Armstrong <narmstrong@baylibre.com> * Copyright (C) 2014 Amlogic, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <linux/bitfield.h> +#include <linux/bits.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/err.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/math64.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> @@ -70,7 +45,8 @@ #define REG_PWM_A 0x0 #define REG_PWM_B 0x4 -#define PWM_HIGH_SHIFT 16 +#define PWM_LOW_MASK GENMASK(15, 0) +#define PWM_HIGH_MASK GENMASK(31, 16) #define REG_MISC_AB 0x8 #define MISC_B_CLK_EN BIT(23) @@ -80,13 +56,33 @@ #define MISC_A_CLK_DIV_SHIFT 8 #define MISC_B_CLK_SEL_SHIFT 6 #define MISC_A_CLK_SEL_SHIFT 4 -#define MISC_CLK_SEL_WIDTH 2 +#define MISC_CLK_SEL_MASK 0x3 #define MISC_B_EN BIT(1) #define MISC_A_EN BIT(0) -static const unsigned int mux_reg_shifts[] = { - MISC_A_CLK_SEL_SHIFT, - MISC_B_CLK_SEL_SHIFT +#define MESON_NUM_PWMS 2 + +static struct meson_pwm_channel_data { + u8 reg_offset; + u8 clk_sel_shift; + u8 clk_div_shift; + u32 clk_en_mask; + u32 pwm_en_mask; +} meson_pwm_per_channel_data[MESON_NUM_PWMS] = { + { + .reg_offset = REG_PWM_A, + .clk_sel_shift = MISC_A_CLK_SEL_SHIFT, + .clk_div_shift = MISC_A_CLK_DIV_SHIFT, + .clk_en_mask = MISC_A_CLK_EN, + .pwm_en_mask = MISC_A_EN, + }, + { + .reg_offset = REG_PWM_B, + .clk_sel_shift = MISC_B_CLK_SEL_SHIFT, + .clk_div_shift = MISC_B_CLK_DIV_SHIFT, + .clk_en_mask = MISC_B_CLK_EN, + .pwm_en_mask = MISC_B_EN, + } }; struct meson_pwm_channel { @@ -94,8 +90,6 @@ struct meson_pwm_channel { unsigned int lo; u8 pre_div; - struct pwm_state state; - struct clk *clk_parent; struct clk_mux mux; struct clk *clk; @@ -109,8 +103,8 @@ struct meson_pwm_data { struct meson_pwm { struct pwm_chip chip; const struct meson_pwm_data *data; + struct meson_pwm_channel channels[MESON_NUM_PWMS]; void __iomem *base; - u8 inverter_mask; /* * Protects register (write) access to the REG_MISC_AB register * that is shared between the two PWMs. @@ -125,12 +119,16 @@ static inline struct meson_pwm *to_meson_pwm(struct pwm_chip *chip) static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) { - struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); + struct meson_pwm *meson = to_meson_pwm(chip); + struct meson_pwm_channel *channel; struct device *dev = chip->dev; int err; - if (!channel) - return -ENODEV; + channel = pwm_get_chip_data(pwm); + if (channel) + return 0; + + channel = &meson->channels[pwm->hwpwm]; if (channel->clk_parent) { err = clk_set_parent(channel->clk, channel->clk_parent); @@ -149,9 +147,7 @@ static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) return err; } - chip->ops->get_state(chip, pwm, &channel->state); - - return 0; + return pwm_set_chip_data(pwm, channel); } static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) @@ -162,20 +158,18 @@ static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) clk_disable_unprepare(channel->clk); } -static int meson_pwm_calc(struct meson_pwm *meson, - struct meson_pwm_channel *channel, unsigned int id, - unsigned int duty, unsigned int period) +static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm, + struct pwm_state *state) { - unsigned int pre_div, cnt, duty_cnt; + struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); + unsigned int duty, period, pre_div, cnt, duty_cnt; unsigned long fin_freq = -1; - u64 fin_ps; - if (~(meson->inverter_mask >> id) & 0x1) - duty = period - duty; + duty = state->duty_cycle; + period = state->period; - if (period == channel->state.period && - duty == channel->state.duty_cycle) - return 0; + if (state->polarity == PWM_POLARITY_INVERSED) + duty = period - duty; fin_freq = clk_get_rate(channel->clk); if (fin_freq == 0) { @@ -184,24 +178,19 @@ static int meson_pwm_calc(struct meson_pwm *meson, } dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq); - fin_ps = (u64)NSEC_PER_SEC * 1000; - do_div(fin_ps, fin_freq); - - /* Calc pre_div with the period */ - for (pre_div = 0; pre_div <= MISC_CLK_DIV_MASK; pre_div++) { - cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000, - fin_ps * (pre_div + 1)); - dev_dbg(meson->chip.dev, "fin_ps=%llu pre_div=%u cnt=%u\n", - fin_ps, pre_div, cnt); - if (cnt <= 0xffff) - break; - } + pre_div = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * 0xffffLL); if (pre_div > MISC_CLK_DIV_MASK) { dev_err(meson->chip.dev, "unable to get period pre_div\n"); return -EINVAL; } + cnt = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * (pre_div + 1)); + if (cnt > 0xffff) { + dev_err(meson->chip.dev, "unable to get period cnt\n"); + return -EINVAL; + } + dev_dbg(meson->chip.dev, "period=%u pre_div=%u cnt=%u\n", period, pre_div, cnt); @@ -215,8 +204,8 @@ static int meson_pwm_calc(struct meson_pwm *meson, channel->lo = cnt; } else { /* Then check is we can have the duty with the same pre_div */ - duty_cnt = DIV_ROUND_CLOSEST_ULL((u64)duty * 1000, - fin_ps * (pre_div + 1)); + duty_cnt = div64_u64(fin_freq * (u64)duty, + NSEC_PER_SEC * (pre_div + 1)); if (duty_cnt > 0xffff) { dev_err(meson->chip.dev, "unable to get duty cycle\n"); return -EINVAL; @@ -233,73 +222,43 @@ static int meson_pwm_calc(struct meson_pwm *meson, return 0; } -static void meson_pwm_enable(struct meson_pwm *meson, - struct meson_pwm_channel *channel, - unsigned int id) +static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm) { - u32 value, clk_shift, clk_enable, enable; - unsigned int offset; + struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); + struct meson_pwm_channel_data *channel_data; unsigned long flags; + u32 value; - switch (id) { - case 0: - clk_shift = MISC_A_CLK_DIV_SHIFT; - clk_enable = MISC_A_CLK_EN; - enable = MISC_A_EN; - offset = REG_PWM_A; - break; - - case 1: - clk_shift = MISC_B_CLK_DIV_SHIFT; - clk_enable = MISC_B_CLK_EN; - enable = MISC_B_EN; - offset = REG_PWM_B; - break; - - default: - return; - } + channel_data = &meson_pwm_per_channel_data[pwm->hwpwm]; spin_lock_irqsave(&meson->lock, flags); value = readl(meson->base + REG_MISC_AB); - value &= ~(MISC_CLK_DIV_MASK << clk_shift); - value |= channel->pre_div << clk_shift; - value |= clk_enable; + value &= ~(MISC_CLK_DIV_MASK << channel_data->clk_div_shift); + value |= channel->pre_div << channel_data->clk_div_shift; + value |= channel_data->clk_en_mask; writel(value, meson->base + REG_MISC_AB); - value = (channel->hi << PWM_HIGH_SHIFT) | channel->lo; - writel(value, meson->base + offset); + value = FIELD_PREP(PWM_HIGH_MASK, channel->hi) | + FIELD_PREP(PWM_LOW_MASK, channel->lo); + writel(value, meson->base + channel_data->reg_offset); value = readl(meson->base + REG_MISC_AB); - value |= enable; + value |= channel_data->pwm_en_mask; writel(value, meson->base + REG_MISC_AB); spin_unlock_irqrestore(&meson->lock, flags); } -static void meson_pwm_disable(struct meson_pwm *meson, unsigned int id) +static void meson_pwm_disable(struct meson_pwm *meson, struct pwm_device *pwm) { - u32 value, enable; unsigned long flags; - - switch (id) { - case 0: - enable = MISC_A_EN; - break; - - case 1: - enable = MISC_B_EN; - break; - - default: - return; - } + u32 value; spin_lock_irqsave(&meson->lock, flags); value = readl(meson->base + REG_MISC_AB); - value &= ~enable; + value &= ~meson_pwm_per_channel_data[pwm->hwpwm].pwm_en_mask; writel(value, meson->base + REG_MISC_AB); spin_unlock_irqrestore(&meson->lock, flags); @@ -316,64 +275,97 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return -EINVAL; if (!state->enabled) { - meson_pwm_disable(meson, pwm->hwpwm); - channel->state.enabled = false; - - return 0; - } - - if (state->period != channel->state.period || - state->duty_cycle != channel->state.duty_cycle || - state->polarity != channel->state.polarity) { - if (state->polarity != channel->state.polarity) { - if (state->polarity == PWM_POLARITY_NORMAL) - meson->inverter_mask |= BIT(pwm->hwpwm); - else - meson->inverter_mask &= ~BIT(pwm->hwpwm); + if (state->polarity == PWM_POLARITY_INVERSED) { + /* + * This IP block revision doesn't have an "always high" + * setting which we can use for "inverted disabled". + * Instead we achieve this using the same settings + * that we use a pre_div of 0 (to get the shortest + * possible duration for one "count") and + * "period == duty_cycle". This results in a signal + * which is LOW for one "count", while being HIGH for + * the rest of the (so the signal is HIGH for slightly + * less than 100% of the period, but this is the best + * we can achieve). + */ + channel->pre_div = 0; + channel->hi = ~0; + channel->lo = 0; + + meson_pwm_enable(meson, pwm); + } else { + meson_pwm_disable(meson, pwm); } - - err = meson_pwm_calc(meson, channel, pwm->hwpwm, - state->duty_cycle, state->period); + } else { + err = meson_pwm_calc(meson, pwm, state); if (err < 0) return err; - channel->state.polarity = state->polarity; - channel->state.period = state->period; - channel->state.duty_cycle = state->duty_cycle; - } - - if (state->enabled && !channel->state.enabled) { - meson_pwm_enable(meson, channel, pwm->hwpwm); - channel->state.enabled = true; + meson_pwm_enable(meson, pwm); } return 0; } +static unsigned int meson_pwm_cnt_to_ns(struct pwm_chip *chip, + struct pwm_device *pwm, u32 cnt) +{ + struct meson_pwm *meson = to_meson_pwm(chip); + struct meson_pwm_channel *channel; + unsigned long fin_freq; + u32 fin_ns; + + /* to_meson_pwm() can only be used after .get_state() is called */ + channel = &meson->channels[pwm->hwpwm]; + + fin_freq = clk_get_rate(channel->clk); + if (fin_freq == 0) + return 0; + + fin_ns = div_u64(NSEC_PER_SEC, fin_freq); + + return cnt * fin_ns * (channel->pre_div + 1); +} + static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state) { struct meson_pwm *meson = to_meson_pwm(chip); - u32 value, mask; + struct meson_pwm_channel_data *channel_data; + struct meson_pwm_channel *channel; + u32 value, tmp; if (!state) return; - switch (pwm->hwpwm) { - case 0: - mask = MISC_A_EN; - break; + channel = &meson->channels[pwm->hwpwm]; + channel_data = &meson_pwm_per_channel_data[pwm->hwpwm]; - case 1: - mask = MISC_B_EN; - break; + value = readl(meson->base + REG_MISC_AB); - default: - return; - } + tmp = channel_data->pwm_en_mask | channel_data->clk_en_mask; + state->enabled = (value & tmp) == tmp; - value = readl(meson->base + REG_MISC_AB); - state->enabled = (value & mask) != 0; + tmp = value >> channel_data->clk_div_shift; + channel->pre_div = FIELD_GET(MISC_CLK_DIV_MASK, tmp); + + value = readl(meson->base + channel_data->reg_offset); + + channel->lo = FIELD_GET(PWM_LOW_MASK, value); + channel->hi = FIELD_GET(PWM_HIGH_MASK, value); + + if (channel->lo == 0) { + state->period = meson_pwm_cnt_to_ns(chip, pwm, channel->hi); + state->duty_cycle = state->period; + } else if (channel->lo >= channel->hi) { + state->period = meson_pwm_cnt_to_ns(chip, pwm, + channel->lo + channel->hi); + state->duty_cycle = meson_pwm_cnt_to_ns(chip, pwm, + channel->hi); + } else { + state->period = 0; + state->duty_cycle = 0; + } } static const struct pwm_ops meson_pwm_ops = { @@ -433,8 +425,17 @@ static const struct meson_pwm_data pwm_axg_ao_data = { .num_parents = ARRAY_SIZE(pwm_axg_ao_parent_names), }; +static const char * const pwm_g12a_ao_ab_parent_names[] = { + "xtal", "aoclk81", "fclk_div4", "fclk_div5" +}; + +static const struct meson_pwm_data pwm_g12a_ao_ab_data = { + .parent_names = pwm_g12a_ao_ab_parent_names, + .num_parents = ARRAY_SIZE(pwm_g12a_ao_ab_parent_names), +}; + static const char * const pwm_g12a_ao_cd_parent_names[] = { - "aoclk81", "xtal", + "xtal", "aoclk81", }; static const struct meson_pwm_data pwm_g12a_ao_cd_data = { @@ -478,7 +479,7 @@ static const struct of_device_id meson_pwm_matches[] = { }, { .compatible = "amlogic,meson-g12a-ao-pwm-ab", - .data = &pwm_axg_ao_data + .data = &pwm_g12a_ao_ab_data }, { .compatible = "amlogic,meson-g12a-ao-pwm-cd", @@ -488,8 +489,7 @@ static const struct of_device_id meson_pwm_matches[] = { }; MODULE_DEVICE_TABLE(of, meson_pwm_matches); -static int meson_pwm_init_channels(struct meson_pwm *meson, - struct meson_pwm_channel *channels) +static int meson_pwm_init_channels(struct meson_pwm *meson) { struct device *dev = meson->chip.dev; struct clk_init_data init; @@ -498,7 +498,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson, int err; for (i = 0; i < meson->chip.npwm; i++) { - struct meson_pwm_channel *channel = &channels[i]; + struct meson_pwm_channel *channel = &meson->channels[i]; snprintf(name, sizeof(name), "%s#mux%u", dev_name(dev), i); @@ -509,8 +509,9 @@ static int meson_pwm_init_channels(struct meson_pwm *meson, init.num_parents = meson->data->num_parents; channel->mux.reg = meson->base + REG_MISC_AB; - channel->mux.shift = mux_reg_shifts[i]; - channel->mux.mask = BIT(MISC_CLK_SEL_WIDTH) - 1; + channel->mux.shift = + meson_pwm_per_channel_data[i].clk_sel_shift; + channel->mux.mask = MISC_CLK_SEL_MASK; channel->mux.flags = 0; channel->mux.lock = &meson->lock; channel->mux.table = NULL; @@ -525,31 +526,16 @@ static int meson_pwm_init_channels(struct meson_pwm *meson, snprintf(name, sizeof(name), "clkin%u", i); - channel->clk_parent = devm_clk_get(dev, name); - if (IS_ERR(channel->clk_parent)) { - err = PTR_ERR(channel->clk_parent); - if (err == -EPROBE_DEFER) - return err; - - channel->clk_parent = NULL; - } + channel->clk_parent = devm_clk_get_optional(dev, name); + if (IS_ERR(channel->clk_parent)) + return PTR_ERR(channel->clk_parent); } return 0; } -static void meson_pwm_add_channels(struct meson_pwm *meson, - struct meson_pwm_channel *channels) -{ - unsigned int i; - - for (i = 0; i < meson->chip.npwm; i++) - pwm_set_chip_data(&meson->chip.pwms[i], &channels[i]); -} - static int meson_pwm_probe(struct platform_device *pdev) { - struct meson_pwm_channel *channels; struct meson_pwm *meson; struct resource *regs; int err; @@ -567,19 +553,13 @@ static int meson_pwm_probe(struct platform_device *pdev) meson->chip.dev = &pdev->dev; meson->chip.ops = &meson_pwm_ops; meson->chip.base = -1; - meson->chip.npwm = 2; + meson->chip.npwm = MESON_NUM_PWMS; meson->chip.of_xlate = of_pwm_xlate_with_flags; meson->chip.of_pwm_n_cells = 3; meson->data = of_device_get_match_data(&pdev->dev); - meson->inverter_mask = BIT(meson->chip.npwm) - 1; - channels = devm_kcalloc(&pdev->dev, meson->chip.npwm, - sizeof(*channels), GFP_KERNEL); - if (!channels) - return -ENOMEM; - - err = meson_pwm_init_channels(meson, channels); + err = meson_pwm_init_channels(meson); if (err < 0) return err; @@ -589,8 +569,6 @@ static int meson_pwm_probe(struct platform_device *pdev) return err; } - meson_pwm_add_channels(meson, channels); - platform_set_drvdata(pdev, meson); return 0; diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c index f45798679e3c..00772fc53490 100644 --- a/drivers/pwm/pwm-omap-dmtimer.c +++ b/drivers/pwm/pwm-omap-dmtimer.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015 Neil Armstrong <narmstrong@baylibre.com> * Copyright (c) 2014 Joachim Eastwood <manabian@gmail.com> @@ -7,10 +8,6 @@ * * Also based on pwm-samsung.c * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * * Description: * This file is the core OMAP support for the generic, Linux * PWM driver / controller, using the OMAP's dual-mode timers. diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index 567f5e2771c4..168684b02ebc 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for PCA9685 16-channel 12-bit PWM LED controller * @@ -5,18 +6,6 @@ * Copyright (C) 2015 Clemens Gruber <clemens.gruber@pqgruber.com> * * based on the pwm-twl-led.c driver - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/acpi.h> diff --git a/drivers/pwm/pwm-puv3.c b/drivers/pwm/pwm-puv3.c index 754fd9a98f6b..9d0bd87a425e 100644 --- a/drivers/pwm/pwm-puv3.c +++ b/drivers/pwm/pwm-puv3.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/arch/unicore32/kernel/pwm.c * @@ -5,10 +6,6 @@ * * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> * Copyright (C) 2001-2010 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index 4143a46684d2..a2a0912c2dcd 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/pwm/pwm-pxa.c * * simple driver for PWM (Pulse Width Modulator) controller * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * 2008-02-13 initial version * eric miao <eric.miao@marvell.com> */ diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c index cfe7dd1b448e..5b2b8ecc354c 100644 --- a/drivers/pwm/pwm-rcar.c +++ b/drivers/pwm/pwm-rcar.c @@ -254,50 +254,11 @@ static const struct of_device_id rcar_pwm_of_table[] = { }; MODULE_DEVICE_TABLE(of, rcar_pwm_of_table); -#ifdef CONFIG_PM_SLEEP -static struct pwm_device *rcar_pwm_dev_to_pwm_dev(struct device *dev) -{ - struct rcar_pwm_chip *rcar_pwm = dev_get_drvdata(dev); - struct pwm_chip *chip = &rcar_pwm->chip; - - return &chip->pwms[0]; -} - -static int rcar_pwm_suspend(struct device *dev) -{ - struct pwm_device *pwm = rcar_pwm_dev_to_pwm_dev(dev); - - if (!test_bit(PWMF_REQUESTED, &pwm->flags)) - return 0; - - pm_runtime_put(dev); - - return 0; -} - -static int rcar_pwm_resume(struct device *dev) -{ - struct pwm_device *pwm = rcar_pwm_dev_to_pwm_dev(dev); - struct pwm_state state; - - if (!test_bit(PWMF_REQUESTED, &pwm->flags)) - return 0; - - pm_runtime_get_sync(dev); - - pwm_get_state(pwm, &state); - - return rcar_pwm_apply(pwm->chip, pwm, &state); -} -#endif /* CONFIG_PM_SLEEP */ -static SIMPLE_DEV_PM_OPS(rcar_pwm_pm_ops, rcar_pwm_suspend, rcar_pwm_resume); - static struct platform_driver rcar_pwm_driver = { .probe = rcar_pwm_probe, .remove = rcar_pwm_remove, .driver = { .name = "pwm-rcar", - .pm = &rcar_pwm_pm_ops, .of_match_table = of_match_ptr(rcar_pwm_of_table), } }; diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index 4d99d468df09..51b96cb7dd25 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PWM driver for Rockchip SoCs * * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> * Copyright (C) 2014 ROCKCHIP, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c new file mode 100644 index 000000000000..a7c107f19e66 --- /dev/null +++ b/drivers/pwm/pwm-sifive.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017-2018 SiFive + * For SiFive's PWM IP block documentation please refer Chapter 14 of + * Reference Manual : https://static.dev.sifive.com/FU540-C000-v1.0.pdf + * + * Limitations: + * - When changing both duty cycle and period, we cannot prevent in + * software that the output might produce a period with mixed + * settings (new period length and old duty cycle). + * - The hardware cannot generate a 100% duty cycle. + * - The hardware generates only inverted output. + */ +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> +#include <linux/slab.h> +#include <linux/bitfield.h> + +/* Register offsets */ +#define PWM_SIFIVE_PWMCFG 0x0 +#define PWM_SIFIVE_PWMCOUNT 0x8 +#define PWM_SIFIVE_PWMS 0x10 +#define PWM_SIFIVE_PWMCMP0 0x20 + +/* PWMCFG fields */ +#define PWM_SIFIVE_PWMCFG_SCALE GENMASK(3, 0) +#define PWM_SIFIVE_PWMCFG_STICKY BIT(8) +#define PWM_SIFIVE_PWMCFG_ZERO_CMP BIT(9) +#define PWM_SIFIVE_PWMCFG_DEGLITCH BIT(10) +#define PWM_SIFIVE_PWMCFG_EN_ALWAYS BIT(12) +#define PWM_SIFIVE_PWMCFG_EN_ONCE BIT(13) +#define PWM_SIFIVE_PWMCFG_CENTER BIT(16) +#define PWM_SIFIVE_PWMCFG_GANG BIT(24) +#define PWM_SIFIVE_PWMCFG_IP BIT(28) + +/* PWM_SIFIVE_SIZE_PWMCMP is used to calculate offset for pwmcmpX registers */ +#define PWM_SIFIVE_SIZE_PWMCMP 4 +#define PWM_SIFIVE_CMPWIDTH 16 +#define PWM_SIFIVE_DEFAULT_PERIOD 10000000 + +struct pwm_sifive_ddata { + struct pwm_chip chip; + struct mutex lock; /* lock to protect user_count */ + struct notifier_block notifier; + struct clk *clk; + void __iomem *regs; + unsigned int real_period; + unsigned int approx_period; + int user_count; +}; + +static inline +struct pwm_sifive_ddata *pwm_sifive_chip_to_ddata(struct pwm_chip *c) +{ + return container_of(c, struct pwm_sifive_ddata, chip); +} + +static int pwm_sifive_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); + + mutex_lock(&ddata->lock); + ddata->user_count++; + mutex_unlock(&ddata->lock); + + return 0; +} + +static void pwm_sifive_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); + + mutex_lock(&ddata->lock); + ddata->user_count--; + mutex_unlock(&ddata->lock); +} + +static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata, + unsigned long rate) +{ + unsigned long long num; + unsigned long scale_pow; + int scale; + u32 val; + /* + * The PWM unit is used with pwmzerocmp=0, so the only way to modify the + * period length is using pwmscale which provides the number of bits the + * counter is shifted before being feed to the comparators. A period + * lasts (1 << (PWM_SIFIVE_CMPWIDTH + pwmscale)) clock ticks. + * (1 << (PWM_SIFIVE_CMPWIDTH + scale)) * 10^9/rate = period + */ + scale_pow = div64_ul(ddata->approx_period * (u64)rate, NSEC_PER_SEC); + scale = clamp(ilog2(scale_pow) - PWM_SIFIVE_CMPWIDTH, 0, 0xf); + + val = PWM_SIFIVE_PWMCFG_EN_ALWAYS | + FIELD_PREP(PWM_SIFIVE_PWMCFG_SCALE, scale); + writel(val, ddata->regs + PWM_SIFIVE_PWMCFG); + + /* As scale <= 15 the shift operation cannot overflow. */ + num = (unsigned long long)NSEC_PER_SEC << (PWM_SIFIVE_CMPWIDTH + scale); + ddata->real_period = div64_ul(num, rate); + dev_dbg(ddata->chip.dev, + "New real_period = %u ns\n", ddata->real_period); +} + +static void pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); + u32 duty, val; + + duty = readl(ddata->regs + PWM_SIFIVE_PWMCMP0 + + pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP); + + state->enabled = duty > 0; + + val = readl(ddata->regs + PWM_SIFIVE_PWMCFG); + if (!(val & PWM_SIFIVE_PWMCFG_EN_ALWAYS)) + state->enabled = false; + + state->period = ddata->real_period; + state->duty_cycle = + (u64)duty * ddata->real_period >> PWM_SIFIVE_CMPWIDTH; + state->polarity = PWM_POLARITY_INVERSED; +} + +static int pwm_sifive_enable(struct pwm_chip *chip, bool enable) +{ + struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); + int ret; + + if (enable) { + ret = clk_enable(ddata->clk); + if (ret) { + dev_err(ddata->chip.dev, "Enable clk failed\n"); + return ret; + } + } + + if (!enable) + clk_disable(ddata->clk); + + return 0; +} + +static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); + struct pwm_state cur_state; + unsigned int duty_cycle; + unsigned long long num; + bool enabled; + int ret = 0; + u32 frac; + + if (state->polarity != PWM_POLARITY_INVERSED) + return -EINVAL; + + ret = clk_enable(ddata->clk); + if (ret) { + dev_err(ddata->chip.dev, "Enable clk failed\n"); + return ret; + } + + mutex_lock(&ddata->lock); + cur_state = pwm->state; + enabled = cur_state.enabled; + + duty_cycle = state->duty_cycle; + if (!state->enabled) + duty_cycle = 0; + + /* + * The problem of output producing mixed setting as mentioned at top, + * occurs here. To minimize the window for this problem, we are + * calculating the register values first and then writing them + * consecutively + */ + num = (u64)duty_cycle * (1U << PWM_SIFIVE_CMPWIDTH); + frac = DIV_ROUND_CLOSEST_ULL(num, state->period); + /* The hardware cannot generate a 100% duty cycle */ + frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1); + + if (state->period != ddata->approx_period) { + if (ddata->user_count != 1) { + ret = -EBUSY; + goto exit; + } + ddata->approx_period = state->period; + pwm_sifive_update_clock(ddata, clk_get_rate(ddata->clk)); + } + + writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP0 + + pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP); + + if (state->enabled != enabled) + pwm_sifive_enable(chip, state->enabled); + +exit: + clk_disable(ddata->clk); + mutex_unlock(&ddata->lock); + return ret; +} + +static const struct pwm_ops pwm_sifive_ops = { + .request = pwm_sifive_request, + .free = pwm_sifive_free, + .get_state = pwm_sifive_get_state, + .apply = pwm_sifive_apply, + .owner = THIS_MODULE, +}; + +static int pwm_sifive_clock_notifier(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct clk_notifier_data *ndata = data; + struct pwm_sifive_ddata *ddata = + container_of(nb, struct pwm_sifive_ddata, notifier); + + if (event == POST_RATE_CHANGE) + pwm_sifive_update_clock(ddata, ndata->new_rate); + + return NOTIFY_OK; +} + +static int pwm_sifive_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pwm_sifive_ddata *ddata; + struct pwm_chip *chip; + struct resource *res; + int ret; + + ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + mutex_init(&ddata->lock); + chip = &ddata->chip; + chip->dev = dev; + chip->ops = &pwm_sifive_ops; + chip->of_xlate = of_pwm_xlate_with_flags; + chip->of_pwm_n_cells = 3; + chip->base = -1; + chip->npwm = 4; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ddata->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(ddata->regs)) { + dev_err(dev, "Unable to map IO resources\n"); + return PTR_ERR(ddata->regs); + } + + ddata->clk = devm_clk_get(dev, NULL); + if (IS_ERR(ddata->clk)) { + if (PTR_ERR(ddata->clk) != -EPROBE_DEFER) + dev_err(dev, "Unable to find controller clock\n"); + return PTR_ERR(ddata->clk); + } + + ret = clk_prepare_enable(ddata->clk); + if (ret) { + dev_err(dev, "failed to enable clock for pwm: %d\n", ret); + return ret; + } + + /* Watch for changes to underlying clock frequency */ + ddata->notifier.notifier_call = pwm_sifive_clock_notifier; + ret = clk_notifier_register(ddata->clk, &ddata->notifier); + if (ret) { + dev_err(dev, "failed to register clock notifier: %d\n", ret); + goto disable_clk; + } + + ret = pwmchip_add(chip); + if (ret < 0) { + dev_err(dev, "cannot register PWM: %d\n", ret); + goto unregister_clk; + } + + platform_set_drvdata(pdev, ddata); + dev_dbg(dev, "SiFive PWM chip registered %d PWMs\n", chip->npwm); + + return 0; + +unregister_clk: + clk_notifier_unregister(ddata->clk, &ddata->notifier); +disable_clk: + clk_disable_unprepare(ddata->clk); + + return ret; +} + +static int pwm_sifive_remove(struct platform_device *dev) +{ + struct pwm_sifive_ddata *ddata = platform_get_drvdata(dev); + bool is_enabled = false; + struct pwm_device *pwm; + int ret, ch; + + for (ch = 0; ch < ddata->chip.npwm; ch++) { + pwm = &ddata->chip.pwms[ch]; + if (pwm->state.enabled) { + is_enabled = true; + break; + } + } + if (is_enabled) + clk_disable(ddata->clk); + + clk_disable_unprepare(ddata->clk); + ret = pwmchip_remove(&ddata->chip); + clk_notifier_unregister(ddata->clk, &ddata->notifier); + + return ret; +} + +static const struct of_device_id pwm_sifive_of_match[] = { + { .compatible = "sifive,pwm0" }, + {}, +}; +MODULE_DEVICE_TABLE(of, pwm_sifive_of_match); + +static struct platform_driver pwm_sifive_driver = { + .probe = pwm_sifive_probe, + .remove = pwm_sifive_remove, + .driver = { + .name = "pwm-sifive", + .of_match_table = pwm_sifive_of_match, + }, +}; +module_platform_driver(pwm_sifive_driver); + +MODULE_DESCRIPTION("SiFive PWM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c index 0059b24cfdc3..2211a642066d 100644 --- a/drivers/pwm/pwm-stm32-lp.c +++ b/drivers/pwm/pwm-stm32-lp.c @@ -13,6 +13,7 @@ #include <linux/mfd/stm32-lptimer.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/pwm.h> @@ -223,6 +224,29 @@ static int stm32_pwm_lp_remove(struct platform_device *pdev) return pwmchip_remove(&priv->chip); } +static int __maybe_unused stm32_pwm_lp_suspend(struct device *dev) +{ + struct stm32_pwm_lp *priv = dev_get_drvdata(dev); + struct pwm_state state; + + pwm_get_state(&priv->chip.pwms[0], &state); + if (state.enabled) { + dev_err(dev, "The consumer didn't stop us (%s)\n", + priv->chip.pwms[0].label); + return -EBUSY; + } + + return pinctrl_pm_select_sleep_state(dev); +} + +static int __maybe_unused stm32_pwm_lp_resume(struct device *dev) +{ + return pinctrl_pm_select_default_state(dev); +} + +static SIMPLE_DEV_PM_OPS(stm32_pwm_lp_pm_ops, stm32_pwm_lp_suspend, + stm32_pwm_lp_resume); + static const struct of_device_id stm32_pwm_lp_of_match[] = { { .compatible = "st,stm32-pwm-lp", }, {}, @@ -235,6 +259,7 @@ static struct platform_driver stm32_pwm_lp_driver = { .driver = { .name = "stm32-pwm-lp", .of_match_table = of_match_ptr(stm32_pwm_lp_of_match), + .pm = &stm32_pwm_lp_pm_ops, }, }; module_platform_driver(stm32_pwm_lp_driver); diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index 4f842550fbd1..740e2dec8313 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -608,6 +608,8 @@ static int stm32_pwm_probe(struct platform_device *pdev) priv->regmap = ddata->regmap; priv->clk = ddata->clk; priv->max_arr = ddata->max_arr; + priv->chip.of_xlate = of_pwm_xlate_with_flags; + priv->chip.of_pwm_n_cells = 3; if (!priv->regmap || !priv->clk) return -EINVAL; diff --git a/drivers/pwm/pwm-stmpe.c b/drivers/pwm/pwm-stmpe.c index 3439f1e902cb..be5f6d7359d4 100644 --- a/drivers/pwm/pwm-stmpe.c +++ b/drivers/pwm/pwm-stmpe.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Linaro Ltd. * * Author: Linus Walleij <linus.walleij@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * */ #include <linux/bitops.h> diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c index 01153622778b..630b9a578820 100644 --- a/drivers/pwm/pwm-twl-led.c +++ b/drivers/pwm/pwm-twl-led.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for TWL4030/6030 Pulse Width Modulator used as LED driver * @@ -6,18 +7,6 @@ * * This driver is a complete rewrite of the former pwm-twl6030.c authorded by: * Hemanth V <hemanthv@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c index b7a45be99815..aee67974f353 100644 --- a/drivers/pwm/pwm-twl.c +++ b/drivers/pwm/pwm-twl.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for TWL4030/6030 Generic Pulse Width Modulator * * Copyright (C) 2012 Texas Instruments * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> diff --git a/drivers/pwm/pwm-zx.c b/drivers/pwm/pwm-zx.c index 5d27c16edfb1..e24f4be35316 100644 --- a/drivers/pwm/pwm-zx.c +++ b/drivers/pwm/pwm-zx.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 Sanechips Technology Co., Ltd. * Copyright 2017 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index bf6823fe0812..2389b8669846 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -18,6 +18,7 @@ struct pwm_export { struct device child; struct pwm_device *pwm; struct mutex lock; + struct pwm_state suspend; }; static struct pwm_export *child_to_pwm_export(struct device *child) @@ -372,10 +373,111 @@ static struct attribute *pwm_chip_attrs[] = { }; ATTRIBUTE_GROUPS(pwm_chip); +/* takes export->lock on success */ +static struct pwm_export *pwm_class_get_state(struct device *parent, + struct pwm_device *pwm, + struct pwm_state *state) +{ + struct device *child; + struct pwm_export *export; + + if (!test_bit(PWMF_EXPORTED, &pwm->flags)) + return NULL; + + child = device_find_child(parent, pwm, pwm_unexport_match); + if (!child) + return NULL; + + export = child_to_pwm_export(child); + put_device(child); /* for device_find_child() */ + + mutex_lock(&export->lock); + pwm_get_state(pwm, state); + + return export; +} + +static int pwm_class_apply_state(struct pwm_export *export, + struct pwm_device *pwm, + struct pwm_state *state) +{ + int ret = pwm_apply_state(pwm, state); + + /* release lock taken in pwm_class_get_state */ + mutex_unlock(&export->lock); + + return ret; +} + +static int pwm_class_resume_npwm(struct device *parent, unsigned int npwm) +{ + struct pwm_chip *chip = dev_get_drvdata(parent); + unsigned int i; + int ret = 0; + + for (i = 0; i < npwm; i++) { + struct pwm_device *pwm = &chip->pwms[i]; + struct pwm_state state; + struct pwm_export *export; + + export = pwm_class_get_state(parent, pwm, &state); + if (!export) + continue; + + state.enabled = export->suspend.enabled; + ret = pwm_class_apply_state(export, pwm, &state); + if (ret < 0) + break; + } + + return ret; +} + +static int __maybe_unused pwm_class_suspend(struct device *parent) +{ + struct pwm_chip *chip = dev_get_drvdata(parent); + unsigned int i; + int ret = 0; + + for (i = 0; i < chip->npwm; i++) { + struct pwm_device *pwm = &chip->pwms[i]; + struct pwm_state state; + struct pwm_export *export; + + export = pwm_class_get_state(parent, pwm, &state); + if (!export) + continue; + + export->suspend = state; + state.enabled = false; + ret = pwm_class_apply_state(export, pwm, &state); + if (ret < 0) { + /* + * roll back the PWM devices that were disabled by + * this suspend function. + */ + pwm_class_resume_npwm(parent, i); + break; + } + } + + return ret; +} + +static int __maybe_unused pwm_class_resume(struct device *parent) +{ + struct pwm_chip *chip = dev_get_drvdata(parent); + + return pwm_class_resume_npwm(parent, chip->npwm); +} + +static SIMPLE_DEV_PM_OPS(pwm_class_pm_ops, pwm_class_suspend, pwm_class_resume); + static struct class pwm_class = { .name = "pwm", .owner = THIS_MODULE, .dev_groups = pwm_chip_groups, + .pm = &pwm_class_pm_ops, }; static int pwmchip_sysfs_match(struct device *parent, const void *data) diff --git a/drivers/ras/cec.c b/drivers/ras/cec.c index 673f8a128397..5d545806d930 100644 --- a/drivers/ras/cec.c +++ b/drivers/ras/cec.c @@ -1,4 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017-2019 Borislav Petkov, SUSE Labs. + */ #include <linux/mm.h> #include <linux/gfp.h> #include <linux/kernel.h> @@ -37,9 +40,9 @@ * thus emulate an an LRU-like behavior when deleting elements to free up space * in the page. * - * When an element reaches it's max count of count_threshold, we try to poison - * it by assuming that errors triggered count_threshold times in a single page - * are excessive and that page shouldn't be used anymore. count_threshold is + * When an element reaches it's max count of action_threshold, we try to poison + * it by assuming that errors triggered action_threshold times in a single page + * are excessive and that page shouldn't be used anymore. action_threshold is * initialized to COUNT_MASK which is the maximum. * * That error event entry causes cec_add_elem() to return !0 value and thus @@ -122,7 +125,7 @@ static DEFINE_MUTEX(ce_mutex); static u64 dfs_pfn; /* Amount of errors after which we offline */ -static unsigned int count_threshold = COUNT_MASK; +static u64 action_threshold = COUNT_MASK; /* Each element "decays" each decay_interval which is 24hrs by default. */ #define CEC_DECAY_DEFAULT_INTERVAL 24 * 60 * 60 /* 24 hrs */ @@ -276,11 +279,39 @@ static u64 __maybe_unused del_lru_elem(void) return pfn; } +static bool sanity_check(struct ce_array *ca) +{ + bool ret = false; + u64 prev = 0; + int i; + + for (i = 0; i < ca->n; i++) { + u64 this = PFN(ca->array[i]); + + if (WARN(prev > this, "prev: 0x%016llx <-> this: 0x%016llx\n", prev, this)) + ret = true; + + prev = this; + } + + if (!ret) + return ret; + + pr_info("Sanity check dump:\n{ n: %d\n", ca->n); + for (i = 0; i < ca->n; i++) { + u64 this = PFN(ca->array[i]); + + pr_info(" %03d: [%016llx|%03llx]\n", i, this, FULL_COUNT(ca->array[i])); + } + pr_info("}\n"); + + return ret; +} int cec_add_elem(u64 pfn) { struct ce_array *ca = &ce_arr; - unsigned int to; + unsigned int to = 0; int count, ret = 0; /* @@ -294,6 +325,7 @@ int cec_add_elem(u64 pfn) ca->ces_entered++; + /* Array full, free the LRU slot. */ if (ca->n == MAX_ELEMS) WARN_ON(!del_lru_elem_unlocked(ca)); @@ -306,24 +338,17 @@ int cec_add_elem(u64 pfn) (void *)&ca->array[to], (ca->n - to) * sizeof(u64)); - ca->array[to] = (pfn << PAGE_SHIFT) | - (DECAY_MASK << COUNT_BITS) | 1; - + ca->array[to] = pfn << PAGE_SHIFT; ca->n++; - - ret = 0; - - goto decay; } - count = COUNT(ca->array[to]); - - if (count < count_threshold) { - ca->array[to] |= (DECAY_MASK << COUNT_BITS); - ca->array[to]++; + /* Add/refresh element generation and increment count */ + ca->array[to] |= DECAY_MASK << COUNT_BITS; + ca->array[to]++; - ret = 0; - } else { + /* Check action threshold and soft-offline, if reached. */ + count = COUNT(ca->array[to]); + if (count >= action_threshold) { u64 pfn = ca->array[to] >> PAGE_SHIFT; if (!pfn_valid(pfn)) { @@ -338,20 +363,21 @@ int cec_add_elem(u64 pfn) del_elem(ca, to); /* - * Return a >0 value to denote that we've reached the offlining - * threshold. + * Return a >0 value to callers, to denote that we've reached + * the offlining threshold. */ ret = 1; goto unlock; } -decay: ca->decay_count++; if (ca->decay_count >= CLEAN_ELEMS) do_spring_cleaning(ca); + WARN_ON_ONCE(sanity_check(ca)); + unlock: mutex_unlock(&ce_mutex); @@ -369,45 +395,48 @@ static int pfn_set(void *data, u64 val) { *(u64 *)data = val; - return cec_add_elem(val); + cec_add_elem(val); + + return 0; } DEFINE_DEBUGFS_ATTRIBUTE(pfn_ops, u64_get, pfn_set, "0x%llx\n"); static int decay_interval_set(void *data, u64 val) { - *(u64 *)data = val; - if (val < CEC_DECAY_MIN_INTERVAL) return -EINVAL; if (val > CEC_DECAY_MAX_INTERVAL) return -EINVAL; + *(u64 *)data = val; decay_interval = val; cec_mod_work(decay_interval); + return 0; } DEFINE_DEBUGFS_ATTRIBUTE(decay_interval_ops, u64_get, decay_interval_set, "%lld\n"); -static int count_threshold_set(void *data, u64 val) +static int action_threshold_set(void *data, u64 val) { *(u64 *)data = val; if (val > COUNT_MASK) val = COUNT_MASK; - count_threshold = val; + action_threshold = val; return 0; } -DEFINE_DEBUGFS_ATTRIBUTE(count_threshold_ops, u64_get, count_threshold_set, "%lld\n"); +DEFINE_DEBUGFS_ATTRIBUTE(action_threshold_ops, u64_get, action_threshold_set, "%lld\n"); + +static const char * const bins[] = { "00", "01", "10", "11" }; static int array_dump(struct seq_file *m, void *v) { struct ce_array *ca = &ce_arr; - u64 prev = 0; int i; mutex_lock(&ce_mutex); @@ -416,11 +445,8 @@ static int array_dump(struct seq_file *m, void *v) for (i = 0; i < ca->n; i++) { u64 this = PFN(ca->array[i]); - seq_printf(m, " %03d: [%016llx|%03llx]\n", i, this, FULL_COUNT(ca->array[i])); - - WARN_ON(prev > this); - - prev = this; + seq_printf(m, " %3d: [%016llx|%s|%03llx]\n", + i, this, bins[DECAY(ca->array[i])], COUNT(ca->array[i])); } seq_printf(m, "}\n"); @@ -433,7 +459,7 @@ static int array_dump(struct seq_file *m, void *v) seq_printf(m, "Decay interval: %lld seconds\n", decay_interval); seq_printf(m, "Decays: %lld\n", ca->decays_done); - seq_printf(m, "Action threshold: %d\n", count_threshold); + seq_printf(m, "Action threshold: %lld\n", action_threshold); mutex_unlock(&ce_mutex); @@ -463,18 +489,6 @@ static int __init create_debugfs_nodes(void) return -1; } - pfn = debugfs_create_file("pfn", S_IRUSR | S_IWUSR, d, &dfs_pfn, &pfn_ops); - if (!pfn) { - pr_warn("Error creating pfn debugfs node!\n"); - goto err; - } - - array = debugfs_create_file("array", S_IRUSR, d, NULL, &array_ops); - if (!array) { - pr_warn("Error creating array debugfs node!\n"); - goto err; - } - decay = debugfs_create_file("decay_interval", S_IRUSR | S_IWUSR, d, &decay_interval, &decay_interval_ops); if (!decay) { @@ -482,13 +496,27 @@ static int __init create_debugfs_nodes(void) goto err; } - count = debugfs_create_file("count_threshold", S_IRUSR | S_IWUSR, d, - &count_threshold, &count_threshold_ops); + count = debugfs_create_file("action_threshold", S_IRUSR | S_IWUSR, d, + &action_threshold, &action_threshold_ops); if (!count) { - pr_warn("Error creating count_threshold debugfs node!\n"); + pr_warn("Error creating action_threshold debugfs node!\n"); + goto err; + } + + if (!IS_ENABLED(CONFIG_RAS_CEC_DEBUG)) + return 0; + + pfn = debugfs_create_file("pfn", S_IRUSR | S_IWUSR, d, &dfs_pfn, &pfn_ops); + if (!pfn) { + pr_warn("Error creating pfn debugfs node!\n"); goto err; } + array = debugfs_create_file("array", S_IRUSR, d, NULL, &array_ops); + if (!array) { + pr_warn("Error creating array debugfs node!\n"); + goto err; + } return 0; @@ -509,8 +537,10 @@ void __init cec_init(void) return; } - if (create_debugfs_nodes()) + if (create_debugfs_nodes()) { + free_page((unsigned long)ce_arr.array); return; + } INIT_DELAYED_WORK(&cec_work, cec_work_fn); schedule_delayed_work(&cec_work, CEC_DECAY_DEFAULT_INTERVAL); diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800-regulator.c index 9fd379732d18..69ae25886181 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800-regulator.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Regulators driver for Marvell 88PM800 * * Copyright (C) 2012 Marvell International Ltd. * Joseph(Yossi) Hanin <yhanin@marvell.com> * Yi Zhang <yizhang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/moduleparam.h> diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 35d767aeeb57..1d1c4a7ec3e2 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Regulators driver for Marvell 88PM8607 * * Copyright (C) 2009 Marvell International Ltd. * Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/init.h> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 8553bdf87c1d..7928960563e6 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -136,19 +136,20 @@ config REGULATOR_AB8500 signal AB8500 PMIC config REGULATOR_ARIZONA_LDO1 - tristate "Wolfson Arizona class devices LDO1" - depends on MFD_ARIZONA + tristate "Cirrus Madera and Wolfson Arizona class devices LDO1" + depends on MFD_ARIZONA || MFD_MADERA depends on SND_SOC help - Support for the LDO1 regulators found on Wolfson Arizona class - devices. + Support for the LDO1 regulators found on Cirrus Logic Madera codecs + and Wolfson Microelectronic Arizona codecs. config REGULATOR_ARIZONA_MICSUPP - tristate "Wolfson Arizona class devices MICSUPP" - depends on MFD_ARIZONA + tristate "Cirrus Madera and Wolfson Arizona class devices MICSUPP" + depends on MFD_ARIZONA || MFD_MADERA depends on SND_SOC help - Support for the MICSUPP regulators found on Wolfson Arizona class + Support for the MICSUPP regulators found on Cirrus Logic Madera codecs + and Wolfson Microelectronic Arizona codecs devices. config REGULATOR_AS3711 @@ -258,7 +259,7 @@ config REGULATOR_DA9062 config REGULATOR_DA9063 tristate "Dialog Semiconductor DA9063 regulators" - depends on MFD_DA9063 + depends on MFD_DA9063 && OF help Say y here to support the BUCKs and LDOs regulators found on DA9063 PMICs. @@ -364,7 +365,7 @@ config REGULATOR_LM363X tristate "TI LM363X voltage regulators" depends on MFD_TI_LMU help - This driver supports LM3631 and LM3632 voltage regulators for + This driver supports LM3631, LM3632 and LM36274 voltage regulators for the LCD bias. One boost output voltage is configurable and always on. Other LDOs are used for the display module. @@ -829,6 +830,26 @@ config REGULATOR_SKY81452 This driver can also be built as a module. If so, the module will be called sky81452-regulator. +config REGULATOR_SLG51000 + tristate "Dialog Semiconductor SLG51000 regulators" + depends on I2C + select REGMAP_I2C + help + Say y here to support for the Dialog Semiconductor SLG51000. + The SLG51000 is seven compact and customizable low dropout + regulators. + +config REGULATOR_STM32_BOOSTER + tristate "STMicroelectronics STM32 BOOSTER" + depends on ARCH_STM32 || COMPILE_TEST + help + This driver supports internal booster (3V3) embedded in some + STMicroelectronics STM32 chips. It can be used to supply ADC analog + input switches when vdda supply is below 2.7V. + + This driver can also be built as a module. If so, the module + will be called stm32-booster. + config REGULATOR_STM32_VREFBUF tristate "STMicroelectronics STM32 VREFBUF" depends on ARCH_STM32 || COMPILE_TEST diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 93f53840e8f1..eef73b5a35a4 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -11,7 +11,7 @@ obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o obj-$(CONFIG_REGULATOR_88PG86X) += 88pg86x.o -obj-$(CONFIG_REGULATOR_88PM800) += 88pm800.o +obj-$(CONFIG_REGULATOR_88PM800) += 88pm800-regulator.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o obj-$(CONFIG_REGULATOR_CPCAP) += cpcap-regulator.o obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o @@ -104,6 +104,8 @@ obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o +obj-$(CONFIG_REGULATOR_SLG51000) += slg51000-regulator.o +obj-$(CONFIG_REGULATOR_STM32_BOOSTER) += stm32-booster.o obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index e4bc7b1e5ccd..1a3d7b720f5e 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -25,6 +25,10 @@ #include <linux/mfd/arizona/pdata.h> #include <linux/mfd/arizona/registers.h> +#include <linux/mfd/madera/core.h> +#include <linux/mfd/madera/pdata.h> +#include <linux/mfd/madera/registers.h> + struct arizona_ldo1 { struct regulator_dev *regulator; struct regmap *regmap; @@ -158,6 +162,31 @@ static const struct regulator_init_data arizona_ldo1_wm5110 = { .num_consumer_supplies = 1, }; +static const struct regulator_desc madera_ldo1 = { + .name = "LDO1", + .supply_name = "LDOVDD", + .type = REGULATOR_VOLTAGE, + .ops = &arizona_ldo1_ops, + + .vsel_reg = MADERA_LDO1_CONTROL_1, + .vsel_mask = MADERA_LDO1_VSEL_MASK, + .min_uV = 900000, + .uV_step = 25000, + .n_voltages = 13, + .enable_time = 3000, + + .owner = THIS_MODULE, +}; + +static const struct regulator_init_data madera_ldo1_default = { + .constraints = { + .min_uV = 1200000, + .max_uV = 1200000, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, +}; + static int arizona_ldo1_of_get_pdata(struct arizona_ldo1_pdata *pdata, struct regulator_config *config, const struct regulator_desc *desc, @@ -320,6 +349,32 @@ static int arizona_ldo1_remove(struct platform_device *pdev) return 0; } +static int madera_ldo1_probe(struct platform_device *pdev) +{ + struct madera *madera = dev_get_drvdata(pdev->dev.parent); + struct arizona_ldo1 *ldo1; + bool external_dcvdd; + int ret; + + ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL); + if (!ldo1) + return -ENOMEM; + + ldo1->regmap = madera->regmap; + + ldo1->init_data = madera_ldo1_default; + + ret = arizona_ldo1_common_init(pdev, ldo1, &madera_ldo1, + &madera->pdata.ldo1, + &external_dcvdd); + if (ret) + return ret; + + madera->internal_dcvdd = !external_dcvdd; + + return 0; +} + static struct platform_driver arizona_ldo1_driver = { .probe = arizona_ldo1_probe, .remove = arizona_ldo1_remove, @@ -328,10 +383,36 @@ static struct platform_driver arizona_ldo1_driver = { }, }; -module_platform_driver(arizona_ldo1_driver); +static struct platform_driver madera_ldo1_driver = { + .probe = madera_ldo1_probe, + .remove = arizona_ldo1_remove, + .driver = { + .name = "madera-ldo1", + }, +}; + +static struct platform_driver * const madera_ldo1_drivers[] = { + &arizona_ldo1_driver, + &madera_ldo1_driver, +}; + +static int __init arizona_ldo1_init(void) +{ + return platform_register_drivers(madera_ldo1_drivers, + ARRAY_SIZE(madera_ldo1_drivers)); +} +module_init(arizona_ldo1_init); + +static void __exit madera_ldo1_exit(void) +{ + platform_unregister_drivers(madera_ldo1_drivers, + ARRAY_SIZE(madera_ldo1_drivers)); +} +module_exit(madera_ldo1_exit); /* Module information */ MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_DESCRIPTION("Arizona LDO1 driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:arizona-ldo1"); +MODULE_ALIAS("platform:madera-ldo1"); diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index be0d46da51a1..ae1a5de3e57d 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -16,7 +16,6 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> -#include <linux/gpio.h> #include <linux/slab.h> #include <linux/workqueue.h> #include <sound/soc.h> @@ -25,6 +24,10 @@ #include <linux/mfd/arizona/pdata.h> #include <linux/mfd/arizona/registers.h> +#include <linux/mfd/madera/core.h> +#include <linux/mfd/madera/pdata.h> +#include <linux/mfd/madera/registers.h> + #include <linux/regulator/arizona-micsupp.h> struct arizona_micsupp { @@ -200,6 +203,28 @@ static const struct regulator_init_data arizona_micsupp_ext_default = { .num_consumer_supplies = 1, }; +static const struct regulator_desc madera_micsupp = { + .name = "MICVDD", + .supply_name = "CPVDD1", + .type = REGULATOR_VOLTAGE, + .n_voltages = 40, + .ops = &arizona_micsupp_ops, + + .vsel_reg = MADERA_LDO2_CONTROL_1, + .vsel_mask = MADERA_LDO2_VSEL_MASK, + .enable_reg = MADERA_MIC_CHARGE_PUMP_1, + .enable_mask = MADERA_CPMIC_ENA, + .bypass_reg = MADERA_MIC_CHARGE_PUMP_1, + .bypass_mask = MADERA_CPMIC_BYPASS, + + .linear_ranges = arizona_micsupp_ext_ranges, + .n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ext_ranges), + + .enable_time = 3000, + + .owner = THIS_MODULE, +}; + static int arizona_micsupp_of_get_pdata(struct arizona_micsupp_pdata *pdata, struct regulator_config *config, const struct regulator_desc *desc) @@ -316,6 +341,24 @@ static int arizona_micsupp_probe(struct platform_device *pdev) &arizona->pdata.micvdd); } +static int madera_micsupp_probe(struct platform_device *pdev) +{ + struct madera *madera = dev_get_drvdata(pdev->dev.parent); + struct arizona_micsupp *micsupp; + + micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL); + if (!micsupp) + return -ENOMEM; + + micsupp->regmap = madera->regmap; + micsupp->dapm = &madera->dapm; + micsupp->dev = madera->dev; + micsupp->init_data = arizona_micsupp_ext_default; + + return arizona_micsupp_common_init(pdev, micsupp, &madera_micsupp, + &madera->pdata.micvdd); +} + static struct platform_driver arizona_micsupp_driver = { .probe = arizona_micsupp_probe, .driver = { @@ -323,10 +366,35 @@ static struct platform_driver arizona_micsupp_driver = { }, }; -module_platform_driver(arizona_micsupp_driver); +static struct platform_driver madera_micsupp_driver = { + .probe = madera_micsupp_probe, + .driver = { + .name = "madera-micsupp", + }, +}; + +static struct platform_driver * const arizona_micsupp_drivers[] = { + &arizona_micsupp_driver, + &madera_micsupp_driver, +}; + +static int __init arizona_micsupp_init(void) +{ + return platform_register_drivers(arizona_micsupp_drivers, + ARRAY_SIZE(arizona_micsupp_drivers)); +} +module_init(arizona_micsupp_init); + +static void __exit arizona_micsupp_exit(void) +{ + platform_unregister_drivers(arizona_micsupp_drivers, + ARRAY_SIZE(arizona_micsupp_drivers)); +} +module_exit(arizona_micsupp_exit); /* Module information */ MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_DESCRIPTION("Arizona microphone supply driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:arizona-micsupp"); +MODULE_ALIAS("platform:madera-micsupp"); diff --git a/drivers/regulator/bd70528-regulator.c b/drivers/regulator/bd70528-regulator.c index 30e3ed430a8a..0248a61f1006 100644 --- a/drivers/regulator/bd70528-regulator.c +++ b/drivers/regulator/bd70528-regulator.c @@ -4,7 +4,6 @@ #include <linux/delay.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/mfd/rohm-bd70528.h> diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c index fde4264da6ff..8c22cfb76173 100644 --- a/drivers/regulator/bd718x7-regulator.c +++ b/drivers/regulator/bd718x7-regulator.c @@ -4,7 +4,6 @@ #include <linux/delay.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/mfd/rohm-bd718x7.h> diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index c894cf0d8a28..86ae1825cec1 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1,12 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* - * core.c -- Voltage/Current Regulator framework. - * - * Copyright 2007, 2008 Wolfson Microelectronics PLC. - * Copyright 2008 SlimLogic Ltd. - * - * Author: Liam Girdwood <lrg@slimlogic.co.uk> - */ +// +// core.c -- Voltage/Current Regulator framework. +// +// Copyright 2007, 2008 Wolfson Microelectronics PLC. +// Copyright 2008 SlimLogic Ltd. +// +// Author: Liam Girdwood <lrg@slimlogic.co.uk> #include <linux/kernel.h> #include <linux/init.h> @@ -23,6 +22,7 @@ #include <linux/regmap.h> #include <linux/regulator/of_regulator.h> #include <linux/regulator/consumer.h> +#include <linux/regulator/coupler.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/module.h> @@ -50,6 +50,7 @@ static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_map_list); static LIST_HEAD(regulator_ena_gpio_list); static LIST_HEAD(regulator_supply_alias_list); +static LIST_HEAD(regulator_coupler_list); static bool has_full_constraints; static struct dentry *debugfs_root; @@ -93,7 +94,6 @@ struct regulator_supply_alias { static int _regulator_is_enabled(struct regulator_dev *rdev); static int _regulator_disable(struct regulator *regulator); -static int _regulator_get_voltage(struct regulator_dev *rdev); static int _regulator_get_current_limit(struct regulator_dev *rdev); static unsigned int _regulator_get_mode(struct regulator_dev *rdev); static int _notifier_call_chain(struct regulator_dev *rdev, @@ -102,15 +102,12 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV); static int regulator_balance_voltage(struct regulator_dev *rdev, suspend_state_t state); -static int regulator_set_voltage_rdev(struct regulator_dev *rdev, - int min_uV, int max_uV, - suspend_state_t state); static struct regulator *create_regulator(struct regulator_dev *rdev, struct device *dev, const char *supply_name); static void _regulator_put(struct regulator *regulator); -static const char *rdev_get_name(struct regulator_dev *rdev) +const char *rdev_get_name(struct regulator_dev *rdev) { if (rdev->constraints && rdev->constraints->name) return rdev->constraints->name; @@ -424,8 +421,8 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp } /* Platform voltage constraint check */ -static int regulator_check_voltage(struct regulator_dev *rdev, - int *min_uV, int *max_uV) +int regulator_check_voltage(struct regulator_dev *rdev, + int *min_uV, int *max_uV) { BUG_ON(*min_uV > *max_uV); @@ -457,9 +454,9 @@ static int regulator_check_states(suspend_state_t state) /* Make sure we select a voltage that suits the needs of all * regulator consumers */ -static int regulator_check_consumers(struct regulator_dev *rdev, - int *min_uV, int *max_uV, - suspend_state_t state) +int regulator_check_consumers(struct regulator_dev *rdev, + int *min_uV, int *max_uV, + suspend_state_t state) { struct regulator *regulator; struct regulator_voltage *voltage; @@ -570,7 +567,7 @@ static ssize_t regulator_uV_show(struct device *dev, ssize_t ret; regulator_lock(rdev); - ret = sprintf(buf, "%d\n", _regulator_get_voltage(rdev)); + ret = sprintf(buf, "%d\n", regulator_get_voltage_rdev(rdev)); regulator_unlock(rdev); return ret; @@ -941,7 +938,7 @@ static int drms_uA_update(struct regulator_dev *rdev) rdev_err(rdev, "failed to set load %d\n", current_uA); } else { /* get output voltage */ - output_uV = _regulator_get_voltage(rdev); + output_uV = regulator_get_voltage_rdev(rdev); if (output_uV <= 0) { rdev_err(rdev, "invalid output voltage found\n"); return -EINVAL; @@ -1054,7 +1051,7 @@ static void print_constraints(struct regulator_dev *rdev) if (!constraints->min_uV || constraints->min_uV != constraints->max_uV) { - ret = _regulator_get_voltage(rdev); + ret = regulator_get_voltage_rdev(rdev); if (ret > 0) count += scnprintf(buf + count, len - count, "at %d mV ", ret / 1000); @@ -1113,7 +1110,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, if (rdev->constraints->apply_uV && rdev->constraints->min_uV && rdev->constraints->max_uV) { int target_min, target_max; - int current_uV = _regulator_get_voltage(rdev); + int current_uV = regulator_get_voltage_rdev(rdev); if (current_uV == -ENOTRECOVERABLE) { /* This regulator can't be read and must be initialized */ @@ -1123,7 +1120,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, _regulator_do_set_voltage(rdev, rdev->constraints->min_uV, rdev->constraints->max_uV); - current_uV = _regulator_get_voltage(rdev); + current_uV = regulator_get_voltage_rdev(rdev); } if (current_uV < 0) { @@ -1645,9 +1642,9 @@ static int _regulator_get_enable_time(struct regulator_dev *rdev) { if (rdev->constraints && rdev->constraints->enable_time) return rdev->constraints->enable_time; - if (!rdev->desc->ops->enable_time) - return rdev->desc->enable_time; - return rdev->desc->ops->enable_time(rdev); + if (rdev->desc->ops->enable_time) + return rdev->desc->ops->enable_time(rdev); + return rdev->desc->enable_time; } static struct regulator_supply_alias *regulator_find_supply_alias( @@ -3065,7 +3062,7 @@ static int _regulator_call_set_voltage(struct regulator_dev *rdev, struct pre_voltage_change_data data; int ret; - data.old_uV = _regulator_get_voltage(rdev); + data.old_uV = regulator_get_voltage_rdev(rdev); data.min_uV = min_uV; data.max_uV = max_uV; ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE, @@ -3089,7 +3086,7 @@ static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev, struct pre_voltage_change_data data; int ret; - data.old_uV = _regulator_get_voltage(rdev); + data.old_uV = regulator_get_voltage_rdev(rdev); data.min_uV = uV; data.max_uV = uV; ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE, @@ -3107,6 +3104,66 @@ static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev, return ret; } +static int _regulator_set_voltage_sel_step(struct regulator_dev *rdev, + int uV, int new_selector) +{ + const struct regulator_ops *ops = rdev->desc->ops; + int diff, old_sel, curr_sel, ret; + + /* Stepping is only needed if the regulator is enabled. */ + if (!_regulator_is_enabled(rdev)) + goto final_set; + + if (!ops->get_voltage_sel) + return -EINVAL; + + old_sel = ops->get_voltage_sel(rdev); + if (old_sel < 0) + return old_sel; + + diff = new_selector - old_sel; + if (diff == 0) + return 0; /* No change needed. */ + + if (diff > 0) { + /* Stepping up. */ + for (curr_sel = old_sel + rdev->desc->vsel_step; + curr_sel < new_selector; + curr_sel += rdev->desc->vsel_step) { + /* + * Call the callback directly instead of using + * _regulator_call_set_voltage_sel() as we don't + * want to notify anyone yet. Same in the branch + * below. + */ + ret = ops->set_voltage_sel(rdev, curr_sel); + if (ret) + goto try_revert; + } + } else { + /* Stepping down. */ + for (curr_sel = old_sel - rdev->desc->vsel_step; + curr_sel > new_selector; + curr_sel -= rdev->desc->vsel_step) { + ret = ops->set_voltage_sel(rdev, curr_sel); + if (ret) + goto try_revert; + } + } + +final_set: + /* The final selector will trigger the notifiers. */ + return _regulator_call_set_voltage_sel(rdev, uV, new_selector); + +try_revert: + /* + * At least try to return to the previous voltage if setting a new + * one failed. + */ + (void)ops->set_voltage_sel(rdev, old_sel); + return ret; +} + static int _regulator_set_voltage_time(struct regulator_dev *rdev, int old_uV, int new_uV) { @@ -3142,7 +3199,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, unsigned int selector; int old_selector = -1; const struct regulator_ops *ops = rdev->desc->ops; - int old_uV = _regulator_get_voltage(rdev); + int old_uV = regulator_get_voltage_rdev(rdev); trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); @@ -3169,7 +3226,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, best_val = ops->list_voltage(rdev, selector); else - best_val = _regulator_get_voltage(rdev); + best_val = regulator_get_voltage_rdev(rdev); } } else if (ops->set_voltage_sel) { @@ -3180,6 +3237,9 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, selector = ret; if (old_selector == selector) ret = 0; + else if (rdev->desc->vsel_step) + ret = _regulator_set_voltage_sel_step( + rdev, best_val, selector); else ret = _regulator_call_set_voltage_sel( rdev, best_val, selector); @@ -3288,7 +3348,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, * changing the voltage. */ if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { - current_uV = _regulator_get_voltage(rdev); + current_uV = regulator_get_voltage_rdev(rdev); if (min_uV <= current_uV && current_uV <= max_uV) { voltage->min_uV = min_uV; voltage->max_uV = max_uV; @@ -3325,8 +3385,8 @@ out: return ret; } -static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, - int max_uV, suspend_state_t state) +int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, + int max_uV, suspend_state_t state) { int best_supply_uV = 0; int supply_change_uV = 0; @@ -3354,7 +3414,7 @@ static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, best_supply_uV += rdev->desc->min_dropout_uV; - current_supply_uV = _regulator_get_voltage(rdev->supply->rdev); + current_supply_uV = regulator_get_voltage_rdev(rdev->supply->rdev); if (current_supply_uV < 0) { ret = current_supply_uV; goto out; @@ -3405,7 +3465,7 @@ static int regulator_limit_voltage_step(struct regulator_dev *rdev, return 1; if (*current_uV < 0) { - *current_uV = _regulator_get_voltage(rdev); + *current_uV = regulator_get_voltage_rdev(rdev); if (*current_uV < 0) return *current_uV; @@ -3434,11 +3494,10 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev, struct coupling_desc *c_desc = &rdev->coupling_desc; struct regulator_dev **c_rdevs = c_desc->coupled_rdevs; struct regulation_constraints *constraints = rdev->constraints; - int max_spread = constraints->max_spread; int desired_min_uV = 0, desired_max_uV = INT_MAX; int max_current_uV = 0, min_current_uV = INT_MAX; int highest_min_uV = 0, target_uV, possible_uV; - int i, ret; + int i, ret, max_spread; bool done; *current_uV = -1; @@ -3492,6 +3551,8 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev, } } + max_spread = constraints->max_spread[0]; + /* * Let target_uV be equal to the desired one if possible. * If not, set it to minimum voltage, allowed by other coupled @@ -3509,7 +3570,7 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev, if (!_regulator_is_enabled(c_rdevs[i])) continue; - tmp_act = _regulator_get_voltage(c_rdevs[i]); + tmp_act = regulator_get_voltage_rdev(c_rdevs[i]); if (tmp_act < 0) return tmp_act; @@ -3551,7 +3612,7 @@ finish: if (n_coupled > 1 && *current_uV == -1) { if (_regulator_is_enabled(rdev)) { - ret = _regulator_get_voltage(rdev); + ret = regulator_get_voltage_rdev(rdev); if (ret < 0) return ret; @@ -3573,9 +3634,11 @@ static int regulator_balance_voltage(struct regulator_dev *rdev, struct regulator_dev **c_rdevs; struct regulator_dev *best_rdev; struct coupling_desc *c_desc = &rdev->coupling_desc; + struct regulator_coupler *coupler = c_desc->coupler; int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev; - bool best_c_rdev_done, c_rdev_done[MAX_COUPLED]; unsigned int delta, best_delta; + unsigned long c_rdev_done = 0; + bool best_c_rdev_done; c_rdevs = c_desc->coupled_rdevs; n_coupled = c_desc->n_coupled; @@ -3592,8 +3655,9 @@ static int regulator_balance_voltage(struct regulator_dev *rdev, return -EPERM; } - for (i = 0; i < n_coupled; i++) - c_rdev_done[i] = false; + /* Invoke custom balancer for customized couplers */ + if (coupler && coupler->balance_voltage) + return coupler->balance_voltage(coupler, rdev, state); /* * Find the best possible voltage change on each loop. Leave the loop @@ -3620,7 +3684,7 @@ static int regulator_balance_voltage(struct regulator_dev *rdev, */ int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0; - if (c_rdev_done[i]) + if (test_bit(i, &c_rdev_done)) continue; ret = regulator_get_optimal_voltage(c_rdevs[i], @@ -3655,7 +3719,8 @@ static int regulator_balance_voltage(struct regulator_dev *rdev, if (ret < 0) goto out; - c_rdev_done[best_c_rdev] = best_c_rdev_done; + if (best_c_rdev_done) + set_bit(best_c_rdev, &c_rdev_done); } while (n_coupled > 1); @@ -3911,7 +3976,7 @@ out: } EXPORT_SYMBOL_GPL(regulator_sync_voltage); -static int _regulator_get_voltage(struct regulator_dev *rdev) +int regulator_get_voltage_rdev(struct regulator_dev *rdev) { int sel, ret; bool bypassed; @@ -3928,7 +3993,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev) return -EPROBE_DEFER; } - return _regulator_get_voltage(rdev->supply->rdev); + return regulator_get_voltage_rdev(rdev->supply->rdev); } } @@ -3944,7 +4009,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev) } else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) { ret = rdev->desc->fixed_uV; } else if (rdev->supply) { - ret = _regulator_get_voltage(rdev->supply->rdev); + ret = regulator_get_voltage_rdev(rdev->supply->rdev); } else { return -EINVAL; } @@ -3969,7 +4034,7 @@ int regulator_get_voltage(struct regulator *regulator) int ret; regulator_lock_dependent(regulator->rdev, &ww_ctx); - ret = _regulator_get_voltage(regulator->rdev); + ret = regulator_get_voltage_rdev(regulator->rdev); regulator_unlock_dependent(regulator->rdev, &ww_ctx); return ret; @@ -4707,8 +4772,60 @@ static int regulator_register_resolve_supply(struct device *dev, void *data) return 0; } +int regulator_coupler_register(struct regulator_coupler *coupler) +{ + mutex_lock(®ulator_list_mutex); + list_add_tail(&coupler->list, ®ulator_coupler_list); + mutex_unlock(®ulator_list_mutex); + + return 0; +} + +static struct regulator_coupler * +regulator_find_coupler(struct regulator_dev *rdev) +{ + struct regulator_coupler *coupler; + int err; + + /* + * Note that regulators are appended to the list and the generic + * coupler is registered first, hence it will be attached at last + * if nobody cared. + */ + list_for_each_entry_reverse(coupler, ®ulator_coupler_list, list) { + err = coupler->attach_regulator(coupler, rdev); + if (!err) { + if (!coupler->balance_voltage && + rdev->coupling_desc.n_coupled > 2) + goto err_unsupported; + + return coupler; + } + + if (err < 0) + return ERR_PTR(err); + + if (err == 1) + continue; + + break; + } + + return ERR_PTR(-EINVAL); + +err_unsupported: + if (coupler->detach_regulator) + coupler->detach_regulator(coupler, rdev); + + rdev_err(rdev, + "Voltage balancing for multiple regulator couples is unimplemented\n"); + + return ERR_PTR(-EPERM); +} + static void regulator_resolve_coupling(struct regulator_dev *rdev) { + struct regulator_coupler *coupler = rdev->coupling_desc.coupler; struct coupling_desc *c_desc = &rdev->coupling_desc; int n_coupled = c_desc->n_coupled; struct regulator_dev *c_rdev; @@ -4724,6 +4841,12 @@ static void regulator_resolve_coupling(struct regulator_dev *rdev) if (!c_rdev) continue; + if (c_rdev->coupling_desc.coupler != coupler) { + rdev_err(rdev, "coupler mismatch with %s\n", + rdev_get_name(c_rdev)); + return; + } + regulator_lock(c_rdev); c_desc->coupled_rdevs[i] = c_rdev; @@ -4737,10 +4860,12 @@ static void regulator_resolve_coupling(struct regulator_dev *rdev) static void regulator_remove_coupling(struct regulator_dev *rdev) { + struct regulator_coupler *coupler = rdev->coupling_desc.coupler; struct coupling_desc *__c_desc, *c_desc = &rdev->coupling_desc; struct regulator_dev *__c_rdev, *c_rdev; unsigned int __n_coupled, n_coupled; int i, k; + int err; n_coupled = c_desc->n_coupled; @@ -4770,21 +4895,33 @@ static void regulator_remove_coupling(struct regulator_dev *rdev) c_desc->coupled_rdevs[i] = NULL; c_desc->n_resolved--; } + + if (coupler && coupler->detach_regulator) { + err = coupler->detach_regulator(coupler, rdev); + if (err) + rdev_err(rdev, "failed to detach from coupler: %d\n", + err); + } + + kfree(rdev->coupling_desc.coupled_rdevs); + rdev->coupling_desc.coupled_rdevs = NULL; } static int regulator_init_coupling(struct regulator_dev *rdev) { - int n_phandles; + int err, n_phandles; + size_t alloc_size; if (!IS_ENABLED(CONFIG_OF)) n_phandles = 0; else n_phandles = of_get_n_coupled(rdev); - if (n_phandles + 1 > MAX_COUPLED) { - rdev_err(rdev, "too many regulators coupled\n"); - return -EPERM; - } + alloc_size = sizeof(*rdev) * (n_phandles + 1); + + rdev->coupling_desc.coupled_rdevs = kzalloc(alloc_size, GFP_KERNEL); + if (!rdev->coupling_desc.coupled_rdevs) + return -ENOMEM; /* * Every regulator should always have coupling descriptor filled with @@ -4798,23 +4935,35 @@ static int regulator_init_coupling(struct regulator_dev *rdev) if (n_phandles == 0) return 0; - /* regulator, which can't change its voltage, can't be coupled */ - if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { - rdev_err(rdev, "voltage operation not allowed\n"); + if (!of_check_coupling_data(rdev)) return -EPERM; - } - if (rdev->constraints->max_spread <= 0) { - rdev_err(rdev, "wrong max_spread value\n"); - return -EPERM; + rdev->coupling_desc.coupler = regulator_find_coupler(rdev); + if (IS_ERR(rdev->coupling_desc.coupler)) { + err = PTR_ERR(rdev->coupling_desc.coupler); + rdev_err(rdev, "failed to get coupler: %d\n", err); + return err; } - if (!of_check_coupling_data(rdev)) + return 0; +} + +static int generic_coupler_attach(struct regulator_coupler *coupler, + struct regulator_dev *rdev) +{ + if (rdev->coupling_desc.n_coupled > 2) { + rdev_err(rdev, + "Voltage balancing for multiple regulator couples is unimplemented\n"); return -EPERM; + } return 0; } +static struct regulator_coupler generic_regulator_coupler = { + .attach_regulator = generic_coupler_attach, +}; + /** * regulator_register - register regulator * @regulator_desc: regulator to register @@ -4976,7 +5125,9 @@ regulator_register(const struct regulator_desc *regulator_desc, if (ret < 0) goto wash; + mutex_lock(®ulator_list_mutex); ret = regulator_init_coupling(rdev); + mutex_unlock(®ulator_list_mutex); if (ret < 0) goto wash; @@ -5025,6 +5176,7 @@ regulator_register(const struct regulator_desc *regulator_desc, unset_supplies: mutex_lock(®ulator_list_mutex); unset_regulator_supplies(rdev); + regulator_remove_coupling(rdev); mutex_unlock(®ulator_list_mutex); wash: kfree(rdev->constraints); @@ -5278,7 +5430,7 @@ static void regulator_summary_show_subtree(struct seq_file *s, rdev->use_count, rdev->open_count, rdev->bypass_count, regulator_opmode_to_str(opmode)); - seq_printf(s, "%5dmV ", _regulator_get_voltage(rdev) / 1000); + seq_printf(s, "%5dmV ", regulator_get_voltage_rdev(rdev) / 1000); seq_printf(s, "%5dmA ", _regulator_get_current_limit_unlocked(rdev) / 1000); @@ -5480,6 +5632,8 @@ static int __init regulator_init(void) #endif regulator_dummy_init(); + regulator_coupler_register(&generic_regulator_coupler); + return ret; } diff --git a/drivers/regulator/cpcap-regulator.c b/drivers/regulator/cpcap-regulator.c index d3284361e594..f80781d58a28 100644 --- a/drivers/regulator/cpcap-regulator.c +++ b/drivers/regulator/cpcap-regulator.c @@ -90,7 +90,7 @@ #define CPCAP_REG_OFF_MODE_SEC BIT(15) /** - * SoC specific configuraion for CPCAP regulator. There are at least three + * SoC specific configuration for CPCAP regulator. There are at least three * different SoCs each with their own parameters: omap3, omap4 and tegra2. * * The assign_reg and assign_mask seem to allow toggling between primary diff --git a/drivers/regulator/da9062-regulator.c b/drivers/regulator/da9062-regulator.c index a02e0488410f..2ffc64622451 100644 --- a/drivers/regulator/da9062-regulator.c +++ b/drivers/regulator/da9062-regulator.c @@ -493,12 +493,13 @@ static const struct da9062_regulator_info local_da9061_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (900))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO1_CONT, .desc.enable_mask = DA9062AA_LDO1_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO1_A, .desc.vsel_mask = DA9062AA_VLDO1_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO1_A, __builtin_ffs((int)DA9062AA_LDO1_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - @@ -525,12 +526,13 @@ static const struct da9062_regulator_info local_da9061_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (600))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO2_CONT, .desc.enable_mask = DA9062AA_LDO2_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO2_A, .desc.vsel_mask = DA9062AA_VLDO2_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO2_A, __builtin_ffs((int)DA9062AA_LDO2_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - @@ -557,12 +559,13 @@ static const struct da9062_regulator_info local_da9061_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (900))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO3_CONT, .desc.enable_mask = DA9062AA_LDO3_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO3_A, .desc.vsel_mask = DA9062AA_VLDO3_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO3_A, __builtin_ffs((int)DA9062AA_LDO3_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - @@ -589,12 +592,13 @@ static const struct da9062_regulator_info local_da9061_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (900))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO4_CONT, .desc.enable_mask = DA9062AA_LDO4_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO4_A, .desc.vsel_mask = DA9062AA_VLDO4_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO4_A, __builtin_ffs((int)DA9062AA_LDO4_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - @@ -769,12 +773,13 @@ static const struct da9062_regulator_info local_da9062_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (900))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO1_CONT, .desc.enable_mask = DA9062AA_LDO1_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO1_A, .desc.vsel_mask = DA9062AA_VLDO1_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO1_A, __builtin_ffs((int)DA9062AA_LDO1_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - @@ -801,12 +806,13 @@ static const struct da9062_regulator_info local_da9062_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (600))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO2_CONT, .desc.enable_mask = DA9062AA_LDO2_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO2_A, .desc.vsel_mask = DA9062AA_VLDO2_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO2_A, __builtin_ffs((int)DA9062AA_LDO2_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - @@ -833,12 +839,13 @@ static const struct da9062_regulator_info local_da9062_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (900))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO3_CONT, .desc.enable_mask = DA9062AA_LDO3_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO3_A, .desc.vsel_mask = DA9062AA_VLDO3_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO3_A, __builtin_ffs((int)DA9062AA_LDO3_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - @@ -865,12 +872,13 @@ static const struct da9062_regulator_info local_da9062_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (900))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO4_CONT, .desc.enable_mask = DA9062AA_LDO4_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO4_A, .desc.vsel_mask = DA9062AA_VLDO4_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO4_A, __builtin_ffs((int)DA9062AA_LDO4_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 6f9ce1a6e44d..02f816318fba 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -19,7 +19,6 @@ #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> #include <linux/mfd/da9063/core.h> -#include <linux/mfd/da9063/pdata.h> #include <linux/mfd/da9063/registers.h> @@ -28,6 +27,49 @@ REG_FIELD(_reg, __builtin_ffs((int)_mask) - 1, \ sizeof(unsigned int) * 8 - __builtin_clz((_mask)) - 1) +/* DA9063 and DA9063L regulator IDs */ +enum { + /* BUCKs */ + DA9063_ID_BCORE1, + DA9063_ID_BCORE2, + DA9063_ID_BPRO, + DA9063_ID_BMEM, + DA9063_ID_BIO, + DA9063_ID_BPERI, + + /* BCORE1 and BCORE2 in merged mode */ + DA9063_ID_BCORES_MERGED, + /* BMEM and BIO in merged mode */ + DA9063_ID_BMEM_BIO_MERGED, + /* When two BUCKs are merged, they cannot be reused separately */ + + /* LDOs on both DA9063 and DA9063L */ + DA9063_ID_LDO3, + DA9063_ID_LDO7, + DA9063_ID_LDO8, + DA9063_ID_LDO9, + DA9063_ID_LDO11, + + /* DA9063-only LDOs */ + DA9063_ID_LDO1, + DA9063_ID_LDO2, + DA9063_ID_LDO4, + DA9063_ID_LDO5, + DA9063_ID_LDO6, + DA9063_ID_LDO10, +}; + +/* Old regulator platform data */ +struct da9063_regulator_data { + int id; + struct regulator_init_data *initdata; +}; + +struct da9063_regulators_pdata { + unsigned n_regulators; + struct da9063_regulator_data *regulator_data; +}; + /* Regulator capabilities and registers description */ struct da9063_regulator_info { struct regulator_desc desc; @@ -592,7 +634,6 @@ static const struct regulator_init_data *da9063_get_regulator_initdata( return NULL; } -#ifdef CONFIG_OF static struct of_regulator_match da9063_matches[] = { [DA9063_ID_BCORE1] = { .name = "bcore1" }, [DA9063_ID_BCORE2] = { .name = "bcore2" }, @@ -670,20 +711,10 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt( *da9063_reg_matches = da9063_matches; return pdata; } -#else -static struct da9063_regulators_pdata *da9063_parse_regulators_dt( - struct platform_device *pdev, - struct of_regulator_match **da9063_reg_matches) -{ - *da9063_reg_matches = NULL; - return ERR_PTR(-ENODEV); -} -#endif static int da9063_regulator_probe(struct platform_device *pdev) { struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); - struct da9063_pdata *da9063_pdata = dev_get_platdata(da9063->dev); struct of_regulator_match *da9063_reg_matches = NULL; struct da9063_regulators_pdata *regl_pdata; const struct da9063_dev_model *model; @@ -693,11 +724,7 @@ static int da9063_regulator_probe(struct platform_device *pdev) bool bcores_merged, bmem_bio_merged; int id, irq, n, n_regulators, ret, val; - regl_pdata = da9063_pdata ? da9063_pdata->regulators_pdata : NULL; - - if (!regl_pdata) - regl_pdata = da9063_parse_regulators_dt(pdev, - &da9063_reg_matches); + regl_pdata = da9063_parse_regulators_dt(pdev, &da9063_reg_matches); if (IS_ERR(regl_pdata) || regl_pdata->n_regulators == 0) { dev_err(&pdev->dev, diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index da37b4ccd834..0309823d2c72 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -289,6 +289,8 @@ static struct da9211_pdata *da9211_parse_regulators_dt( 0, GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, "da9211-enable"); + if (IS_ERR(pdata->gpiod_ren[n])) + pdata->gpiod_ren[n] = NULL; n++; } diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index b9ae45d2d199..4986cc5064a1 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -1,10 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* - * helpers.c -- Voltage/Current Regulator framework helper functions. - * - * Copyright 2007, 2008 Wolfson Microelectronics PLC. - * Copyright 2008 SlimLogic Ltd. - */ +// +// helpers.c -- Voltage/Current Regulator framework helper functions. +// +// Copyright 2007, 2008 Wolfson Microelectronics PLC. +// Copyright 2008 SlimLogic Ltd. #include <linux/kernel.h> #include <linux/err.h> diff --git a/drivers/regulator/lm363x-regulator.c b/drivers/regulator/lm363x-regulator.c index e02fdd1dd092..5647e2f97ff8 100644 --- a/drivers/regulator/lm363x-regulator.c +++ b/drivers/regulator/lm363x-regulator.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LM363X Regulator Driver * * Copyright 2015 Texas Instruments * * Author: Milo Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> @@ -37,6 +34,11 @@ #define LM3632_VBOOST_MIN 4500000 #define LM3632_VLDO_MIN 4000000 +/* LM36274 */ +#define LM36274_BOOST_VSEL_MAX 0x3f +#define LM36274_LDO_VSEL_MAX 0x34 +#define LM36274_VOLTAGE_MIN 4000000 + /* Common */ #define LM363X_STEP_50mV 50000 #define LM363X_STEP_500mV 500000 @@ -217,6 +219,51 @@ static const struct regulator_desc lm363x_regulator_desc[] = { .enable_reg = LM3632_REG_BIAS_CONFIG, .enable_mask = LM3632_EN_VNEG_MASK, }, + + /* LM36274 */ + { + .name = "vboost", + .of_match = "vboost", + .id = LM36274_BOOST, + .ops = &lm363x_boost_voltage_table_ops, + .n_voltages = LM36274_BOOST_VSEL_MAX, + .min_uV = LM36274_VOLTAGE_MIN, + .uV_step = LM363X_STEP_50mV, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LM36274_REG_VOUT_BOOST, + .vsel_mask = LM36274_VOUT_MASK, + }, + { + .name = "ldo_vpos", + .of_match = "vpos", + .id = LM36274_LDO_POS, + .ops = &lm363x_regulator_voltage_table_ops, + .n_voltages = LM36274_LDO_VSEL_MAX, + .min_uV = LM36274_VOLTAGE_MIN, + .uV_step = LM363X_STEP_50mV, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LM36274_REG_VOUT_POS, + .vsel_mask = LM36274_VOUT_MASK, + .enable_reg = LM36274_REG_BIAS_CONFIG_1, + .enable_mask = LM36274_EN_VPOS_MASK, + }, + { + .name = "ldo_vneg", + .of_match = "vneg", + .id = LM36274_LDO_NEG, + .ops = &lm363x_regulator_voltage_table_ops, + .n_voltages = LM36274_LDO_VSEL_MAX, + .min_uV = LM36274_VOLTAGE_MIN, + .uV_step = LM363X_STEP_50mV, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LM36274_REG_VOUT_NEG, + .vsel_mask = LM36274_VOUT_MASK, + .enable_reg = LM36274_REG_BIAS_CONFIG_1, + .enable_mask = LM36274_EN_VNEG_MASK, + }, }; static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev, int id) @@ -229,9 +276,11 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev, */ switch (id) { case LM3632_LDO_POS: + case LM36274_LDO_POS: return gpiod_get_index_optional(dev, "enable", 0, GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); case LM3632_LDO_NEG: + case LM36274_LDO_NEG: return gpiod_get_index_optional(dev, "enable", 1, GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); default: @@ -239,6 +288,27 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev, } } +static int lm363x_regulator_set_ext_en(struct regmap *regmap, int id) +{ + int ext_en_mask = 0; + + switch (id) { + case LM3632_LDO_POS: + case LM3632_LDO_NEG: + ext_en_mask = LM3632_EXT_EN_MASK; + break; + case LM36274_LDO_POS: + case LM36274_LDO_NEG: + ext_en_mask = LM36274_EXT_EN_MASK; + break; + default: + return -ENODEV; + } + + return regmap_update_bits(regmap, lm363x_regulator_desc[id].enable_reg, + ext_en_mask, ext_en_mask); +} + static int lm363x_regulator_probe(struct platform_device *pdev) { struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent); @@ -263,10 +333,7 @@ static int lm363x_regulator_probe(struct platform_device *pdev) if (gpiod) { cfg.ena_gpiod = gpiod; - - ret = regmap_update_bits(regmap, LM3632_REG_BIAS_CONFIG, - LM3632_EXT_EN_MASK, - LM3632_EXT_EN_MASK); + ret = lm363x_regulator_set_ext_en(regmap, id); if (ret) { gpiod_put(gpiod); dev_err(dev, "External pin err: %d\n", ret); diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 9e45112658ba..bc96e65ef7c0 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Regulator driver for National Semiconductors LP3971 PMIC chip * @@ -5,11 +6,6 @@ * Author: Marek Szyprowski <m.szyprowski@samsung.com> * * Based on wm8350.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/bug.h> diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index fb098198b688..2d276bbeedf2 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Regulator driver for National Semiconductors LP3972 PMIC chip * * Based on lp3971.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/bug.h> diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index ca95257ce252..303d7e2dc838 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2012 Texas Instruments * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c index 2e16a6ab491d..4291df077c39 100644 --- a/drivers/regulator/lp8755.c +++ b/drivers/regulator/lp8755.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LP8755 High Performance Power Management Unit : System Interface Driver * (based on rev. 0.26) * Copyright 2012 Texas Instruments * * Author: Daniel(Geon Si) Jeong <daniel.jeong@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c index a7d30550bb5f..222502a29658 100644 --- a/drivers/regulator/lp8788-buck.c +++ b/drivers/regulator/lp8788-buck.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LP8788 MFD - buck regulator driver * * Copyright 2012 Texas Instruments * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c index a2ef146e6b3a..1b00f3638996 100644 --- a/drivers/regulator/lp8788-ldo.c +++ b/drivers/regulator/lp8788-ldo.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LP8788 MFD - ldo regulator driver * * Copyright 2012 Texas Instruments * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c index 0db367b54ae7..8d9731e4052b 100644 --- a/drivers/regulator/max77620-regulator.c +++ b/drivers/regulator/max77620-regulator.c @@ -467,7 +467,7 @@ static int max77620_regulator_is_enabled(struct regulator_dev *rdev) { struct max77620_regulator *pmic = rdev_get_drvdata(rdev); int id = rdev_get_id(rdev); - int ret = 1; + int ret; if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE) return 1; @@ -758,6 +758,24 @@ static struct max77620_regulator_info max20024_regs_info[MAX77620_NUM_REGS] = { RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000), }; +static struct max77620_regulator_info max77663_regs_info[MAX77620_NUM_REGS] = { + RAIL_SD(SD0, sd0, "in-sd0", SD0, 600000, 3387500, 12500, 0xFF, NONE), + RAIL_SD(SD1, sd1, "in-sd1", SD1, 800000, 1587500, 12500, 0xFF, NONE), + RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE), + RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE), + RAIL_SD(SD4, sd4, "in-sd4", SDX, 600000, 3787500, 12500, 0xFF, NONE), + + RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000), + RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000), + RAIL_LDO(LDO2, ldo2, "in-ldo2", P, 800000, 3950000, 50000), + RAIL_LDO(LDO3, ldo3, "in-ldo3-5", P, 800000, 3950000, 50000), + RAIL_LDO(LDO4, ldo4, "in-ldo4-6", P, 800000, 1587500, 12500), + RAIL_LDO(LDO5, ldo5, "in-ldo3-5", P, 800000, 3950000, 50000), + RAIL_LDO(LDO6, ldo6, "in-ldo4-6", P, 800000, 3950000, 50000), + RAIL_LDO(LDO7, ldo7, "in-ldo7-8", N, 800000, 3950000, 50000), + RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000), +}; + static int max77620_regulator_probe(struct platform_device *pdev) { struct max77620_chip *max77620_chip = dev_get_drvdata(pdev->dev.parent); @@ -782,9 +800,14 @@ static int max77620_regulator_probe(struct platform_device *pdev) case MAX77620: rinfo = max77620_regs_info; break; - default: + case MAX20024: rinfo = max20024_regs_info; break; + case MAX77663: + rinfo = max77663_regs_info; + break; + default: + return -EINVAL; } config.regmap = pmic->rmap; @@ -878,6 +901,7 @@ static const struct dev_pm_ops max77620_regulator_pm_ops = { static const struct platform_device_id max77620_regulator_devtype[] = { { .name = "max77620-pmic", }, { .name = "max20024-pmic", }, + { .name = "max77663-pmic", }, {}, }; MODULE_DEVICE_TABLE(platform, max77620_regulator_devtype); diff --git a/drivers/regulator/max77650-regulator.c b/drivers/regulator/max77650-regulator.c index 5c4f86c98510..e57fc9197d62 100644 --- a/drivers/regulator/max77650-regulator.c +++ b/drivers/regulator/max77650-regulator.c @@ -20,6 +20,8 @@ #define MAX77650_REGULATOR_V_LDO_MASK GENMASK(6, 0) #define MAX77650_REGULATOR_V_SBB_MASK GENMASK(5, 0) +#define MAX77651_REGULATOR_V_SBB1_MASK GENMASK(5, 2) +#define MAX77651_REGULATOR_V_SBB1_RANGE_MASK GENMASK(1, 0) #define MAX77650_REGULATOR_AD_MASK BIT(3) #define MAX77650_REGULATOR_AD_DISABLED 0x00 @@ -41,43 +43,22 @@ struct max77650_regulator_desc { unsigned int regB; }; -static const unsigned int max77651_sbb1_regulator_volt_table[] = { - 2400000, 3200000, 4000000, 4800000, - 2450000, 3250000, 4050000, 4850000, - 2500000, 3300000, 4100000, 4900000, - 2550000, 3350000, 4150000, 4950000, - 2600000, 3400000, 4200000, 5000000, - 2650000, 3450000, 4250000, 5050000, - 2700000, 3500000, 4300000, 5100000, - 2750000, 3550000, 4350000, 5150000, - 2800000, 3600000, 4400000, 5200000, - 2850000, 3650000, 4450000, 5250000, - 2900000, 3700000, 4500000, 0, - 2950000, 3750000, 4550000, 0, - 3000000, 3800000, 4600000, 0, - 3050000, 3850000, 4650000, 0, - 3100000, 3900000, 4700000, 0, - 3150000, 3950000, 4750000, 0, +static struct max77650_regulator_desc max77651_SBB1_desc; + +static const unsigned int max77651_sbb1_volt_range_sel[] = { + 0x0, 0x1, 0x2, 0x3 }; -#define MAX77651_REGULATOR_SBB1_SEL_DEC(_val) \ - (((_val & 0x3c) >> 2) | ((_val & 0x03) << 4)) -#define MAX77651_REGULATOR_SBB1_SEL_ENC(_val) \ - (((_val & 0x30) >> 4) | ((_val & 0x0f) << 2)) - -#define MAX77650_REGULATOR_SBB1_SEL_DECR(_val) \ - do { \ - _val = MAX77651_REGULATOR_SBB1_SEL_DEC(_val); \ - _val--; \ - _val = MAX77651_REGULATOR_SBB1_SEL_ENC(_val); \ - } while (0) - -#define MAX77650_REGULATOR_SBB1_SEL_INCR(_val) \ - do { \ - _val = MAX77651_REGULATOR_SBB1_SEL_DEC(_val); \ - _val++; \ - _val = MAX77651_REGULATOR_SBB1_SEL_ENC(_val); \ - } while (0) +static const struct regulator_linear_range max77651_sbb1_volt_ranges[] = { + /* range index 0 */ + REGULATOR_LINEAR_RANGE(2400000, 0x00, 0x0f, 50000), + /* range index 1 */ + REGULATOR_LINEAR_RANGE(3200000, 0x00, 0x0f, 50000), + /* range index 2 */ + REGULATOR_LINEAR_RANGE(4000000, 0x00, 0x0f, 50000), + /* range index 3 */ + REGULATOR_LINEAR_RANGE(4800000, 0x00, 0x09, 50000), +}; static const unsigned int max77650_current_limit_table[] = { 1000000, 866000, 707000, 500000, @@ -127,96 +108,6 @@ static int max77650_regulator_disable(struct regulator_dev *rdev) MAX77650_REGULATOR_DISABLED); } -static int max77650_regulator_set_voltage_sel(struct regulator_dev *rdev, - unsigned int sel) -{ - int rv = 0, curr, diff; - bool ascending; - - /* - * If the regulator is disabled, we can program the desired - * voltage right away. - */ - if (!max77650_regulator_is_enabled(rdev)) - return regulator_set_voltage_sel_regmap(rdev, sel); - - /* - * Otherwise we need to manually ramp the output voltage up/down - * one step at a time. - */ - - curr = regulator_get_voltage_sel_regmap(rdev); - if (curr < 0) - return curr; - - diff = curr - sel; - if (diff == 0) - return 0; /* Already there. */ - else if (diff > 0) - ascending = false; - else - ascending = true; - - /* - * Make sure we'll get to the right voltage and break the loop even if - * the selector equals 0. - */ - for (ascending ? curr++ : curr--;; ascending ? curr++ : curr--) { - rv = regulator_set_voltage_sel_regmap(rdev, curr); - if (rv) - return rv; - - if (curr == sel) - break; - } - - return 0; -} - -/* - * Special case: non-linear voltage table for max77651 SBB1 - software - * must ensure the voltage is ramped in 50mV increments. - */ -static int max77651_regulator_sbb1_set_voltage_sel(struct regulator_dev *rdev, - unsigned int sel) -{ - int rv = 0, curr, vcurr, vdest, vdiff; - - /* - * If the regulator is disabled, we can program the desired - * voltage right away. - */ - if (!max77650_regulator_is_enabled(rdev)) - return regulator_set_voltage_sel_regmap(rdev, sel); - - curr = regulator_get_voltage_sel_regmap(rdev); - if (curr < 0) - return curr; - - if (curr == sel) - return 0; /* Already there. */ - - vcurr = max77651_sbb1_regulator_volt_table[curr]; - vdest = max77651_sbb1_regulator_volt_table[sel]; - vdiff = vcurr - vdest; - - for (;;) { - if (vdiff > 0) - MAX77650_REGULATOR_SBB1_SEL_DECR(curr); - else - MAX77650_REGULATOR_SBB1_SEL_INCR(curr); - - rv = regulator_set_voltage_sel_regmap(rdev, curr); - if (rv) - return rv; - - if (curr == sel) - break; - }; - - return 0; -} - static const struct regulator_ops max77650_regulator_LDO_ops = { .is_enabled = max77650_regulator_is_enabled, .enable = max77650_regulator_enable, @@ -224,7 +115,7 @@ static const struct regulator_ops max77650_regulator_LDO_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = max77650_regulator_set_voltage_sel, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_active_discharge = regulator_set_active_discharge_regmap, }; @@ -235,20 +126,20 @@ static const struct regulator_ops max77650_regulator_SBB_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = max77650_regulator_set_voltage_sel, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_current_limit = regulator_get_current_limit_regmap, .set_current_limit = regulator_set_current_limit_regmap, .set_active_discharge = regulator_set_active_discharge_regmap, }; -/* Special case for max77651 SBB1 - non-linear voltage mapping. */ +/* Special case for max77651 SBB1 - pickable linear-range voltage mapping. */ static const struct regulator_ops max77651_SBB1_regulator_ops = { .is_enabled = max77650_regulator_is_enabled, .enable = max77650_regulator_enable, .disable = max77650_regulator_disable, - .list_voltage = regulator_list_voltage_table, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = max77651_regulator_sbb1_set_voltage_sel, + .list_voltage = regulator_list_voltage_pickable_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap, + .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap, .get_current_limit = regulator_get_current_limit_regmap, .set_current_limit = regulator_set_current_limit_regmap, .set_active_discharge = regulator_set_active_discharge_regmap, @@ -265,6 +156,7 @@ static struct max77650_regulator_desc max77650_LDO_desc = { .min_uV = 1350000, .uV_step = 12500, .n_voltages = 128, + .vsel_step = 1, .vsel_mask = MAX77650_REGULATOR_V_LDO_MASK, .vsel_reg = MAX77650_REG_CNFG_LDO_A, .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, @@ -290,6 +182,7 @@ static struct max77650_regulator_desc max77650_SBB0_desc = { .min_uV = 800000, .uV_step = 25000, .n_voltages = 64, + .vsel_step = 1, .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, .vsel_reg = MAX77650_REG_CNFG_SBB0_A, .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, @@ -319,6 +212,7 @@ static struct max77650_regulator_desc max77650_SBB1_desc = { .min_uV = 800000, .uV_step = 12500, .n_voltages = 64, + .vsel_step = 1, .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, .vsel_reg = MAX77650_REG_CNFG_SBB1_A, .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, @@ -345,9 +239,14 @@ static struct max77650_regulator_desc max77651_SBB1_desc = { .supply_name = "in-sbb1", .id = MAX77650_REGULATOR_ID_SBB1, .ops = &max77651_SBB1_regulator_ops, - .volt_table = max77651_sbb1_regulator_volt_table, - .n_voltages = ARRAY_SIZE(max77651_sbb1_regulator_volt_table), - .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, + .linear_range_selectors = max77651_sbb1_volt_range_sel, + .linear_ranges = max77651_sbb1_volt_ranges, + .n_linear_ranges = ARRAY_SIZE(max77651_sbb1_volt_ranges), + .n_voltages = 58, + .vsel_step = 1, + .vsel_range_mask = MAX77651_REGULATOR_V_SBB1_RANGE_MASK, + .vsel_range_reg = MAX77650_REG_CNFG_SBB1_A, + .vsel_mask = MAX77651_REGULATOR_V_SBB1_MASK, .vsel_reg = MAX77650_REG_CNFG_SBB1_A, .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED, @@ -376,6 +275,7 @@ static struct max77650_regulator_desc max77650_SBB2_desc = { .min_uV = 800000, .uV_step = 50000, .n_voltages = 64, + .vsel_step = 1, .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, .vsel_reg = MAX77650_REG_CNFG_SBB2_A, .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, @@ -405,6 +305,7 @@ static struct max77650_regulator_desc max77651_SBB2_desc = { .min_uV = 2400000, .uV_step = 50000, .n_voltages = 64, + .vsel_step = 1, .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, .vsel_reg = MAX77650_REG_CNFG_SBB2_A, .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, @@ -496,3 +397,4 @@ module_platform_driver(max77650_regulator_driver); MODULE_DESCRIPTION("MAXIM 77650/77651 regulator driver"); MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:max77650-regulator"); diff --git a/drivers/regulator/max77802-regulator.c b/drivers/regulator/max77802-regulator.c index ea7b50397300..7b8ec8c0bd15 100644 --- a/drivers/regulator/max77802-regulator.c +++ b/drivers/regulator/max77802-regulator.c @@ -14,9 +14,7 @@ #include <linux/kernel.h> #include <linux/bug.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/slab.h> -#include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 81229579ece9..e86d8bd25fdc 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Regulators driver for Maxim max8649 * * Copyright (C) 2009-2010 Marvell International Ltd. * Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c index 860400d2cd85..76152aaa330b 100644 --- a/drivers/regulator/max8907-regulator.c +++ b/drivers/regulator/max8907-regulator.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * max8907-regulator.c -- support regulators in max8907 * @@ -8,10 +9,6 @@ * Copyright 2010 Texas Instruments Inc. * Author: Graeme Gregory <gg@slimlogic.co.uk> * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index aed6727982cd..d953b6b0db77 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Regulators driver for Maxim max8925 * * Copyright (C) 2009 Marvell International Ltd. * Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 2a123b87d9f2..ccd5da63cdf2 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -13,11 +13,9 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/max8952.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/io.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/regulator/of_regulator.h> #include <linux/slab.h> @@ -37,7 +35,8 @@ enum { struct max8952_data { struct i2c_client *client; struct max8952_platform_data *pdata; - + struct gpio_desc *vid0_gpiod; + struct gpio_desc *vid1_gpiod; bool vid0; bool vid1; }; @@ -87,16 +86,15 @@ static int max8952_set_voltage_sel(struct regulator_dev *rdev, { struct max8952_data *max8952 = rdev_get_drvdata(rdev); - if (!gpio_is_valid(max8952->pdata->gpio_vid0) || - !gpio_is_valid(max8952->pdata->gpio_vid1)) { + if (!max8952->vid0_gpiod || !max8952->vid1_gpiod) { /* DVS not supported */ return -EPERM; } max8952->vid0 = selector & 0x1; max8952->vid1 = (selector >> 1) & 0x1; - gpio_set_value(max8952->pdata->gpio_vid0, max8952->vid0); - gpio_set_value(max8952->pdata->gpio_vid1, max8952->vid1); + gpiod_set_value(max8952->vid0_gpiod, max8952->vid0); + gpiod_set_value(max8952->vid1_gpiod, max8952->vid1); return 0; } @@ -134,9 +132,6 @@ static struct max8952_platform_data *max8952_parse_dt(struct device *dev) if (!pd) return NULL; - pd->gpio_vid0 = of_get_named_gpio(np, "max8952,vid-gpios", 0); - pd->gpio_vid1 = of_get_named_gpio(np, "max8952,vid-gpios", 1); - if (of_property_read_u32(np, "max8952,default-mode", &pd->default_mode)) dev_warn(dev, "Default mode not specified, assuming 0\n"); @@ -179,7 +174,7 @@ static struct max8952_platform_data *max8952_parse_dt(struct device *dev) static int max8952_pmic_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; struct max8952_platform_data *pdata = dev_get_platdata(&client->dev); struct regulator_config config = { }; struct max8952_data *max8952; @@ -187,7 +182,7 @@ static int max8952_pmic_probe(struct i2c_client *client, struct gpio_desc *gpiod; enum gpiod_flags gflags; - int ret = 0, err = 0; + int ret = 0; if (client->dev.of_node) pdata = max8952_parse_dt(&client->dev); @@ -240,32 +235,31 @@ static int max8952_pmic_probe(struct i2c_client *client, max8952->vid0 = pdata->default_mode & 0x1; max8952->vid1 = (pdata->default_mode >> 1) & 0x1; - if (gpio_is_valid(pdata->gpio_vid0) && - gpio_is_valid(pdata->gpio_vid1)) { - unsigned long gpio_flags; - - gpio_flags = max8952->vid0 ? - GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; - if (devm_gpio_request_one(&client->dev, pdata->gpio_vid0, - gpio_flags, "MAX8952 VID0")) - err = 1; - - gpio_flags = max8952->vid1 ? - GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; - if (devm_gpio_request_one(&client->dev, pdata->gpio_vid1, - gpio_flags, "MAX8952 VID1")) - err = 2; - } else - err = 3; - - if (err) { + /* Fetch vid0 and vid1 GPIOs if available */ + gflags = max8952->vid0 ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + max8952->vid0_gpiod = devm_gpiod_get_index_optional(&client->dev, + "max8952,vid", + 0, gflags); + if (IS_ERR(max8952->vid0_gpiod)) + return PTR_ERR(max8952->vid0_gpiod); + gflags = max8952->vid1 ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + max8952->vid1_gpiod = devm_gpiod_get_index_optional(&client->dev, + "max8952,vid", + 1, gflags); + if (IS_ERR(max8952->vid1_gpiod)) + return PTR_ERR(max8952->vid1_gpiod); + + /* If either VID GPIO is missing just disable this */ + if (!max8952->vid0_gpiod || !max8952->vid1_gpiod) { dev_warn(&client->dev, "VID0/1 gpio invalid: " - "DVS not available.\n"); + "DVS not available.\n"); max8952->vid0 = 0; max8952->vid1 = 0; - /* Mark invalid */ - pdata->gpio_vid0 = -1; - pdata->gpio_vid1 = -1; + /* Make sure if we have any descriptors they get set to low */ + if (max8952->vid0_gpiod) + gpiod_set_value(max8952->vid0_gpiod, 0); + if (max8952->vid1_gpiod) + gpiod_set_value(max8952->vid1_gpiod, 0); /* Disable Pulldown of EN only */ max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60); diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 0ead1164e4d6..397918ebba55 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -21,7 +21,8 @@ static const char *const regulator_states[PM_SUSPEND_MAX + 1] = { [PM_SUSPEND_MAX] = "regulator-state-disk", }; -static void of_get_regulation_constraints(struct device_node *np, +static int of_get_regulation_constraints(struct device *dev, + struct device_node *np, struct regulator_init_data **init_data, const struct regulator_desc *desc) { @@ -30,8 +31,13 @@ static void of_get_regulation_constraints(struct device_node *np, struct device_node *suspend_np; unsigned int mode; int ret, i, len; + int n_phandles; u32 pval; + n_phandles = of_count_phandle_with_args(np, "regulator-coupled-with", + NULL); + n_phandles = max(n_phandles, 0); + constraints->name = of_get_property(np, "regulator-name", NULL); if (!of_property_read_u32(np, "regulator-min-microvolt", &pval)) @@ -163,9 +169,17 @@ static void of_get_regulation_constraints(struct device_node *np, if (!of_property_read_u32(np, "regulator-system-load", &pval)) constraints->system_load = pval; - if (!of_property_read_u32(np, "regulator-coupled-max-spread", - &pval)) - constraints->max_spread = pval; + if (n_phandles) { + constraints->max_spread = devm_kzalloc(dev, + sizeof(*constraints->max_spread) * n_phandles, + GFP_KERNEL); + + if (!constraints->max_spread) + return -ENOMEM; + + of_property_read_u32_array(np, "regulator-coupled-max-spread", + constraints->max_spread, n_phandles); + } if (!of_property_read_u32(np, "regulator-max-step-microvolt", &pval)) @@ -242,6 +256,8 @@ static void of_get_regulation_constraints(struct device_node *np, suspend_state = NULL; suspend_np = NULL; } + + return 0; } /** @@ -267,7 +283,9 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, if (!init_data) return NULL; /* Out of memory? */ - of_get_regulation_constraints(node, &init_data, desc); + if (of_get_regulation_constraints(dev, node, &init_data, desc)) + return NULL; + return init_data; } EXPORT_SYMBOL_GPL(of_get_regulator_init_data); @@ -473,7 +491,8 @@ int of_get_n_coupled(struct regulator_dev *rdev) /* Looks for "to_find" device_node in src's "regulator-coupled-with" property */ static bool of_coupling_find_node(struct device_node *src, - struct device_node *to_find) + struct device_node *to_find, + int *index) { int n_phandles, i; bool found = false; @@ -495,8 +514,10 @@ static bool of_coupling_find_node(struct device_node *src, of_node_put(tmp); - if (found) + if (found) { + *index = i; break; + } } return found; @@ -517,22 +538,23 @@ static bool of_coupling_find_node(struct device_node *src, */ bool of_check_coupling_data(struct regulator_dev *rdev) { - int max_spread = rdev->constraints->max_spread; struct device_node *node = rdev->dev.of_node; int n_phandles = of_get_n_coupled(rdev); struct device_node *c_node; + int index; int i; bool ret = true; - if (max_spread <= 0) { - dev_err(&rdev->dev, "max_spread value invalid\n"); - return false; - } - /* iterate over rdev's phandles */ for (i = 0; i < n_phandles; i++) { + int max_spread = rdev->constraints->max_spread[i]; int c_max_spread, c_n_phandles; + if (max_spread <= 0) { + dev_err(&rdev->dev, "max_spread value invalid\n"); + return false; + } + c_node = of_parse_phandle(node, "regulator-coupled-with", i); @@ -549,22 +571,23 @@ bool of_check_coupling_data(struct regulator_dev *rdev) goto clean; } - if (of_property_read_u32(c_node, "regulator-coupled-max-spread", - &c_max_spread)) { + if (!of_coupling_find_node(c_node, node, &index)) { + dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n"); ret = false; goto clean; } - if (c_max_spread != max_spread) { - dev_err(&rdev->dev, - "coupled regulators max_spread mismatch\n"); + if (of_property_read_u32_index(c_node, "regulator-coupled-max-spread", + index, &c_max_spread)) { ret = false; goto clean; } - if (!of_coupling_find_node(c_node, node)) { - dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n"); + if (c_max_spread != max_spread) { + dev_err(&rdev->dev, + "coupled regulators max_spread mismatch\n"); ret = false; + goto clean; } clean: diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index 3f53f9134b32..e74e11101fc1 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Regulator driver for PWM Regulators * * Copyright (C) 2014 - STMicroelectronics Inc. * * Author: Lee Jones <lee.jones@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 6dfc9e176360..7f51c5fc8194 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -96,6 +96,8 @@ enum spmi_regulator_logical_type { SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS, SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS, SPMI_REGULATOR_LOGICAL_TYPE_ULT_LDO, + SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS426, + SPMI_REGULATOR_LOGICAL_TYPE_HFS430, }; enum spmi_regulator_type { @@ -142,11 +144,13 @@ enum spmi_regulator_subtype { SPMI_REGULATOR_SUBTYPE_5V_BOOST = 0x01, SPMI_REGULATOR_SUBTYPE_FTS_CTL = 0x08, SPMI_REGULATOR_SUBTYPE_FTS2p5_CTL = 0x09, + SPMI_REGULATOR_SUBTYPE_FTS426_CTL = 0x0a, SPMI_REGULATOR_SUBTYPE_BB_2A = 0x01, SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL1 = 0x0d, SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL2 = 0x0e, SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL3 = 0x0f, SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL4 = 0x10, + SPMI_REGULATOR_SUBTYPE_HFS430 = 0x0a, }; enum spmi_common_regulator_registers { @@ -162,6 +166,18 @@ enum spmi_common_regulator_registers { SPMI_COMMON_REG_STEP_CTRL = 0x61, }; +/* + * Second common register layout used by newer devices starting with ftsmps426 + * Note that some of the registers from the first common layout remain + * unchanged and their definition is not duplicated. + */ +enum spmi_ftsmps426_regulator_registers { + SPMI_FTSMPS426_REG_VOLTAGE_LSB = 0x40, + SPMI_FTSMPS426_REG_VOLTAGE_MSB = 0x41, + SPMI_FTSMPS426_REG_VOLTAGE_ULS_LSB = 0x68, + SPMI_FTSMPS426_REG_VOLTAGE_ULS_MSB = 0x69, +}; + enum spmi_vs_registers { SPMI_VS_REG_OCP = 0x4a, SPMI_VS_REG_SOFT_START = 0x4c, @@ -221,6 +237,14 @@ enum spmi_common_control_register_index { #define SPMI_COMMON_MODE_FOLLOW_HW_EN0_MASK 0x01 #define SPMI_COMMON_MODE_FOLLOW_ALL_MASK 0x1f +#define SPMI_FTSMPS426_MODE_BYPASS_MASK 3 +#define SPMI_FTSMPS426_MODE_RETENTION_MASK 4 +#define SPMI_FTSMPS426_MODE_LPM_MASK 5 +#define SPMI_FTSMPS426_MODE_AUTO_MASK 6 +#define SPMI_FTSMPS426_MODE_HPM_MASK 7 + +#define SPMI_FTSMPS426_MODE_MASK 0x07 + /* Common regulator pull down control register layout */ #define SPMI_COMMON_PULL_DOWN_ENABLE_MASK 0x80 @@ -266,6 +290,25 @@ enum spmi_common_control_register_index { #define SPMI_FTSMPS_STEP_MARGIN_NUM 4 #define SPMI_FTSMPS_STEP_MARGIN_DEN 5 +#define SPMI_FTSMPS426_STEP_CTRL_DELAY_MASK 0x03 +#define SPMI_FTSMPS426_STEP_CTRL_DELAY_SHIFT 0 + +/* Clock rate in kHz of the FTSMPS426 regulator reference clock. */ +#define SPMI_FTSMPS426_CLOCK_RATE 4800 + +#define SPMI_HFS430_CLOCK_RATE 1600 + +/* Minimum voltage stepper delay for each step. */ +#define SPMI_FTSMPS426_STEP_DELAY 2 + +/* + * The ratio SPMI_FTSMPS426_STEP_MARGIN_NUM/SPMI_FTSMPS426_STEP_MARGIN_DEN is + * used to adjust the step rate in order to account for oscillator variance. + */ +#define SPMI_FTSMPS426_STEP_MARGIN_NUM 10 +#define SPMI_FTSMPS426_STEP_MARGIN_DEN 11 + + /* VSET value to decide the range of ULT SMPS */ #define ULT_SMPS_RANGE_SPLIT 0x60 @@ -439,6 +482,10 @@ static struct spmi_voltage_range ftsmps2p5_ranges[] = { SPMI_VOLTAGE_RANGE(1, 160000, 1360000, 2200000, 2200000, 10000), }; +static struct spmi_voltage_range ftsmps426_ranges[] = { + SPMI_VOLTAGE_RANGE(0, 0, 320000, 1352000, 1352000, 4000), +}; + static struct spmi_voltage_range boost_ranges[] = { SPMI_VOLTAGE_RANGE(0, 4000000, 4000000, 5550000, 5550000, 50000), }; @@ -464,6 +511,10 @@ static struct spmi_voltage_range ult_pldo_ranges[] = { SPMI_VOLTAGE_RANGE(0, 1750000, 1750000, 3337500, 3337500, 12500), }; +static struct spmi_voltage_range hfs430_ranges[] = { + SPMI_VOLTAGE_RANGE(0, 320000, 320000, 2040000, 2040000, 8000), +}; + static DEFINE_SPMI_SET_POINTS(pldo); static DEFINE_SPMI_SET_POINTS(nldo1); static DEFINE_SPMI_SET_POINTS(nldo2); @@ -472,12 +523,14 @@ static DEFINE_SPMI_SET_POINTS(ln_ldo); static DEFINE_SPMI_SET_POINTS(smps); static DEFINE_SPMI_SET_POINTS(ftsmps); static DEFINE_SPMI_SET_POINTS(ftsmps2p5); +static DEFINE_SPMI_SET_POINTS(ftsmps426); static DEFINE_SPMI_SET_POINTS(boost); static DEFINE_SPMI_SET_POINTS(boost_byp); static DEFINE_SPMI_SET_POINTS(ult_lo_smps); static DEFINE_SPMI_SET_POINTS(ult_ho_smps); static DEFINE_SPMI_SET_POINTS(ult_nldo); static DEFINE_SPMI_SET_POINTS(ult_pldo); +static DEFINE_SPMI_SET_POINTS(hfs430); static inline int spmi_vreg_read(struct spmi_regulator *vreg, u16 addr, u8 *buf, int len) @@ -739,18 +792,31 @@ spmi_regulator_common_set_voltage(struct regulator_dev *rdev, unsigned selector) return spmi_vreg_write(vreg, SPMI_COMMON_REG_VOLTAGE_RANGE, buf, 2); } +static int spmi_regulator_common_list_voltage(struct regulator_dev *rdev, + unsigned selector); + +static int spmi_regulator_ftsmps426_set_voltage(struct regulator_dev *rdev, + unsigned selector) +{ + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); + u8 buf[2]; + int mV; + + mV = spmi_regulator_common_list_voltage(rdev, selector) / 1000; + + buf[0] = mV & 0xff; + buf[1] = mV >> 8; + return spmi_vreg_write(vreg, SPMI_FTSMPS426_REG_VOLTAGE_LSB, buf, 2); +} + static int spmi_regulator_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int old_selector, unsigned int new_selector) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); - const struct spmi_voltage_range *range; int diff_uV; - range = spmi_regulator_find_range(vreg); - if (!range) - return -EINVAL; - - diff_uV = abs(new_selector - old_selector) * range->step_uV; + diff_uV = abs(spmi_regulator_common_list_voltage(rdev, new_selector) - + spmi_regulator_common_list_voltage(rdev, old_selector)); return DIV_ROUND_UP(diff_uV, vreg->slew_rate); } @@ -770,6 +836,21 @@ static int spmi_regulator_common_get_voltage(struct regulator_dev *rdev) return spmi_hw_selector_to_sw(vreg, voltage_sel, range); } +static int spmi_regulator_ftsmps426_get_voltage(struct regulator_dev *rdev) +{ + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); + const struct spmi_voltage_range *range; + u8 buf[2]; + int uV; + + spmi_vreg_read(vreg, SPMI_FTSMPS426_REG_VOLTAGE_LSB, buf, 2); + + uV = (((unsigned int)buf[1] << 8) | (unsigned int)buf[0]) * 1000; + range = vreg->set_points->range; + + return (uV - range->set_point_min_uV) / range->step_uV; +} + static int spmi_regulator_single_map_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { @@ -903,13 +984,33 @@ static unsigned int spmi_regulator_common_get_mode(struct regulator_dev *rdev) spmi_vreg_read(vreg, SPMI_COMMON_REG_MODE, ®, 1); - if (reg & SPMI_COMMON_MODE_HPM_MASK) - return REGULATOR_MODE_NORMAL; + reg &= SPMI_COMMON_MODE_HPM_MASK | SPMI_COMMON_MODE_AUTO_MASK; - if (reg & SPMI_COMMON_MODE_AUTO_MASK) + switch (reg) { + case SPMI_COMMON_MODE_HPM_MASK: + return REGULATOR_MODE_NORMAL; + case SPMI_COMMON_MODE_AUTO_MASK: return REGULATOR_MODE_FAST; + default: + return REGULATOR_MODE_IDLE; + } +} - return REGULATOR_MODE_IDLE; +static unsigned int spmi_regulator_ftsmps426_get_mode(struct regulator_dev *rdev) +{ + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); + u8 reg; + + spmi_vreg_read(vreg, SPMI_COMMON_REG_MODE, ®, 1); + + switch (reg) { + case SPMI_FTSMPS426_MODE_HPM_MASK: + return REGULATOR_MODE_NORMAL; + case SPMI_FTSMPS426_MODE_AUTO_MASK: + return REGULATOR_MODE_FAST; + default: + return REGULATOR_MODE_IDLE; + } } static int @@ -917,12 +1018,43 @@ spmi_regulator_common_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); u8 mask = SPMI_COMMON_MODE_HPM_MASK | SPMI_COMMON_MODE_AUTO_MASK; - u8 val = 0; + u8 val; - if (mode == REGULATOR_MODE_NORMAL) + switch (mode) { + case REGULATOR_MODE_NORMAL: val = SPMI_COMMON_MODE_HPM_MASK; - else if (mode == REGULATOR_MODE_FAST) + break; + case REGULATOR_MODE_FAST: val = SPMI_COMMON_MODE_AUTO_MASK; + break; + default: + val = 0; + break; + } + + return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_MODE, val, mask); +} + +static int +spmi_regulator_ftsmps426_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); + u8 mask = SPMI_FTSMPS426_MODE_MASK; + u8 val; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + val = SPMI_FTSMPS426_MODE_HPM_MASK; + break; + case REGULATOR_MODE_FAST: + val = SPMI_FTSMPS426_MODE_AUTO_MASK; + break; + case REGULATOR_MODE_IDLE: + val = SPMI_FTSMPS426_MODE_LPM_MASK; + break; + default: + return -EINVAL; + } return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_MODE, val, mask); } @@ -1256,12 +1388,41 @@ static struct regulator_ops spmi_ult_ldo_ops = { .set_soft_start = spmi_regulator_common_set_soft_start, }; +static struct regulator_ops spmi_ftsmps426_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_voltage_sel = spmi_regulator_ftsmps426_set_voltage, + .set_voltage_time_sel = spmi_regulator_set_voltage_time_sel, + .get_voltage_sel = spmi_regulator_ftsmps426_get_voltage, + .map_voltage = spmi_regulator_single_map_voltage, + .list_voltage = spmi_regulator_common_list_voltage, + .set_mode = spmi_regulator_ftsmps426_set_mode, + .get_mode = spmi_regulator_ftsmps426_get_mode, + .set_load = spmi_regulator_common_set_load, + .set_pull_down = spmi_regulator_common_set_pull_down, +}; + +static struct regulator_ops spmi_hfs430_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_voltage_sel = spmi_regulator_ftsmps426_set_voltage, + .set_voltage_time_sel = spmi_regulator_set_voltage_time_sel, + .get_voltage_sel = spmi_regulator_ftsmps426_get_voltage, + .map_voltage = spmi_regulator_single_map_voltage, + .list_voltage = spmi_regulator_common_list_voltage, + .set_mode = spmi_regulator_ftsmps426_set_mode, + .get_mode = spmi_regulator_ftsmps426_get_mode, +}; + /* Maximum possible digital major revision value */ #define INF 0xFF static const struct spmi_regulator_mapping supported_regulators[] = { /* type subtype dig_min dig_max ltype ops setpoints hpm_min */ SPMI_VREG(BUCK, GP_CTL, 0, INF, SMPS, smps, smps, 100000), + SPMI_VREG(BUCK, HFS430, 0, INF, HFS430, hfs430, hfs430, 10000), SPMI_VREG(LDO, N300, 0, INF, LDO, ldo, nldo1, 10000), SPMI_VREG(LDO, N600, 0, 0, LDO, ldo, nldo2, 10000), SPMI_VREG(LDO, N1200, 0, 0, LDO, ldo, nldo2, 10000), @@ -1291,6 +1452,7 @@ static const struct spmi_regulator_mapping supported_regulators[] = { SPMI_VREG(BOOST, 5V_BOOST, 0, INF, BOOST, boost, boost, 0), SPMI_VREG(FTS, FTS_CTL, 0, INF, FTSMPS, ftsmps, ftsmps, 100000), SPMI_VREG(FTS, FTS2p5_CTL, 0, INF, FTSMPS, ftsmps, ftsmps2p5, 100000), + SPMI_VREG(FTS, FTS426_CTL, 0, INF, FTSMPS426, ftsmps426, ftsmps426, 100000), SPMI_VREG(BOOST_BYP, BB_2A, 0, INF, BOOST_BYP, boost, boost_byp, 0), SPMI_VREG(ULT_BUCK, ULT_HF_CTL1, 0, INF, ULT_LO_SMPS, ult_lo_smps, ult_lo_smps, 100000), @@ -1428,6 +1590,35 @@ static int spmi_regulator_init_slew_rate(struct spmi_regulator *vreg) return ret; } +static int spmi_regulator_init_slew_rate_ftsmps426(struct spmi_regulator *vreg, + int clock_rate) +{ + int ret; + u8 reg = 0; + int delay, slew_rate; + const struct spmi_voltage_range *range = &vreg->set_points->range[0]; + + ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_STEP_CTRL, ®, 1); + if (ret) { + dev_err(vreg->dev, "spmi read failed, ret=%d\n", ret); + return ret; + } + + delay = reg & SPMI_FTSMPS426_STEP_CTRL_DELAY_MASK; + delay >>= SPMI_FTSMPS426_STEP_CTRL_DELAY_SHIFT; + + /* slew_rate has units of uV/us */ + slew_rate = clock_rate * range->step_uV; + slew_rate /= 1000 * (SPMI_FTSMPS426_STEP_DELAY << delay); + slew_rate *= SPMI_FTSMPS426_STEP_MARGIN_NUM; + slew_rate /= SPMI_FTSMPS426_STEP_MARGIN_DEN; + + /* Ensure that the slew rate is greater than 0 */ + vreg->slew_rate = max(slew_rate, 1); + + return ret; +} + static int spmi_regulator_init_registers(struct spmi_regulator *vreg, const struct spmi_regulator_init_data *data) { @@ -1567,6 +1758,19 @@ static int spmi_regulator_of_parse(struct device_node *node, ret = spmi_regulator_init_slew_rate(vreg); if (ret) return ret; + break; + case SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS426: + ret = spmi_regulator_init_slew_rate_ftsmps426(vreg, + SPMI_FTSMPS426_CLOCK_RATE); + if (ret) + return ret; + break; + case SPMI_REGULATOR_LOGICAL_TYPE_HFS430: + ret = spmi_regulator_init_slew_rate_ftsmps426(vreg, + SPMI_HFS430_CLOCK_RATE); + if (ret) + return ret; + break; default: break; } @@ -1723,12 +1927,27 @@ static const struct spmi_regulator_data pmi8994_regulators[] = { { } }; +static const struct spmi_regulator_data pm8005_regulators[] = { + { "s1", 0x1400, "vdd_s1", }, + { "s2", 0x1700, "vdd_s2", }, + { "s3", 0x1a00, "vdd_s3", }, + { "s4", 0x1d00, "vdd_s4", }, + { } +}; + +static const struct spmi_regulator_data pms405_regulators[] = { + { "s3", 0x1a00, "vdd_s3"}, + { } +}; + static const struct of_device_id qcom_spmi_regulator_match[] = { + { .compatible = "qcom,pm8005-regulators", .data = &pm8005_regulators }, { .compatible = "qcom,pm8841-regulators", .data = &pm8841_regulators }, { .compatible = "qcom,pm8916-regulators", .data = &pm8916_regulators }, { .compatible = "qcom,pm8941-regulators", .data = &pm8941_regulators }, { .compatible = "qcom,pm8994-regulators", .data = &pm8994_regulators }, { .compatible = "qcom,pmi8994-regulators", .data = &pmi8994_regulators }, + { .compatible = "qcom,pms405-regulators", .data = &pms405_regulators }, { } }; MODULE_DEVICE_TABLE(of, qcom_spmi_regulator_match); @@ -1736,6 +1955,7 @@ MODULE_DEVICE_TABLE(of, qcom_spmi_regulator_match); static int qcom_spmi_regulator_probe(struct platform_device *pdev) { const struct spmi_regulator_data *reg; + const struct spmi_voltage_range *range; const struct of_device_id *match; struct regulator_config config = { }; struct regulator_dev *rdev; @@ -1825,6 +2045,12 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) } } + if (vreg->set_points && vreg->set_points->count == 1) { + /* since there is only one range */ + range = vreg->set_points->range; + vreg->desc.uV_step = range->step_uV; + } + config.dev = dev; config.driver_data = vreg; config.regmap = regmap; diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 134c62db36c5..054baaadfdfd 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -34,7 +34,7 @@ struct s2mps11_info { enum sec_device_type dev_type; /* - * One bit for each S2MPS13/S2MPS14/S2MPU02 regulator whether + * One bit for each S2MPS11/S2MPS13/S2MPS14/S2MPU02 regulator whether * the suspend mode was enabled. */ DECLARE_BITMAP(suspend_state, S2MPS_REGULATOR_MAX); @@ -70,10 +70,11 @@ static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int new_selector) { struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + int rdev_id = rdev_get_id(rdev); unsigned int ramp_delay = 0; int old_volt, new_volt; - switch (rdev_get_id(rdev)) { + switch (rdev_id) { case S2MPS11_BUCK2: ramp_delay = s2mps11->ramp_delay2; break; @@ -111,9 +112,10 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); unsigned int ramp_val, ramp_shift, ramp_reg = S2MPS11_REG_RAMP_BUCK; unsigned int ramp_enable = 1, enable_shift = 0; + int rdev_id = rdev_get_id(rdev); int ret; - switch (rdev_get_id(rdev)) { + switch (rdev_id) { case S2MPS11_BUCK1: if (ramp_delay > s2mps11->ramp_delay16) s2mps11->ramp_delay16 = ramp_delay; @@ -203,9 +205,8 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) goto ramp_disable; /* Ramp delay can be enabled/disabled only for buck[2346] */ - if ((rdev_get_id(rdev) >= S2MPS11_BUCK2 && - rdev_get_id(rdev) <= S2MPS11_BUCK4) || - rdev_get_id(rdev) == S2MPS11_BUCK6) { + if ((rdev_id >= S2MPS11_BUCK2 && rdev_id <= S2MPS11_BUCK4) || + rdev_id == S2MPS11_BUCK6) { ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP, 1 << enable_shift, 1 << enable_shift); if (ret) { @@ -224,27 +225,133 @@ ramp_disable: 1 << enable_shift, 0); } +static int s2mps11_regulator_enable(struct regulator_dev *rdev) +{ + struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + int rdev_id = rdev_get_id(rdev); + unsigned int val; + + switch (s2mps11->dev_type) { + case S2MPS11X: + if (test_bit(rdev_id, s2mps11->suspend_state)) + val = S2MPS14_ENABLE_SUSPEND; + else + val = rdev->desc->enable_mask; + break; + case S2MPS13X: + case S2MPS14X: + if (test_bit(rdev_id, s2mps11->suspend_state)) + val = S2MPS14_ENABLE_SUSPEND; + else if (s2mps11->ext_control_gpiod[rdev_id]) + val = S2MPS14_ENABLE_EXT_CONTROL; + else + val = rdev->desc->enable_mask; + break; + case S2MPU02: + if (test_bit(rdev_id, s2mps11->suspend_state)) + val = S2MPU02_ENABLE_SUSPEND; + else + val = rdev->desc->enable_mask; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val); +} + +static int s2mps11_regulator_set_suspend_disable(struct regulator_dev *rdev) +{ + int ret; + unsigned int val, state; + struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + int rdev_id = rdev_get_id(rdev); + + /* Below LDO should be always on or does not support suspend mode. */ + switch (s2mps11->dev_type) { + case S2MPS11X: + switch (rdev_id) { + case S2MPS11_LDO2: + case S2MPS11_LDO36: + case S2MPS11_LDO37: + case S2MPS11_LDO38: + return 0; + default: + state = S2MPS14_ENABLE_SUSPEND; + break; + } + break; + case S2MPS13X: + case S2MPS14X: + switch (rdev_id) { + case S2MPS14_LDO3: + return 0; + default: + state = S2MPS14_ENABLE_SUSPEND; + break; + } + break; + case S2MPU02: + switch (rdev_id) { + case S2MPU02_LDO13: + case S2MPU02_LDO14: + case S2MPU02_LDO15: + case S2MPU02_LDO17: + case S2MPU02_BUCK7: + state = S2MPU02_DISABLE_SUSPEND; + break; + default: + state = S2MPU02_ENABLE_SUSPEND; + break; + } + break; + default: + return -EINVAL; + } + + ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val); + if (ret < 0) + return ret; + + set_bit(rdev_id, s2mps11->suspend_state); + /* + * Don't enable suspend mode if regulator is already disabled because + * this would effectively for a short time turn on the regulator after + * resuming. + * However we still want to toggle the suspend_state bit for regulator + * in case if it got enabled before suspending the system. + */ + if (!(val & rdev->desc->enable_mask)) + return 0; + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, state); +} + static const struct regulator_ops s2mps11_ldo_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, + .enable = s2mps11_regulator_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_disable = s2mps11_regulator_set_suspend_disable, }; static const struct regulator_ops s2mps11_buck_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, + .enable = s2mps11_regulator_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = s2mps11_regulator_set_voltage_time_sel, .set_ramp_delay = s2mps11_set_ramp_delay, + .set_suspend_disable = s2mps11_regulator_set_suspend_disable, }; #define regulator_desc_s2mps11_ldo(num, step) { \ @@ -269,9 +376,10 @@ static const struct regulator_ops s2mps11_buck_ops = { .ops = &s2mps11_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .min_uV = MIN_600_MV, \ + .min_uV = MIN_650_MV, \ .uV_step = STEP_6_25_MV, \ - .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ + .linear_min_sel = 8, \ + .n_voltages = S2MPS11_BUCK12346_N_VOLTAGES, \ .ramp_delay = S2MPS11_RAMP_DELAY, \ .vsel_reg = S2MPS11_REG_B1CTRL2 + (num - 1) * 2, \ .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ @@ -285,9 +393,10 @@ static const struct regulator_ops s2mps11_buck_ops = { .ops = &s2mps11_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .min_uV = MIN_600_MV, \ + .min_uV = MIN_650_MV, \ .uV_step = STEP_6_25_MV, \ - .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ + .linear_min_sel = 8, \ + .n_voltages = S2MPS11_BUCK5_N_VOLTAGES, \ .ramp_delay = S2MPS11_RAMP_DELAY, \ .vsel_reg = S2MPS11_REG_B5CTRL2, \ .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ @@ -295,7 +404,7 @@ static const struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_s2mps11_buck67810(num, min, step) { \ +#define regulator_desc_s2mps11_buck67810(num, min, step, min_sel, voltages) { \ .name = "BUCK"#num, \ .id = S2MPS11_BUCK##num, \ .ops = &s2mps11_buck_ops, \ @@ -303,7 +412,8 @@ static const struct regulator_ops s2mps11_buck_ops = { .owner = THIS_MODULE, \ .min_uV = min, \ .uV_step = step, \ - .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ + .linear_min_sel = min_sel, \ + .n_voltages = voltages, \ .ramp_delay = S2MPS11_RAMP_DELAY, \ .vsel_reg = S2MPS11_REG_B6CTRL2 + (num - 6) * 2, \ .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ @@ -371,11 +481,15 @@ static const struct regulator_desc s2mps11_regulators[] = { regulator_desc_s2mps11_buck1_4(3), regulator_desc_s2mps11_buck1_4(4), regulator_desc_s2mps11_buck5, - regulator_desc_s2mps11_buck67810(6, MIN_600_MV, STEP_6_25_MV), - regulator_desc_s2mps11_buck67810(7, MIN_600_MV, STEP_12_5_MV), - regulator_desc_s2mps11_buck67810(8, MIN_600_MV, STEP_12_5_MV), + regulator_desc_s2mps11_buck67810(6, MIN_650_MV, STEP_6_25_MV, 8, + S2MPS11_BUCK12346_N_VOLTAGES), + regulator_desc_s2mps11_buck67810(7, MIN_750_MV, STEP_12_5_MV, 0, + S2MPS11_BUCK7810_N_VOLTAGES), + regulator_desc_s2mps11_buck67810(8, MIN_750_MV, STEP_12_5_MV, 0, + S2MPS11_BUCK7810_N_VOLTAGES), regulator_desc_s2mps11_buck9, - regulator_desc_s2mps11_buck67810(10, MIN_750_MV, STEP_12_5_MV), + regulator_desc_s2mps11_buck67810(10, MIN_750_MV, STEP_12_5_MV, 0, + S2MPS11_BUCK7810_N_VOLTAGES), }; static const struct regulator_ops s2mps14_reg_ops; @@ -500,101 +614,16 @@ static const struct regulator_desc s2mps13_regulators[] = { regulator_desc_s2mps13_buck8_10(10, MIN_500_MV, STEP_6_25_MV, 0x10), }; -static int s2mps14_regulator_enable(struct regulator_dev *rdev) -{ - struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); - unsigned int val; - - switch (s2mps11->dev_type) { - case S2MPS13X: - case S2MPS14X: - if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state)) - val = S2MPS14_ENABLE_SUSPEND; - else if (s2mps11->ext_control_gpiod[rdev_get_id(rdev)]) - val = S2MPS14_ENABLE_EXT_CONTROL; - else - val = rdev->desc->enable_mask; - break; - case S2MPU02: - if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state)) - val = S2MPU02_ENABLE_SUSPEND; - else - val = rdev->desc->enable_mask; - break; - default: - return -EINVAL; - } - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, val); -} - -static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev) -{ - int ret; - unsigned int val, state; - struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); - int rdev_id = rdev_get_id(rdev); - - /* Below LDO should be always on or does not support suspend mode. */ - switch (s2mps11->dev_type) { - case S2MPS13X: - case S2MPS14X: - switch (rdev_id) { - case S2MPS14_LDO3: - return 0; - default: - state = S2MPS14_ENABLE_SUSPEND; - break; - } - break; - case S2MPU02: - switch (rdev_id) { - case S2MPU02_LDO13: - case S2MPU02_LDO14: - case S2MPU02_LDO15: - case S2MPU02_LDO17: - case S2MPU02_BUCK7: - state = S2MPU02_DISABLE_SUSPEND; - break; - default: - state = S2MPU02_ENABLE_SUSPEND; - break; - } - break; - default: - return -EINVAL; - } - - ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val); - if (ret < 0) - return ret; - - set_bit(rdev_get_id(rdev), s2mps11->suspend_state); - /* - * Don't enable suspend mode if regulator is already disabled because - * this would effectively for a short time turn on the regulator after - * resuming. - * However we still want to toggle the suspend_state bit for regulator - * in case if it got enabled before suspending the system. - */ - if (!(val & rdev->desc->enable_mask)) - return 0; - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, state); -} - static const struct regulator_ops s2mps14_reg_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = s2mps14_regulator_enable, + .enable = s2mps11_regulator_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_suspend_disable = s2mps14_regulator_set_suspend_disable, + .set_suspend_disable = s2mps11_regulator_set_suspend_disable, }; #define regulator_desc_s2mps14_ldo(num, min, step) { \ @@ -821,9 +850,12 @@ static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev, 0, GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, "s2mps11-regulator"); - if (IS_ERR(gpio[reg])) { + if (PTR_ERR(gpio[reg]) == -ENOENT) + gpio[reg] = NULL; + else if (IS_ERR(gpio[reg])) { dev_err(&pdev->dev, "Failed to get control GPIO for %d/%s\n", reg, rdata[reg].name); + gpio[reg] = NULL; continue; } if (gpio[reg]) @@ -856,8 +888,9 @@ static int s2mps11_pmic_dt_parse(struct platform_device *pdev, static int s2mpu02_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) { unsigned int ramp_val, ramp_shift, ramp_reg; + int rdev_id = rdev_get_id(rdev); - switch (rdev_get_id(rdev)) { + switch (rdev_id) { case S2MPU02_BUCK1: ramp_shift = S2MPU02_BUCK1_RAMP_SHIFT; break; @@ -885,24 +918,24 @@ static const struct regulator_ops s2mpu02_ldo_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = s2mps14_regulator_enable, + .enable = s2mps11_regulator_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_suspend_disable = s2mps14_regulator_set_suspend_disable, + .set_suspend_disable = s2mps11_regulator_set_suspend_disable, }; static const struct regulator_ops s2mpu02_buck_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = s2mps14_regulator_enable, + .enable = s2mps11_regulator_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_suspend_disable = s2mps14_regulator_set_suspend_disable, + .set_suspend_disable = s2mps11_regulator_set_suspend_disable, .set_ramp_delay = s2mpu02_set_ramp_delay, }; diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index bb9d1a083299..6ca27e9d5ef7 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -574,7 +574,9 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, 0, GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, "s5m8767"); - if (IS_ERR(rdata->ext_control_gpiod)) + if (PTR_ERR(rdata->ext_control_gpiod) == -ENOENT) + rdata->ext_control_gpiod = NULL; + else if (IS_ERR(rdata->ext_control_gpiod)) return PTR_ERR(rdata->ext_control_gpiod); rdata->id = i; diff --git a/drivers/regulator/slg51000-regulator.c b/drivers/regulator/slg51000-regulator.c new file mode 100644 index 000000000000..04b732991d69 --- /dev/null +++ b/drivers/regulator/slg51000-regulator.c @@ -0,0 +1,523 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// SLG51000 High PSRR, Multi-Output Regulators +// Copyright (C) 2019 Dialog Semiconductor +// +// Author: Eric Jeong <eric.jeong.opensource@diasemi.com> + +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include "slg51000-regulator.h" + +#define SLG51000_SCTL_EVT 7 +#define SLG51000_MAX_EVT_REGISTER 8 +#define SLG51000_LDOHP_LV_MIN 1200000 +#define SLG51000_LDOHP_HV_MIN 2400000 + +enum slg51000_regulators { + SLG51000_REGULATOR_LDO1 = 0, + SLG51000_REGULATOR_LDO2, + SLG51000_REGULATOR_LDO3, + SLG51000_REGULATOR_LDO4, + SLG51000_REGULATOR_LDO5, + SLG51000_REGULATOR_LDO6, + SLG51000_REGULATOR_LDO7, + SLG51000_MAX_REGULATORS, +}; + +struct slg51000 { + struct device *dev; + struct regmap *regmap; + struct regulator_desc *rdesc[SLG51000_MAX_REGULATORS]; + struct regulator_dev *rdev[SLG51000_MAX_REGULATORS]; + struct gpio_desc *cs_gpiod; + int chip_irq; +}; + +struct slg51000_evt_sta { + unsigned int ereg; + unsigned int sreg; +}; + +static const struct slg51000_evt_sta es_reg[SLG51000_MAX_EVT_REGISTER] = { + {SLG51000_LDO1_EVENT, SLG51000_LDO1_STATUS}, + {SLG51000_LDO2_EVENT, SLG51000_LDO2_STATUS}, + {SLG51000_LDO3_EVENT, SLG51000_LDO3_STATUS}, + {SLG51000_LDO4_EVENT, SLG51000_LDO4_STATUS}, + {SLG51000_LDO5_EVENT, SLG51000_LDO5_STATUS}, + {SLG51000_LDO6_EVENT, SLG51000_LDO6_STATUS}, + {SLG51000_LDO7_EVENT, SLG51000_LDO7_STATUS}, + {SLG51000_SYSCTL_EVENT, SLG51000_SYSCTL_STATUS}, +}; + +static const struct regmap_range slg51000_writeable_ranges[] = { + regmap_reg_range(SLG51000_SYSCTL_MATRIX_CONF_A, + SLG51000_SYSCTL_MATRIX_CONF_A), + regmap_reg_range(SLG51000_LDO1_VSEL, SLG51000_LDO1_VSEL), + regmap_reg_range(SLG51000_LDO1_MINV, SLG51000_LDO1_MAXV), + regmap_reg_range(SLG51000_LDO1_IRQ_MASK, SLG51000_LDO1_IRQ_MASK), + regmap_reg_range(SLG51000_LDO2_VSEL, SLG51000_LDO2_VSEL), + regmap_reg_range(SLG51000_LDO2_MINV, SLG51000_LDO2_MAXV), + regmap_reg_range(SLG51000_LDO2_IRQ_MASK, SLG51000_LDO2_IRQ_MASK), + regmap_reg_range(SLG51000_LDO3_VSEL, SLG51000_LDO3_VSEL), + regmap_reg_range(SLG51000_LDO3_MINV, SLG51000_LDO3_MAXV), + regmap_reg_range(SLG51000_LDO3_IRQ_MASK, SLG51000_LDO3_IRQ_MASK), + regmap_reg_range(SLG51000_LDO4_VSEL, SLG51000_LDO4_VSEL), + regmap_reg_range(SLG51000_LDO4_MINV, SLG51000_LDO4_MAXV), + regmap_reg_range(SLG51000_LDO4_IRQ_MASK, SLG51000_LDO4_IRQ_MASK), + regmap_reg_range(SLG51000_LDO5_VSEL, SLG51000_LDO5_VSEL), + regmap_reg_range(SLG51000_LDO5_MINV, SLG51000_LDO5_MAXV), + regmap_reg_range(SLG51000_LDO5_IRQ_MASK, SLG51000_LDO5_IRQ_MASK), + regmap_reg_range(SLG51000_LDO6_VSEL, SLG51000_LDO6_VSEL), + regmap_reg_range(SLG51000_LDO6_MINV, SLG51000_LDO6_MAXV), + regmap_reg_range(SLG51000_LDO6_IRQ_MASK, SLG51000_LDO6_IRQ_MASK), + regmap_reg_range(SLG51000_LDO7_VSEL, SLG51000_LDO7_VSEL), + regmap_reg_range(SLG51000_LDO7_MINV, SLG51000_LDO7_MAXV), + regmap_reg_range(SLG51000_LDO7_IRQ_MASK, SLG51000_LDO7_IRQ_MASK), + regmap_reg_range(SLG51000_OTP_IRQ_MASK, SLG51000_OTP_IRQ_MASK), +}; + +static const struct regmap_range slg51000_readable_ranges[] = { + regmap_reg_range(SLG51000_SYSCTL_PATN_ID_B0, + SLG51000_SYSCTL_PATN_ID_B2), + regmap_reg_range(SLG51000_SYSCTL_SYS_CONF_A, + SLG51000_SYSCTL_SYS_CONF_A), + regmap_reg_range(SLG51000_SYSCTL_SYS_CONF_D, + SLG51000_SYSCTL_MATRIX_CONF_B), + regmap_reg_range(SLG51000_SYSCTL_REFGEN_CONF_C, + SLG51000_SYSCTL_UVLO_CONF_A), + regmap_reg_range(SLG51000_SYSCTL_FAULT_LOG1, SLG51000_SYSCTL_IRQ_MASK), + regmap_reg_range(SLG51000_IO_GPIO1_CONF, SLG51000_IO_GPIO_STATUS), + regmap_reg_range(SLG51000_LUTARRAY_LUT_VAL_0, + SLG51000_LUTARRAY_LUT_VAL_11), + regmap_reg_range(SLG51000_MUXARRAY_INPUT_SEL_0, + SLG51000_MUXARRAY_INPUT_SEL_63), + regmap_reg_range(SLG51000_PWRSEQ_RESOURCE_EN_0, + SLG51000_PWRSEQ_INPUT_SENSE_CONF_B), + regmap_reg_range(SLG51000_LDO1_VSEL, SLG51000_LDO1_VSEL), + regmap_reg_range(SLG51000_LDO1_MINV, SLG51000_LDO1_MAXV), + regmap_reg_range(SLG51000_LDO1_MISC1, SLG51000_LDO1_VSEL_ACTUAL), + regmap_reg_range(SLG51000_LDO1_EVENT, SLG51000_LDO1_IRQ_MASK), + regmap_reg_range(SLG51000_LDO2_VSEL, SLG51000_LDO2_VSEL), + regmap_reg_range(SLG51000_LDO2_MINV, SLG51000_LDO2_MAXV), + regmap_reg_range(SLG51000_LDO2_MISC1, SLG51000_LDO2_VSEL_ACTUAL), + regmap_reg_range(SLG51000_LDO2_EVENT, SLG51000_LDO2_IRQ_MASK), + regmap_reg_range(SLG51000_LDO3_VSEL, SLG51000_LDO3_VSEL), + regmap_reg_range(SLG51000_LDO3_MINV, SLG51000_LDO3_MAXV), + regmap_reg_range(SLG51000_LDO3_CONF1, SLG51000_LDO3_VSEL_ACTUAL), + regmap_reg_range(SLG51000_LDO3_EVENT, SLG51000_LDO3_IRQ_MASK), + regmap_reg_range(SLG51000_LDO4_VSEL, SLG51000_LDO4_VSEL), + regmap_reg_range(SLG51000_LDO4_MINV, SLG51000_LDO4_MAXV), + regmap_reg_range(SLG51000_LDO4_CONF1, SLG51000_LDO4_VSEL_ACTUAL), + regmap_reg_range(SLG51000_LDO4_EVENT, SLG51000_LDO4_IRQ_MASK), + regmap_reg_range(SLG51000_LDO5_VSEL, SLG51000_LDO5_VSEL), + regmap_reg_range(SLG51000_LDO5_MINV, SLG51000_LDO5_MAXV), + regmap_reg_range(SLG51000_LDO5_TRIM2, SLG51000_LDO5_TRIM2), + regmap_reg_range(SLG51000_LDO5_CONF1, SLG51000_LDO5_VSEL_ACTUAL), + regmap_reg_range(SLG51000_LDO5_EVENT, SLG51000_LDO5_IRQ_MASK), + regmap_reg_range(SLG51000_LDO6_VSEL, SLG51000_LDO6_VSEL), + regmap_reg_range(SLG51000_LDO6_MINV, SLG51000_LDO6_MAXV), + regmap_reg_range(SLG51000_LDO6_TRIM2, SLG51000_LDO6_TRIM2), + regmap_reg_range(SLG51000_LDO6_CONF1, SLG51000_LDO6_VSEL_ACTUAL), + regmap_reg_range(SLG51000_LDO6_EVENT, SLG51000_LDO6_IRQ_MASK), + regmap_reg_range(SLG51000_LDO7_VSEL, SLG51000_LDO7_VSEL), + regmap_reg_range(SLG51000_LDO7_MINV, SLG51000_LDO7_MAXV), + regmap_reg_range(SLG51000_LDO7_CONF1, SLG51000_LDO7_VSEL_ACTUAL), + regmap_reg_range(SLG51000_LDO7_EVENT, SLG51000_LDO7_IRQ_MASK), + regmap_reg_range(SLG51000_OTP_EVENT, SLG51000_OTP_EVENT), + regmap_reg_range(SLG51000_OTP_IRQ_MASK, SLG51000_OTP_IRQ_MASK), + regmap_reg_range(SLG51000_OTP_LOCK_OTP_PROG, SLG51000_OTP_LOCK_CTRL), + regmap_reg_range(SLG51000_LOCK_GLOBAL_LOCK_CTRL1, + SLG51000_LOCK_GLOBAL_LOCK_CTRL1), +}; + +static const struct regmap_range slg51000_volatile_ranges[] = { + regmap_reg_range(SLG51000_SYSCTL_FAULT_LOG1, SLG51000_SYSCTL_STATUS), + regmap_reg_range(SLG51000_IO_GPIO_STATUS, SLG51000_IO_GPIO_STATUS), + regmap_reg_range(SLG51000_LDO1_EVENT, SLG51000_LDO1_STATUS), + regmap_reg_range(SLG51000_LDO2_EVENT, SLG51000_LDO2_STATUS), + regmap_reg_range(SLG51000_LDO3_EVENT, SLG51000_LDO3_STATUS), + regmap_reg_range(SLG51000_LDO4_EVENT, SLG51000_LDO4_STATUS), + regmap_reg_range(SLG51000_LDO5_EVENT, SLG51000_LDO5_STATUS), + regmap_reg_range(SLG51000_LDO6_EVENT, SLG51000_LDO6_STATUS), + regmap_reg_range(SLG51000_LDO7_EVENT, SLG51000_LDO7_STATUS), + regmap_reg_range(SLG51000_OTP_EVENT, SLG51000_OTP_EVENT), +}; + +static const struct regmap_access_table slg51000_writeable_table = { + .yes_ranges = slg51000_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(slg51000_writeable_ranges), +}; + +static const struct regmap_access_table slg51000_readable_table = { + .yes_ranges = slg51000_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(slg51000_readable_ranges), +}; + +static const struct regmap_access_table slg51000_volatile_table = { + .yes_ranges = slg51000_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(slg51000_volatile_ranges), +}; + +static const struct regmap_config slg51000_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = 0x8000, + .wr_table = &slg51000_writeable_table, + .rd_table = &slg51000_readable_table, + .volatile_table = &slg51000_volatile_table, +}; + +static const struct regulator_ops slg51000_regl_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static const struct regulator_ops slg51000_switch_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static int slg51000_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct slg51000 *chip = config->driver_data; + struct gpio_desc *ena_gpiod; + enum gpiod_flags gflags = GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE; + + ena_gpiod = devm_gpiod_get_from_of_node(chip->dev, np, + "enable-gpios", 0, + gflags, "gpio-en-ldo"); + if (ena_gpiod) { + config->ena_gpiod = ena_gpiod; + devm_gpiod_unhinge(chip->dev, config->ena_gpiod); + } + + return 0; +} + +#define SLG51000_REGL_DESC(_id, _name, _s_name, _min, _step) \ + [SLG51000_REGULATOR_##_id] = { \ + .name = #_name, \ + .supply_name = _s_name, \ + .id = SLG51000_REGULATOR_##_id, \ + .of_match = of_match_ptr(#_name), \ + .of_parse_cb = slg51000_of_parse_cb, \ + .ops = &slg51000_regl_ops, \ + .regulators_node = of_match_ptr("regulators"), \ + .n_voltages = 256, \ + .min_uV = _min, \ + .uV_step = _step, \ + .linear_min_sel = 0, \ + .vsel_mask = SLG51000_VSEL_MASK, \ + .vsel_reg = SLG51000_##_id##_VSEL, \ + .enable_reg = SLG51000_SYSCTL_MATRIX_CONF_A, \ + .enable_mask = BIT(SLG51000_REGULATOR_##_id), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + } + +static struct regulator_desc regls_desc[SLG51000_MAX_REGULATORS] = { + SLG51000_REGL_DESC(LDO1, ldo1, NULL, 2400000, 5000), + SLG51000_REGL_DESC(LDO2, ldo2, NULL, 2400000, 5000), + SLG51000_REGL_DESC(LDO3, ldo3, "vin3", 1200000, 10000), + SLG51000_REGL_DESC(LDO4, ldo4, "vin4", 1200000, 10000), + SLG51000_REGL_DESC(LDO5, ldo5, "vin5", 400000, 5000), + SLG51000_REGL_DESC(LDO6, ldo6, "vin6", 400000, 5000), + SLG51000_REGL_DESC(LDO7, ldo7, "vin7", 1200000, 10000), +}; + +static int slg51000_regulator_init(struct slg51000 *chip) +{ + struct regulator_config config = { }; + struct regulator_desc *rdesc; + unsigned int reg, val; + u8 vsel_range[2]; + int id, ret = 0; + const unsigned int min_regs[SLG51000_MAX_REGULATORS] = { + SLG51000_LDO1_MINV, SLG51000_LDO2_MINV, SLG51000_LDO3_MINV, + SLG51000_LDO4_MINV, SLG51000_LDO5_MINV, SLG51000_LDO6_MINV, + SLG51000_LDO7_MINV, + }; + + for (id = 0; id < SLG51000_MAX_REGULATORS; id++) { + chip->rdesc[id] = ®ls_desc[id]; + rdesc = chip->rdesc[id]; + config.regmap = chip->regmap; + config.dev = chip->dev; + config.driver_data = chip; + + ret = regmap_bulk_read(chip->regmap, min_regs[id], + vsel_range, 2); + if (ret < 0) { + dev_err(chip->dev, + "Failed to read the MIN register\n"); + return ret; + } + + switch (id) { + case SLG51000_REGULATOR_LDO1: + case SLG51000_REGULATOR_LDO2: + if (id == SLG51000_REGULATOR_LDO1) + reg = SLG51000_LDO1_MISC1; + else + reg = SLG51000_LDO2_MISC1; + + ret = regmap_read(chip->regmap, reg, &val); + if (ret < 0) { + dev_err(chip->dev, + "Failed to read voltage range of ldo%d\n", + id + 1); + return ret; + } + + rdesc->linear_min_sel = vsel_range[0]; + rdesc->n_voltages = vsel_range[1] + 1; + if (val & SLG51000_SEL_VRANGE_MASK) + rdesc->min_uV = SLG51000_LDOHP_HV_MIN + + (vsel_range[0] + * rdesc->uV_step); + else + rdesc->min_uV = SLG51000_LDOHP_LV_MIN + + (vsel_range[0] + * rdesc->uV_step); + break; + + case SLG51000_REGULATOR_LDO5: + case SLG51000_REGULATOR_LDO6: + if (id == SLG51000_REGULATOR_LDO5) + reg = SLG51000_LDO5_TRIM2; + else + reg = SLG51000_LDO6_TRIM2; + + ret = regmap_read(chip->regmap, reg, &val); + if (ret < 0) { + dev_err(chip->dev, + "Failed to read LDO mode register\n"); + return ret; + } + + if (val & SLG51000_SEL_BYP_MODE_MASK) { + rdesc->ops = &slg51000_switch_ops; + rdesc->n_voltages = 0; + rdesc->min_uV = 0; + rdesc->uV_step = 0; + rdesc->linear_min_sel = 0; + break; + } + /* Fall through - to the check below.*/ + + default: + rdesc->linear_min_sel = vsel_range[0]; + rdesc->n_voltages = vsel_range[1] + 1; + rdesc->min_uV = rdesc->min_uV + + (vsel_range[0] * rdesc->uV_step); + break; + } + + chip->rdev[id] = devm_regulator_register(chip->dev, rdesc, + &config); + if (IS_ERR(chip->rdev[id])) { + ret = PTR_ERR(chip->rdev[id]); + dev_err(chip->dev, + "Failed to register regulator(%s):%d\n", + chip->rdesc[id]->name, ret); + return ret; + } + } + + return 0; +} + +static irqreturn_t slg51000_irq_handler(int irq, void *data) +{ + struct slg51000 *chip = data; + struct regmap *regmap = chip->regmap; + enum { R0 = 0, R1, R2, REG_MAX }; + u8 evt[SLG51000_MAX_EVT_REGISTER][REG_MAX]; + int ret, i, handled = IRQ_NONE; + unsigned int evt_otp, mask_otp; + + /* Read event[R0], status[R1] and mask[R2] register */ + for (i = 0; i < SLG51000_MAX_EVT_REGISTER; i++) { + ret = regmap_bulk_read(regmap, es_reg[i].ereg, evt[i], REG_MAX); + if (ret < 0) { + dev_err(chip->dev, + "Failed to read event registers(%d)\n", ret); + return IRQ_NONE; + } + } + + ret = regmap_read(regmap, SLG51000_OTP_EVENT, &evt_otp); + if (ret < 0) { + dev_err(chip->dev, + "Failed to read otp event registers(%d)\n", ret); + return IRQ_NONE; + } + + ret = regmap_read(regmap, SLG51000_OTP_IRQ_MASK, &mask_otp); + if (ret < 0) { + dev_err(chip->dev, + "Failed to read otp mask register(%d)\n", ret); + return IRQ_NONE; + } + + if ((evt_otp & SLG51000_EVT_CRC_MASK) && + !(mask_otp & SLG51000_IRQ_CRC_MASK)) { + dev_info(chip->dev, + "OTP has been read or OTP crc is not zero\n"); + handled = IRQ_HANDLED; + } + + for (i = 0; i < SLG51000_MAX_REGULATORS; i++) { + if (!(evt[i][R2] & SLG51000_IRQ_ILIM_FLAG_MASK) && + (evt[i][R0] & SLG51000_EVT_ILIM_FLAG_MASK)) { + regulator_lock(chip->rdev[i]); + regulator_notifier_call_chain(chip->rdev[i], + REGULATOR_EVENT_OVER_CURRENT, NULL); + regulator_unlock(chip->rdev[i]); + + if (evt[i][R1] & SLG51000_STA_ILIM_FLAG_MASK) + dev_warn(chip->dev, + "Over-current limit(ldo%d)\n", i + 1); + handled = IRQ_HANDLED; + } + } + + if (!(evt[SLG51000_SCTL_EVT][R2] & SLG51000_IRQ_HIGH_TEMP_WARN_MASK) && + (evt[SLG51000_SCTL_EVT][R0] & SLG51000_EVT_HIGH_TEMP_WARN_MASK)) { + for (i = 0; i < SLG51000_MAX_REGULATORS; i++) { + if (!(evt[i][R1] & SLG51000_STA_ILIM_FLAG_MASK) && + (evt[i][R1] & SLG51000_STA_VOUT_OK_FLAG_MASK)) { + regulator_lock(chip->rdev[i]); + regulator_notifier_call_chain(chip->rdev[i], + REGULATOR_EVENT_OVER_TEMP, NULL); + regulator_unlock(chip->rdev[i]); + } + } + handled = IRQ_HANDLED; + if (evt[SLG51000_SCTL_EVT][R1] & + SLG51000_STA_HIGH_TEMP_WARN_MASK) + dev_warn(chip->dev, "High temperature warning!\n"); + } + + return handled; +} + +static void slg51000_clear_fault_log(struct slg51000 *chip) +{ + unsigned int val = 0; + int ret = 0; + + ret = regmap_read(chip->regmap, SLG51000_SYSCTL_FAULT_LOG1, &val); + if (ret < 0) { + dev_err(chip->dev, "Failed to read Fault log register\n"); + return; + } + + if (val & SLG51000_FLT_OVER_TEMP_MASK) + dev_dbg(chip->dev, "Fault log: FLT_OVER_TEMP\n"); + if (val & SLG51000_FLT_POWER_SEQ_CRASH_REQ_MASK) + dev_dbg(chip->dev, "Fault log: FLT_POWER_SEQ_CRASH_REQ\n"); + if (val & SLG51000_FLT_RST_MASK) + dev_dbg(chip->dev, "Fault log: FLT_RST\n"); + if (val & SLG51000_FLT_POR_MASK) + dev_dbg(chip->dev, "Fault log: FLT_POR\n"); +} + +static int slg51000_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct slg51000 *chip; + struct gpio_desc *cs_gpiod = NULL; + int error, ret; + + chip = devm_kzalloc(dev, sizeof(struct slg51000), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + cs_gpiod = devm_gpiod_get_from_of_node(dev, dev->of_node, + "dlg,cs-gpios", 0, + GPIOD_OUT_HIGH + | GPIOD_FLAGS_BIT_NONEXCLUSIVE, + "slg51000-cs"); + if (cs_gpiod) { + dev_info(dev, "Found chip selector property\n"); + chip->cs_gpiod = cs_gpiod; + } + + i2c_set_clientdata(client, chip); + chip->chip_irq = client->irq; + chip->dev = dev; + chip->regmap = devm_regmap_init_i2c(client, &slg51000_regmap_config); + if (IS_ERR(chip->regmap)) { + error = PTR_ERR(chip->regmap); + dev_err(dev, "Failed to allocate register map: %d\n", + error); + return error; + } + + ret = slg51000_regulator_init(chip); + if (ret < 0) { + dev_err(chip->dev, "Failed to init regulator(%d)\n", ret); + return ret; + } + + slg51000_clear_fault_log(chip); + + if (chip->chip_irq) { + ret = devm_request_threaded_irq(dev, chip->chip_irq, NULL, + slg51000_irq_handler, + (IRQF_TRIGGER_HIGH | + IRQF_ONESHOT), + "slg51000-irq", chip); + if (ret != 0) { + dev_err(dev, "Failed to request IRQ: %d\n", + chip->chip_irq); + return ret; + } + } else { + dev_info(dev, "No IRQ configured\n"); + } + + return ret; +} + +static const struct i2c_device_id slg51000_i2c_id[] = { + {"slg51000", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, slg51000_i2c_id); + +static struct i2c_driver slg51000_regulator_driver = { + .driver = { + .name = "slg51000-regulator", + }, + .probe = slg51000_i2c_probe, + .id_table = slg51000_i2c_id, +}; + +module_i2c_driver(slg51000_regulator_driver); + +MODULE_AUTHOR("Eric Jeong <eric.jeong.opensource@diasemi.com>"); +MODULE_DESCRIPTION("SLG51000 regulator driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/regulator/slg51000-regulator.h b/drivers/regulator/slg51000-regulator.h new file mode 100644 index 000000000000..20feb7f91942 --- /dev/null +++ b/drivers/regulator/slg51000-regulator.h @@ -0,0 +1,505 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * SLG51000 High PSRR, Multi-Output Regulators + * Copyright (C) 2019 Dialog Semiconductor + * + * Author: Eric Jeong <eric.jeong.opensource@diasemi.com> + */ + +#ifndef __SLG51000_REGISTERS_H__ +#define __SLG51000_REGISTERS_H__ + +/* Registers */ + +#define SLG51000_SYSCTL_PATN_ID_B0 0x1105 +#define SLG51000_SYSCTL_PATN_ID_B1 0x1106 +#define SLG51000_SYSCTL_PATN_ID_B2 0x1107 +#define SLG51000_SYSCTL_SYS_CONF_A 0x1109 +#define SLG51000_SYSCTL_SYS_CONF_D 0x110c +#define SLG51000_SYSCTL_MATRIX_CONF_A 0x110d +#define SLG51000_SYSCTL_MATRIX_CONF_B 0x110e +#define SLG51000_SYSCTL_REFGEN_CONF_C 0x1111 +#define SLG51000_SYSCTL_UVLO_CONF_A 0x1112 +#define SLG51000_SYSCTL_FAULT_LOG1 0x1115 +#define SLG51000_SYSCTL_EVENT 0x1116 +#define SLG51000_SYSCTL_STATUS 0x1117 +#define SLG51000_SYSCTL_IRQ_MASK 0x1118 +#define SLG51000_IO_GPIO1_CONF 0x1500 +#define SLG51000_IO_GPIO2_CONF 0x1501 +#define SLG51000_IO_GPIO3_CONF 0x1502 +#define SLG51000_IO_GPIO4_CONF 0x1503 +#define SLG51000_IO_GPIO5_CONF 0x1504 +#define SLG51000_IO_GPIO6_CONF 0x1505 +#define SLG51000_IO_GPIO_STATUS 0x1506 +#define SLG51000_LUTARRAY_LUT_VAL_0 0x1600 +#define SLG51000_LUTARRAY_LUT_VAL_1 0x1601 +#define SLG51000_LUTARRAY_LUT_VAL_2 0x1602 +#define SLG51000_LUTARRAY_LUT_VAL_3 0x1603 +#define SLG51000_LUTARRAY_LUT_VAL_4 0x1604 +#define SLG51000_LUTARRAY_LUT_VAL_5 0x1605 +#define SLG51000_LUTARRAY_LUT_VAL_6 0x1606 +#define SLG51000_LUTARRAY_LUT_VAL_7 0x1607 +#define SLG51000_LUTARRAY_LUT_VAL_8 0x1608 +#define SLG51000_LUTARRAY_LUT_VAL_9 0x1609 +#define SLG51000_LUTARRAY_LUT_VAL_10 0x160a +#define SLG51000_LUTARRAY_LUT_VAL_11 0x160b +#define SLG51000_MUXARRAY_INPUT_SEL_0 0x1700 +#define SLG51000_MUXARRAY_INPUT_SEL_1 0x1701 +#define SLG51000_MUXARRAY_INPUT_SEL_2 0x1702 +#define SLG51000_MUXARRAY_INPUT_SEL_3 0x1703 +#define SLG51000_MUXARRAY_INPUT_SEL_4 0x1704 +#define SLG51000_MUXARRAY_INPUT_SEL_5 0x1705 +#define SLG51000_MUXARRAY_INPUT_SEL_6 0x1706 +#define SLG51000_MUXARRAY_INPUT_SEL_7 0x1707 +#define SLG51000_MUXARRAY_INPUT_SEL_8 0x1708 +#define SLG51000_MUXARRAY_INPUT_SEL_9 0x1709 +#define SLG51000_MUXARRAY_INPUT_SEL_10 0x170a +#define SLG51000_MUXARRAY_INPUT_SEL_11 0x170b +#define SLG51000_MUXARRAY_INPUT_SEL_12 0x170c +#define SLG51000_MUXARRAY_INPUT_SEL_13 0x170d +#define SLG51000_MUXARRAY_INPUT_SEL_14 0x170e +#define SLG51000_MUXARRAY_INPUT_SEL_15 0x170f +#define SLG51000_MUXARRAY_INPUT_SEL_16 0x1710 +#define SLG51000_MUXARRAY_INPUT_SEL_17 0x1711 +#define SLG51000_MUXARRAY_INPUT_SEL_18 0x1712 +#define SLG51000_MUXARRAY_INPUT_SEL_19 0x1713 +#define SLG51000_MUXARRAY_INPUT_SEL_20 0x1714 +#define SLG51000_MUXARRAY_INPUT_SEL_21 0x1715 +#define SLG51000_MUXARRAY_INPUT_SEL_22 0x1716 +#define SLG51000_MUXARRAY_INPUT_SEL_23 0x1717 +#define SLG51000_MUXARRAY_INPUT_SEL_24 0x1718 +#define SLG51000_MUXARRAY_INPUT_SEL_25 0x1719 +#define SLG51000_MUXARRAY_INPUT_SEL_26 0x171a +#define SLG51000_MUXARRAY_INPUT_SEL_27 0x171b +#define SLG51000_MUXARRAY_INPUT_SEL_28 0x171c +#define SLG51000_MUXARRAY_INPUT_SEL_29 0x171d +#define SLG51000_MUXARRAY_INPUT_SEL_30 0x171e +#define SLG51000_MUXARRAY_INPUT_SEL_31 0x171f +#define SLG51000_MUXARRAY_INPUT_SEL_32 0x1720 +#define SLG51000_MUXARRAY_INPUT_SEL_33 0x1721 +#define SLG51000_MUXARRAY_INPUT_SEL_34 0x1722 +#define SLG51000_MUXARRAY_INPUT_SEL_35 0x1723 +#define SLG51000_MUXARRAY_INPUT_SEL_36 0x1724 +#define SLG51000_MUXARRAY_INPUT_SEL_37 0x1725 +#define SLG51000_MUXARRAY_INPUT_SEL_38 0x1726 +#define SLG51000_MUXARRAY_INPUT_SEL_39 0x1727 +#define SLG51000_MUXARRAY_INPUT_SEL_40 0x1728 +#define SLG51000_MUXARRAY_INPUT_SEL_41 0x1729 +#define SLG51000_MUXARRAY_INPUT_SEL_42 0x172a +#define SLG51000_MUXARRAY_INPUT_SEL_43 0x172b +#define SLG51000_MUXARRAY_INPUT_SEL_44 0x172c +#define SLG51000_MUXARRAY_INPUT_SEL_45 0x172d +#define SLG51000_MUXARRAY_INPUT_SEL_46 0x172e +#define SLG51000_MUXARRAY_INPUT_SEL_47 0x172f +#define SLG51000_MUXARRAY_INPUT_SEL_48 0x1730 +#define SLG51000_MUXARRAY_INPUT_SEL_49 0x1731 +#define SLG51000_MUXARRAY_INPUT_SEL_50 0x1732 +#define SLG51000_MUXARRAY_INPUT_SEL_51 0x1733 +#define SLG51000_MUXARRAY_INPUT_SEL_52 0x1734 +#define SLG51000_MUXARRAY_INPUT_SEL_53 0x1735 +#define SLG51000_MUXARRAY_INPUT_SEL_54 0x1736 +#define SLG51000_MUXARRAY_INPUT_SEL_55 0x1737 +#define SLG51000_MUXARRAY_INPUT_SEL_56 0x1738 +#define SLG51000_MUXARRAY_INPUT_SEL_57 0x1739 +#define SLG51000_MUXARRAY_INPUT_SEL_58 0x173a +#define SLG51000_MUXARRAY_INPUT_SEL_59 0x173b +#define SLG51000_MUXARRAY_INPUT_SEL_60 0x173c +#define SLG51000_MUXARRAY_INPUT_SEL_61 0x173d +#define SLG51000_MUXARRAY_INPUT_SEL_62 0x173e +#define SLG51000_MUXARRAY_INPUT_SEL_63 0x173f +#define SLG51000_PWRSEQ_RESOURCE_EN_0 0x1900 +#define SLG51000_PWRSEQ_RESOURCE_EN_1 0x1901 +#define SLG51000_PWRSEQ_RESOURCE_EN_2 0x1902 +#define SLG51000_PWRSEQ_RESOURCE_EN_3 0x1903 +#define SLG51000_PWRSEQ_RESOURCE_EN_4 0x1904 +#define SLG51000_PWRSEQ_RESOURCE_EN_5 0x1905 +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP0 0x1906 +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN0 0x1907 +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP1 0x1908 +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN1 0x1909 +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP2 0x190a +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN2 0x190b +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP3 0x190c +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN3 0x190d +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP4 0x190e +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN4 0x190f +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP5 0x1910 +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN5 0x1911 +#define SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_A 0x1912 +#define SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_B 0x1913 +#define SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_C 0x1914 +#define SLG51000_PWRSEQ_INPUT_SENSE_CONF_A 0x1915 +#define SLG51000_PWRSEQ_INPUT_SENSE_CONF_B 0x1916 +#define SLG51000_LDO1_VSEL 0x2000 +#define SLG51000_LDO1_MINV 0x2060 +#define SLG51000_LDO1_MAXV 0x2061 +#define SLG51000_LDO1_MISC1 0x2064 +#define SLG51000_LDO1_VSEL_ACTUAL 0x2065 +#define SLG51000_LDO1_EVENT 0x20c0 +#define SLG51000_LDO1_STATUS 0x20c1 +#define SLG51000_LDO1_IRQ_MASK 0x20c2 +#define SLG51000_LDO2_VSEL 0x2200 +#define SLG51000_LDO2_MINV 0x2260 +#define SLG51000_LDO2_MAXV 0x2261 +#define SLG51000_LDO2_MISC1 0x2264 +#define SLG51000_LDO2_VSEL_ACTUAL 0x2265 +#define SLG51000_LDO2_EVENT 0x22c0 +#define SLG51000_LDO2_STATUS 0x22c1 +#define SLG51000_LDO2_IRQ_MASK 0x22c2 +#define SLG51000_LDO3_VSEL 0x2300 +#define SLG51000_LDO3_MINV 0x2360 +#define SLG51000_LDO3_MAXV 0x2361 +#define SLG51000_LDO3_CONF1 0x2364 +#define SLG51000_LDO3_CONF2 0x2365 +#define SLG51000_LDO3_VSEL_ACTUAL 0x2366 +#define SLG51000_LDO3_EVENT 0x23c0 +#define SLG51000_LDO3_STATUS 0x23c1 +#define SLG51000_LDO3_IRQ_MASK 0x23c2 +#define SLG51000_LDO4_VSEL 0x2500 +#define SLG51000_LDO4_MINV 0x2560 +#define SLG51000_LDO4_MAXV 0x2561 +#define SLG51000_LDO4_CONF1 0x2564 +#define SLG51000_LDO4_CONF2 0x2565 +#define SLG51000_LDO4_VSEL_ACTUAL 0x2566 +#define SLG51000_LDO4_EVENT 0x25c0 +#define SLG51000_LDO4_STATUS 0x25c1 +#define SLG51000_LDO4_IRQ_MASK 0x25c2 +#define SLG51000_LDO5_VSEL 0x2700 +#define SLG51000_LDO5_MINV 0x2760 +#define SLG51000_LDO5_MAXV 0x2761 +#define SLG51000_LDO5_TRIM2 0x2763 +#define SLG51000_LDO5_CONF1 0x2765 +#define SLG51000_LDO5_CONF2 0x2766 +#define SLG51000_LDO5_VSEL_ACTUAL 0x2767 +#define SLG51000_LDO5_EVENT 0x27c0 +#define SLG51000_LDO5_STATUS 0x27c1 +#define SLG51000_LDO5_IRQ_MASK 0x27c2 +#define SLG51000_LDO6_VSEL 0x2900 +#define SLG51000_LDO6_MINV 0x2960 +#define SLG51000_LDO6_MAXV 0x2961 +#define SLG51000_LDO6_TRIM2 0x2963 +#define SLG51000_LDO6_CONF1 0x2965 +#define SLG51000_LDO6_CONF2 0x2966 +#define SLG51000_LDO6_VSEL_ACTUAL 0x2967 +#define SLG51000_LDO6_EVENT 0x29c0 +#define SLG51000_LDO6_STATUS 0x29c1 +#define SLG51000_LDO6_IRQ_MASK 0x29c2 +#define SLG51000_LDO7_VSEL 0x3100 +#define SLG51000_LDO7_MINV 0x3160 +#define SLG51000_LDO7_MAXV 0x3161 +#define SLG51000_LDO7_CONF1 0x3164 +#define SLG51000_LDO7_CONF2 0x3165 +#define SLG51000_LDO7_VSEL_ACTUAL 0x3166 +#define SLG51000_LDO7_EVENT 0x31c0 +#define SLG51000_LDO7_STATUS 0x31c1 +#define SLG51000_LDO7_IRQ_MASK 0x31c2 +#define SLG51000_OTP_EVENT 0x782b +#define SLG51000_OTP_IRQ_MASK 0x782d +#define SLG51000_OTP_LOCK_OTP_PROG 0x78fe +#define SLG51000_OTP_LOCK_CTRL 0x78ff +#define SLG51000_LOCK_GLOBAL_LOCK_CTRL1 0x8000 + +/* Register Bit Fields */ + +/* SLG51000_SYSCTL_PATTERN_ID_BYTE0 = 0x1105 */ +#define SLG51000_PATTERN_ID_BYTE0_SHIFT 0 +#define SLG51000_PATTERN_ID_BYTE0_MASK (0xff << 0) + +/* SLG51000_SYSCTL_PATTERN_ID_BYTE1 = 0x1106 */ +#define SLG51000_PATTERN_ID_BYTE1_SHIFT 0 +#define SLG51000_PATTERN_ID_BYTE1_MASK (0xff << 0) + +/* SLG51000_SYSCTL_PATTERN_ID_BYTE2 = 0x1107 */ +#define SLG51000_PATTERN_ID_BYTE2_SHIFT 0 +#define SLG51000_PATTERN_ID_BYTE2_MASK (0xff << 0) + +/* SLG51000_SYSCTL_SYS_CONF_A = 0x1109 */ +#define SLG51000_I2C_ADDRESS_SHIFT 0 +#define SLG51000_I2C_ADDRESS_MASK (0x7f << 0) +#define SLG51000_I2C_DISABLE_SHIFT 7 +#define SLG51000_I2C_DISABLE_MASK (0x01 << 7) + +/* SLG51000_SYSCTL_SYS_CONF_D = 0x110c */ +#define SLG51000_CS_T_DEB_SHIFT 6 +#define SLG51000_CS_T_DEB_MASK (0x03 << 6) +#define SLG51000_I2C_CLR_MODE_SHIFT 5 +#define SLG51000_I2C_CLR_MODE_MASK (0x01 << 5) + +/* SLG51000_SYSCTL_MATRIX_CTRL_CONF_A = 0x110d */ +#define SLG51000_RESOURCE_CTRL_SHIFT 0 +#define SLG51000_RESOURCE_CTRL_MASK (0xff << 0) + +/* SLG51000_SYSCTL_MATRIX_CTRL_CONF_B = 0x110e */ +#define SLG51000_MATRIX_EVENT_SENSE_SHIFT 0 +#define SLG51000_MATRIX_EVENT_SENSE_MASK (0x07 << 0) + +/* SLG51000_SYSCTL_REFGEN_CONF_C = 0x1111 */ +#define SLG51000_REFGEN_SEL_TEMP_WARN_DEBOUNCE_SHIFT 2 +#define SLG51000_REFGEN_SEL_TEMP_WARN_DEBOUNCE_MASK (0x03 << 2) +#define SLG51000_REFGEN_SEL_TEMP_WARN_THR_SHIFT 0 +#define SLG51000_REFGEN_SEL_TEMP_WARN_THR_MASK (0x03 << 0) + +/* SLG51000_SYSCTL_UVLO_CONF_A = 0x1112 */ +#define SLG51000_VMON_UVLO_SEL_THR_SHIFT 0 +#define SLG51000_VMON_UVLO_SEL_THR_MASK (0x1f << 0) + +/* SLG51000_SYSCTL_FAULT_LOG1 = 0x1115 */ +#define SLG51000_FLT_POR_SHIFT 5 +#define SLG51000_FLT_POR_MASK (0x01 << 5) +#define SLG51000_FLT_RST_SHIFT 4 +#define SLG51000_FLT_RST_MASK (0x01 << 4) +#define SLG51000_FLT_POWER_SEQ_CRASH_REQ_SHIFT 2 +#define SLG51000_FLT_POWER_SEQ_CRASH_REQ_MASK (0x01 << 2) +#define SLG51000_FLT_OVER_TEMP_SHIFT 1 +#define SLG51000_FLT_OVER_TEMP_MASK (0x01 << 1) + +/* SLG51000_SYSCTL_EVENT = 0x1116 */ +#define SLG51000_EVT_MATRIX_SHIFT 1 +#define SLG51000_EVT_MATRIX_MASK (0x01 << 1) +#define SLG51000_EVT_HIGH_TEMP_WARN_SHIFT 0 +#define SLG51000_EVT_HIGH_TEMP_WARN_MASK (0x01 << 0) + +/* SLG51000_SYSCTL_STATUS = 0x1117 */ +#define SLG51000_STA_MATRIX_SHIFT 1 +#define SLG51000_STA_MATRIX_MASK (0x01 << 1) +#define SLG51000_STA_HIGH_TEMP_WARN_SHIFT 0 +#define SLG51000_STA_HIGH_TEMP_WARN_MASK (0x01 << 0) + +/* SLG51000_SYSCTL_IRQ_MASK = 0x1118 */ +#define SLG51000_IRQ_MATRIX_SHIFT 1 +#define SLG51000_IRQ_MATRIX_MASK (0x01 << 1) +#define SLG51000_IRQ_HIGH_TEMP_WARN_SHIFT 0 +#define SLG51000_IRQ_HIGH_TEMP_WARN_MASK (0x01 << 0) + +/* SLG51000_IO_GPIO1_CONF ~ SLG51000_IO_GPIO5_CONF = + * 0x1500, 0x1501, 0x1502, 0x1503, 0x1504 + */ +#define SLG51000_GPIO_DIR_SHIFT 7 +#define SLG51000_GPIO_DIR_MASK (0x01 << 7) +#define SLG51000_GPIO_SENS_SHIFT 5 +#define SLG51000_GPIO_SENS_MASK (0x03 << 5) +#define SLG51000_GPIO_INVERT_SHIFT 4 +#define SLG51000_GPIO_INVERT_MASK (0x01 << 4) +#define SLG51000_GPIO_BYP_SHIFT 3 +#define SLG51000_GPIO_BYP_MASK (0x01 << 3) +#define SLG51000_GPIO_T_DEB_SHIFT 1 +#define SLG51000_GPIO_T_DEB_MASK (0x03 << 1) +#define SLG51000_GPIO_LEVEL_SHIFT 0 +#define SLG51000_GPIO_LEVEL_MASK (0x01 << 0) + +/* SLG51000_IO_GPIO6_CONF = 0x1505 */ +#define SLG51000_GPIO6_SENS_SHIFT 5 +#define SLG51000_GPIO6_SENS_MASK (0x03 << 5) +#define SLG51000_GPIO6_INVERT_SHIFT 4 +#define SLG51000_GPIO6_INVERT_MASK (0x01 << 4) +#define SLG51000_GPIO6_T_DEB_SHIFT 1 +#define SLG51000_GPIO6_T_DEB_MASK (0x03 << 1) +#define SLG51000_GPIO6_LEVEL_SHIFT 0 +#define SLG51000_GPIO6_LEVEL_MASK (0x01 << 0) + +/* SLG51000_IO_GPIO_STATUS = 0x1506 */ +#define SLG51000_GPIO6_STATUS_SHIFT 5 +#define SLG51000_GPIO6_STATUS_MASK (0x01 << 5) +#define SLG51000_GPIO5_STATUS_SHIFT 4 +#define SLG51000_GPIO5_STATUS_MASK (0x01 << 4) +#define SLG51000_GPIO4_STATUS_SHIFT 3 +#define SLG51000_GPIO4_STATUS_MASK (0x01 << 3) +#define SLG51000_GPIO3_STATUS_SHIFT 2 +#define SLG51000_GPIO3_STATUS_MASK (0x01 << 2) +#define SLG51000_GPIO2_STATUS_SHIFT 1 +#define SLG51000_GPIO2_STATUS_MASK (0x01 << 1) +#define SLG51000_GPIO1_STATUS_SHIFT 0 +#define SLG51000_GPIO1_STATUS_MASK (0x01 << 0) + +/* SLG51000_LUTARRAY_LUT_VAL_0 ~ SLG51000_LUTARRAY_LUT_VAL_11 + * 0x1600, 0x1601, 0x1602, 0x1603, 0x1604, 0x1605, + * 0x1606, 0x1607, 0x1608, 0x1609, 0x160a, 0x160b + */ +#define SLG51000_LUT_VAL_SHIFT 0 +#define SLG51000_LUT_VAL_MASK (0xff << 0) + +/* SLG51000_MUXARRAY_INPUT_SEL_0 ~ SLG51000_MUXARRAY_INPUT_SEL_63 + * 0x1700, 0x1701, 0x1702, 0x1703, 0x1704, 0x1705, + * 0x1706, 0x1707, 0x1708, 0x1709, 0x170a, 0x170b, + * 0x170c, 0x170d, 0x170e, 0x170f, 0x1710, 0x1711, + * 0x1712, 0x1713, 0x1714, 0x1715, 0x1716, 0x1717, + * 0x1718, 0x1719, 0x171a, 0x171b, 0x171c, 0x171d, + * 0x171e, 0x171f, 0x1720, 0x1721, 0x1722, 0x1723, + * 0x1724, 0x1725, 0x1726, 0x1727, 0x1728, 0x1729, + * 0x173a, 0x173b, 0x173c, 0x173d, 0x173e, 0x173f, + */ +#define SLG51000_INPUT_SEL_SHIFT 0 +#define SLG51000_INPUT_SEL_MASK (0x3f << 0) + +/* SLG51000_PWRSEQ_RESOURCE_EN_0 ~ SLG51000_PWRSEQ_RESOURCE_EN_5 + * 0x1900, 0x1901, 0x1902, 0x1903, 0x1904, 0x1905 + */ +#define SLG51000_RESOURCE_EN_DOWN0_SHIFT 4 +#define SLG51000_RESOURCE_EN_DOWN0_MASK (0x07 << 4) +#define SLG51000_RESOURCE_EN_UP0_SHIFT 0 +#define SLG51000_RESOURCE_EN_UP0_MASK (0x07 << 0) + +/* SLG51000_PWRSEQ_SLOT_TIME_MIN_UP0 ~ SLG51000_PWRSEQ_SLOT_TIME_MIN_UP5 + * 0x1906, 0x1908, 0x190a, 0x190c, 0x190e, 0x1910 + */ +#define SLG51000_SLOT_TIME_MIN_UP_SHIFT 0 +#define SLG51000_SLOT_TIME_MIN_UP_MASK (0xff << 0) + +/* SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN0 ~ SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN5 + * 0x1907, 0x1909, 0x190b, 0x190d, 0x190f, 0x1911 + */ +#define SLG51000_SLOT_TIME_MIN_DOWN_SHIFT 0 +#define SLG51000_SLOT_TIME_MIN_DOWN_MASK (0xff << 0) + +/* SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_A ~ SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_C + * 0x1912, 0x1913, 0x1914 + */ +#define SLG51000_SLOT_TIME_MAX_DOWN1_SHIFT 6 +#define SLG51000_SLOT_TIME_MAX_DOWN1_MASK (0x03 << 6) +#define SLG51000_SLOT_TIME_MAX_UP1_SHIFT 4 +#define SLG51000_SLOT_TIME_MAX_UP1_MASK (0x03 << 4) +#define SLG51000_SLOT_TIME_MAX_DOWN0_SHIFT 2 +#define SLG51000_SLOT_TIME_MAX_DOWN0_MASK (0x03 << 2) +#define SLG51000_SLOT_TIME_MAX_UP0_SHIFT 0 +#define SLG51000_SLOT_TIME_MAX_UP0_MASK (0x03 << 0) + +/* SLG51000_PWRSEQ_INPUT_SENSE_CONF_A = 0x1915 */ +#define SLG51000_TRIG_UP_SENSE_SHIFT 6 +#define SLG51000_TRIG_UP_SENSE_MASK (0x01 << 6) +#define SLG51000_UP_EN_SENSE5_SHIFT 5 +#define SLG51000_UP_EN_SENSE5_MASK (0x01 << 5) +#define SLG51000_UP_EN_SENSE4_SHIFT 4 +#define SLG51000_UP_EN_SENSE4_MASK (0x01 << 4) +#define SLG51000_UP_EN_SENSE3_SHIFT 3 +#define SLG51000_UP_EN_SENSE3_MASK (0x01 << 3) +#define SLG51000_UP_EN_SENSE2_SHIFT 2 +#define SLG51000_UP_EN_SENSE2_MASK (0x01 << 2) +#define SLG51000_UP_EN_SENSE1_SHIFT 1 +#define SLG51000_UP_EN_SENSE1_MASK (0x01 << 1) +#define SLG51000_UP_EN_SENSE0_SHIFT 0 +#define SLG51000_UP_EN_SENSE0_MASK (0x01 << 0) + +/* SLG51000_PWRSEQ_INPUT_SENSE_CONF_B = 0x1916 */ +#define SLG51000_CRASH_DETECT_SENSE_SHIFT 7 +#define SLG51000_CRASH_DETECT_SENSE_MASK (0x01 << 7) +#define SLG51000_TRIG_DOWN_SENSE_SHIFT 6 +#define SLG51000_TRIG_DOWN_SENSE_MASK (0x01 << 6) +#define SLG51000_DOWN_EN_SENSE5_SHIFT 5 +#define SLG51000_DOWN_EN_SENSE5_MASK (0x01 << 5) +#define SLG51000_DOWN_EN_SENSE4_SHIFT 4 +#define SLG51000_DOWN_EN_SENSE4_MASK (0x01 << 4) +#define SLG51000_DOWN_EN_SENSE3_SHIFT 3 +#define SLG51000_DOWN_EN_SENSE3_MASK (0x01 << 3) +#define SLG51000_DOWN_EN_SENSE2_SHIFT 2 +#define SLG51000_DOWN_EN_SENSE2_MASK (0x01 << 2) +#define SLG51000_DOWN_EN_SENSE1_SHIFT 1 +#define SLG51000_DOWN_EN_SENSE1_MASK (0x01 << 1) +#define SLG51000_DOWN_EN_SENSE0_SHIFT 0 +#define SLG51000_DOWN_EN_SENSE0_MASK (0x01 << 0) + +/* SLG51000_LDO1_VSEL ~ SLG51000_LDO7_VSEL = + * 0x2000, 0x2200, 0x2300, 0x2500, 0x2700, 0x2900, 0x3100 + */ +#define SLG51000_VSEL_SHIFT 0 +#define SLG51000_VSEL_MASK (0xff << 0) + +/* SLG51000_LDO1_MINV ~ SLG51000_LDO7_MINV = + * 0x2060, 0x2260, 0x2360, 0x2560, 0x2760, 0x2960, 0x3160 + */ +#define SLG51000_MINV_SHIFT 0 +#define SLG51000_MINV_MASK (0xff << 0) + +/* SLG51000_LDO1_MAXV ~ SLG51000_LDO7_MAXV = + * 0x2061, 0x2261, 0x2361, 0x2561, 0x2761, 0x2961, 0x3161 + */ +#define SLG51000_MAXV_SHIFT 0 +#define SLG51000_MAXV_MASK (0xff << 0) + +/* SLG51000_LDO1_MISC1 = 0x2064, SLG51000_LDO2_MISC1 = 0x2264 */ +#define SLG51000_SEL_VRANGE_SHIFT 0 +#define SLG51000_SEL_VRANGE_MASK (0x01 << 0) + +/* SLG51000_LDO1_VSEL_ACTUAL ~ SLG51000_LDO7_VSEL_ACTUAL = + * 0x2065, 0x2265, 0x2366, 0x2566, 0x2767, 0x2967, 0x3166 + */ +#define SLG51000_VSEL_ACTUAL_SHIFT 0 +#define SLG51000_VSEL_ACTUAL_MASK (0xff << 0) + +/* SLG51000_LDO1_EVENT ~ SLG51000_LDO7_EVENT = + * 0x20c0, 0x22c0, 0x23c0, 0x25c0, 0x27c0, 0x29c0, 0x31c0 + */ +#define SLG51000_EVT_ILIM_FLAG_SHIFT 0 +#define SLG51000_EVT_ILIM_FLAG_MASK (0x01 << 0) +#define SLG51000_EVT_VOUT_OK_FLAG_SHIFT 1 +#define SLG51000_EVT_VOUT_OK_FLAG_MASK (0x01 << 1) + +/* SLG51000_LDO1_STATUS ~ SLG51000_LDO7_STATUS = + * 0x20c1, 0x22c1, 0x23c1, 0x25c1, 0x27c1, 0x29c1, 0x31c1 + */ +#define SLG51000_STA_ILIM_FLAG_SHIFT 0 +#define SLG51000_STA_ILIM_FLAG_MASK (0x01 << 0) +#define SLG51000_STA_VOUT_OK_FLAG_SHIFT 1 +#define SLG51000_STA_VOUT_OK_FLAG_MASK (0x01 << 1) + +/* SLG51000_LDO1_IRQ_MASK ~ SLG51000_LDO7_IRQ_MASK = + * 0x20c2, 0x22c2, 0x23c2, 0x25c2, 0x27c2, 0x29c2, 0x31c2 + */ +#define SLG51000_IRQ_ILIM_FLAG_SHIFT 0 +#define SLG51000_IRQ_ILIM_FLAG_MASK (0x01 << 0) + +/* SLG51000_LDO3_CONF1 ~ SLG51000_LDO7_CONF1 = + * 0x2364, 0x2564, 0x2765, 0x2965, 0x3164 + */ +#define SLG51000_SEL_START_ILIM_SHIFT 0 +#define SLG51000_SEL_START_ILIM_MASK (0x7f << 0) + +/* SLG51000_LDO3_CONF2 ~ SLG51000_LDO7_CONF2 = + * 0x2365, 0x2565, 0x2766, 0x2966, 0x3165 + */ +#define SLG51000_SEL_FUNC_ILIM_SHIFT 0 +#define SLG51000_SEL_FUNC_ILIM_MASK (0x7f << 0) + +/* SLG51000_LDO5_TRIM2 = 0x2763, SLG51000_LDO6_TRIM2 = 0x2963 */ +#define SLG51000_SEL_BYP_SLEW_RATE_SHIFT 2 +#define SLG51000_SEL_BYP_SLEW_RATE_MASK (0x03 << 2) +#define SLG51000_SEL_BYP_VGATE_SHIFT 1 +#define SLG51000_SEL_BYP_VGATE_MASK (0x01 << 1) +#define SLG51000_SEL_BYP_MODE_SHIFT 0 +#define SLG51000_SEL_BYP_MODE_MASK (0x01 << 0) + +/* SLG51000_OTP_EVENT = 0x782b */ +#define SLG51000_EVT_CRC_SHIFT 0 +#define SLG51000_EVT_CRC_MASK (0x01 << 0) + +/* SLG51000_OTP_IRQ_MASK = 0x782d */ +#define SLG51000_IRQ_CRC_SHIFT 0 +#define SLG51000_IRQ_CRC_MASK (0x01 << 0) + +/* SLG51000_OTP_LOCK_OTP_PROG = 0x78fe */ +#define SLG51000_LOCK_OTP_PROG_SHIFT 0 +#define SLG51000_LOCK_OTP_PROG_MASK (0x01 << 0) + +/* SLG51000_OTP_LOCK_CTRL = 0x78ff */ +#define SLG51000_LOCK_DFT_SHIFT 1 +#define SLG51000_LOCK_DFT_MASK (0x01 << 1) +#define SLG51000_LOCK_RWT_SHIFT 0 +#define SLG51000_LOCK_RWT_MASK (0x01 << 0) + +/* SLG51000_LOCK_GLOBAL_LOCK_CTRL1 = 0x8000 */ +#define SLG51000_LDO7_LOCK_SHIFT 7 +#define SLG51000_LDO7_LOCK_MASK (0x01 << 7) +#define SLG51000_LDO6_LOCK_SHIFT 6 +#define SLG51000_LDO6_LOCK_MASK (0x01 << 6) +#define SLG51000_LDO5_LOCK_SHIFT 5 +#define SLG51000_LDO5_LOCK_MASK (0x01 << 5) +#define SLG51000_LDO4_LOCK_SHIFT 4 +#define SLG51000_LDO4_LOCK_MASK (0x01 << 4) +#define SLG51000_LDO3_LOCK_SHIFT 3 +#define SLG51000_LDO3_LOCK_MASK (0x01 << 3) +#define SLG51000_LDO2_LOCK_SHIFT 2 +#define SLG51000_LDO2_LOCK_MASK (0x01 << 2) +#define SLG51000_LDO1_LOCK_SHIFT 1 +#define SLG51000_LDO1_LOCK_MASK (0x01 << 1) + +#endif /* __SLG51000_REGISTERS_H__ */ + diff --git a/drivers/regulator/stm32-booster.c b/drivers/regulator/stm32-booster.c new file mode 100644 index 000000000000..2a897666c650 --- /dev/null +++ b/drivers/regulator/stm32-booster.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2019 +// Author(s): Fabrice Gasnier <fabrice.gasnier@st.com>. + +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +/* STM32H7 SYSCFG register */ +#define STM32H7_SYSCFG_PMCR 0x04 +#define STM32H7_SYSCFG_BOOSTE_MASK BIT(8) + +/* STM32MP1 SYSCFG has set and clear registers */ +#define STM32MP1_SYSCFG_PMCSETR 0x04 +#define STM32MP1_SYSCFG_PMCCLRR 0x44 +#define STM32MP1_SYSCFG_EN_BOOSTER_MASK BIT(8) + +static const struct regulator_ops stm32h7_booster_ops = { + .list_voltage = regulator_list_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_desc stm32h7_booster_desc = { + .name = "booster", + .supply_name = "vdda", + .n_voltages = 1, + .type = REGULATOR_VOLTAGE, + .min_uV = 3300000, + .fixed_uV = 3300000, + .ramp_delay = 66000, /* up to 50us to stabilize */ + .ops = &stm32h7_booster_ops, + .enable_reg = STM32H7_SYSCFG_PMCR, + .enable_mask = STM32H7_SYSCFG_BOOSTE_MASK, + .owner = THIS_MODULE, +}; + +static int stm32mp1_booster_enable(struct regulator_dev *rdev) +{ + return regmap_write(rdev->regmap, STM32MP1_SYSCFG_PMCSETR, + STM32MP1_SYSCFG_EN_BOOSTER_MASK); +} + +static int stm32mp1_booster_disable(struct regulator_dev *rdev) +{ + return regmap_write(rdev->regmap, STM32MP1_SYSCFG_PMCCLRR, + STM32MP1_SYSCFG_EN_BOOSTER_MASK); +} + +static const struct regulator_ops stm32mp1_booster_ops = { + .list_voltage = regulator_list_voltage_linear, + .enable = stm32mp1_booster_enable, + .disable = stm32mp1_booster_disable, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_desc stm32mp1_booster_desc = { + .name = "booster", + .supply_name = "vdda", + .n_voltages = 1, + .type = REGULATOR_VOLTAGE, + .min_uV = 3300000, + .fixed_uV = 3300000, + .ramp_delay = 66000, + .ops = &stm32mp1_booster_ops, + .enable_reg = STM32MP1_SYSCFG_PMCSETR, + .enable_mask = STM32MP1_SYSCFG_EN_BOOSTER_MASK, + .owner = THIS_MODULE, +}; + +static int stm32_booster_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = pdev->dev.of_node; + struct regulator_config config = { }; + const struct regulator_desc *desc; + struct regulator_dev *rdev; + struct regmap *regmap; + int ret; + + regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + desc = (const struct regulator_desc *) + of_match_device(dev->driver->of_match_table, dev)->data; + + config.regmap = regmap; + config.dev = dev; + config.of_node = np; + config.init_data = of_get_regulator_init_data(dev, np, desc); + + rdev = devm_regulator_register(dev, desc, &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(dev, "register failed with error %d\n", ret); + return ret; + } + + return 0; +} + +static const struct of_device_id stm32_booster_of_match[] = { + { + .compatible = "st,stm32h7-booster", + .data = (void *)&stm32h7_booster_desc + }, { + .compatible = "st,stm32mp1-booster", + .data = (void *)&stm32mp1_booster_desc + }, { + }, +}; +MODULE_DEVICE_TABLE(of, stm32_booster_of_match); + +static struct platform_driver stm32_booster_driver = { + .probe = stm32_booster_probe, + .driver = { + .name = "stm32-booster", + .of_match_table = of_match_ptr(stm32_booster_of_match), + }, +}; +module_platform_driver(stm32_booster_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics STM32 booster regulator driver"); +MODULE_ALIAS("platform:stm32-booster"); diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index ca39b3d55123..10ea4b5a0f55 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c @@ -371,11 +371,12 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data( "dcdc-ext-control-gpios", 0, gflags, "tps65090"); - if (IS_ERR(rpdata->gpiod)) - return ERR_CAST(rpdata->gpiod); - if (!rpdata->gpiod) + if (PTR_ERR(rpdata->gpiod) == -ENOENT) { dev_err(&pdev->dev, "could not find DCDC external control GPIO\n"); + rpdata->gpiod = NULL; + } else if (IS_ERR(rpdata->gpiod)) + return ERR_CAST(rpdata->gpiod); } if (of_property_read_u32(tps65090_matches[idx].of_node, diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index ba3dae7b2d2d..09e994e1f9a9 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Regulator driver for TI TPS6586x * @@ -7,10 +8,6 @@ * Based on da903x * Copyright (C) 2006-2008 Marvell International Ltd. * Copyright (C) 2008 Compulab Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index b422eef97b77..018dbbd96771 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -15,7 +15,7 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/mfd/wm831x/core.h> @@ -50,7 +50,7 @@ struct wm831x_dcdc { int base; struct wm831x *wm831x; struct regulator_dev *regulator; - int dvs_gpio; + struct gpio_desc *dvs_gpiod; int dvs_gpio_state; int on_vsel; int dvs_vsel; @@ -217,7 +217,7 @@ static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state) return 0; dcdc->dvs_gpio_state = state; - gpio_set_value(dcdc->dvs_gpio, state); + gpiod_set_value(dcdc->dvs_gpiod, state); /* Should wait for DVS state change to be asserted if we have * a GPIO for it, for now assume the device is configured @@ -237,10 +237,10 @@ static int wm831x_buckv_set_voltage_sel(struct regulator_dev *rdev, int ret; /* If this value is already set then do a GPIO update if we can */ - if (dcdc->dvs_gpio && dcdc->on_vsel == vsel) + if (dcdc->dvs_gpiod && dcdc->on_vsel == vsel) return wm831x_buckv_set_dvs(rdev, 0); - if (dcdc->dvs_gpio && dcdc->dvs_vsel == vsel) + if (dcdc->dvs_gpiod && dcdc->dvs_vsel == vsel) return wm831x_buckv_set_dvs(rdev, 1); /* Always set the ON status to the minimum voltage */ @@ -249,7 +249,7 @@ static int wm831x_buckv_set_voltage_sel(struct regulator_dev *rdev, return ret; dcdc->on_vsel = vsel; - if (!dcdc->dvs_gpio) + if (!dcdc->dvs_gpiod) return ret; /* Kick the voltage transition now */ @@ -296,7 +296,7 @@ static int wm831x_buckv_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); - if (dcdc->dvs_gpio && dcdc->dvs_gpio_state) + if (dcdc->dvs_gpiod && dcdc->dvs_gpio_state) return dcdc->dvs_vsel; else return dcdc->on_vsel; @@ -337,7 +337,7 @@ static void wm831x_buckv_dvs_init(struct platform_device *pdev, int ret; u16 ctrl; - if (!pdata || !pdata->dvs_gpio) + if (!pdata) return; /* gpiolib won't let us read the GPIO status so pick the higher @@ -345,17 +345,14 @@ static void wm831x_buckv_dvs_init(struct platform_device *pdev, */ dcdc->dvs_gpio_state = pdata->dvs_init_state; - ret = devm_gpio_request_one(&pdev->dev, pdata->dvs_gpio, - dcdc->dvs_gpio_state ? GPIOF_INIT_HIGH : 0, - "DCDC DVS"); - if (ret < 0) { - dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n", - dcdc->name, ret); + dcdc->dvs_gpiod = devm_gpiod_get(&pdev->dev, "dvs", + dcdc->dvs_gpio_state ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW); + if (IS_ERR(dcdc->dvs_gpiod)) { + dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %ld\n", + dcdc->name, PTR_ERR(dcdc->dvs_gpiod)); return; } - dcdc->dvs_gpio = pdata->dvs_gpio; - switch (pdata->dvs_control_src) { case 1: ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT; diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index d200334577f6..b2c7af323ed1 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Remote processor machine-specific module for DA8XX * * Copyright (C) 2013 Texas Instruments, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #include <linux/bitops.h> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 54c07fd3f204..36f2f14dad0c 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c index 51049d17b1e5..ee13d23b43a9 100644 --- a/drivers/remoteproc/st_remoteproc.c +++ b/drivers/remoteproc/st_remoteproc.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ST's Remote Processor Control Driver * * Copyright (C) 2015 STMicroelectronics - All Rights Reserved * * Author: Ludovic Barre <ludovic.barre@st.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/reset/hisilicon/hi6220_reset.c b/drivers/reset/hisilicon/hi6220_reset.c index d5e5229308f2..24e6d420b26b 100644 --- a/drivers/reset/hisilicon/hi6220_reset.c +++ b/drivers/reset/hisilicon/hi6220_reset.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Hisilicon Hi6220 reset controller driver * @@ -5,10 +6,6 @@ * Copyright (c) 2015-2016 Hisilicon Limited. * * Author: Feng Chen <puck.chen@hisilicon.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/io.h> diff --git a/drivers/reset/reset-lantiq.c b/drivers/reset/reset-lantiq.c index 11a582e50d30..ac41d093de13 100644 --- a/drivers/reset/reset-lantiq.c +++ b/drivers/reset/reset-lantiq.c @@ -1,7 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. * * Copyright (C) 2010 John Crispin <blogic@phrozen.org> * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG diff --git a/drivers/reset/reset-lpc18xx.c b/drivers/reset/reset-lpc18xx.c index a62ad52e262b..35d8dd4cccfc 100644 --- a/drivers/reset/reset-lpc18xx.c +++ b/drivers/reset/reset-lpc18xx.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Reset driver for NXP LPC18xx/43xx Reset Generation Unit (RGU). * * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/clk.h> diff --git a/drivers/reset/tegra/reset-bpmp.c b/drivers/reset/tegra/reset-bpmp.c index 5daf2ee1a396..24d3395964cc 100644 --- a/drivers/reset/tegra/reset-bpmp.c +++ b/drivers/reset/tegra/reset-bpmp.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/reset-controller.h> diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 73697e4b18a9..434285f495e0 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Real Time Clock driver for Marvell 88PM860x PMIC * * Copyright (c) 2010 Marvell International Ltd. * Author: Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c index ef52741000a8..4a63f0cd2321 100644 --- a/drivers/rtc/rtc-bq32k.c +++ b/drivers/rtc/rtc-bq32k.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for TI BQ32000 RTC. * * Copyright (C) 2009 Semihalf. * Copyright (C) 2014 Pavel Machek <pavel@denx.de> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * You can get hardware description at * http://www.ti.com/lit/ds/symlink/bq32000.pdf */ diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 2d502fc85698..e04d6e862c42 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc-ds1305.c -- driver for DS1305 and DS1306 SPI RTC chips * * Copyright (C) 2008 David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> #include <linux/init.h> diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 07530fe1da2a..93d338e7732b 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc-ds1307.c - RTC driver for some mostly-compatible I2C chips. * @@ -5,10 +6,6 @@ * Copyright (C) 2006 David Brownell * Copyright (C) 2009 Matthias Fuchs (rx8025 support) * Copyright (C) 2012 Bertrand Achard (nvram access fixes) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c index 5208da4cf94a..fa6de31d5793 100644 --- a/drivers/rtc/rtc-ds1343.c +++ b/drivers/rtc/rtc-ds1343.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* rtc-ds1343.c * * Driver for Dallas Semiconductor DS1343 Low Current, SPI Compatible @@ -5,11 +6,6 @@ * * Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com> * Ankur Srivastava <sankurece@gmail.com> : DS1343 Nvram Support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/init.h> diff --git a/drivers/rtc/rtc-ds1347.c b/drivers/rtc/rtc-ds1347.c index 938512c676ee..d392a7bfdd1c 100644 --- a/drivers/rtc/rtc-ds1347.c +++ b/drivers/rtc/rtc-ds1347.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* rtc-ds1347.c * * Driver for Dallas Semiconductor DS1347 Low Current, SPI Compatible * Real Time Clock * * Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/init.h> diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index 3b095401f848..66fc8617d07e 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc-ds1390.c -- driver for the Dallas/Maxim DS1390/93/94 SPI RTC * * Copyright (C) 2008 Mercury IMC Ltd * Written by Mark Jackson <mpfj@mimc.co.uk> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * NOTE: Currently this driver only supports the bare minimum for read * and write the RTC. The extra features provided by the chip family * (alarms, trickle charger, different control registers) are unavailable. diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index b8b6e51c0461..b6a477519280 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An rtc driver for the Dallas DS1511 * * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> * Copyright (C) 2007 Andrew Sharp <andy.sharp@lsi.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Real time clock driver for the Dallas 1511 chip, which also * contains a watchdog timer. There is a tiny amount of code that * platform code could use to mess with the watchdog device a little diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 34af7a802f43..219d6b520a69 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An rtc driver for the Dallas DS1553 * * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 5f4328524183..184e4a3e2bef 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An rtc driver for the Dallas/Maxim DS1685/DS1687 and related real-time * chips. @@ -10,10 +11,6 @@ * DS17x85/DS17x87 3V/5V Real-Time Clocks, 19-5222, Rev 4/10. * DS1689/DS1693 3V/5V Serialized Real-Time Clocks, Rev 112105. * Application Note 90, Using the Multiplex Bus RTC Extended Features. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 5a4c2c5e86fe..2b949f0dbaa9 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An rtc driver for the Dallas DS1742 * * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Copyright (C) 2006 Torsten Ertbjerg Rasmussen <tr@newtec.dk> * - nvram size determined from resource * - this ds1742 driver now supports ds1743. diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c index b0ef8cfe742d..77cca1392253 100644 --- a/drivers/rtc/rtc-em3027.c +++ b/drivers/rtc/rtc-em3027.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An rtc/i2c driver for the EM Microelectronic EM3027 * Copyright 2011 CompuLab, Ltd. @@ -5,10 +6,6 @@ * Author: Mike Rapoport <mike@compulab.co.il> * * Based on rtc-ds1672.c by Alessandro Zummo <a.zummo@towertech.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/i2c.h> diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c index e1137670d4d2..1caa21b82c7d 100644 --- a/drivers/rtc/rtc-fm3130.c +++ b/drivers/rtc/rtc-fm3130.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc-fm3130.c - RTC driver for Ramtron FM3130 I2C chip. * * Copyright (C) 2008 Sergey Lapin * Based on ds1307 driver by James Chapman and David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index 890ccfc9e5aa..961bd5d1d109 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An I2C driver for the Intersil ISL 12022 * @@ -5,10 +6,6 @@ * * Based on the Philips PCF8563 RTC * by Alessandro Zummo <a.zummo@towertech.it>. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. */ #include <linux/i2c.h> diff --git a/drivers/rtc/rtc-lp8788.c b/drivers/rtc/rtc-lp8788.c index e20e7bd822e0..c0b8fbce1082 100644 --- a/drivers/rtc/rtc-lp8788.c +++ b/drivers/rtc/rtc-lp8788.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LP8788 MFD - rtc driver * * Copyright 2012 Texas Instruments * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/err.h> diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index dd5a8991f75b..9fdc284c943b 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C client/driver for the ST M41T80 family of i2c rtc chips. * @@ -6,11 +7,6 @@ * Based on m41t00.c by Mark A. Greer <mgreer@mvista.com> * * 2006 (c) mycable GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c index 4a08a9dabc82..9444cb5f5190 100644 --- a/drivers/rtc/rtc-m41t93.c +++ b/drivers/rtc/rtc-m41t93.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * * Driver for ST M41T93 SPI RTC * * (c) 2010 Nikolaus Voss, Weinmann Medical GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-m41t94.c b/drivers/rtc/rtc-m41t94.c index bab82b4be356..6803b0273302 100644 --- a/drivers/rtc/rtc-m41t94.c +++ b/drivers/rtc/rtc-m41t94.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for ST M41T94 SPI RTC * * Copyright (C) 2008 Kim B. Heino - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 3c8ad1cdfd7c..67e218758a8b 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ST M48T59 RTC driver * * Copyright (c) 2007 Wind River Systems, Inc. * * Author: Mark Zhan <rongkai.zhan@windriver.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index a9533535c3b7..59b54ed9b841 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ST M48T86 / Dallas DS12887 RTC driver * Copyright (c) 2006 Tower Technologies * * Author: Alessandro Zummo <a.zummo@towertech.it> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This drivers only supports the clock running in BCD and 24H mode. * If it will be ever adapted to binary and 12H mode, care must be taken * to not introduce bugs. diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 745827463367..daaeb6fb6c2d 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/rtc/rtc-max6902.c * * Copyright (C) 2006 8D Technologies inc. * Copyright (C) 2004 Compulab Ltd. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Driver for MAX6902 spi RTC - * */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-max6916.c b/drivers/rtc/rtc-max6916.c index 9d4b407cc4b8..e72e768ab8ff 100644 --- a/drivers/rtc/rtc-max6916.c +++ b/drivers/rtc/rtc-max6916.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* rtc-max6916.c * * Driver for MAXIM max6916 Low Current, SPI Compatible * Real Time Clock * * Author : Venkat Prashanth B U <venkat.prashanth2498@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/init.h> diff --git a/drivers/rtc/rtc-max8907.c b/drivers/rtc/rtc-max8907.c index 19c29b72598d..db3495d10274 100644 --- a/drivers/rtc/rtc-max8907.c +++ b/drivers/rtc/rtc-max8907.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * RTC driver for Maxim MAX8907 * @@ -5,10 +6,6 @@ * * Based on drivers/rtc/rtc-max8925.c, * Copyright (C) 2009-2010 Marvell International Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c index 67d6fc2d23e6..64bb8ac6ef62 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * RTC driver for Maxim MAX8925 * * Copyright (C) 2009-2010 Marvell International Ltd. * Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c index f22a945a3794..1660d5e79582 100644 --- a/drivers/rtc/rtc-mcp795.c +++ b/drivers/rtc/rtc-mcp795.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPI Driver for Microchip MCP795 RTC * @@ -7,11 +8,6 @@ * * Device datasheet: * http://ww1.microchip.com/downloads/en/DeviceDoc/22280A.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index dd0364293bc0..15a9d0278778 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Real-time clock driver for MPC5121 * * Copyright 2007, Domen Puncer <domen.puncer@telargo.com> * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved. * Copyright 2011, Dmitry Eremin-Solenikov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 39da8b214275..f431263e2d39 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An SPI driver for the Philips PCF2123 RTC * Copyright 2009 Cyber Switching, Inc. @@ -10,10 +11,6 @@ * Thanks to Christian Pellegrin <chripell@fsfe.org> for * the sysfs contributions to this driver. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Please note that the CS is active high, so platform data * should look something like: * @@ -29,7 +26,6 @@ * }, * ... *}; - * */ #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 7cb786d76e3c..8632f58fed43 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An I2C and SPI driver for the NXP PCF2127/29 RTC * Copyright 2013 Til-Technologies @@ -7,10 +8,6 @@ * based on the other drivers in this same directory. * * Datasheet: http://cache.nxp.com/documents/data_sheet/PCF2127.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/i2c.h> diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index b5c61a70b5df..2f435e533b10 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Avionic Design GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 3efc86c25d27..c569dfe8c2ae 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An I2C driver for the Philips PCF8563 RTC * Copyright 2005-06 Tower Technologies @@ -8,10 +9,6 @@ * based on the other drivers in this same directory. * * http://www.semiconductors.philips.com/acrobat/datasheets/PCF8563-04.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk-provider.h> diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index 7ca9e8871d77..c80ca20e5d8d 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/rtc/rtc-pcf8583.c * * Copyright (C) 2000 Russell King * Copyright (C) 2008 Wolfram Sang & Juergen Beisert, Pengutronix * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Driver for PCF8583 RTC & RAM chip * * Converted to the generic RTC susbsystem by G. Liakhovetski (2006) diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c index 343bb6ed1783..d4a5f8afafbc 100644 --- a/drivers/rtc/rtc-pl030.c +++ b/drivers/rtc/rtc-pl030.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/rtc/rtc-pl030.c * * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/rtc.h> diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c index f77ef282f013..63b9e73fb97d 100644 --- a/drivers/rtc/rtc-puv3.c +++ b/drivers/rtc/rtc-puv3.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * RTC driver code specific to PKUnity SoC and UniCore ISA * * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> * Copyright (C) 2001-2010 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c index a39ccd1cf6e8..84f0d25259ae 100644 --- a/drivers/rtc/rtc-r9701.c +++ b/drivers/rtc/rtc-r9701.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Epson RTC-9701JE * @@ -7,10 +8,6 @@ * * Copyright (C) 2006 8D Technologies inc. * Copyright (C) 2004 Compulab Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c index 6582be707bd0..47c13678449e 100644 --- a/drivers/rtc/rtc-rs5c348.c +++ b/drivers/rtc/rtc-rs5c348.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * A SPI driver for the Ricoh RS5C348 RTC * * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * The board specific init code should provide characteristics of this * device: * Mode 1 (High-Active, Shift-Then-Sample), High Avtive CS diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 66a473a3c3fe..3bd6eaa0dcf6 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An I2C driver for Ricoh RS5C372, R2025S/D and RV5C38[67] RTCs * * Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net> * Copyright (C) 2006 Tower Technologies * Copyright (C) 2008 Paul Mundt - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/i2c.h> diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index 3d6174eb32f6..4a0e8ec015cc 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Micro Crystal RV-3029 / RV-3049 rtc class driver * @@ -5,11 +6,6 @@ * Michael Buesch <m@bues.ch> * * based on previously existing rtc class drivers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-rx4581.c b/drivers/rtc/rtc-rx4581.c index c59a218bdd87..c092e0452347 100644 --- a/drivers/rtc/rtc-rx4581.c +++ b/drivers/rtc/rtc-rx4581.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/rtc/rtc-rx4581.c * * written by Torben Hohn <torbenh@linutronix.de> @@ -8,10 +9,6 @@ * Copyright (C) 2006 8D Technologies inc. * Copyright (C) 2004 Compulab Ltd. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Driver for MAX6902 spi RTC * * and based on: @@ -22,13 +19,8 @@ * Author: Martyn Welch <martyn.welch@ge.com> * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Based on: rtc-pcf8563.c (An I2C driver for the Philips PCF8563 RTC) * Copyright 2005-06 Tower Technologies - * */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 7ddc22eb5b0f..b15ad8e10938 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for the Epson RTC module RX-8010 SJ * * Copyright(C) Timesys Corporation 2015 * Copyright(C) General Electric Company 2015 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index fddc996cb38d..cb082ad19471 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Epson's RTC module RX-8025 SA/NB * @@ -13,10 +14,6 @@ * Code cleanup by Sergei Poselenov, <sposelenov@emcraft.com> * Converted to new style by Wolfgang Grandegger <wg@grandegger.com> * Alarm and periodic interrupt added by Dmitry Rakhchev <rda@emcraft.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #include <linux/bcd.h> #include <linux/bitops.h> diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c index 776e3a2b89e8..490f70f57636 100644 --- a/drivers/rtc/rtc-rx8581.c +++ b/drivers/rtc/rtc-rx8581.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An I2C driver for the Epson RX8581 RTC * * Author: Martyn Welch <martyn.welch@ge.com> * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Based on: rtc-pcf8563.c (An I2C driver for the Philips PCF8563 RTC) * Copyright 2005-06 Tower Technologies */ diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index e81a2b22a5c3..74bf6473a05d 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/rtc/rtc-s3c.c * * Copyright (c) 2010 Samsung Electronics Co., Ltd. @@ -7,10 +8,6 @@ * Ben Dooks, <ben@simtec.co.uk> * http://armlinux.simtec.co.uk/ * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * S3C2410/S3C2440/S3C24XX Internal RTC Driver */ diff --git a/drivers/rtc/rtc-s3c.h b/drivers/rtc/rtc-s3c.h index 004b61a8343f..3552914aa611 100644 --- a/drivers/rtc/rtc-s3c.h +++ b/drivers/rtc/rtc-s3c.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> * http://www.simtec.co.uk/products/SWLINUX/ * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * S3C2410 Internal RTC register definition */ diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index fccbecbb2c98..a833ebc4ecb9 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * A RTC driver for the Simtek STK17TA8 * @@ -5,10 +6,6 @@ * * Based on the DS1553 driver from * Atsushi Nemoto <anemo@mba.ocn.ne.jp> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index 1f3117b5a83c..63ffba21397b 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/rtc/rtc-v3020.c * * Copyright (C) 2006 8D Technologies inc. * Copyright (C) 2004 Compulab Ltd. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Driver for the V3020 RTC * * Changelog: @@ -17,7 +14,6 @@ * * ??-???-2004: Someone at Compulab * - Initial driver creation. - * */ #include <linux/platform_device.h> #include <linux/module.h> diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index ad2ae2f0536e..d1d5a44d9122 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An i2c driver for the Xicor/Intersil X1205 RTC * Copyright 2004 Karen Spearel @@ -11,10 +12,6 @@ * * Information and datasheet: * http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/i2c.h> diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig index 9ac7574e3cfb..a8682f69effc 100644 --- a/drivers/s390/block/Kconfig +++ b/drivers/s390/block/Kconfig @@ -38,7 +38,7 @@ config DASD_PROFILE depends on DASD help Enable this option if you want to see profiling information - in /proc/dasd/statistics. + in /proc/dasd/statistics. config DASD_ECKD def_tristate y diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index fab35c6170cc..245f33c2f71e 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -203,7 +203,7 @@ static int __init dasd_feature_list(char *str) else if (len == 8 && !strncmp(str, "failfast", 8)) features |= DASD_FEATURE_FAILFAST; else { - pr_warn("%*s is not a supported device option\n", + pr_warn("%.*s is not a supported device option\n", len, str); rc = -EINVAL; } diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index ab0b243a947d..6cc4b19acf85 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig @@ -79,27 +79,6 @@ config SCLP_VT220_CONSOLE Include support for using an IBM SCLP VT220-compatible terminal as a Linux system console. -config SCLP_ASYNC - def_tristate m - prompt "Support for Call Home via Asynchronous SCLP Records" - depends on S390 - help - This option enables the call home function, which is able to inform - the service element and connected organisations about a kernel panic. - You should only select this option if you know what you are doing, - want for inform other people about your kernel panics, - need this feature and intend to run your kernel in LPAR. - -config SCLP_ASYNC_ID - string "Component ID for Call Home" - depends on SCLP_ASYNC - default "000000000" - help - The Component ID for Call Home is used to identify the correct - problem reporting queue the call home records should be sent to. - - If your are unsure, please use the default value "000000000". - config HMC_DRV def_tristate m prompt "Support for file transfers from HMC drive CD/DVD-ROM" @@ -205,4 +184,3 @@ config S390_VMUR depends on S390 help Character device driver for z/VM reader, puncher and printer. - diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index 3072b89785dd..b8a8816d94e7 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -31,7 +31,6 @@ obj-$(CONFIG_TN3215) += con3215.o obj-$(CONFIG_SCLP_TTY) += sclp_tty.o obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o -obj-$(CONFIG_SCLP_ASYNC) += sclp_async.o obj-$(CONFIG_PCI) += sclp_pci.o diff --git a/drivers/s390/char/sclp_async.c b/drivers/s390/char/sclp_async.c deleted file mode 100644 index e69b12a40636..000000000000 --- a/drivers/s390/char/sclp_async.c +++ /dev/null @@ -1,189 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Enable Asynchronous Notification via SCLP. - * - * Copyright IBM Corp. 2009 - * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> - * - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/stat.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/ctype.h> -#include <linux/kmod.h> -#include <linux/err.h> -#include <linux/errno.h> -#include <linux/proc_fs.h> -#include <linux/sysctl.h> -#include <linux/utsname.h> -#include "sclp.h" - -static int callhome_enabled; -static struct sclp_req *request; -static struct sclp_async_sccb *sccb; -static int sclp_async_send_wait(char *message); -static struct ctl_table_header *callhome_sysctl_header; -static DEFINE_SPINLOCK(sclp_async_lock); -#define SCLP_NORMAL_WRITE 0x00 - -struct async_evbuf { - struct evbuf_header header; - u64 reserved; - u8 rflags; - u8 empty; - u8 rtype; - u8 otype; - char comp_id[12]; - char data[3000]; /* there is still some space left */ -} __attribute__((packed)); - -struct sclp_async_sccb { - struct sccb_header header; - struct async_evbuf evbuf; -} __attribute__((packed)); - -static struct sclp_register sclp_async_register = { - .send_mask = EVTYP_ASYNC_MASK, -}; - -static int call_home_on_panic(struct notifier_block *self, - unsigned long event, void *data) -{ - strncat(data, init_utsname()->nodename, - sizeof(init_utsname()->nodename)); - sclp_async_send_wait(data); - return NOTIFY_DONE; -} - -static struct notifier_block call_home_panic_nb = { - .notifier_call = call_home_on_panic, - .priority = INT_MAX, -}; - -static int zero; -static int one = 1; - -static struct ctl_table callhome_table[] = { - { - .procname = "callhome", - .data = &callhome_enabled, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, - {} -}; - -static struct ctl_table kern_dir_table[] = { - { - .procname = "kernel", - .maxlen = 0, - .mode = 0555, - .child = callhome_table, - }, - {} -}; - -/* - * Function used to transfer asynchronous notification - * records which waits for send completion - */ -static int sclp_async_send_wait(char *message) -{ - struct async_evbuf *evb; - int rc; - unsigned long flags; - - if (!callhome_enabled) - return 0; - sccb->evbuf.header.type = EVTYP_ASYNC; - sccb->evbuf.rtype = 0xA5; - sccb->evbuf.otype = 0x00; - evb = &sccb->evbuf; - request->command = SCLP_CMDW_WRITE_EVENT_DATA; - request->sccb = sccb; - request->status = SCLP_REQ_FILLED; - strncpy(sccb->evbuf.data, message, sizeof(sccb->evbuf.data)); - /* - * Retain Queue - * e.g. 5639CC140 500 Red Hat RHEL5 Linux for zSeries (RHEL AS) - */ - strncpy(sccb->evbuf.comp_id, CONFIG_SCLP_ASYNC_ID, - sizeof(sccb->evbuf.comp_id)); - sccb->evbuf.header.length = sizeof(sccb->evbuf); - sccb->header.length = sizeof(sccb->evbuf) + sizeof(sccb->header); - sccb->header.function_code = SCLP_NORMAL_WRITE; - rc = sclp_add_request(request); - if (rc) - return rc; - spin_lock_irqsave(&sclp_async_lock, flags); - while (request->status != SCLP_REQ_DONE && - request->status != SCLP_REQ_FAILED) { - sclp_sync_wait(); - } - spin_unlock_irqrestore(&sclp_async_lock, flags); - if (request->status != SCLP_REQ_DONE) - return -EIO; - rc = ((struct sclp_async_sccb *) - request->sccb)->header.response_code; - if (rc != 0x0020) - return -EIO; - if (evb->header.flags != 0x80) - return -EIO; - return rc; -} - -static int __init sclp_async_init(void) -{ - int rc; - - rc = sclp_register(&sclp_async_register); - if (rc) - return rc; - rc = -EOPNOTSUPP; - if (!(sclp_async_register.sclp_receive_mask & EVTYP_ASYNC_MASK)) - goto out_sclp; - rc = -ENOMEM; - callhome_sysctl_header = register_sysctl_table(kern_dir_table); - if (!callhome_sysctl_header) - goto out_sclp; - request = kzalloc(sizeof(struct sclp_req), GFP_KERNEL); - sccb = (struct sclp_async_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!request || !sccb) - goto out_mem; - rc = atomic_notifier_chain_register(&panic_notifier_list, - &call_home_panic_nb); - if (!rc) - goto out; -out_mem: - kfree(request); - free_page((unsigned long) sccb); - unregister_sysctl_table(callhome_sysctl_header); -out_sclp: - sclp_unregister(&sclp_async_register); -out: - return rc; -} -module_init(sclp_async_init); - -static void __exit sclp_async_exit(void) -{ - atomic_notifier_chain_unregister(&panic_notifier_list, - &call_home_panic_nb); - unregister_sysctl_table(callhome_sysctl_header); - sclp_unregister(&sclp_async_register); - free_page((unsigned long) sccb); - kfree(request); -} -module_exit(sclp_async_exit); - -MODULE_AUTHOR("Copyright IBM Corp. 2009"); -MODULE_AUTHOR("Hans-Joachim Picht <hans@linux.vnet.ibm.com>"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("SCLP Asynchronous Notification Records"); diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 405a60538630..08f812475f5e 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -4,7 +4,7 @@ * dumps on SCSI disks (zfcpdump). The "zcore/mem" debugfs file shows the same * dump format as s390 standalone dumps. * - * For more information please refer to Documentation/s390/zfcpdump.txt + * For more information please refer to Documentation/s390/zfcpdump.rst * * Copyright IBM Corp. 2003, 2008 * Author(s): Michael Holzheu diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index 4534afc63591..427b2e24a8ce 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -16,9 +16,11 @@ #include <linux/mutex.h> #include <linux/rculist.h> #include <linux/slab.h> +#include <linux/dmapool.h> #include <asm/airq.h> #include <asm/isc.h> +#include <asm/cio.h> #include "cio.h" #include "cio_debug.h" @@ -27,7 +29,7 @@ static DEFINE_SPINLOCK(airq_lists_lock); static struct hlist_head airq_lists[MAX_ISC+1]; -static struct kmem_cache *airq_iv_cache; +static struct dma_pool *airq_iv_cache; /** * register_adapter_interrupt() - register adapter interrupt handler @@ -115,6 +117,11 @@ void __init init_airq_interrupts(void) setup_irq(THIN_INTERRUPT, &airq_interrupt); } +static inline unsigned long iv_size(unsigned long bits) +{ + return BITS_TO_LONGS(bits) * sizeof(unsigned long); +} + /** * airq_iv_create - create an interrupt vector * @bits: number of bits in the interrupt vector @@ -132,17 +139,19 @@ struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags) goto out; iv->bits = bits; iv->flags = flags; - size = BITS_TO_LONGS(bits) * sizeof(unsigned long); + size = iv_size(bits); if (flags & AIRQ_IV_CACHELINE) { - if ((cache_line_size() * BITS_PER_BYTE) < bits) + if ((cache_line_size() * BITS_PER_BYTE) < bits + || !airq_iv_cache) goto out_free; - iv->vector = kmem_cache_zalloc(airq_iv_cache, GFP_KERNEL); + iv->vector = dma_pool_zalloc(airq_iv_cache, GFP_KERNEL, + &iv->vector_dma); if (!iv->vector) goto out_free; } else { - iv->vector = kzalloc(size, GFP_KERNEL); + iv->vector = cio_dma_zalloc(size); if (!iv->vector) goto out_free; } @@ -178,10 +187,10 @@ out_free: kfree(iv->ptr); kfree(iv->bitlock); kfree(iv->avail); - if (iv->flags & AIRQ_IV_CACHELINE) - kmem_cache_free(airq_iv_cache, iv->vector); + if (iv->flags & AIRQ_IV_CACHELINE && iv->vector) + dma_pool_free(airq_iv_cache, iv->vector, iv->vector_dma); else - kfree(iv->vector); + cio_dma_free(iv->vector, size); kfree(iv); out: return NULL; @@ -198,9 +207,9 @@ void airq_iv_release(struct airq_iv *iv) kfree(iv->ptr); kfree(iv->bitlock); if (iv->flags & AIRQ_IV_CACHELINE) - kmem_cache_free(airq_iv_cache, iv->vector); + dma_pool_free(airq_iv_cache, iv->vector, iv->vector_dma); else - kfree(iv->vector); + cio_dma_free(iv->vector, iv_size(iv->bits)); kfree(iv->avail); kfree(iv); } @@ -295,12 +304,12 @@ unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start, } EXPORT_SYMBOL(airq_iv_scan); -static int __init airq_init(void) +int __init airq_init(void) { - airq_iv_cache = kmem_cache_create("airq_iv_cache", cache_line_size(), - cache_line_size(), 0, NULL); + airq_iv_cache = dma_pool_create("airq_iv_cache", cio_get_dma_css_dev(), + cache_line_size(), + cache_line_size(), PAGE_SIZE); if (!airq_iv_cache) return -ENOMEM; return 0; } -subsys_initcall(airq_init); diff --git a/drivers/s390/cio/ccwreq.c b/drivers/s390/cio/ccwreq.c index 603268a33ea1..73582a0a2622 100644 --- a/drivers/s390/cio/ccwreq.c +++ b/drivers/s390/cio/ccwreq.c @@ -63,7 +63,7 @@ static void ccwreq_stop(struct ccw_device *cdev, int rc) return; req->done = 1; ccw_device_set_timeout(cdev, 0); - memset(&cdev->private->irb, 0, sizeof(struct irb)); + memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb)); if (rc && rc != -ENODEV && req->drc) rc = req->drc; req->callback(cdev, req->data, rc); @@ -86,7 +86,7 @@ static void ccwreq_do(struct ccw_device *cdev) continue; } /* Perform start function. */ - memset(&cdev->private->irb, 0, sizeof(struct irb)); + memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb)); rc = cio_start(sch, cp, (u8) req->mask); if (rc == 0) { /* I/O started successfully. */ @@ -169,7 +169,7 @@ int ccw_request_cancel(struct ccw_device *cdev) */ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb) { - struct irb *irb = &cdev->private->irb; + struct irb *irb = &cdev->private->dma_area->irb; struct cmd_scsw *scsw = &irb->scsw.cmd; enum uc_todo todo; @@ -187,7 +187,8 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb) CIO_TRACE_EVENT(2, "sensedata"); CIO_HEX_EVENT(2, &cdev->private->dev_id, sizeof(struct ccw_dev_id)); - CIO_HEX_EVENT(2, &cdev->private->irb.ecw, SENSE_MAX_COUNT); + CIO_HEX_EVENT(2, &cdev->private->dma_area->irb.ecw, + SENSE_MAX_COUNT); /* Check for command reject. */ if (irb->ecw[0] & SNS0_CMD_REJECT) return IO_REJECTED; diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index a835b31aad99..6392a1b95b02 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -323,36 +323,6 @@ struct chsc_sei { } __packed __aligned(PAGE_SIZE); /* - * Node Descriptor as defined in SA22-7204, "Common I/O-Device Commands" - */ - -#define ND_VALIDITY_VALID 0 -#define ND_VALIDITY_OUTDATED 1 -#define ND_VALIDITY_INVALID 2 - -struct node_descriptor { - /* Flags. */ - union { - struct { - u32 validity:3; - u32 reserved:5; - } __packed; - u8 byte0; - } __packed; - - /* Node parameters. */ - u32 params:24; - - /* Node ID. */ - char type[6]; - char model[3]; - char manufacturer[3]; - char plant[2]; - char seq[12]; - u16 tag; -} __packed; - -/* * Link Incident Record as defined in SA22-7202, "ESCON I/O Interface" */ diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 06a91743335a..ba7d2480613b 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -113,6 +113,7 @@ struct subchannel { enum sch_todo todo; struct work_struct todo_work; struct schib_config config; + char *driver_override; /* Driver name to force a match */ } __attribute__ ((aligned(8))); DECLARE_PER_CPU_ALIGNED(struct irb, cio_irb); @@ -135,6 +136,8 @@ extern int cio_commit_config(struct subchannel *sch); int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key); int cio_tm_intrg(struct subchannel *sch); +extern int __init airq_init(void); + /* Use with care. */ #ifdef CONFIG_CCW_CONSOLE extern struct subchannel *cio_probe_console(void); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index aea502922646..e1f2d0eed544 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -20,6 +20,8 @@ #include <linux/reboot.h> #include <linux/suspend.h> #include <linux/proc_fs.h> +#include <linux/genalloc.h> +#include <linux/dma-mapping.h> #include <asm/isc.h> #include <asm/crw.h> @@ -165,6 +167,7 @@ static void css_subchannel_release(struct device *dev) sch->config.intparm = 0; cio_commit_config(sch); + kfree(sch->driver_override); kfree(sch->lock); kfree(sch); } @@ -224,6 +227,12 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid, INIT_WORK(&sch->todo_work, css_sch_todo); sch->dev.release = &css_subchannel_release; device_initialize(&sch->dev); + /* + * The physical addresses of some the dma structures that can + * belong to a subchannel need to fit 31 bit width (e.g. ccw). + */ + sch->dev.coherent_dma_mask = DMA_BIT_MASK(31); + sch->dev.dma_mask = &sch->dev.coherent_dma_mask; return sch; err: @@ -315,9 +324,57 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RO(modalias); +static ssize_t driver_override_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct subchannel *sch = to_subchannel(dev); + char *driver_override, *old, *cp; + + /* We need to keep extra room for a newline */ + if (count >= (PAGE_SIZE - 1)) + return -EINVAL; + + driver_override = kstrndup(buf, count, GFP_KERNEL); + if (!driver_override) + return -ENOMEM; + + cp = strchr(driver_override, '\n'); + if (cp) + *cp = '\0'; + + device_lock(dev); + old = sch->driver_override; + if (strlen(driver_override)) { + sch->driver_override = driver_override; + } else { + kfree(driver_override); + sch->driver_override = NULL; + } + device_unlock(dev); + + kfree(old); + + return count; +} + +static ssize_t driver_override_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct subchannel *sch = to_subchannel(dev); + ssize_t len; + + device_lock(dev); + len = snprintf(buf, PAGE_SIZE, "%s\n", sch->driver_override); + device_unlock(dev); + return len; +} +static DEVICE_ATTR_RW(driver_override); + static struct attribute *subch_attrs[] = { &dev_attr_type.attr, &dev_attr_modalias.attr, + &dev_attr_driver_override.attr, NULL, }; @@ -899,6 +956,13 @@ static int __init setup_css(int nr) dev_set_name(&css->device, "css%x", nr); css->device.groups = cssdev_attr_groups; css->device.release = channel_subsystem_release; + /* + * We currently allocate notifier bits with this (using + * css->device as the device argument with the DMA API) + * and are fine with 64 bit addresses. + */ + css->device.coherent_dma_mask = DMA_BIT_MASK(64); + css->device.dma_mask = &css->device.coherent_dma_mask; mutex_init(&css->mutex); css->cssid = chsc_get_cssid(nr); @@ -1018,6 +1082,111 @@ static struct notifier_block css_power_notifier = { .notifier_call = css_power_event, }; +#define CIO_DMA_GFP (GFP_KERNEL | __GFP_ZERO) +static struct gen_pool *cio_dma_pool; + +/* Currently cio supports only a single css */ +struct device *cio_get_dma_css_dev(void) +{ + return &channel_subsystems[0]->device; +} + +struct gen_pool *cio_gp_dma_create(struct device *dma_dev, int nr_pages) +{ + struct gen_pool *gp_dma; + void *cpu_addr; + dma_addr_t dma_addr; + int i; + + gp_dma = gen_pool_create(3, -1); + if (!gp_dma) + return NULL; + for (i = 0; i < nr_pages; ++i) { + cpu_addr = dma_alloc_coherent(dma_dev, PAGE_SIZE, &dma_addr, + CIO_DMA_GFP); + if (!cpu_addr) + return gp_dma; + gen_pool_add_virt(gp_dma, (unsigned long) cpu_addr, + dma_addr, PAGE_SIZE, -1); + } + return gp_dma; +} + +static void __gp_dma_free_dma(struct gen_pool *pool, + struct gen_pool_chunk *chunk, void *data) +{ + size_t chunk_size = chunk->end_addr - chunk->start_addr + 1; + + dma_free_coherent((struct device *) data, chunk_size, + (void *) chunk->start_addr, + (dma_addr_t) chunk->phys_addr); +} + +void cio_gp_dma_destroy(struct gen_pool *gp_dma, struct device *dma_dev) +{ + if (!gp_dma) + return; + /* this is quite ugly but no better idea */ + gen_pool_for_each_chunk(gp_dma, __gp_dma_free_dma, dma_dev); + gen_pool_destroy(gp_dma); +} + +static int cio_dma_pool_init(void) +{ + /* No need to free up the resources: compiled in */ + cio_dma_pool = cio_gp_dma_create(cio_get_dma_css_dev(), 1); + if (!cio_dma_pool) + return -ENOMEM; + return 0; +} + +void *cio_gp_dma_zalloc(struct gen_pool *gp_dma, struct device *dma_dev, + size_t size) +{ + dma_addr_t dma_addr; + unsigned long addr; + size_t chunk_size; + + if (!gp_dma) + return NULL; + addr = gen_pool_alloc(gp_dma, size); + while (!addr) { + chunk_size = round_up(size, PAGE_SIZE); + addr = (unsigned long) dma_alloc_coherent(dma_dev, + chunk_size, &dma_addr, CIO_DMA_GFP); + if (!addr) + return NULL; + gen_pool_add_virt(gp_dma, addr, dma_addr, chunk_size, -1); + addr = gen_pool_alloc(gp_dma, size); + } + return (void *) addr; +} + +void cio_gp_dma_free(struct gen_pool *gp_dma, void *cpu_addr, size_t size) +{ + if (!cpu_addr) + return; + memset(cpu_addr, 0, size); + gen_pool_free(gp_dma, (unsigned long) cpu_addr, size); +} + +/* + * Allocate dma memory from the css global pool. Intended for memory not + * specific to any single device within the css. The allocated memory + * is not guaranteed to be 31-bit addressable. + * + * Caution: Not suitable for early stuff like console. + */ +void *cio_dma_zalloc(size_t size) +{ + return cio_gp_dma_zalloc(cio_dma_pool, cio_get_dma_css_dev(), size); +} + +void cio_dma_free(void *cpu_addr, size_t size) +{ + cio_gp_dma_free(cio_dma_pool, cpu_addr, size); +} + /* * Now that the driver core is running, we can setup our channel subsystem. * The struct subchannel's are created during probing. @@ -1059,16 +1228,22 @@ static int __init css_bus_init(void) if (ret) goto out_unregister; ret = register_pm_notifier(&css_power_notifier); - if (ret) { - unregister_reboot_notifier(&css_reboot_notifier); - goto out_unregister; - } + if (ret) + goto out_unregister_rn; + ret = cio_dma_pool_init(); + if (ret) + goto out_unregister_pmn; + airq_init(); css_init_done = 1; /* Enable default isc for I/O subchannels. */ isc_register(IO_SCH_ISC); return 0; +out_unregister_pmn: + unregister_pm_notifier(&css_power_notifier); +out_unregister_rn: + unregister_reboot_notifier(&css_reboot_notifier); out_unregister: while (i-- > 0) { struct channel_subsystem *css = channel_subsystems[i]; @@ -1222,6 +1397,10 @@ static int css_bus_match(struct device *dev, struct device_driver *drv) struct css_driver *driver = to_cssdriver(drv); struct css_device_id *id; + /* When driver_override is set, only bind to the matching driver */ + if (sch->driver_override && strcmp(sch->driver_override, drv->name)) + return 0; + for (id = driver->subchannel_type; id->match_flags; id++) { if (sch->st == id->type) return 1; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 1540229a37bb..9985b7484a6b 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -24,6 +24,7 @@ #include <linux/timer.h> #include <linux/kernel_stat.h> #include <linux/sched/signal.h> +#include <linux/dma-mapping.h> #include <asm/ccwdev.h> #include <asm/cio.h> @@ -687,6 +688,9 @@ ccw_device_release(struct device *dev) struct ccw_device *cdev; cdev = to_ccwdev(dev); + cio_gp_dma_free(cdev->private->dma_pool, cdev->private->dma_area, + sizeof(*cdev->private->dma_area)); + cio_gp_dma_destroy(cdev->private->dma_pool, &cdev->dev); /* Release reference of parent subchannel. */ put_device(cdev->dev.parent); kfree(cdev->private); @@ -696,15 +700,33 @@ ccw_device_release(struct device *dev) static struct ccw_device * io_subchannel_allocate_dev(struct subchannel *sch) { struct ccw_device *cdev; + struct gen_pool *dma_pool; cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); - if (cdev) { - cdev->private = kzalloc(sizeof(struct ccw_device_private), - GFP_KERNEL | GFP_DMA); - if (cdev->private) - return cdev; - } + if (!cdev) + goto err_cdev; + cdev->private = kzalloc(sizeof(struct ccw_device_private), + GFP_KERNEL | GFP_DMA); + if (!cdev->private) + goto err_priv; + cdev->dev.coherent_dma_mask = sch->dev.coherent_dma_mask; + cdev->dev.dma_mask = &cdev->dev.coherent_dma_mask; + dma_pool = cio_gp_dma_create(&cdev->dev, 1); + if (!dma_pool) + goto err_dma_pool; + cdev->private->dma_pool = dma_pool; + cdev->private->dma_area = cio_gp_dma_zalloc(dma_pool, &cdev->dev, + sizeof(*cdev->private->dma_area)); + if (!cdev->private->dma_area) + goto err_dma_area; + return cdev; +err_dma_area: + cio_gp_dma_destroy(dma_pool, &cdev->dev); +err_dma_pool: + kfree(cdev->private); +err_priv: kfree(cdev); +err_cdev: return ERR_PTR(-ENOMEM); } @@ -884,7 +906,7 @@ io_subchannel_recog_done(struct ccw_device *cdev) wake_up(&ccw_device_init_wq); break; case DEV_STATE_OFFLINE: - /* + /* * We can't register the device in interrupt context so * we schedule a work item. */ @@ -1062,6 +1084,14 @@ static int io_subchannel_probe(struct subchannel *sch) if (!io_priv) goto out_schedule; + io_priv->dma_area = dma_alloc_coherent(&sch->dev, + sizeof(*io_priv->dma_area), + &io_priv->dma_area_dma, GFP_KERNEL); + if (!io_priv->dma_area) { + kfree(io_priv); + goto out_schedule; + } + set_io_private(sch, io_priv); css_schedule_eval(sch->schid); return 0; @@ -1088,6 +1118,8 @@ static int io_subchannel_remove(struct subchannel *sch) set_io_private(sch, NULL); spin_unlock_irq(sch->lock); out_free: + dma_free_coherent(&sch->dev, sizeof(*io_priv->dma_area), + io_priv->dma_area, io_priv->dma_area_dma); kfree(io_priv); sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); return 0; @@ -1593,13 +1625,19 @@ struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv) return ERR_CAST(sch); io_priv = kzalloc(sizeof(*io_priv), GFP_KERNEL | GFP_DMA); - if (!io_priv) { - put_device(&sch->dev); - return ERR_PTR(-ENOMEM); - } + if (!io_priv) + goto err_priv; + io_priv->dma_area = dma_alloc_coherent(&sch->dev, + sizeof(*io_priv->dma_area), + &io_priv->dma_area_dma, GFP_KERNEL); + if (!io_priv->dma_area) + goto err_dma_area; set_io_private(sch, io_priv); cdev = io_subchannel_create_ccwdev(sch); if (IS_ERR(cdev)) { + dma_free_coherent(&sch->dev, sizeof(*io_priv->dma_area), + io_priv->dma_area, io_priv->dma_area_dma); + set_io_private(sch, NULL); put_device(&sch->dev); kfree(io_priv); return cdev; @@ -1607,6 +1645,12 @@ struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv) cdev->drv = drv; ccw_device_set_int_class(cdev); return cdev; + +err_dma_area: + kfree(io_priv); +err_priv: + put_device(&sch->dev); + return ERR_PTR(-ENOMEM); } void __init ccw_device_destroy_console(struct ccw_device *cdev) @@ -1617,6 +1661,8 @@ void __init ccw_device_destroy_console(struct ccw_device *cdev) set_io_private(sch, NULL); put_device(&sch->dev); put_device(&cdev->dev); + dma_free_coherent(&sch->dev, sizeof(*io_priv->dma_area), + io_priv->dma_area, io_priv->dma_area_dma); kfree(io_priv); } diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 9169af7dbb43..8fc267324ebb 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -67,8 +67,10 @@ static void ccw_timeout_log(struct ccw_device *cdev) sizeof(struct tcw), 0); } else { printk(KERN_WARNING "cio: orb indicates command mode\n"); - if ((void *)(addr_t)orb->cmd.cpa == &private->sense_ccw || - (void *)(addr_t)orb->cmd.cpa == cdev->private->iccws) + if ((void *)(addr_t)orb->cmd.cpa == + &private->dma_area->sense_ccw || + (void *)(addr_t)orb->cmd.cpa == + cdev->private->dma_area->iccws) printk(KERN_WARNING "cio: last channel program " "(intern):\n"); else @@ -143,18 +145,22 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) void ccw_device_update_sense_data(struct ccw_device *cdev) { memset(&cdev->id, 0, sizeof(cdev->id)); - cdev->id.cu_type = cdev->private->senseid.cu_type; - cdev->id.cu_model = cdev->private->senseid.cu_model; - cdev->id.dev_type = cdev->private->senseid.dev_type; - cdev->id.dev_model = cdev->private->senseid.dev_model; + cdev->id.cu_type = cdev->private->dma_area->senseid.cu_type; + cdev->id.cu_model = cdev->private->dma_area->senseid.cu_model; + cdev->id.dev_type = cdev->private->dma_area->senseid.dev_type; + cdev->id.dev_model = cdev->private->dma_area->senseid.dev_model; } int ccw_device_test_sense_data(struct ccw_device *cdev) { - return cdev->id.cu_type == cdev->private->senseid.cu_type && - cdev->id.cu_model == cdev->private->senseid.cu_model && - cdev->id.dev_type == cdev->private->senseid.dev_type && - cdev->id.dev_model == cdev->private->senseid.dev_model; + return cdev->id.cu_type == + cdev->private->dma_area->senseid.cu_type && + cdev->id.cu_model == + cdev->private->dma_area->senseid.cu_model && + cdev->id.dev_type == + cdev->private->dma_area->senseid.dev_type && + cdev->id.dev_model == + cdev->private->dma_area->senseid.dev_model; } /* @@ -342,7 +348,7 @@ ccw_device_done(struct ccw_device *cdev, int state) cio_disable_subchannel(sch); /* Reset device status. */ - memset(&cdev->private->irb, 0, sizeof(struct irb)); + memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb)); cdev->private->state = state; @@ -509,13 +515,14 @@ callback: ccw_device_done(cdev, DEV_STATE_ONLINE); /* Deliver fake irb to device driver, if needed. */ if (cdev->private->flags.fake_irb) { - create_fake_irb(&cdev->private->irb, + create_fake_irb(&cdev->private->dma_area->irb, cdev->private->flags.fake_irb); cdev->private->flags.fake_irb = 0; if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - &cdev->private->irb); - memset(&cdev->private->irb, 0, sizeof(struct irb)); + &cdev->private->dma_area->irb); + memset(&cdev->private->dma_area->irb, 0, + sizeof(struct irb)); } ccw_device_report_path_events(cdev); ccw_device_handle_broken_paths(cdev); @@ -672,7 +679,8 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) if (scsw_actl(&sch->schib.scsw) != 0 || (scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_STATUS_PEND) || - (scsw_stctl(&cdev->private->irb.scsw) & SCSW_STCTL_STATUS_PEND)) { + (scsw_stctl(&cdev->private->dma_area->irb.scsw) & + SCSW_STCTL_STATUS_PEND)) { /* * No final status yet or final status not yet delivered * to the device driver. Can't do path verification now, @@ -719,7 +727,7 @@ static int ccw_device_call_handler(struct ccw_device *cdev) * - fast notification was requested (primary status) * - unsolicited interrupts */ - stctl = scsw_stctl(&cdev->private->irb.scsw); + stctl = scsw_stctl(&cdev->private->dma_area->irb.scsw); ending_status = (stctl & SCSW_STCTL_SEC_STATUS) || (stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) || (stctl == SCSW_STCTL_STATUS_PEND); @@ -735,9 +743,9 @@ static int ccw_device_call_handler(struct ccw_device *cdev) if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - &cdev->private->irb); + &cdev->private->dma_area->irb); - memset(&cdev->private->irb, 0, sizeof(struct irb)); + memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb)); return 1; } @@ -759,7 +767,8 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event) /* Unit check but no sense data. Need basic sense. */ if (ccw_device_do_sense(cdev, irb) != 0) goto call_handler_unsol; - memcpy(&cdev->private->irb, irb, sizeof(struct irb)); + memcpy(&cdev->private->dma_area->irb, irb, + sizeof(struct irb)); cdev->private->state = DEV_STATE_W4SENSE; cdev->private->intparm = 0; return; @@ -842,7 +851,7 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) if (scsw_fctl(&irb->scsw) & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { cdev->private->flags.dosense = 0; - memset(&cdev->private->irb, 0, sizeof(struct irb)); + memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb)); ccw_device_accumulate_irb(cdev, irb); goto call_handler; } diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index f6df83a9dfbb..740996d0dc8c 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c @@ -99,7 +99,7 @@ static int diag210_to_senseid(struct senseid *senseid, struct diag210 *diag) static int diag210_get_dev_info(struct ccw_device *cdev) { struct ccw_dev_id *dev_id = &cdev->private->dev_id; - struct senseid *senseid = &cdev->private->senseid; + struct senseid *senseid = &cdev->private->dma_area->senseid; struct diag210 diag_data; int rc; @@ -134,8 +134,10 @@ err_failed: static void snsid_init(struct ccw_device *cdev) { cdev->private->flags.esid = 0; - memset(&cdev->private->senseid, 0, sizeof(cdev->private->senseid)); - cdev->private->senseid.cu_type = 0xffff; + + memset(&cdev->private->dma_area->senseid, 0, + sizeof(cdev->private->dma_area->senseid)); + cdev->private->dma_area->senseid.cu_type = 0xffff; } /* @@ -143,16 +145,16 @@ static void snsid_init(struct ccw_device *cdev) */ static int snsid_check(struct ccw_device *cdev, void *data) { - struct cmd_scsw *scsw = &cdev->private->irb.scsw.cmd; + struct cmd_scsw *scsw = &cdev->private->dma_area->irb.scsw.cmd; int len = sizeof(struct senseid) - scsw->count; /* Check for incomplete SENSE ID data. */ if (len < SENSE_ID_MIN_LEN) goto out_restart; - if (cdev->private->senseid.cu_type == 0xffff) + if (cdev->private->dma_area->senseid.cu_type == 0xffff) goto out_restart; /* Check for incompatible SENSE ID data. */ - if (cdev->private->senseid.reserved != 0xff) + if (cdev->private->dma_area->senseid.reserved != 0xff) return -EOPNOTSUPP; /* Check for extended-identification information. */ if (len > SENSE_ID_BASIC_LEN) @@ -170,7 +172,7 @@ out_restart: static void snsid_callback(struct ccw_device *cdev, void *data, int rc) { struct ccw_dev_id *id = &cdev->private->dev_id; - struct senseid *senseid = &cdev->private->senseid; + struct senseid *senseid = &cdev->private->dma_area->senseid; int vm = 0; if (rc && MACHINE_IS_VM) { @@ -200,7 +202,7 @@ void ccw_device_sense_id_start(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); struct ccw_request *req = &cdev->private->req; - struct ccw1 *cp = cdev->private->iccws; + struct ccw1 *cp = cdev->private->dma_area->iccws; CIO_TRACE_EVENT(4, "snsid"); CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); @@ -208,7 +210,7 @@ void ccw_device_sense_id_start(struct ccw_device *cdev) snsid_init(cdev); /* Channel program setup. */ cp->cmd_code = CCW_CMD_SENSE_ID; - cp->cda = (u32) (addr_t) &cdev->private->senseid; + cp->cda = (u32) (addr_t) &cdev->private->dma_area->senseid; cp->count = sizeof(struct senseid); cp->flags = CCW_FLAG_SLI; /* Request setup. */ diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 4435ae0b3027..d722458c5928 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -429,8 +429,8 @@ struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct) if (cdev->private->flags.esid == 0) return NULL; for (ciw_cnt = 0; ciw_cnt < MAX_CIWS; ciw_cnt++) - if (cdev->private->senseid.ciw[ciw_cnt].ct == ct) - return cdev->private->senseid.ciw + ciw_cnt; + if (cdev->private->dma_area->senseid.ciw[ciw_cnt].ct == ct) + return cdev->private->dma_area->senseid.ciw + ciw_cnt; return NULL; } @@ -699,6 +699,23 @@ void ccw_device_get_schid(struct ccw_device *cdev, struct subchannel_id *schid) } EXPORT_SYMBOL_GPL(ccw_device_get_schid); +/* + * Allocate zeroed dma coherent 31 bit addressable memory using + * the subchannels dma pool. Maximal size of allocation supported + * is PAGE_SIZE. + */ +void *ccw_device_dma_zalloc(struct ccw_device *cdev, size_t size) +{ + return cio_gp_dma_zalloc(cdev->private->dma_pool, &cdev->dev, size); +} +EXPORT_SYMBOL(ccw_device_dma_zalloc); + +void ccw_device_dma_free(struct ccw_device *cdev, void *cpu_addr, size_t size) +{ + cio_gp_dma_free(cdev->private->dma_pool, cpu_addr, size); +} +EXPORT_SYMBOL(ccw_device_dma_free); + EXPORT_SYMBOL(ccw_device_set_options_mask); EXPORT_SYMBOL(ccw_device_set_options); EXPORT_SYMBOL(ccw_device_clear_options); diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index d30a3babf176..767a85635a0f 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c @@ -57,7 +57,7 @@ out: static void nop_build_cp(struct ccw_device *cdev) { struct ccw_request *req = &cdev->private->req; - struct ccw1 *cp = cdev->private->iccws; + struct ccw1 *cp = cdev->private->dma_area->iccws; cp->cmd_code = CCW_CMD_NOOP; cp->cda = 0; @@ -134,9 +134,9 @@ err: static void spid_build_cp(struct ccw_device *cdev, u8 fn) { struct ccw_request *req = &cdev->private->req; - struct ccw1 *cp = cdev->private->iccws; + struct ccw1 *cp = cdev->private->dma_area->iccws; int i = pathmask_to_pos(req->lpm); - struct pgid *pgid = &cdev->private->pgid[i]; + struct pgid *pgid = &cdev->private->dma_area->pgid[i]; pgid->inf.fc = fn; cp->cmd_code = CCW_CMD_SET_PGID; @@ -300,7 +300,7 @@ static int pgid_cmp(struct pgid *p1, struct pgid *p2) static void pgid_analyze(struct ccw_device *cdev, struct pgid **p, int *mismatch, u8 *reserved, u8 *reset) { - struct pgid *pgid = &cdev->private->pgid[0]; + struct pgid *pgid = &cdev->private->dma_area->pgid[0]; struct pgid *first = NULL; int lpm; int i; @@ -342,7 +342,7 @@ static u8 pgid_to_donepm(struct ccw_device *cdev) lpm = 0x80 >> i; if ((cdev->private->pgid_valid_mask & lpm) == 0) continue; - pgid = &cdev->private->pgid[i]; + pgid = &cdev->private->dma_area->pgid[i]; if (sch->opm & lpm) { if (pgid->inf.ps.state1 != SNID_STATE1_GROUPED) continue; @@ -368,7 +368,8 @@ static void pgid_fill(struct ccw_device *cdev, struct pgid *pgid) int i; for (i = 0; i < 8; i++) - memcpy(&cdev->private->pgid[i], pgid, sizeof(struct pgid)); + memcpy(&cdev->private->dma_area->pgid[i], pgid, + sizeof(struct pgid)); } /* @@ -435,12 +436,12 @@ out: static void snid_build_cp(struct ccw_device *cdev) { struct ccw_request *req = &cdev->private->req; - struct ccw1 *cp = cdev->private->iccws; + struct ccw1 *cp = cdev->private->dma_area->iccws; int i = pathmask_to_pos(req->lpm); /* Channel program setup. */ cp->cmd_code = CCW_CMD_SENSE_PGID; - cp->cda = (u32) (addr_t) &cdev->private->pgid[i]; + cp->cda = (u32) (addr_t) &cdev->private->dma_area->pgid[i]; cp->count = sizeof(struct pgid); cp->flags = CCW_FLAG_SLI; req->cp = cp; @@ -516,7 +517,8 @@ static void verify_start(struct ccw_device *cdev) sch->lpm = sch->schib.pmcw.pam; /* Initialize PGID data. */ - memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid)); + memset(cdev->private->dma_area->pgid, 0, + sizeof(cdev->private->dma_area->pgid)); cdev->private->pgid_valid_mask = 0; cdev->private->pgid_todo_mask = sch->schib.pmcw.pam; cdev->private->path_notoper_mask = 0; @@ -626,7 +628,7 @@ struct stlck_data { static void stlck_build_cp(struct ccw_device *cdev, void *buf1, void *buf2) { struct ccw_request *req = &cdev->private->req; - struct ccw1 *cp = cdev->private->iccws; + struct ccw1 *cp = cdev->private->dma_area->iccws; cp[0].cmd_code = CCW_CMD_STLCK; cp[0].cda = (u32) (addr_t) buf1; diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index 7d5c7892b2c4..0bd8f2642732 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -79,15 +79,15 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb) * are condition that have to be met for the extended control * bit to have meaning. Sick. */ - cdev->private->irb.scsw.cmd.ectl = 0; + cdev->private->dma_area->irb.scsw.cmd.ectl = 0; if ((irb->scsw.cmd.stctl & SCSW_STCTL_ALERT_STATUS) && !(irb->scsw.cmd.stctl & SCSW_STCTL_INTER_STATUS)) - cdev->private->irb.scsw.cmd.ectl = irb->scsw.cmd.ectl; + cdev->private->dma_area->irb.scsw.cmd.ectl = irb->scsw.cmd.ectl; /* Check if extended control word is valid. */ - if (!cdev->private->irb.scsw.cmd.ectl) + if (!cdev->private->dma_area->irb.scsw.cmd.ectl) return; /* Copy concurrent sense / model dependent information. */ - memcpy (&cdev->private->irb.ecw, irb->ecw, sizeof (irb->ecw)); + memcpy(&cdev->private->dma_area->irb.ecw, irb->ecw, sizeof(irb->ecw)); } /* @@ -118,7 +118,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb) if (!ccw_device_accumulate_esw_valid(irb)) return; - cdev_irb = &cdev->private->irb; + cdev_irb = &cdev->private->dma_area->irb; /* Copy last path used mask. */ cdev_irb->esw.esw1.lpum = irb->esw.esw1.lpum; @@ -210,7 +210,7 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb) ccw_device_path_notoper(cdev); /* No irb accumulation for transport mode irbs. */ if (scsw_is_tm(&irb->scsw)) { - memcpy(&cdev->private->irb, irb, sizeof(struct irb)); + memcpy(&cdev->private->dma_area->irb, irb, sizeof(struct irb)); return; } /* @@ -219,7 +219,7 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb) if (!scsw_is_solicited(&irb->scsw)) return; - cdev_irb = &cdev->private->irb; + cdev_irb = &cdev->private->dma_area->irb; /* * If the clear function had been performed, all formerly pending @@ -227,7 +227,7 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb) * intermediate accumulated status to the device driver. */ if (irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC) - memset(&cdev->private->irb, 0, sizeof(struct irb)); + memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb)); /* Copy bits which are valid only for the start function. */ if (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) { @@ -329,9 +329,9 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) /* * We have ending status but no sense information. Do a basic sense. */ - sense_ccw = &to_io_private(sch)->sense_ccw; + sense_ccw = &to_io_private(sch)->dma_area->sense_ccw; sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE; - sense_ccw->cda = (__u32) __pa(cdev->private->irb.ecw); + sense_ccw->cda = (__u32) __pa(cdev->private->dma_area->irb.ecw); sense_ccw->count = SENSE_MAX_COUNT; sense_ccw->flags = CCW_FLAG_SLI; @@ -364,7 +364,7 @@ ccw_device_accumulate_basic_sense(struct ccw_device *cdev, struct irb *irb) if (!(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && (irb->scsw.cmd.dstat & DEV_STAT_CHN_END)) { - cdev->private->irb.esw.esw0.erw.cons = 1; + cdev->private->dma_area->irb.esw.esw0.erw.cons = 1; cdev->private->flags.dosense = 0; } /* Check if path verification is required. */ @@ -386,7 +386,7 @@ ccw_device_accumulate_and_sense(struct ccw_device *cdev, struct irb *irb) /* Check for basic sense. */ if (cdev->private->flags.dosense && !(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)) { - cdev->private->irb.esw.esw0.erw.cons = 1; + cdev->private->dma_area->irb.esw.esw0.erw.cons = 1; cdev->private->flags.dosense = 0; return 0; } diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index 90e4e3a7841b..c03b4a19974e 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h @@ -9,15 +9,20 @@ #include "css.h" #include "orb.h" +struct io_subchannel_dma_area { + struct ccw1 sense_ccw; /* static ccw for sense command */ +}; + struct io_subchannel_private { union orb orb; /* operation request block */ - struct ccw1 sense_ccw; /* static ccw for sense command */ struct ccw_device *cdev;/* pointer to the child ccw device */ struct { unsigned int suspend:1; /* allow suspend */ unsigned int prefetch:1;/* deny prefetch */ unsigned int inter:1; /* suppress intermediate interrupts */ } __packed options; + struct io_subchannel_dma_area *dma_area; + dma_addr_t dma_area_dma; } __aligned(8); #define to_io_private(n) ((struct io_subchannel_private *) \ @@ -115,6 +120,13 @@ enum cdev_todo { #define FAKE_CMD_IRB 1 #define FAKE_TM_IRB 2 +struct ccw_device_dma_area { + struct senseid senseid; /* SenseID info */ + struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ + struct irb irb; /* device status */ + struct pgid pgid[8]; /* path group IDs per chpid*/ +}; + struct ccw_device_private { struct ccw_device *cdev; struct subchannel *sch; @@ -156,11 +168,7 @@ struct ccw_device_private { } __attribute__((packed)) flags; unsigned long intparm; /* user interruption parameter */ struct qdio_irq *qdio_data; - struct irb irb; /* device status */ int async_kill_io_rc; - struct senseid senseid; /* SenseID info */ - struct pgid pgid[8]; /* path group IDs per chpid*/ - struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ struct work_struct todo_work; enum cdev_todo todo; wait_queue_head_t wait_q; @@ -169,6 +177,8 @@ struct ccw_device_private { struct list_head cmb_list; /* list of measured devices */ u64 cmb_start_time; /* clock value of cmb reset */ void *cmb_wait; /* deferred cmb enable/disable */ + struct gen_pool *dma_pool; + struct ccw_device_dma_area *dma_area; enum interruption_class int_class; }; diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 7b7620de2acd..730c4e68094b 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -736,6 +736,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q, unsigned int start) switch (state) { case SLSB_P_OUTPUT_EMPTY: + case SLSB_P_OUTPUT_PENDING: /* the adapter got it */ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out empty:%1d %02x", q->nr, count); diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 99d7d2566a3a..d4101cecdc8d 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -150,6 +150,7 @@ static int __qdio_allocate_qs(struct qdio_q **irq_ptr_qs, int nr_queues) return -ENOMEM; } irq_ptr_qs[i] = q; + INIT_LIST_HEAD(&q->entry); } return 0; } @@ -178,6 +179,7 @@ static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr, q->mask = 1 << (31 - i); q->nr = i; q->handler = handler; + INIT_LIST_HEAD(&q->entry); } static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr, diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 28d59ac2204c..93ee067c10ca 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -79,7 +79,6 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr) mutex_lock(&tiq_list_lock); list_add_rcu(&irq_ptr->input_qs[0]->entry, &tiq_list); mutex_unlock(&tiq_list_lock); - xchg(irq_ptr->dsci, 1 << 7); } void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) @@ -87,14 +86,14 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) struct qdio_q *q; q = irq_ptr->input_qs[0]; - /* if establish triggered an error */ - if (!q || !q->entry.prev || !q->entry.next) + if (!q) return; mutex_lock(&tiq_list_lock); list_del_rcu(&q->entry); mutex_unlock(&tiq_list_lock); synchronize_rcu(); + INIT_LIST_HEAD(&q->entry); } static inline int has_multiple_inq_on_dsci(struct qdio_irq *irq_ptr) @@ -178,6 +177,7 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq) /** * tiqdio_thinint_handler - thin interrupt handler for qdio * @airq: pointer to adapter interrupt descriptor + * @floating: flag to recognize floating vs. directed interrupts (unused) */ static void tiqdio_thinint_handler(struct airq_struct *airq, bool floating) { diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c index 0e79799e9a71..1d4c893ead23 100644 --- a/drivers/s390/cio/vfio_ccw_cp.c +++ b/drivers/s390/cio/vfio_ccw_cp.c @@ -16,12 +16,6 @@ #include "vfio_ccw_cp.h" -/* - * Max length for ccw chain. - * XXX: Limit to 256, need to check more? - */ -#define CCWCHAIN_LEN_MAX 256 - struct pfn_array { /* Starting guest physical I/O address. */ unsigned long pa_iova; @@ -33,11 +27,6 @@ struct pfn_array { int pa_nr; }; -struct pfn_array_table { - struct pfn_array *pat_pa; - int pat_nr; -}; - struct ccwchain { struct list_head next; struct ccw1 *ch_ccw; @@ -46,35 +35,29 @@ struct ccwchain { /* Count of the valid ccws in chain. */ int ch_len; /* Pinned PAGEs for the original data. */ - struct pfn_array_table *ch_pat; + struct pfn_array *ch_pa; }; /* - * pfn_array_alloc_pin() - alloc memory for PFNs, then pin user pages in memory + * pfn_array_alloc() - alloc memory for PFNs * @pa: pfn_array on which to perform the operation - * @mdev: the mediated device to perform pin/unpin operations * @iova: target guest physical address * @len: number of bytes that should be pinned from @iova * - * Attempt to allocate memory for PFNs, and pin user pages in memory. + * Attempt to allocate memory for PFNs. * * Usage of pfn_array: * We expect (pa_nr == 0) and (pa_iova_pfn == NULL), any field in * this structure will be filled in by this function. * * Returns: - * Number of pages pinned on success. - * If @pa->pa_nr is not 0, or @pa->pa_iova_pfn is not NULL initially, - * returns -EINVAL. - * If no pages were pinned, returns -errno. + * 0 if PFNs are allocated + * -EINVAL if pa->pa_nr is not initially zero, or pa->pa_iova_pfn is not NULL + * -ENOMEM if alloc failed */ -static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev, - u64 iova, unsigned int len) +static int pfn_array_alloc(struct pfn_array *pa, u64 iova, unsigned int len) { - int i, ret = 0; - - if (!len) - return 0; + int i; if (pa->pa_nr || pa->pa_iova_pfn) return -EINVAL; @@ -94,8 +77,27 @@ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev, pa->pa_pfn = pa->pa_iova_pfn + pa->pa_nr; pa->pa_iova_pfn[0] = pa->pa_iova >> PAGE_SHIFT; - for (i = 1; i < pa->pa_nr; i++) + pa->pa_pfn[0] = -1ULL; + for (i = 1; i < pa->pa_nr; i++) { pa->pa_iova_pfn[i] = pa->pa_iova_pfn[i - 1] + 1; + pa->pa_pfn[i] = -1ULL; + } + + return 0; +} + +/* + * pfn_array_pin() - Pin user pages in memory + * @pa: pfn_array on which to perform the operation + * @mdev: the mediated device to perform pin operations + * + * Returns number of pages pinned upon success. + * If the pin request partially succeeds, or fails completely, + * all pages are left unpinned and a negative error value is returned. + */ +static int pfn_array_pin(struct pfn_array *pa, struct device *mdev) +{ + int ret = 0; ret = vfio_pin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr, IOMMU_READ | IOMMU_WRITE, pa->pa_pfn); @@ -112,8 +114,6 @@ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev, err_out: pa->pa_nr = 0; - kfree(pa->pa_iova_pfn); - pa->pa_iova_pfn = NULL; return ret; } @@ -121,60 +121,30 @@ err_out: /* Unpin the pages before releasing the memory. */ static void pfn_array_unpin_free(struct pfn_array *pa, struct device *mdev) { - vfio_unpin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr); + /* Only unpin if any pages were pinned to begin with */ + if (pa->pa_nr) + vfio_unpin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr); pa->pa_nr = 0; kfree(pa->pa_iova_pfn); } -static int pfn_array_table_init(struct pfn_array_table *pat, int nr) -{ - pat->pat_pa = kcalloc(nr, sizeof(*pat->pat_pa), GFP_KERNEL); - if (unlikely(ZERO_OR_NULL_PTR(pat->pat_pa))) { - pat->pat_nr = 0; - return -ENOMEM; - } - - pat->pat_nr = nr; - - return 0; -} - -static void pfn_array_table_unpin_free(struct pfn_array_table *pat, - struct device *mdev) +static bool pfn_array_iova_pinned(struct pfn_array *pa, unsigned long iova) { - int i; - - for (i = 0; i < pat->pat_nr; i++) - pfn_array_unpin_free(pat->pat_pa + i, mdev); - - if (pat->pat_nr) { - kfree(pat->pat_pa); - pat->pat_pa = NULL; - pat->pat_nr = 0; - } -} - -static bool pfn_array_table_iova_pinned(struct pfn_array_table *pat, - unsigned long iova) -{ - struct pfn_array *pa = pat->pat_pa; unsigned long iova_pfn = iova >> PAGE_SHIFT; - int i, j; + int i; - for (i = 0; i < pat->pat_nr; i++, pa++) - for (j = 0; j < pa->pa_nr; j++) - if (pa->pa_iova_pfn[j] == iova_pfn) - return true; + for (i = 0; i < pa->pa_nr; i++) + if (pa->pa_iova_pfn[i] == iova_pfn) + return true; return false; } -/* Create the list idal words for a pfn_array_table. */ -static inline void pfn_array_table_idal_create_words( - struct pfn_array_table *pat, +/* Create the list of IDAL words for a pfn_array. */ +static inline void pfn_array_idal_create_words( + struct pfn_array *pa, unsigned long *idaws) { - struct pfn_array *pa; - int i, j, k; + int i; /* * Idal words (execept the first one) rely on the memory being 4k @@ -183,19 +153,36 @@ static inline void pfn_array_table_idal_create_words( * there will be no problem here to simply use the phys to create an * idaw. */ - k = 0; - for (i = 0; i < pat->pat_nr; i++) { - pa = pat->pat_pa + i; - for (j = 0; j < pa->pa_nr; j++) { - idaws[k] = pa->pa_pfn[j] << PAGE_SHIFT; - if (k == 0) - idaws[k] += pa->pa_iova & (PAGE_SIZE - 1); - k++; + + for (i = 0; i < pa->pa_nr; i++) + idaws[i] = pa->pa_pfn[i] << PAGE_SHIFT; + + /* Adjust the first IDAW, since it may not start on a page boundary */ + idaws[0] += pa->pa_iova & (PAGE_SIZE - 1); +} + +static void convert_ccw0_to_ccw1(struct ccw1 *source, unsigned long len) +{ + struct ccw0 ccw0; + struct ccw1 *pccw1 = source; + int i; + + for (i = 0; i < len; i++) { + ccw0 = *(struct ccw0 *)pccw1; + if ((pccw1->cmd_code & 0x0f) == CCW_CMD_TIC) { + pccw1->cmd_code = CCW_CMD_TIC; + pccw1->flags = 0; + pccw1->count = 0; + } else { + pccw1->cmd_code = ccw0.cmd_code; + pccw1->flags = ccw0.flags; + pccw1->count = ccw0.count; } + pccw1->cda = ccw0.cda; + pccw1++; } } - /* * Within the domain (@mdev), copy @n bytes from a guest physical * address (@iova) to a host physical address (@to). @@ -209,9 +196,15 @@ static long copy_from_iova(struct device *mdev, int i, ret; unsigned long l, m; - ret = pfn_array_alloc_pin(&pa, mdev, iova, n); - if (ret <= 0) + ret = pfn_array_alloc(&pa, iova, n); + if (ret < 0) + return ret; + + ret = pfn_array_pin(&pa, mdev); + if (ret < 0) { + pfn_array_unpin_free(&pa, mdev); return ret; + } l = n; for (i = 0; i < pa.pa_nr; i++) { @@ -235,55 +228,60 @@ static long copy_from_iova(struct device *mdev, return l; } -static long copy_ccw_from_iova(struct channel_program *cp, - struct ccw1 *to, u64 iova, - unsigned long len) -{ - struct ccw0 ccw0; - struct ccw1 *pccw1; - int ret; - int i; - - ret = copy_from_iova(cp->mdev, to, iova, len * sizeof(struct ccw1)); - if (ret) - return ret; - - if (!cp->orb.cmd.fmt) { - pccw1 = to; - for (i = 0; i < len; i++) { - ccw0 = *(struct ccw0 *)pccw1; - if ((pccw1->cmd_code & 0x0f) == CCW_CMD_TIC) { - pccw1->cmd_code = CCW_CMD_TIC; - pccw1->flags = 0; - pccw1->count = 0; - } else { - pccw1->cmd_code = ccw0.cmd_code; - pccw1->flags = ccw0.flags; - pccw1->count = ccw0.count; - } - pccw1->cda = ccw0.cda; - pccw1++; - } - } - - return ret; -} - /* * Helpers to operate ccwchain. */ -#define ccw_is_test(_ccw) (((_ccw)->cmd_code & 0x0F) == 0) +#define ccw_is_read(_ccw) (((_ccw)->cmd_code & 0x03) == 0x02) +#define ccw_is_read_backward(_ccw) (((_ccw)->cmd_code & 0x0F) == 0x0C) +#define ccw_is_sense(_ccw) (((_ccw)->cmd_code & 0x0F) == CCW_CMD_BASIC_SENSE) #define ccw_is_noop(_ccw) ((_ccw)->cmd_code == CCW_CMD_NOOP) #define ccw_is_tic(_ccw) ((_ccw)->cmd_code == CCW_CMD_TIC) #define ccw_is_idal(_ccw) ((_ccw)->flags & CCW_FLAG_IDA) - +#define ccw_is_skip(_ccw) ((_ccw)->flags & CCW_FLAG_SKIP) #define ccw_is_chain(_ccw) ((_ccw)->flags & (CCW_FLAG_CC | CCW_FLAG_DC)) /* + * ccw_does_data_transfer() + * + * Determine whether a CCW will move any data, such that the guest pages + * would need to be pinned before performing the I/O. + * + * Returns 1 if yes, 0 if no. + */ +static inline int ccw_does_data_transfer(struct ccw1 *ccw) +{ + /* If the count field is zero, then no data will be transferred */ + if (ccw->count == 0) + return 0; + + /* If the command is a NOP, then no data will be transferred */ + if (ccw_is_noop(ccw)) + return 0; + + /* If the skip flag is off, then data will be transferred */ + if (!ccw_is_skip(ccw)) + return 1; + + /* + * If the skip flag is on, it is only meaningful if the command + * code is a read, read backward, sense, or sense ID. In those + * cases, no data will be transferred. + */ + if (ccw_is_read(ccw) || ccw_is_read_backward(ccw)) + return 0; + + if (ccw_is_sense(ccw)) + return 0; + + /* The skip flag is on, but it is ignored for this command code. */ + return 1; +} + +/* * is_cpa_within_range() * * @cpa: channel program address being questioned @@ -319,7 +317,7 @@ static struct ccwchain *ccwchain_alloc(struct channel_program *cp, int len) /* Make ccw address aligned to 8. */ size = ((sizeof(*chain) + 7L) & -8L) + sizeof(*chain->ch_ccw) * len + - sizeof(*chain->ch_pat) * len; + sizeof(*chain->ch_pa) * len; chain = kzalloc(size, GFP_DMA | GFP_KERNEL); if (!chain) return NULL; @@ -328,7 +326,7 @@ static struct ccwchain *ccwchain_alloc(struct channel_program *cp, int len) chain->ch_ccw = (struct ccw1 *)data; data = (u8 *)(chain->ch_ccw) + sizeof(*chain->ch_ccw) * len; - chain->ch_pat = (struct pfn_array_table *)data; + chain->ch_pa = (struct pfn_array *)data; chain->ch_len = len; @@ -348,31 +346,12 @@ static void ccwchain_cda_free(struct ccwchain *chain, int idx) { struct ccw1 *ccw = chain->ch_ccw + idx; - if (ccw_is_test(ccw) || ccw_is_noop(ccw) || ccw_is_tic(ccw)) - return; - if (!ccw->count) + if (ccw_is_tic(ccw)) return; kfree((void *)(u64)ccw->cda); } -/* Unpin the pages then free the memory resources. */ -static void cp_unpin_free(struct channel_program *cp) -{ - struct ccwchain *chain, *temp; - int i; - - cp->initialized = false; - list_for_each_entry_safe(chain, temp, &cp->ccwchain_list, next) { - for (i = 0; i < chain->ch_len; i++) { - pfn_array_table_unpin_free(chain->ch_pat + i, - cp->mdev); - ccwchain_cda_free(chain, i); - } - ccwchain_free(chain); - } -} - /** * ccwchain_calc_length - calculate the length of the ccw chain. * @iova: guest physical address of the target ccw chain @@ -388,25 +367,9 @@ static void cp_unpin_free(struct channel_program *cp) */ static int ccwchain_calc_length(u64 iova, struct channel_program *cp) { - struct ccw1 *ccw, *p; - int cnt; - - /* - * Copy current chain from guest to host kernel. - * Currently the chain length is limited to CCWCHAIN_LEN_MAX (256). - * So copying 2K is enough (safe). - */ - p = ccw = kcalloc(CCWCHAIN_LEN_MAX, sizeof(*ccw), GFP_KERNEL); - if (!ccw) - return -ENOMEM; - - cnt = copy_ccw_from_iova(cp, ccw, iova, CCWCHAIN_LEN_MAX); - if (cnt) { - kfree(ccw); - return cnt; - } + struct ccw1 *ccw = cp->guest_cp; + int cnt = 0; - cnt = 0; do { cnt++; @@ -415,10 +378,8 @@ static int ccwchain_calc_length(u64 iova, struct channel_program *cp) * orb specified one of the unsupported formats, we defer * checking for IDAWs in unsupported formats to here. */ - if ((!cp->orb.cmd.c64 || cp->orb.cmd.i2k) && ccw_is_idal(ccw)) { - kfree(p); + if ((!cp->orb.cmd.c64 || cp->orb.cmd.i2k) && ccw_is_idal(ccw)) return -EOPNOTSUPP; - } /* * We want to keep counting if the current CCW has the @@ -437,7 +398,6 @@ static int ccwchain_calc_length(u64 iova, struct channel_program *cp) if (cnt == CCWCHAIN_LEN_MAX + 1) cnt = -EINVAL; - kfree(p); return cnt; } @@ -458,17 +418,23 @@ static int tic_target_chain_exists(struct ccw1 *tic, struct channel_program *cp) static int ccwchain_loop_tic(struct ccwchain *chain, struct channel_program *cp); -static int ccwchain_handle_tic(struct ccw1 *tic, struct channel_program *cp) +static int ccwchain_handle_ccw(u32 cda, struct channel_program *cp) { struct ccwchain *chain; - int len, ret; + int len; - /* May transfer to an existing chain. */ - if (tic_target_chain_exists(tic, cp)) - return 0; + /* Copy 2K (the most we support today) of possible CCWs */ + len = copy_from_iova(cp->mdev, cp->guest_cp, cda, + CCWCHAIN_LEN_MAX * sizeof(struct ccw1)); + if (len) + return len; - /* Get chain length. */ - len = ccwchain_calc_length(tic->cda, cp); + /* Convert any Format-0 CCWs to Format-1 */ + if (!cp->orb.cmd.fmt) + convert_ccw0_to_ccw1(cp->guest_cp, CCWCHAIN_LEN_MAX); + + /* Count the CCWs in the current chain */ + len = ccwchain_calc_length(cda, cp); if (len < 0) return len; @@ -476,14 +442,10 @@ static int ccwchain_handle_tic(struct ccw1 *tic, struct channel_program *cp) chain = ccwchain_alloc(cp, len); if (!chain) return -ENOMEM; - chain->ch_iova = tic->cda; + chain->ch_iova = cda; - /* Copy the new chain from user. */ - ret = copy_ccw_from_iova(cp, chain->ch_ccw, tic->cda, len); - if (ret) { - ccwchain_free(chain); - return ret; - } + /* Copy the actual CCWs into the new chain */ + memcpy(chain->ch_ccw, cp->guest_cp, len * sizeof(struct ccw1)); /* Loop for tics on this new chain. */ return ccwchain_loop_tic(chain, cp); @@ -501,7 +463,12 @@ static int ccwchain_loop_tic(struct ccwchain *chain, struct channel_program *cp) if (!ccw_is_tic(tic)) continue; - ret = ccwchain_handle_tic(tic, cp); + /* May transfer to an existing chain. */ + if (tic_target_chain_exists(tic, cp)) + continue; + + /* Build a ccwchain for the next segment */ + ret = ccwchain_handle_ccw(tic->cda, cp); if (ret) return ret; } @@ -534,115 +501,90 @@ static int ccwchain_fetch_direct(struct ccwchain *chain, struct channel_program *cp) { struct ccw1 *ccw; - struct pfn_array_table *pat; + struct pfn_array *pa; + u64 iova; unsigned long *idaws; int ret; + int bytes = 1; + int idaw_nr, idal_len; + int i; ccw = chain->ch_ccw + idx; - if (!ccw->count) { - /* - * We just want the translation result of any direct ccw - * to be an IDA ccw, so let's add the IDA flag for it. - * Although the flag will be ignored by firmware. - */ - ccw->flags |= CCW_FLAG_IDA; - return 0; - } - - /* - * Pin data page(s) in memory. - * The number of pages actually is the count of the idaws which will be - * needed when translating a direct ccw to a idal ccw. - */ - pat = chain->ch_pat + idx; - ret = pfn_array_table_init(pat, 1); - if (ret) - goto out_init; - - ret = pfn_array_alloc_pin(pat->pat_pa, cp->mdev, ccw->cda, ccw->count); - if (ret < 0) - goto out_unpin; + if (ccw->count) + bytes = ccw->count; - /* Translate this direct ccw to a idal ccw. */ - idaws = kcalloc(ret, sizeof(*idaws), GFP_DMA | GFP_KERNEL); - if (!idaws) { - ret = -ENOMEM; - goto out_unpin; + /* Calculate size of IDAL */ + if (ccw_is_idal(ccw)) { + /* Read first IDAW to see if it's 4K-aligned or not. */ + /* All subsequent IDAws will be 4K-aligned. */ + ret = copy_from_iova(cp->mdev, &iova, ccw->cda, sizeof(iova)); + if (ret) + return ret; + } else { + iova = ccw->cda; } - ccw->cda = (__u32) virt_to_phys(idaws); - ccw->flags |= CCW_FLAG_IDA; - - pfn_array_table_idal_create_words(pat, idaws); - - return 0; - -out_unpin: - pfn_array_table_unpin_free(pat, cp->mdev); -out_init: - ccw->cda = 0; - return ret; -} - -static int ccwchain_fetch_idal(struct ccwchain *chain, - int idx, - struct channel_program *cp) -{ - struct ccw1 *ccw; - struct pfn_array_table *pat; - unsigned long *idaws; - u64 idaw_iova; - unsigned int idaw_nr, idaw_len; - int i, ret; - - ccw = chain->ch_ccw + idx; - - if (!ccw->count) - return 0; - - /* Calculate size of idaws. */ - ret = copy_from_iova(cp->mdev, &idaw_iova, ccw->cda, sizeof(idaw_iova)); - if (ret) - return ret; - idaw_nr = idal_nr_words((void *)(idaw_iova), ccw->count); - idaw_len = idaw_nr * sizeof(*idaws); - - /* Pin data page(s) in memory. */ - pat = chain->ch_pat + idx; - ret = pfn_array_table_init(pat, idaw_nr); - if (ret) - goto out_init; + idaw_nr = idal_nr_words((void *)iova, bytes); + idal_len = idaw_nr * sizeof(*idaws); - /* Translate idal ccw to use new allocated idaws. */ - idaws = kzalloc(idaw_len, GFP_DMA | GFP_KERNEL); + /* Allocate an IDAL from host storage */ + idaws = kcalloc(idaw_nr, sizeof(*idaws), GFP_DMA | GFP_KERNEL); if (!idaws) { ret = -ENOMEM; - goto out_unpin; + goto out_init; } - ret = copy_from_iova(cp->mdev, idaws, ccw->cda, idaw_len); - if (ret) + /* + * Allocate an array of pfn's for pages to pin/translate. + * The number of pages is actually the count of the idaws + * required for the data transfer, since we only only support + * 4K IDAWs today. + */ + pa = chain->ch_pa + idx; + ret = pfn_array_alloc(pa, iova, bytes); + if (ret < 0) goto out_free_idaws; - ccw->cda = virt_to_phys(idaws); + if (ccw_is_idal(ccw)) { + /* Copy guest IDAL into host IDAL */ + ret = copy_from_iova(cp->mdev, idaws, ccw->cda, idal_len); + if (ret) + goto out_unpin; - for (i = 0; i < idaw_nr; i++) { - idaw_iova = *(idaws + i); + /* + * Copy guest IDAWs into pfn_array, in case the memory they + * occupy is not contiguous. + */ + for (i = 0; i < idaw_nr; i++) + pa->pa_iova_pfn[i] = idaws[i] >> PAGE_SHIFT; + } else { + /* + * No action is required here; the iova addresses in pfn_array + * were initialized sequentially in pfn_array_alloc() beginning + * with the contents of ccw->cda. + */ + } - ret = pfn_array_alloc_pin(pat->pat_pa + i, cp->mdev, - idaw_iova, 1); + if (ccw_does_data_transfer(ccw)) { + ret = pfn_array_pin(pa, cp->mdev); if (ret < 0) - goto out_free_idaws; + goto out_unpin; + } else { + pa->pa_nr = 0; } - pfn_array_table_idal_create_words(pat, idaws); + ccw->cda = (__u32) virt_to_phys(idaws); + ccw->flags |= CCW_FLAG_IDA; + + /* Populate the IDAL with pinned/translated addresses from pfn */ + pfn_array_idal_create_words(pa, idaws); return 0; +out_unpin: + pfn_array_unpin_free(pa, cp->mdev); out_free_idaws: kfree(idaws); -out_unpin: - pfn_array_table_unpin_free(pat, cp->mdev); out_init: ccw->cda = 0; return ret; @@ -660,15 +602,9 @@ static int ccwchain_fetch_one(struct ccwchain *chain, { struct ccw1 *ccw = chain->ch_ccw + idx; - if (ccw_is_test(ccw) || ccw_is_noop(ccw)) - return 0; - if (ccw_is_tic(ccw)) return ccwchain_fetch_tic(chain, idx, cp); - if (ccw_is_idal(ccw)) - return ccwchain_fetch_idal(chain, idx, cp); - return ccwchain_fetch_direct(chain, idx, cp); } @@ -691,9 +627,7 @@ static int ccwchain_fetch_one(struct ccwchain *chain, */ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) { - u64 iova = orb->cmd.cpa; - struct ccwchain *chain; - int len, ret; + int ret; /* * XXX: @@ -706,28 +640,11 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) memcpy(&cp->orb, orb, sizeof(*orb)); cp->mdev = mdev; - /* Get chain length. */ - len = ccwchain_calc_length(iova, cp); - if (len < 0) - return len; - - /* Alloc mem for the head chain. */ - chain = ccwchain_alloc(cp, len); - if (!chain) - return -ENOMEM; - chain->ch_iova = iova; - - /* Copy the head chain from guest. */ - ret = copy_ccw_from_iova(cp, chain->ch_ccw, iova, len); - if (ret) { - ccwchain_free(chain); - return ret; - } - - /* Now loop for its TICs. */ - ret = ccwchain_loop_tic(chain, cp); + /* Build a ccwchain for the first CCW segment */ + ret = ccwchain_handle_ccw(orb->cmd.cpa, cp); if (ret) - cp_unpin_free(cp); + cp_free(cp); + /* It is safe to force: if not set but idals used * ccwchain_calc_length returns an error. */ @@ -750,8 +667,20 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) */ void cp_free(struct channel_program *cp) { - if (cp->initialized) - cp_unpin_free(cp); + struct ccwchain *chain, *temp; + int i; + + if (!cp->initialized) + return; + + cp->initialized = false; + list_for_each_entry_safe(chain, temp, &cp->ccwchain_list, next) { + for (i = 0; i < chain->ch_len; i++) { + pfn_array_unpin_free(chain->ch_pa + i, cp->mdev); + ccwchain_cda_free(chain, i); + } + ccwchain_free(chain); + } } /** @@ -886,7 +815,11 @@ void cp_update_scsw(struct channel_program *cp, union scsw *scsw) */ list_for_each_entry(chain, &cp->ccwchain_list, next) { ccw_head = (u32)(u64)chain->ch_ccw; - if (is_cpa_within_range(cpa, ccw_head, chain->ch_len)) { + /* + * On successful execution, cpa points just beyond the end + * of the chain. + */ + if (is_cpa_within_range(cpa, ccw_head, chain->ch_len + 1)) { /* * (cpa - ccw_head) is the offset value of the host * physical ccw to its chain head. @@ -919,8 +852,7 @@ bool cp_iova_pinned(struct channel_program *cp, u64 iova) list_for_each_entry(chain, &cp->ccwchain_list, next) { for (i = 0; i < chain->ch_len; i++) - if (pfn_array_table_iova_pinned(chain->ch_pat + i, - iova)) + if (pfn_array_iova_pinned(chain->ch_pa + i, iova)) return true; } diff --git a/drivers/s390/cio/vfio_ccw_cp.h b/drivers/s390/cio/vfio_ccw_cp.h index 3c20cd208da5..7cdc38049033 100644 --- a/drivers/s390/cio/vfio_ccw_cp.h +++ b/drivers/s390/cio/vfio_ccw_cp.h @@ -16,6 +16,12 @@ #include "orb.h" +/* + * Max length for ccw chain. + * XXX: Limit to 256, need to check more? + */ +#define CCWCHAIN_LEN_MAX 256 + /** * struct channel_program - manage information for channel program * @ccwchain_list: list head of ccwchains @@ -32,6 +38,7 @@ struct channel_program { union orb orb; struct device *mdev; bool initialized; + struct ccw1 *guest_cp; }; extern int cp_init(struct channel_program *cp, struct device *mdev, diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c index ee8767f5845a..2b90a5ecaeb9 100644 --- a/drivers/s390/cio/vfio_ccw_drv.c +++ b/drivers/s390/cio/vfio_ccw_drv.c @@ -95,11 +95,11 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work) memcpy(private->io_region->irb_area, irb, sizeof(*irb)); mutex_unlock(&private->io_mutex); - if (private->io_trigger) - eventfd_signal(private->io_trigger, 1); - if (private->mdev && is_final) private->state = VFIO_CCW_STATE_IDLE; + + if (private->io_trigger) + eventfd_signal(private->io_trigger, 1); } /* @@ -129,6 +129,11 @@ static int vfio_ccw_sch_probe(struct subchannel *sch) if (!private) return -ENOMEM; + private->cp.guest_cp = kcalloc(CCWCHAIN_LEN_MAX, sizeof(struct ccw1), + GFP_KERNEL); + if (!private->cp.guest_cp) + goto out_free; + private->io_region = kmem_cache_zalloc(vfio_ccw_io_region, GFP_KERNEL | GFP_DMA); if (!private->io_region) @@ -169,6 +174,7 @@ out_free: kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region); if (private->io_region) kmem_cache_free(vfio_ccw_io_region, private->io_region); + kfree(private->cp.guest_cp); kfree(private); return ret; } @@ -185,6 +191,7 @@ static int vfio_ccw_sch_remove(struct subchannel *sch) kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region); kmem_cache_free(vfio_ccw_io_region, private->io_region); + kfree(private->cp.guest_cp); kfree(private); return 0; @@ -299,6 +306,7 @@ static void __exit vfio_ccw_sch_exit(void) css_driver_unregister(&vfio_ccw_sch_driver); isc_unregister(VFIO_CCW_ISC); kmem_cache_destroy(vfio_ccw_io_region); + kmem_cache_destroy(vfio_ccw_cmd_region); destroy_workqueue(vfio_ccw_work_q); } module_init(vfio_ccw_sch_init); diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index 45eb0c14b880..7f418d2d8cdf 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -690,7 +690,7 @@ int pkey_clr2protkey(u32 keytype, */ if (!cpacf_test_func(&pckmo_functions, fc)) { DEBUG_ERR("%s pckmo functions not available\n", __func__); - return -EOPNOTSUPP; + return -ENODEV; } /* prepare param block */ @@ -1695,15 +1695,15 @@ static int __init pkey_init(void) * are able to work with protected keys. */ if (!cpacf_query(CPACF_PCKMO, &pckmo_functions)) - return -EOPNOTSUPP; + return -ENODEV; /* check for kmc instructions available */ if (!cpacf_query(CPACF_KMC, &kmc_functions)) - return -EOPNOTSUPP; + return -ENODEV; if (!cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_128) || !cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_192) || !cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_256)) - return -EOPNOTSUPP; + return -ENODEV; pkey_debug_init(); diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c index e9824c35c34f..003662aa8060 100644 --- a/drivers/s390/crypto/vfio_ap_drv.c +++ b/drivers/s390/crypto/vfio_ap_drv.c @@ -5,6 +5,7 @@ * Copyright IBM Corp. 2018 * * Author(s): Tony Krowiak <akrowiak@linux.ibm.com> + * Pierre Morel <pmorel@linux.ibm.com> */ #include <linux/module.h> @@ -40,14 +41,45 @@ static struct ap_device_id ap_queue_ids[] = { MODULE_DEVICE_TABLE(vfio_ap, ap_queue_ids); +/** + * vfio_ap_queue_dev_probe: + * + * Allocate a vfio_ap_queue structure and associate it + * with the device as driver_data. + */ static int vfio_ap_queue_dev_probe(struct ap_device *apdev) { + struct vfio_ap_queue *q; + + q = kzalloc(sizeof(*q), GFP_KERNEL); + if (!q) + return -ENOMEM; + dev_set_drvdata(&apdev->device, q); + q->apqn = to_ap_queue(&apdev->device)->qid; + q->saved_isc = VFIO_AP_ISC_INVALID; return 0; } +/** + * vfio_ap_queue_dev_remove: + * + * Takes the matrix lock to avoid actions on this device while removing + * Free the associated vfio_ap_queue structure + */ static void vfio_ap_queue_dev_remove(struct ap_device *apdev) { - /* Nothing to do yet */ + struct vfio_ap_queue *q; + int apid, apqi; + + mutex_lock(&matrix_dev->lock); + q = dev_get_drvdata(&apdev->device); + dev_set_drvdata(&apdev->device, NULL); + apid = AP_QID_CARD(q->apqn); + apqi = AP_QID_QUEUE(q->apqn); + vfio_ap_mdev_reset_queue(apid, apqi, 1); + vfio_ap_irq_disable(q); + kfree(q); + mutex_unlock(&matrix_dev->lock); } static void vfio_ap_matrix_dev_release(struct device *dev) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 900b9cf20ca5..2c9fb1423a39 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -24,6 +24,296 @@ #define VFIO_AP_MDEV_TYPE_HWVIRT "passthrough" #define VFIO_AP_MDEV_NAME_HWVIRT "VFIO AP Passthrough Device" +static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev); + +static int match_apqn(struct device *dev, void *data) +{ + struct vfio_ap_queue *q = dev_get_drvdata(dev); + + return (q->apqn == *(int *)(data)) ? 1 : 0; +} + +/** + * vfio_ap_get_queue: Retrieve a queue with a specific APQN from a list + * @matrix_mdev: the associated mediated matrix + * @apqn: The queue APQN + * + * Retrieve a queue with a specific APQN from the list of the + * devices of the vfio_ap_drv. + * Verify that the APID and the APQI are set in the matrix. + * + * Returns the pointer to the associated vfio_ap_queue + */ +static struct vfio_ap_queue *vfio_ap_get_queue( + struct ap_matrix_mdev *matrix_mdev, + int apqn) +{ + struct vfio_ap_queue *q; + struct device *dev; + + if (!test_bit_inv(AP_QID_CARD(apqn), matrix_mdev->matrix.apm)) + return NULL; + if (!test_bit_inv(AP_QID_QUEUE(apqn), matrix_mdev->matrix.aqm)) + return NULL; + + dev = driver_find_device(&matrix_dev->vfio_ap_drv->driver, NULL, + &apqn, match_apqn); + if (!dev) + return NULL; + q = dev_get_drvdata(dev); + q->matrix_mdev = matrix_mdev; + put_device(dev); + + return q; +} + +/** + * vfio_ap_wait_for_irqclear + * @apqn: The AP Queue number + * + * Checks the IRQ bit for the status of this APQN using ap_tapq. + * Returns if the ap_tapq function succeeded and the bit is clear. + * Returns if ap_tapq function failed with invalid, deconfigured or + * checkstopped AP. + * Otherwise retries up to 5 times after waiting 20ms. + * + */ +static void vfio_ap_wait_for_irqclear(int apqn) +{ + struct ap_queue_status status; + int retry = 5; + + do { + status = ap_tapq(apqn, NULL); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + case AP_RESPONSE_RESET_IN_PROGRESS: + if (!status.irq_enabled) + return; + /* Fall through */ + case AP_RESPONSE_BUSY: + msleep(20); + break; + case AP_RESPONSE_Q_NOT_AVAIL: + case AP_RESPONSE_DECONFIGURED: + case AP_RESPONSE_CHECKSTOPPED: + default: + WARN_ONCE(1, "%s: tapq rc %02x: %04x\n", __func__, + status.response_code, apqn); + return; + } + } while (--retry); + + WARN_ONCE(1, "%s: tapq rc %02x: %04x could not clear IR bit\n", + __func__, status.response_code, apqn); +} + +/** + * vfio_ap_free_aqic_resources + * @q: The vfio_ap_queue + * + * Unregisters the ISC in the GIB when the saved ISC not invalid. + * Unpin the guest's page holding the NIB when it exist. + * Reset the saved_pfn and saved_isc to invalid values. + * Clear the pointer to the matrix mediated device. + * + */ +static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q) +{ + if (q->saved_isc != VFIO_AP_ISC_INVALID && q->matrix_mdev) + kvm_s390_gisc_unregister(q->matrix_mdev->kvm, q->saved_isc); + if (q->saved_pfn && q->matrix_mdev) + vfio_unpin_pages(mdev_dev(q->matrix_mdev->mdev), + &q->saved_pfn, 1); + q->saved_pfn = 0; + q->saved_isc = VFIO_AP_ISC_INVALID; + q->matrix_mdev = NULL; +} + +/** + * vfio_ap_irq_disable + * @q: The vfio_ap_queue + * + * Uses ap_aqic to disable the interruption and in case of success, reset + * in progress or IRQ disable command already proceeded: calls + * vfio_ap_wait_for_irqclear() to check for the IRQ bit to be clear + * and calls vfio_ap_free_aqic_resources() to free the resources associated + * with the AP interrupt handling. + * + * In the case the AP is busy, or a reset is in progress, + * retries after 20ms, up to 5 times. + * + * Returns if ap_aqic function failed with invalid, deconfigured or + * checkstopped AP. + */ +struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q) +{ + struct ap_qirq_ctrl aqic_gisa = {}; + struct ap_queue_status status; + int retries = 5; + + do { + status = ap_aqic(q->apqn, aqic_gisa, NULL); + switch (status.response_code) { + case AP_RESPONSE_OTHERWISE_CHANGED: + case AP_RESPONSE_NORMAL: + vfio_ap_wait_for_irqclear(q->apqn); + goto end_free; + case AP_RESPONSE_RESET_IN_PROGRESS: + case AP_RESPONSE_BUSY: + msleep(20); + break; + case AP_RESPONSE_Q_NOT_AVAIL: + case AP_RESPONSE_DECONFIGURED: + case AP_RESPONSE_CHECKSTOPPED: + case AP_RESPONSE_INVALID_ADDRESS: + default: + /* All cases in default means AP not operational */ + WARN_ONCE(1, "%s: ap_aqic status %d\n", __func__, + status.response_code); + goto end_free; + } + } while (retries--); + + WARN_ONCE(1, "%s: ap_aqic status %d\n", __func__, + status.response_code); +end_free: + vfio_ap_free_aqic_resources(q); + return status; +} + +/** + * vfio_ap_setirq: Enable Interruption for a APQN + * + * @dev: the device associated with the ap_queue + * @q: the vfio_ap_queue holding AQIC parameters + * + * Pin the NIB saved in *q + * Register the guest ISC to GIB interface and retrieve the + * host ISC to issue the host side PQAP/AQIC + * + * Response.status may be set to AP_RESPONSE_INVALID_ADDRESS in case the + * vfio_pin_pages failed. + * + * Otherwise return the ap_queue_status returned by the ap_aqic(), + * all retry handling will be done by the guest. + */ +static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q, + int isc, + unsigned long nib) +{ + struct ap_qirq_ctrl aqic_gisa = {}; + struct ap_queue_status status = {}; + struct kvm_s390_gisa *gisa; + struct kvm *kvm; + unsigned long h_nib, g_pfn, h_pfn; + int ret; + + g_pfn = nib >> PAGE_SHIFT; + ret = vfio_pin_pages(mdev_dev(q->matrix_mdev->mdev), &g_pfn, 1, + IOMMU_READ | IOMMU_WRITE, &h_pfn); + switch (ret) { + case 1: + break; + default: + status.response_code = AP_RESPONSE_INVALID_ADDRESS; + return status; + } + + kvm = q->matrix_mdev->kvm; + gisa = kvm->arch.gisa_int.origin; + + h_nib = (h_pfn << PAGE_SHIFT) | (nib & ~PAGE_MASK); + aqic_gisa.gisc = isc; + aqic_gisa.isc = kvm_s390_gisc_register(kvm, isc); + aqic_gisa.ir = 1; + aqic_gisa.gisa = (uint64_t)gisa >> 4; + + status = ap_aqic(q->apqn, aqic_gisa, (void *)h_nib); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + /* See if we did clear older IRQ configuration */ + vfio_ap_free_aqic_resources(q); + q->saved_pfn = g_pfn; + q->saved_isc = isc; + break; + case AP_RESPONSE_OTHERWISE_CHANGED: + /* We could not modify IRQ setings: clear new configuration */ + vfio_unpin_pages(mdev_dev(q->matrix_mdev->mdev), &g_pfn, 1); + kvm_s390_gisc_unregister(kvm, isc); + break; + default: + pr_warn("%s: apqn %04x: response: %02x\n", __func__, q->apqn, + status.response_code); + vfio_ap_irq_disable(q); + break; + } + + return status; +} + +/** + * handle_pqap: PQAP instruction callback + * + * @vcpu: The vcpu on which we received the PQAP instruction + * + * Get the general register contents to initialize internal variables. + * REG[0]: APQN + * REG[1]: IR and ISC + * REG[2]: NIB + * + * Response.status may be set to following Response Code: + * - AP_RESPONSE_Q_NOT_AVAIL: if the queue is not available + * - AP_RESPONSE_DECONFIGURED: if the queue is not configured + * - AP_RESPONSE_NORMAL (0) : in case of successs + * Check vfio_ap_setirq() and vfio_ap_clrirq() for other possible RC. + * We take the matrix_dev lock to ensure serialization on queues and + * mediated device access. + * + * Return 0 if we could handle the request inside KVM. + * otherwise, returns -EOPNOTSUPP to let QEMU handle the fault. + */ +static int handle_pqap(struct kvm_vcpu *vcpu) +{ + uint64_t status; + uint16_t apqn; + struct vfio_ap_queue *q; + struct ap_queue_status qstatus = { + .response_code = AP_RESPONSE_Q_NOT_AVAIL, }; + struct ap_matrix_mdev *matrix_mdev; + + /* If we do not use the AIV facility just go to userland */ + if (!(vcpu->arch.sie_block->eca & ECA_AIV)) + return -EOPNOTSUPP; + + apqn = vcpu->run->s.regs.gprs[0] & 0xffff; + mutex_lock(&matrix_dev->lock); + + if (!vcpu->kvm->arch.crypto.pqap_hook) + goto out_unlock; + matrix_mdev = container_of(vcpu->kvm->arch.crypto.pqap_hook, + struct ap_matrix_mdev, pqap_hook); + + q = vfio_ap_get_queue(matrix_mdev, apqn); + if (!q) + goto out_unlock; + + status = vcpu->run->s.regs.gprs[1]; + + /* If IR bit(16) is set we enable the interrupt */ + if ((status >> (63 - 16)) & 0x01) + qstatus = vfio_ap_irq_enable(q, status & 0x07, + vcpu->run->s.regs.gprs[2]); + else + qstatus = vfio_ap_irq_disable(q); + +out_unlock: + memcpy(&vcpu->run->s.regs.gprs[1], &qstatus, sizeof(qstatus)); + vcpu->run->s.regs.gprs[1] >>= 32; + mutex_unlock(&matrix_dev->lock); + return 0; +} + static void vfio_ap_matrix_init(struct ap_config_info *info, struct ap_matrix *matrix) { @@ -45,8 +335,11 @@ static int vfio_ap_mdev_create(struct kobject *kobj, struct mdev_device *mdev) return -ENOMEM; } + matrix_mdev->mdev = mdev; vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->matrix); mdev_set_drvdata(mdev, matrix_mdev); + matrix_mdev->pqap_hook.hook = handle_pqap; + matrix_mdev->pqap_hook.owner = THIS_MODULE; mutex_lock(&matrix_dev->lock); list_add(&matrix_mdev->node, &matrix_dev->mdev_list); mutex_unlock(&matrix_dev->lock); @@ -62,6 +355,7 @@ static int vfio_ap_mdev_remove(struct mdev_device *mdev) return -EBUSY; mutex_lock(&matrix_dev->lock); + vfio_ap_mdev_reset_queues(mdev); list_del(&matrix_mdev->node); mutex_unlock(&matrix_dev->lock); @@ -754,11 +1048,42 @@ static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev, } matrix_mdev->kvm = kvm; + kvm_get_kvm(kvm); + kvm->arch.crypto.pqap_hook = &matrix_mdev->pqap_hook; mutex_unlock(&matrix_dev->lock); return 0; } +/* + * vfio_ap_mdev_iommu_notifier: IOMMU notifier callback + * + * @nb: The notifier block + * @action: Action to be taken + * @data: data associated with the request + * + * For an UNMAP request, unpin the guest IOVA (the NIB guest address we + * pinned before). Other requests are ignored. + * + */ +static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct ap_matrix_mdev *matrix_mdev; + + matrix_mdev = container_of(nb, struct ap_matrix_mdev, iommu_notifier); + + if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) { + struct vfio_iommu_type1_dma_unmap *unmap = data; + unsigned long g_pfn = unmap->iova >> PAGE_SHIFT; + + vfio_unpin_pages(mdev_dev(matrix_mdev->mdev), &g_pfn, 1); + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} + static int vfio_ap_mdev_group_notifier(struct notifier_block *nb, unsigned long action, void *data) { @@ -790,15 +1115,36 @@ static int vfio_ap_mdev_group_notifier(struct notifier_block *nb, return NOTIFY_OK; } -static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, - unsigned int retry) +static void vfio_ap_irq_disable_apqn(int apqn) +{ + struct device *dev; + struct vfio_ap_queue *q; + + dev = driver_find_device(&matrix_dev->vfio_ap_drv->driver, NULL, + &apqn, match_apqn); + if (dev) { + q = dev_get_drvdata(dev); + vfio_ap_irq_disable(q); + put_device(dev); + } +} + +int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, + unsigned int retry) { struct ap_queue_status status; + int retry2 = 2; + int apqn = AP_MKQID(apid, apqi); do { - status = ap_zapq(AP_MKQID(apid, apqi)); + status = ap_zapq(apqn); switch (status.response_code) { case AP_RESPONSE_NORMAL: + while (!status.queue_empty && retry2--) { + msleep(20); + status = ap_tapq(apqn, NULL); + } + WARN_ON_ONCE(retry <= 0); return 0; case AP_RESPONSE_RESET_IN_PROGRESS: case AP_RESPONSE_BUSY: @@ -832,6 +1178,7 @@ static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev) */ if (ret) rc = ret; + vfio_ap_irq_disable_apqn(AP_MKQID(apid, apqi)); } } @@ -858,20 +1205,37 @@ static int vfio_ap_mdev_open(struct mdev_device *mdev) return ret; } - return 0; + matrix_mdev->iommu_notifier.notifier_call = vfio_ap_mdev_iommu_notifier; + events = VFIO_IOMMU_NOTIFY_DMA_UNMAP; + ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, + &events, &matrix_mdev->iommu_notifier); + if (!ret) + return ret; + + vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY, + &matrix_mdev->group_notifier); + module_put(THIS_MODULE); + return ret; } static void vfio_ap_mdev_release(struct mdev_device *mdev) { struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); - if (matrix_mdev->kvm) + mutex_lock(&matrix_dev->lock); + if (matrix_mdev->kvm) { kvm_arch_crypto_clear_masks(matrix_mdev->kvm); + matrix_mdev->kvm->arch.crypto.pqap_hook = NULL; + vfio_ap_mdev_reset_queues(mdev); + kvm_put_kvm(matrix_mdev->kvm); + matrix_mdev->kvm = NULL; + } + mutex_unlock(&matrix_dev->lock); - vfio_ap_mdev_reset_queues(mdev); + vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, + &matrix_mdev->iommu_notifier); vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY, &matrix_mdev->group_notifier); - matrix_mdev->kvm = NULL; module_put(THIS_MODULE); } @@ -900,6 +1264,7 @@ static ssize_t vfio_ap_mdev_ioctl(struct mdev_device *mdev, { int ret; + mutex_lock(&matrix_dev->lock); switch (cmd) { case VFIO_DEVICE_GET_INFO: ret = vfio_ap_mdev_get_device_info(arg); @@ -911,6 +1276,7 @@ static ssize_t vfio_ap_mdev_ioctl(struct mdev_device *mdev, ret = -EOPNOTSUPP; break; } + mutex_unlock(&matrix_dev->lock); return ret; } diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h index 76b7f98e47e9..f46dde56b464 100644 --- a/drivers/s390/crypto/vfio_ap_private.h +++ b/drivers/s390/crypto/vfio_ap_private.h @@ -4,6 +4,7 @@ * * Author(s): Tony Krowiak <akrowiak@linux.ibm.com> * Halil Pasic <pasic@linux.ibm.com> + * Pierre Morel <pmorel@linux.ibm.com> * * Copyright IBM Corp. 2018 */ @@ -16,6 +17,7 @@ #include <linux/mdev.h> #include <linux/delay.h> #include <linux/mutex.h> +#include <linux/kvm_host.h> #include "ap_bus.h" @@ -80,10 +82,23 @@ struct ap_matrix_mdev { struct list_head node; struct ap_matrix matrix; struct notifier_block group_notifier; + struct notifier_block iommu_notifier; struct kvm *kvm; + struct kvm_s390_module_hook pqap_hook; + struct mdev_device *mdev; }; extern int vfio_ap_mdev_register(void); extern void vfio_ap_mdev_unregister(void); +int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, + unsigned int retry); +struct vfio_ap_queue { + struct ap_matrix_mdev *matrix_mdev; + unsigned long saved_pfn; + int apqn; +#define VFIO_AP_ISC_INVALID 0xff + unsigned char saved_isc; +}; +struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q); #endif /* _VFIO_AP_PRIVATE_H_ */ diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index 0cbcc238ef98..12fe9deb265e 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -567,6 +567,10 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg, payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt); *fcode = payload_hdr->func_val & 0xFFFF; + /* enable special processing based on the cprbs flags special bit */ + if (msg->cprbx.flags & 0x20) + ap_msg->special = 1; + return 0; } diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index 7c5a25ddf832..ced896d1534a 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig @@ -7,10 +7,10 @@ config LCS prompt "Lan Channel Station Interface" depends on CCW && NETDEVICES && (ETHERNET || FDDI) help - Select this option if you want to use LCS networking on IBM System z. - This device driver supports FDDI (IEEE 802.7) and Ethernet. - To compile as a module, choose M. The module name is lcs. - If you do not know what it is, it's safe to choose Y. + Select this option if you want to use LCS networking on IBM System z. + This device driver supports FDDI (IEEE 802.7) and Ethernet. + To compile as a module, choose M. The module name is lcs. + If you do not know what it is, it's safe to choose Y. config CTCM def_tristate m diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index 6a3076881321..1a55e5942d36 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -46,9 +46,15 @@ struct vq_config_block { #define VIRTIO_CCW_CONFIG_SIZE 0x100 /* same as PCI config space size, should be enough for all drivers */ +struct vcdev_dma_area { + unsigned long indicators; + unsigned long indicators2; + struct vq_config_block config_block; + __u8 status; +}; + struct virtio_ccw_device { struct virtio_device vdev; - __u8 *status; __u8 config[VIRTIO_CCW_CONFIG_SIZE]; struct ccw_device *cdev; __u32 curr_io; @@ -58,17 +64,24 @@ struct virtio_ccw_device { spinlock_t lock; struct mutex io_lock; /* Serializes I/O requests */ struct list_head virtqueues; - unsigned long indicators; - unsigned long indicators2; - struct vq_config_block *config_block; bool is_thinint; bool going_away; bool device_lost; unsigned int config_ready; void *airq_info; - u64 dma_mask; + struct vcdev_dma_area *dma_area; }; +static inline unsigned long *indicators(struct virtio_ccw_device *vcdev) +{ + return &vcdev->dma_area->indicators; +} + +static inline unsigned long *indicators2(struct virtio_ccw_device *vcdev) +{ + return &vcdev->dma_area->indicators2; +} + struct vq_info_block_legacy { __u64 queue; __u32 align; @@ -127,11 +140,17 @@ static int virtio_ccw_use_airq = 1; struct airq_info { rwlock_t lock; - u8 summary_indicator; + u8 summary_indicator_idx; struct airq_struct airq; struct airq_iv *aiv; }; static struct airq_info *airq_areas[MAX_AIRQ_AREAS]; +static u8 *summary_indicators; + +static inline u8 *get_summary_indicator(struct airq_info *info) +{ + return summary_indicators + info->summary_indicator_idx; +} #define CCW_CMD_SET_VQ 0x13 #define CCW_CMD_VDEV_RESET 0x33 @@ -196,7 +215,7 @@ static void virtio_airq_handler(struct airq_struct *airq, bool floating) break; vring_interrupt(0, (void *)airq_iv_get_ptr(info->aiv, ai)); } - info->summary_indicator = 0; + *(get_summary_indicator(info)) = 0; smp_wmb(); /* Walk through indicators field, summary indicator not active. */ for (ai = 0;;) { @@ -208,7 +227,7 @@ static void virtio_airq_handler(struct airq_struct *airq, bool floating) read_unlock(&info->lock); } -static struct airq_info *new_airq_info(void) +static struct airq_info *new_airq_info(int index) { struct airq_info *info; int rc; @@ -217,13 +236,15 @@ static struct airq_info *new_airq_info(void) if (!info) return NULL; rwlock_init(&info->lock); - info->aiv = airq_iv_create(VIRTIO_IV_BITS, AIRQ_IV_ALLOC | AIRQ_IV_PTR); + info->aiv = airq_iv_create(VIRTIO_IV_BITS, AIRQ_IV_ALLOC | AIRQ_IV_PTR + | AIRQ_IV_CACHELINE); if (!info->aiv) { kfree(info); return NULL; } info->airq.handler = virtio_airq_handler; - info->airq.lsi_ptr = &info->summary_indicator; + info->summary_indicator_idx = index; + info->airq.lsi_ptr = get_summary_indicator(info); info->airq.lsi_mask = 0xff; info->airq.isc = VIRTIO_AIRQ_ISC; rc = register_adapter_interrupt(&info->airq); @@ -245,7 +266,7 @@ static unsigned long get_airq_indicator(struct virtqueue *vqs[], int nvqs, for (i = 0; i < MAX_AIRQ_AREAS && !indicator_addr; i++) { if (!airq_areas[i]) - airq_areas[i] = new_airq_info(); + airq_areas[i] = new_airq_info(i); info = airq_areas[i]; if (!info) return 0; @@ -326,29 +347,29 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev, struct airq_info *airq_info = vcdev->airq_info; if (vcdev->is_thinint) { - thinint_area = kzalloc(sizeof(*thinint_area), - GFP_DMA | GFP_KERNEL); + thinint_area = ccw_device_dma_zalloc(vcdev->cdev, + sizeof(*thinint_area)); if (!thinint_area) return; thinint_area->summary_indicator = - (unsigned long) &airq_info->summary_indicator; + (unsigned long) get_summary_indicator(airq_info); thinint_area->isc = VIRTIO_AIRQ_ISC; ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER; ccw->count = sizeof(*thinint_area); ccw->cda = (__u32)(unsigned long) thinint_area; } else { /* payload is the address of the indicators */ - indicatorp = kmalloc(sizeof(&vcdev->indicators), - GFP_DMA | GFP_KERNEL); + indicatorp = ccw_device_dma_zalloc(vcdev->cdev, + sizeof(indicators(vcdev))); if (!indicatorp) return; *indicatorp = 0; ccw->cmd_code = CCW_CMD_SET_IND; - ccw->count = sizeof(&vcdev->indicators); + ccw->count = sizeof(indicators(vcdev)); ccw->cda = (__u32)(unsigned long) indicatorp; } /* Deregister indicators from host. */ - vcdev->indicators = 0; + *indicators(vcdev) = 0; ccw->flags = 0; ret = ccw_io_helper(vcdev, ccw, vcdev->is_thinint ? @@ -359,8 +380,8 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev, "Failed to deregister indicators (%d)\n", ret); else if (vcdev->is_thinint) virtio_ccw_drop_indicators(vcdev); - kfree(indicatorp); - kfree(thinint_area); + ccw_device_dma_free(vcdev->cdev, indicatorp, sizeof(indicators(vcdev))); + ccw_device_dma_free(vcdev->cdev, thinint_area, sizeof(*thinint_area)); } static inline long __do_kvm_notify(struct subchannel_id schid, @@ -407,15 +428,15 @@ static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev, { int ret; - vcdev->config_block->index = index; + vcdev->dma_area->config_block.index = index; ccw->cmd_code = CCW_CMD_READ_VQ_CONF; ccw->flags = 0; ccw->count = sizeof(struct vq_config_block); - ccw->cda = (__u32)(unsigned long)(vcdev->config_block); + ccw->cda = (__u32)(unsigned long)(&vcdev->dma_area->config_block); ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_VQ_CONF); if (ret) return ret; - return vcdev->config_block->num ?: -ENOENT; + return vcdev->dma_area->config_block.num ?: -ENOENT; } static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw) @@ -460,7 +481,8 @@ static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw) ret, index); vring_del_virtqueue(vq); - kfree(info->info_block); + ccw_device_dma_free(vcdev->cdev, info->info_block, + sizeof(*info->info_block)); kfree(info); } @@ -470,7 +492,7 @@ static void virtio_ccw_del_vqs(struct virtio_device *vdev) struct ccw1 *ccw; struct virtio_ccw_device *vcdev = to_vc_device(vdev); - ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); + ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw)); if (!ccw) return; @@ -479,7 +501,7 @@ static void virtio_ccw_del_vqs(struct virtio_device *vdev) list_for_each_entry_safe(vq, n, &vdev->vqs, list) virtio_ccw_del_vq(vq, ccw); - kfree(ccw); + ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw)); } static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, @@ -502,8 +524,8 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, err = -ENOMEM; goto out_err; } - info->info_block = kzalloc(sizeof(*info->info_block), - GFP_DMA | GFP_KERNEL); + info->info_block = ccw_device_dma_zalloc(vcdev->cdev, + sizeof(*info->info_block)); if (!info->info_block) { dev_warn(&vcdev->cdev->dev, "no info block\n"); err = -ENOMEM; @@ -567,7 +589,8 @@ out_err: if (vq) vring_del_virtqueue(vq); if (info) { - kfree(info->info_block); + ccw_device_dma_free(vcdev->cdev, info->info_block, + sizeof(*info->info_block)); } kfree(info); return ERR_PTR(err); @@ -581,7 +604,8 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev, struct virtio_thinint_area *thinint_area = NULL; struct airq_info *info; - thinint_area = kzalloc(sizeof(*thinint_area), GFP_DMA | GFP_KERNEL); + thinint_area = ccw_device_dma_zalloc(vcdev->cdev, + sizeof(*thinint_area)); if (!thinint_area) { ret = -ENOMEM; goto out; @@ -596,7 +620,7 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev, } info = vcdev->airq_info; thinint_area->summary_indicator = - (unsigned long) &info->summary_indicator; + (unsigned long) get_summary_indicator(info); thinint_area->isc = VIRTIO_AIRQ_ISC; ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER; ccw->flags = CCW_FLAG_SLI; @@ -617,7 +641,7 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev, virtio_ccw_drop_indicators(vcdev); } out: - kfree(thinint_area); + ccw_device_dma_free(vcdev->cdev, thinint_area, sizeof(*thinint_area)); return ret; } @@ -633,7 +657,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, int ret, i, queue_idx = 0; struct ccw1 *ccw; - ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); + ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw)); if (!ccw) return -ENOMEM; @@ -657,10 +681,11 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, * We need a data area under 2G to communicate. Our payload is * the address of the indicators. */ - indicatorp = kmalloc(sizeof(&vcdev->indicators), GFP_DMA | GFP_KERNEL); + indicatorp = ccw_device_dma_zalloc(vcdev->cdev, + sizeof(indicators(vcdev))); if (!indicatorp) goto out; - *indicatorp = (unsigned long) &vcdev->indicators; + *indicatorp = (unsigned long) indicators(vcdev); if (vcdev->is_thinint) { ret = virtio_ccw_register_adapter_ind(vcdev, vqs, nvqs, ccw); if (ret) @@ -669,32 +694,36 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, } if (!vcdev->is_thinint) { /* Register queue indicators with host. */ - vcdev->indicators = 0; + *indicators(vcdev) = 0; ccw->cmd_code = CCW_CMD_SET_IND; ccw->flags = 0; - ccw->count = sizeof(&vcdev->indicators); + ccw->count = sizeof(indicators(vcdev)); ccw->cda = (__u32)(unsigned long) indicatorp; ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND); if (ret) goto out; } /* Register indicators2 with host for config changes */ - *indicatorp = (unsigned long) &vcdev->indicators2; - vcdev->indicators2 = 0; + *indicatorp = (unsigned long) indicators2(vcdev); + *indicators2(vcdev) = 0; ccw->cmd_code = CCW_CMD_SET_CONF_IND; ccw->flags = 0; - ccw->count = sizeof(&vcdev->indicators2); + ccw->count = sizeof(indicators2(vcdev)); ccw->cda = (__u32)(unsigned long) indicatorp; ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_CONF_IND); if (ret) goto out; - kfree(indicatorp); - kfree(ccw); + if (indicatorp) + ccw_device_dma_free(vcdev->cdev, indicatorp, + sizeof(indicators(vcdev))); + ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw)); return 0; out: - kfree(indicatorp); - kfree(ccw); + if (indicatorp) + ccw_device_dma_free(vcdev->cdev, indicatorp, + sizeof(indicators(vcdev))); + ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw)); virtio_ccw_del_vqs(vdev); return ret; } @@ -704,12 +733,12 @@ static void virtio_ccw_reset(struct virtio_device *vdev) struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct ccw1 *ccw; - ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); + ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw)); if (!ccw) return; /* Zero status bits. */ - *vcdev->status = 0; + vcdev->dma_area->status = 0; /* Send a reset ccw on device. */ ccw->cmd_code = CCW_CMD_VDEV_RESET; @@ -717,7 +746,7 @@ static void virtio_ccw_reset(struct virtio_device *vdev) ccw->count = 0; ccw->cda = 0; ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_RESET); - kfree(ccw); + ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw)); } static u64 virtio_ccw_get_features(struct virtio_device *vdev) @@ -728,11 +757,11 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev) u64 rc; struct ccw1 *ccw; - ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); + ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw)); if (!ccw) return 0; - features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL); + features = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*features)); if (!features) { rc = 0; goto out_free; @@ -765,8 +794,8 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev) rc |= (u64)le32_to_cpu(features->features) << 32; out_free: - kfree(features); - kfree(ccw); + ccw_device_dma_free(vcdev->cdev, features, sizeof(*features)); + ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw)); return rc; } @@ -791,11 +820,11 @@ static int virtio_ccw_finalize_features(struct virtio_device *vdev) return -EINVAL; } - ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); + ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw)); if (!ccw) return -ENOMEM; - features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL); + features = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*features)); if (!features) { ret = -ENOMEM; goto out_free; @@ -830,8 +859,8 @@ static int virtio_ccw_finalize_features(struct virtio_device *vdev) ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT); out_free: - kfree(features); - kfree(ccw); + ccw_device_dma_free(vcdev->cdev, features, sizeof(*features)); + ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw)); return ret; } @@ -845,11 +874,12 @@ static void virtio_ccw_get_config(struct virtio_device *vdev, void *config_area; unsigned long flags; - ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); + ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw)); if (!ccw) return; - config_area = kzalloc(VIRTIO_CCW_CONFIG_SIZE, GFP_DMA | GFP_KERNEL); + config_area = ccw_device_dma_zalloc(vcdev->cdev, + VIRTIO_CCW_CONFIG_SIZE); if (!config_area) goto out_free; @@ -871,8 +901,8 @@ static void virtio_ccw_get_config(struct virtio_device *vdev, memcpy(buf, config_area + offset, len); out_free: - kfree(config_area); - kfree(ccw); + ccw_device_dma_free(vcdev->cdev, config_area, VIRTIO_CCW_CONFIG_SIZE); + ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw)); } static void virtio_ccw_set_config(struct virtio_device *vdev, @@ -884,11 +914,12 @@ static void virtio_ccw_set_config(struct virtio_device *vdev, void *config_area; unsigned long flags; - ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); + ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw)); if (!ccw) return; - config_area = kzalloc(VIRTIO_CCW_CONFIG_SIZE, GFP_DMA | GFP_KERNEL); + config_area = ccw_device_dma_zalloc(vcdev->cdev, + VIRTIO_CCW_CONFIG_SIZE); if (!config_area) goto out_free; @@ -907,61 +938,61 @@ static void virtio_ccw_set_config(struct virtio_device *vdev, ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_CONFIG); out_free: - kfree(config_area); - kfree(ccw); + ccw_device_dma_free(vcdev->cdev, config_area, VIRTIO_CCW_CONFIG_SIZE); + ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw)); } static u8 virtio_ccw_get_status(struct virtio_device *vdev) { struct virtio_ccw_device *vcdev = to_vc_device(vdev); - u8 old_status = *vcdev->status; + u8 old_status = vcdev->dma_area->status; struct ccw1 *ccw; if (vcdev->revision < 1) - return *vcdev->status; + return vcdev->dma_area->status; - ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); + ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw)); if (!ccw) return old_status; ccw->cmd_code = CCW_CMD_READ_STATUS; ccw->flags = 0; - ccw->count = sizeof(*vcdev->status); - ccw->cda = (__u32)(unsigned long)vcdev->status; + ccw->count = sizeof(vcdev->dma_area->status); + ccw->cda = (__u32)(unsigned long)&vcdev->dma_area->status; ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_STATUS); /* * If the channel program failed (should only happen if the device * was hotunplugged, and then we clean up via the machine check - * handler anyway), vcdev->status was not overwritten and we just + * handler anyway), vcdev->dma_area->status was not overwritten and we just * return the old status, which is fine. */ - kfree(ccw); + ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw)); - return *vcdev->status; + return vcdev->dma_area->status; } static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status) { struct virtio_ccw_device *vcdev = to_vc_device(vdev); - u8 old_status = *vcdev->status; + u8 old_status = vcdev->dma_area->status; struct ccw1 *ccw; int ret; - ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); + ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw)); if (!ccw) return; /* Write the status to the host. */ - *vcdev->status = status; + vcdev->dma_area->status = status; ccw->cmd_code = CCW_CMD_WRITE_STATUS; ccw->flags = 0; ccw->count = sizeof(status); - ccw->cda = (__u32)(unsigned long)vcdev->status; + ccw->cda = (__u32)(unsigned long)&vcdev->dma_area->status; ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_STATUS); /* Write failed? We assume status is unchanged. */ if (ret) - *vcdev->status = old_status; - kfree(ccw); + vcdev->dma_area->status = old_status; + ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw)); } static const char *virtio_ccw_bus_name(struct virtio_device *vdev) @@ -994,8 +1025,8 @@ static void virtio_ccw_release_dev(struct device *_d) struct virtio_device *dev = dev_to_virtio(_d); struct virtio_ccw_device *vcdev = to_vc_device(dev); - kfree(vcdev->status); - kfree(vcdev->config_block); + ccw_device_dma_free(vcdev->cdev, vcdev->dma_area, + sizeof(*vcdev->dma_area)); kfree(vcdev); } @@ -1093,17 +1124,17 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev, vcdev->err = -EIO; } virtio_ccw_check_activity(vcdev, activity); - for_each_set_bit(i, &vcdev->indicators, - sizeof(vcdev->indicators) * BITS_PER_BYTE) { + for_each_set_bit(i, indicators(vcdev), + sizeof(*indicators(vcdev)) * BITS_PER_BYTE) { /* The bit clear must happen before the vring kick. */ - clear_bit(i, &vcdev->indicators); + clear_bit(i, indicators(vcdev)); barrier(); vq = virtio_ccw_vq_by_ind(vcdev, i); vring_interrupt(0, vq); } - if (test_bit(0, &vcdev->indicators2)) { + if (test_bit(0, indicators2(vcdev))) { virtio_config_changed(&vcdev->vdev); - clear_bit(0, &vcdev->indicators2); + clear_bit(0, indicators2(vcdev)); } } @@ -1203,12 +1234,12 @@ static int virtio_ccw_set_transport_rev(struct virtio_ccw_device *vcdev) struct ccw1 *ccw; int ret; - ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); + ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw)); if (!ccw) return -ENOMEM; - rev = kzalloc(sizeof(*rev), GFP_DMA | GFP_KERNEL); + rev = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*rev)); if (!rev) { - kfree(ccw); + ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw)); return -ENOMEM; } @@ -1238,8 +1269,8 @@ static int virtio_ccw_set_transport_rev(struct virtio_ccw_device *vcdev) } } while (ret == -EOPNOTSUPP); - kfree(ccw); - kfree(rev); + ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw)); + ccw_device_dma_free(vcdev->cdev, rev, sizeof(*rev)); return ret; } @@ -1255,24 +1286,11 @@ static int virtio_ccw_online(struct ccw_device *cdev) ret = -ENOMEM; goto out_free; } - vcdev->vdev.dev.parent = &cdev->dev; - cdev->dev.dma_mask = &vcdev->dma_mask; - /* we are fine with common virtio infrastructure using 64 bit DMA */ - ret = dma_set_mask_and_coherent(&cdev->dev, DMA_BIT_MASK(64)); - if (ret) { - dev_warn(&cdev->dev, "Failed to enable 64-bit DMA.\n"); - goto out_free; - } - - vcdev->config_block = kzalloc(sizeof(*vcdev->config_block), - GFP_DMA | GFP_KERNEL); - if (!vcdev->config_block) { - ret = -ENOMEM; - goto out_free; - } - vcdev->status = kzalloc(sizeof(*vcdev->status), GFP_DMA | GFP_KERNEL); - if (!vcdev->status) { + vcdev->cdev = cdev; + vcdev->dma_area = ccw_device_dma_zalloc(vcdev->cdev, + sizeof(*vcdev->dma_area)); + if (!vcdev->dma_area) { ret = -ENOMEM; goto out_free; } @@ -1281,7 +1299,6 @@ static int virtio_ccw_online(struct ccw_device *cdev) vcdev->vdev.dev.release = virtio_ccw_release_dev; vcdev->vdev.config = &virtio_ccw_config_ops; - vcdev->cdev = cdev; init_waitqueue_head(&vcdev->wait_q); INIT_LIST_HEAD(&vcdev->virtqueues); spin_lock_init(&vcdev->lock); @@ -1312,8 +1329,8 @@ out_put: return ret; out_free: if (vcdev) { - kfree(vcdev->status); - kfree(vcdev->config_block); + ccw_device_dma_free(vcdev->cdev, vcdev->dma_area, + sizeof(*vcdev->dma_area)); } kfree(vcdev); return ret; @@ -1483,8 +1500,17 @@ static void __init no_auto_parse(void) static int __init virtio_ccw_init(void) { + int rc; + /* parse no_auto string before we do anything further */ no_auto_parse(); - return ccw_driver_register(&virtio_ccw_driver); + + summary_indicators = cio_dma_zalloc(MAX_AIRQ_AREAS); + if (!summary_indicators) + return -ENOMEM; + rc = ccw_driver_register(&virtio_ccw_driver); + if (rc) + cio_dma_free(summary_indicators, MAX_AIRQ_AREAS); + return rc; } device_initcall(virtio_ccw_init); diff --git a/drivers/scsi/aic94xx/Kconfig b/drivers/scsi/aic94xx/Kconfig index c83fe751d0bb..71931c371b1c 100644 --- a/drivers/scsi/aic94xx/Kconfig +++ b/drivers/scsi/aic94xx/Kconfig @@ -1,28 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Kernel configuration file for aic94xx SAS/SATA driver. # # Copyright (c) 2005 Adaptec, Inc. All rights reserved. # Copyright (c) 2005 Luben Tuikov <luben_tuikov@adaptec.com> # -# This file is licensed under GPLv2. -# -# This file is part of the aic94xx driver. -# -# The aic94xx driver is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 of the -# License. -# -# The aic94xx driver is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Aic94xx Driver; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# -# config SCSI_AIC94XX tristate "Adaptec AIC94xx SAS/SATA support" diff --git a/drivers/scsi/arm/acornscsi-io.S b/drivers/scsi/arm/acornscsi-io.S index 22171b2110a8..fdd7237bb829 100644 --- a/drivers/scsi/arm/acornscsi-io.S +++ b/drivers/scsi/arm/acornscsi-io.S @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/acorn/scsi/acornscsi-io.S: Acorn SCSI card IO - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/linkage.h> diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index d7509859dc00..d12dd89538df 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/acornscsi.c * * Acorn SCSI 3 driver * By R.M.King. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Abandoned using the Select and Transfer command since there were * some nasty races between our software and the target devices that * were not easy to solve, and the device errata had a lot of entries diff --git a/drivers/scsi/arm/acornscsi.h b/drivers/scsi/arm/acornscsi.h index 01bc715a3aec..376c76bc2aca 100644 --- a/drivers/scsi/arm/acornscsi.h +++ b/drivers/scsi/arm/acornscsi.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/acorn/scsi/acornscsi.h * * Copyright (C) 1997 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Acorn SCSI driver */ #ifndef ACORNSCSI_H diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c index 40afcbd8de61..a1f3e9ee4e63 100644 --- a/drivers/scsi/arm/cumana_2.c +++ b/drivers/scsi/arm/cumana_2.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/cumana_2.c * * Copyright (C) 1997-2005 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Changelog: * 30-08-1997 RMK 0.0.0 Created, READONLY version. * 22-01-1998 RMK 0.0.1 Updated to 2.1.80. diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c index 8f64c370a8a7..134f040d58e2 100644 --- a/drivers/scsi/arm/eesox.c +++ b/drivers/scsi/arm/eesox.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/eesox.c * * Copyright (C) 1997-2005 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This driver is based on experimentation. Hence, it may have made * assumptions about the particular card that I have available, and * may not be reliable! diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index 27bda2b05de6..aea4fd73c862 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/fas216.c * * Copyright (C) 1997-2003 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and * other sources, including: * the AMD Am53CF94 data sheet diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h index c57c16ef8193..847413ce14cf 100644 --- a/drivers/scsi/arm/fas216.h +++ b/drivers/scsi/arm/fas216.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/acorn/scsi/fas216.h * * Copyright (C) 1997-2000 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * FAS216 generic driver */ #ifndef FAS216_H diff --git a/drivers/scsi/arm/msgqueue.c b/drivers/scsi/arm/msgqueue.c index 7c95c7582b29..58115831362f 100644 --- a/drivers/scsi/arm/msgqueue.c +++ b/drivers/scsi/arm/msgqueue.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/msgqueue.c * * Copyright (C) 1997-1998 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * message queue handling */ #include <linux/module.h> diff --git a/drivers/scsi/arm/msgqueue.h b/drivers/scsi/arm/msgqueue.h index 41c7333df3e3..4bcc400f556b 100644 --- a/drivers/scsi/arm/msgqueue.h +++ b/drivers/scsi/arm/msgqueue.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/acorn/scsi/msgqueue.h * * Copyright (C) 1997 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * message queue handling */ #ifndef MSGQUEUE_H diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c index 759f95ba993c..c795537a671c 100644 --- a/drivers/scsi/arm/powertec.c +++ b/drivers/scsi/arm/powertec.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/powertec.c * * Copyright (C) 1997-2005 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/blkdev.h> diff --git a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c index 996dfe903928..e5559f27669d 100644 --- a/drivers/scsi/arm/queue.c +++ b/drivers/scsi/arm/queue.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/queue.c: queue handling primitives * * Copyright (C) 1997-2000 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Changelog: * 15-Sep-1997 RMK Created. * 11-Oct-1997 RMK Corrected problem with queue_remove_exclude diff --git a/drivers/scsi/arm/queue.h b/drivers/scsi/arm/queue.h index 3c519c9237b2..cb51379dce94 100644 --- a/drivers/scsi/arm/queue.h +++ b/drivers/scsi/arm/queue.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/acorn/scsi/queue.h: queue handling * * Copyright (C) 1997 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef QUEUE_H #define QUEUE_H diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h index 138a521ba1a8..4d5ff7b4e864 100644 --- a/drivers/scsi/arm/scsi.h +++ b/drivers/scsi/arm/scsi.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/acorn/scsi/scsi.h * * Copyright (C) 2002 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Commonly used scsi driver functions. */ diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index aafcffaa25f7..2c3bb8a966e5 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -274,6 +274,7 @@ struct lpfc_stats { uint32_t elsXmitADISC; uint32_t elsXmitLOGO; uint32_t elsXmitSCR; + uint32_t elsXmitRSCN; uint32_t elsXmitRNID; uint32_t elsXmitFARP; uint32_t elsXmitFARPR; @@ -819,6 +820,7 @@ struct lpfc_hba { uint32_t cfg_use_msi; uint32_t cfg_auto_imax; uint32_t cfg_fcp_imax; + uint32_t cfg_force_rscn; uint32_t cfg_cq_poll_threshold; uint32_t cfg_cq_max_proc_limit; uint32_t cfg_fcp_cpu_map; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index d4c65e2109e2..2bd1e014103b 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -4959,6 +4959,64 @@ static DEVICE_ATTR(lpfc_req_fw_upgrade, S_IRUGO | S_IWUSR, lpfc_request_firmware_upgrade_store); /** + * lpfc_force_rscn_store + * + * @dev: class device that is converted into a Scsi_host. + * @attr: device attribute, not used. + * @buf: unused string + * @count: unused variable. + * + * Description: + * Force the switch to send a RSCN to all other NPorts in our zone + * If we are direct connect pt2pt, build the RSCN command ourself + * and send to the other NPort. Not supported for private loop. + * + * Returns: + * 0 - on success + * -EIO - if command is not sent + **/ +static ssize_t +lpfc_force_rscn_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + int i; + + i = lpfc_issue_els_rscn(vport, 0); + if (i) + return -EIO; + return strlen(buf); +} + +/* + * lpfc_force_rscn: Force an RSCN to be sent to all remote NPorts + * connected to the HBA. + * + * Value range is any ascii value + */ +static int lpfc_force_rscn; +module_param(lpfc_force_rscn, int, 0644); +MODULE_PARM_DESC(lpfc_force_rscn, + "Force an RSCN to be sent to all remote NPorts"); +lpfc_param_show(force_rscn) + +/** + * lpfc_force_rscn_init - Force an RSCN to be sent to all remote NPorts + * @phba: lpfc_hba pointer. + * @val: unused value. + * + * Returns: + * zero if val saved. + **/ +static int +lpfc_force_rscn_init(struct lpfc_hba *phba, int val) +{ + return 0; +} +static DEVICE_ATTR_RW(lpfc_force_rscn); + +/** * lpfc_fcp_imax_store * * @dev: class device that is converted into a Scsi_host. @@ -5958,6 +6016,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_nvme_oas, &dev_attr_lpfc_nvme_embed_cmd, &dev_attr_lpfc_fcp_imax, + &dev_attr_lpfc_force_rscn, &dev_attr_lpfc_cq_poll_threshold, &dev_attr_lpfc_cq_max_proc_limit, &dev_attr_lpfc_fcp_cpu_map, @@ -7005,6 +7064,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_nvme_oas_init(phba, lpfc_nvme_oas); lpfc_nvme_embed_cmd_init(phba, lpfc_nvme_embed_cmd); lpfc_fcp_imax_init(phba, lpfc_fcp_imax); + lpfc_force_rscn_init(phba, lpfc_force_rscn); lpfc_cq_poll_threshold_init(phba, lpfc_cq_poll_threshold); lpfc_cq_max_proc_limit_init(phba, lpfc_cq_max_proc_limit); lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map); diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index e0b14d791b8c..866374801140 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -141,6 +141,7 @@ int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *); int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t); +int lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry); int lpfc_issue_fabric_reglogin(struct lpfc_vport *); int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); @@ -355,6 +356,7 @@ void lpfc_mbox_timeout_handler(struct lpfc_hba *); struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t); struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *, struct lpfc_name *); +struct lpfc_nodelist *lpfc_findnode_mapped(struct lpfc_vport *vport); int lpfc_sli_issue_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); @@ -555,6 +557,8 @@ void lpfc_ras_stop_fwlog(struct lpfc_hba *phba); int lpfc_check_fwlog_support(struct lpfc_hba *phba); /* NVME interfaces. */ +void lpfc_nvme_rescan_port(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp); void lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp); int lpfc_nvme_register_port(struct lpfc_vport *vport, diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 5ac4f8d76b91..968ed0fd37f7 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -30,6 +30,8 @@ #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport_fc.h> +#include <uapi/scsi/fc/fc_fs.h> +#include <uapi/scsi/fc/fc_els.h> #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -3079,6 +3081,116 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) } /** + * lpfc_issue_els_rscn - Issue an RSCN to the Fabric Controller (Fabric) + * or the other nport (pt2pt). + * @vport: pointer to a host virtual N_Port data structure. + * @retry: number of retries to the command IOCB. + * + * This routine issues a RSCN to the Fabric Controller (DID 0xFFFFFD) + * when connected to a fabric, or to the remote port when connected + * in point-to-point mode. When sent to the Fabric Controller, it will + * replay the RSCN to registered recipients. + * + * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp + * will be incremented by 1 for holding the ndlp and the reference to ndlp + * will be stored into the context1 field of the IOCB for the completion + * callback function to the RSCN ELS command. + * + * Return code + * 0 - Successfully issued RSCN command + * 1 - Failed to issue RSCN command + **/ +int +lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *elsiocb; + struct lpfc_nodelist *ndlp; + struct { + struct fc_els_rscn rscn; + struct fc_els_rscn_page portid; + } *event; + uint32_t nportid; + uint16_t cmdsize = sizeof(*event); + + /* Not supported for private loop */ + if (phba->fc_topology == LPFC_TOPOLOGY_LOOP && + !(vport->fc_flag & FC_PUBLIC_LOOP)) + return 1; + + if (vport->fc_flag & FC_PT2PT) { + /* find any mapped nport - that would be the other nport */ + ndlp = lpfc_findnode_mapped(vport); + if (!ndlp) + return 1; + } else { + nportid = FC_FID_FCTRL; + /* find the fabric controller node */ + ndlp = lpfc_findnode_did(vport, nportid); + if (!ndlp) { + /* if one didn't exist, make one */ + ndlp = lpfc_nlp_init(vport, nportid); + if (!ndlp) + return 1; + lpfc_enqueue_node(vport, ndlp); + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, + NLP_STE_UNUSED_NODE); + if (!ndlp) + return 1; + } + } + + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, + ndlp->nlp_DID, ELS_CMD_RSCN_XMT); + + if (!elsiocb) { + /* This will trigger the release of the node just + * allocated + */ + lpfc_nlp_put(ndlp); + return 1; + } + + event = ((struct lpfc_dmabuf *)elsiocb->context2)->virt; + + event->rscn.rscn_cmd = ELS_RSCN; + event->rscn.rscn_page_len = sizeof(struct fc_els_rscn_page); + event->rscn.rscn_plen = cpu_to_be16(cmdsize); + + nportid = vport->fc_myDID; + /* appears that page flags must be 0 for fabric to broadcast RSCN */ + event->portid.rscn_page_flags = 0; + event->portid.rscn_fid[0] = (nportid & 0x00FF0000) >> 16; + event->portid.rscn_fid[1] = (nportid & 0x0000FF00) >> 8; + event->portid.rscn_fid[2] = nportid & 0x000000FF; + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue RSCN: did:x%x", + ndlp->nlp_DID, 0, 0); + + phba->fc_stat.elsXmitRSCN++; + elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == + IOCB_ERROR) { + /* The additional lpfc_nlp_put will cause the following + * lpfc_els_free_iocb routine to trigger the rlease of + * the node. + */ + lpfc_nlp_put(ndlp); + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } + /* This will cause the callback-function lpfc_cmpl_els_cmd to + * trigger the release of node. + */ + if (!(vport->fc_flag & FC_PT2PT)) + lpfc_nlp_put(ndlp); + + return 0; +} + +/** * lpfc_issue_els_farpr - Issue a farp to an node on a vport * @vport: pointer to a host virtual N_Port data structure. * @nportid: N_Port identifier to the remote node. @@ -6214,6 +6326,8 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport) continue; } + if (ndlp->nlp_fc4_type & NLP_FC4_NVME) + lpfc_nvme_rescan_port(vport, ndlp); lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); @@ -6318,6 +6432,19 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_RSCN, lp[i]); + /* Check if RSCN is coming from a direct-connected remote NPort */ + if (vport->fc_flag & FC_PT2PT) { + /* If so, just ACC it, no other action needed for now */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "2024 pt2pt RSCN %08x Data: x%x x%x\n", + *lp, vport->fc_flag, payload_len); + lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); + + if (ndlp->nlp_fc4_type & NLP_FC4_NVME) + lpfc_nvme_rescan_port(vport, ndlp); + return 0; + } + /* If we are about to begin discovery, just ACC the RSCN. * Discovery processing will satisfy it. */ diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index c43852f97f25..28ecaa7fc715 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -5277,6 +5277,41 @@ lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) } struct lpfc_nodelist * +lpfc_findnode_mapped(struct lpfc_vport *vport) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_nodelist *ndlp; + uint32_t data1; + unsigned long iflags; + + spin_lock_irqsave(shost->host_lock, iflags); + + list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { + if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE || + ndlp->nlp_state == NLP_STE_MAPPED_NODE) { + data1 = (((uint32_t)ndlp->nlp_state << 24) | + ((uint32_t)ndlp->nlp_xri << 16) | + ((uint32_t)ndlp->nlp_type << 8) | + ((uint32_t)ndlp->nlp_rpi & 0xff)); + spin_unlock_irqrestore(shost->host_lock, iflags); + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "2025 FIND node DID " + "Data: x%p x%x x%x x%x %p\n", + ndlp, ndlp->nlp_DID, + ndlp->nlp_flag, data1, + ndlp->active_rrqs_xri_bitmap); + return ndlp; + } + } + spin_unlock_irqrestore(shost->host_lock, iflags); + + /* FIND node did <did> NOT FOUND */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "2026 FIND mapped did NOT FOUND.\n"); + return NULL; +} + +struct lpfc_nodelist * lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index edd8f3982023..5b439a6dcde1 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -601,6 +601,7 @@ struct fc_vft_header { #define ELS_CMD_RPL 0x57000000 #define ELS_CMD_FAN 0x60000000 #define ELS_CMD_RSCN 0x61040000 +#define ELS_CMD_RSCN_XMT 0x61040008 #define ELS_CMD_SCR 0x62000000 #define ELS_CMD_RNID 0x78000000 #define ELS_CMD_LIRR 0x7A000000 @@ -642,6 +643,7 @@ struct fc_vft_header { #define ELS_CMD_RPL 0x57 #define ELS_CMD_FAN 0x60 #define ELS_CMD_RSCN 0x0461 +#define ELS_CMD_RSCN_XMT 0x08000461 #define ELS_CMD_SCR 0x62 #define ELS_CMD_RNID 0x78 #define ELS_CMD_LIRR 0x7A diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 9d99cb915390..fdd16d9f55a1 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -2402,6 +2402,50 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) #endif } +/** + * lpfc_nvme_rescan_port - Check to see if we should rescan this remoteport + * + * If the ndlp represents an NVME Target, that we are logged into, + * ping the NVME FC Transport layer to initiate a device rescan + * on this remote NPort. + */ +void +lpfc_nvme_rescan_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ +#if (IS_ENABLED(CONFIG_NVME_FC)) + struct lpfc_nvme_rport *rport; + struct nvme_fc_remote_port *remoteport; + + rport = ndlp->nrport; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, + "6170 Rescan NPort DID x%06x type x%x " + "state x%x rport %p\n", + ndlp->nlp_DID, ndlp->nlp_type, ndlp->nlp_state, rport); + if (!rport) + goto input_err; + remoteport = rport->remoteport; + if (!remoteport) + goto input_err; + + /* Only rescan if we are an NVME target in the MAPPED state */ + if (remoteport->port_role & FC_PORT_ROLE_NVME_DISCOVERY && + ndlp->nlp_state == NLP_STE_MAPPED_NODE) { + nvme_fc_rescan_remoteport(remoteport); + + lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, + "6172 NVME rescanned DID x%06x " + "port_state x%x\n", + ndlp->nlp_DID, remoteport->port_state); + } + return; +input_err: + lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, + "6169 State error: lport %p, rport%p FCID x%06x\n", + vport->localport, ndlp->rport, ndlp->nlp_DID); +#endif +} + /* lpfc_nvme_unregister_port - unbind the DID and port_role from this rport. * * There is no notion of Devloss or rport recovery from the current diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index d74bfd264495..06170824a69b 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1139,6 +1139,22 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, spin_unlock_irqrestore(&ctxp->ctxlock, iflag); } +static void +lpfc_nvmet_discovery_event(struct nvmet_fc_target_port *tgtport) +{ + struct lpfc_nvmet_tgtport *tgtp; + struct lpfc_hba *phba; + uint32_t rc; + + tgtp = tgtport->private; + phba = tgtp->phba; + + rc = lpfc_issue_els_rscn(phba->pport, 0); + lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + "6420 NVMET subsystem change: Notification %s\n", + (rc) ? "Failed" : "Sent"); +} + static struct nvmet_fc_target_template lpfc_tgttemplate = { .targetport_delete = lpfc_nvmet_targetport_delete, .xmt_ls_rsp = lpfc_nvmet_xmt_ls_rsp, @@ -1146,6 +1162,7 @@ static struct nvmet_fc_target_template lpfc_tgttemplate = { .fcp_abort = lpfc_nvmet_xmt_fcp_abort, .fcp_req_release = lpfc_nvmet_xmt_fcp_release, .defer_rcv = lpfc_nvmet_defer_rcv, + .discovery_event = lpfc_nvmet_discovery_event, .max_hw_queues = 1, .max_sgl_segments = LPFC_NVMET_DEFAULT_SEGS, diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index d1512e4f9791..4329cc44bb55 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -9398,6 +9398,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) { if (pcmd && (*pcmd == ELS_CMD_FLOGI || *pcmd == ELS_CMD_SCR || + *pcmd == ELS_CMD_RSCN_XMT || *pcmd == ELS_CMD_FDISC || *pcmd == ELS_CMD_LOGO || *pcmd == ELS_CMD_PLOGI)) { diff --git a/drivers/scsi/mvsas/Kconfig b/drivers/scsi/mvsas/Kconfig index 78f7e20a0c1c..79812b80743b 100644 --- a/drivers/scsi/mvsas/Kconfig +++ b/drivers/scsi/mvsas/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Kernel configuration file for 88SE64XX/88SE94XX SAS/SATA driver. # @@ -5,25 +6,6 @@ # Copyright 2008 Marvell. <kewei@marvell.com> # Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> # -# This file is licensed under GPLv2. -# -# This file is part of the 88SE64XX/88SE94XX driver. -# -# The 88SE64XX/88SE94XX driver is free software; you can redistribute -# it and/or modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; version 2 of the -# License. -# -# The 88SE64XX/88SE94XX driver is distributed in the hope that it will be -# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with 88SE64XX/88SE94XX Driver; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# -# config SCSI_MVSAS tristate "Marvell 88SE64XX/88SE94XX SAS/SATA support" diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index 8814bfcb6449..f210a3e0c9b1 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -987,6 +987,9 @@ static int qedi_find_boot_info(struct qedi_ctx *qedi, if (!iscsi_is_session_online(cls_sess)) continue; + if (!sess->targetname) + continue; + if (pri_ctrl_flags) { if (!strcmp(pri_tgt->iscsi_name, sess->targetname) && !strcmp(pri_tgt->ip_addr, ep_ip_addr)) { diff --git a/drivers/scsi/qedi/qedi_version.h b/drivers/scsi/qedi/qedi_version.h index f56f0ba0c4a8..0ac1055bd420 100644 --- a/drivers/scsi/qedi/qedi_version.h +++ b/drivers/scsi/qedi/qedi_version.h @@ -4,8 +4,8 @@ * Copyright (c) 2016 Cavium Inc. */ -#define QEDI_MODULE_VERSION "8.33.0.21" +#define QEDI_MODULE_VERSION "8.37.0.20" #define QEDI_DRIVER_MAJOR_VER 8 -#define QEDI_DRIVER_MINOR_VER 33 +#define QEDI_DRIVER_MINOR_VER 37 #define QEDI_DRIVER_REV_VER 0 -#define QEDI_DRIVER_ENG_VER 21 +#define QEDI_DRIVER_ENG_VER 20 diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 172ef21827dd..d056f5e7cf93 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1731,8 +1731,8 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && !qla2x00_isp_reg_stat(ha))) { sp->comp = ∁ - rval = ha->isp_ops->abort_command(sp); spin_unlock_irqrestore(qp->qp_lock_ptr, *flags); + rval = ha->isp_ops->abort_command(sp); switch (rval) { case QLA_SUCCESS: diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index 4e46fdb2d7c9..d4d1104fac99 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c @@ -1,22 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SCSI RDMA (SRP) transport class * * Copyright (C) 2007 FUJITA Tomonori <tomof@acm.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #include <linux/init.h> #include <linux/module.h> diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c b/drivers/scsi/ufs/tc-dwc-g210-pci.c index 2f41722a8c28..67a6a61154b7 100644 --- a/drivers/scsi/ufs/tc-dwc-g210-pci.c +++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Synopsys G210 Test Chip driver * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto <jpinto@synopsys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "ufshcd.h" diff --git a/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c index 6dfe5a9206e9..a1268e4f44d6 100644 --- a/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c +++ b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Synopsys G210 Test Chip driver * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto <jpinto@synopsys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/scsi/ufs/tc-dwc-g210.c b/drivers/scsi/ufs/tc-dwc-g210.c index 3a8bc6d9cb5b..f954a68f6b4c 100644 --- a/drivers/scsi/ufs/tc-dwc-g210.c +++ b/drivers/scsi/ufs/tc-dwc-g210.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Synopsys G210 Test Chip driver * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto <jpinto@synopsys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "ufshcd.h" diff --git a/drivers/scsi/ufs/tc-dwc-g210.h b/drivers/scsi/ufs/tc-dwc-g210.h index fb177db1227d..5a506da03f4a 100644 --- a/drivers/scsi/ufs/tc-dwc-g210.h +++ b/drivers/scsi/ufs/tc-dwc-g210.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Synopsys G210 Test Chip driver * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto <jpinto@synopsys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _TC_DWC_G210_H diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c index 7aed0a1a794e..f4d1dca962c4 100644 --- a/drivers/scsi/ufs/ufs-hisi.c +++ b/drivers/scsi/ufs/ufs-hisi.c @@ -1,11 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HiSilicon Hixxxx UFS Driver * * Copyright (c) 2016-2017 Linaro Ltd. * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd. - * - * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ #include <linux/time.h> diff --git a/drivers/scsi/ufs/ufs-hisi.h b/drivers/scsi/ufs/ufs-hisi.h index 667dfe39b57e..3231d3d81c98 100644 --- a/drivers/scsi/ufs/ufs-hisi.h +++ b/drivers/scsi/ufs/ufs-hisi.h @@ -1,8 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017, HiSilicon. All rights reserved. - * - * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ #ifndef UFS_HISI_H_ diff --git a/drivers/scsi/ufs/ufshcd-dwc.c b/drivers/scsi/ufs/ufshcd-dwc.c index 977b21871a5d..fb9e2ff4f8d2 100644 --- a/drivers/scsi/ufs/ufshcd-dwc.c +++ b/drivers/scsi/ufs/ufshcd-dwc.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * UFS Host driver for Synopsys Designware Core * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto <jpinto@synopsys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "ufshcd.h" diff --git a/drivers/scsi/ufs/ufshcd-dwc.h b/drivers/scsi/ufs/ufshcd-dwc.h index c8be295e0ebe..4268ca2eb64c 100644 --- a/drivers/scsi/ufs/ufshcd-dwc.h +++ b/drivers/scsi/ufs/ufshcd-dwc.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * UFS Host driver for Synopsys Designware Core * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto <jpinto@synopsys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _UFSHCD_DWC_H diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index 8a74ec30c3d2..d7d521b394c3 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -430,24 +430,21 @@ int ufshcd_pltfrm_init(struct platform_device *pdev, goto dealloc_host; } - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - ufshcd_init_lanes_per_dir(hba); err = ufshcd_init(hba, mmio_base, irq); if (err) { dev_err(dev, "Initialization failed\n"); - goto out_disable_rpm; + goto dealloc_host; } platform_set_drvdata(pdev, hba); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + return 0; -out_disable_rpm: - pm_runtime_disable(&pdev->dev); - pm_runtime_set_suspended(&pdev->dev); dealloc_host: ufshcd_dealloc_host(hba); out: diff --git a/drivers/scsi/ufs/ufshci-dwc.h b/drivers/scsi/ufs/ufshci-dwc.h index ca341fece310..6c290e272106 100644 --- a/drivers/scsi/ufs/ufshci-dwc.h +++ b/drivers/scsi/ufs/ufshci-dwc.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * UFS Host driver for Synopsys Designware Core * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto <jpinto@synopsys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _UFSHCI_DWC_H diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index ecee4b3ff073..377b07b2feeb 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -763,6 +763,7 @@ static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd struct pvscsi_adapter *adapter = shost_priv(host); struct pvscsi_ctx *ctx; unsigned long flags; + unsigned char op; spin_lock_irqsave(&adapter->hw_lock, flags); @@ -775,13 +776,14 @@ static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd } cmd->scsi_done = done; + op = cmd->cmnd[0]; dev_dbg(&cmd->device->sdev_gendev, - "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, cmd->cmnd[0]); + "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, op); spin_unlock_irqrestore(&adapter->hw_lock, flags); - pvscsi_kick_io(adapter, cmd->cmnd[0]); + pvscsi_kick_io(adapter, op); return 0; } diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 524ecdc2a9bb..2ec355003524 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_SOC_SAMSUNG) += samsung/ obj-y += sunxi/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ -obj-$(CONFIG_SOC_TI) += ti/ +obj-y += ti/ obj-$(CONFIG_ARCH_U8500) += ux500/ obj-$(CONFIG_PLAT_VERSATILE) += versatile/ obj-y += xilinx/ diff --git a/drivers/soc/bcm/brcmstb/biuctrl.c b/drivers/soc/bcm/brcmstb/biuctrl.c index b3dbdb365749..d326915e0f40 100644 --- a/drivers/soc/bcm/brcmstb/biuctrl.c +++ b/drivers/soc/bcm/brcmstb/biuctrl.c @@ -48,7 +48,7 @@ static inline void cbc_writel(u32 val, int reg) if (offset == -1) return; - writel_relaxed(val, cpubiuctrl_base + offset); + writel(val, cpubiuctrl_base + offset); } enum cpubiuctrl_regs { @@ -238,7 +238,9 @@ static int __init brcmstb_biuctrl_init(void) if (!np) return 0; - setup_hifcpubiuctrl_regs(np); + ret = setup_hifcpubiuctrl_regs(np); + if (ret) + return ret; ret = mcp_write_pairing_set(); if (ret) { diff --git a/drivers/soc/imx/soc-imx8.c b/drivers/soc/imx/soc-imx8.c index fc6429f9170a..b1bd8e2543ac 100644 --- a/drivers/soc/imx/soc-imx8.c +++ b/drivers/soc/imx/soc-imx8.c @@ -103,6 +103,9 @@ static int __init imx8_soc_init(void) if (IS_ERR(soc_dev)) goto free_rev; + if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT)) + platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0); + return 0; free_rev: diff --git a/drivers/soc/ixp4xx/ixp4xx-npe.c b/drivers/soc/ixp4xx/ixp4xx-npe.c index bc10e3194809..ec90b44fa0cd 100644 --- a/drivers/soc/ixp4xx/ixp4xx-npe.c +++ b/drivers/soc/ixp4xx/ixp4xx-npe.c @@ -695,8 +695,8 @@ static int ixp4xx_npe_probe(struct platform_device *pdev) continue; /* NPE already disabled or not present */ } npe->regs = devm_ioremap_resource(dev, res); - if (!npe->regs) - return -ENOMEM; + if (IS_ERR(npe->regs)) + return PTR_ERR(npe->regs); if (npe_reset(npe)) { dev_info(dev, "NPE%d at 0x%08x-0x%08x does not reset\n", diff --git a/drivers/soc/lantiq/fpi-bus.c b/drivers/soc/lantiq/fpi-bus.c index a671c9984c4c..cb0303a0fe60 100644 --- a/drivers/soc/lantiq/fpi-bus.c +++ b/drivers/soc/lantiq/fpi-bus.c @@ -1,7 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. * * Copyright (C) 2011-2015 John Crispin <blogic@phrozen.org> * Copyright (C) 2015 Martin Blumenstingl <martin.blumenstingl@googlemail.com> diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c index 3b81e1d75a97..494cf2b5bf7b 100644 --- a/drivers/soc/rockchip/grf.c +++ b/drivers/soc/rockchip/grf.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Rockchip Generic Register Files setup * * Copyright (c) 2016 Heiko Stuebner <heiko@sntech.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 847c7c482b26..3342332cc007 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Rockchip Generic power domain support. * * Copyright (c) 2015 ROCKCHIP, Co. Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/io.h> diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index 7bfb154d6fa5..3dc54f59cafe 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/of.h> diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig index ea0859f7b185..d7d50d48d05d 100644 --- a/drivers/soc/ti/Kconfig +++ b/drivers/soc/ti/Kconfig @@ -75,10 +75,10 @@ config TI_SCI_PM_DOMAINS called ti_sci_pm_domains. Note this is needed early in boot before rootfs may be available. +endif # SOC_TI + config TI_SCI_INTA_MSI_DOMAIN bool select GENERIC_MSI_IRQ_DOMAIN help Driver to enable Interrupt Aggregator specific MSI Domain. - -endif # SOC_TI diff --git a/drivers/soc/versatile/soc-integrator.c b/drivers/soc/versatile/soc-integrator.c index a5d7d39ae0ad..ae13fa2aa582 100644 --- a/drivers/soc/versatile/soc-integrator.c +++ b/drivers/soc/versatile/soc-integrator.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Linaro Ltd. * * Author: Linus Walleij <linus.walleij@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * */ #include <linux/init.h> #include <linux/io.h> diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c index caf698e5f0b0..9471353dd8c3 100644 --- a/drivers/soc/versatile/soc-realview.c +++ b/drivers/soc/versatile/soc-realview.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Linaro Ltd. * * Author: Linus Walleij <linus.walleij@linaro.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * */ #include <linux/init.h> #include <linux/io.h> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 31336b0271b0..60293a00a14e 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -715,8 +715,8 @@ static int intel_create_dai(struct sdw_cdns *cdns, return -ENOMEM; } - dais[i].playback.channels_min = 1; - dais[i].playback.channels_max = max_ch; + dais[i].capture.channels_min = 1; + dais[i].capture.channels_max = max_ch; dais[i].capture.rates = SNDRV_PCM_RATE_48000; dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE; } diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index d01060dbee96..1d5294b8783b 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -814,7 +814,8 @@ static int do_bank_switch(struct sdw_stream_runtime *stream) goto error; } - mutex_unlock(&bus->msg_lock); + if (bus->multi_link) + mutex_unlock(&bus->msg_lock); } return ret; @@ -1406,9 +1407,7 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave, } for (i = 0; i < num_ports; i++) { - dpn_prop = &dpn_prop[i]; - - if (dpn_prop->num == port_num) + if (dpn_prop[i].num == port_num) return &dpn_prop[i]; } diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 30a40280c157..3a1d8f1170de 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -120,7 +120,7 @@ config SPI_AXI_SPI_ENGINE config SPI_BCM2835 tristate "BCM2835 SPI controller" depends on GPIOLIB - depends on ARCH_BCM2835 || COMPILE_TEST + depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST help This selects a driver for the Broadcom BCM2835 SPI master. @@ -131,7 +131,7 @@ config SPI_BCM2835 config SPI_BCM2835AUX tristate "BCM2835 SPI auxiliary controller" - depends on (ARCH_BCM2835 && GPIOLIB) || COMPILE_TEST + depends on ((ARCH_BCM2835 || ARCH_BRCMSTB) && GPIOLIB) || COMPILE_TEST help This selects a driver for the Broadcom BCM2835 SPI aux master. @@ -733,6 +733,16 @@ config SPI_SUN6I help This enables using the SPI controller on the Allwinner A31 SoCs. +config SPI_SYNQUACER + tristate "Socionext's SynQuacer HighSpeed SPI controller" + depends on ARCH_SYNQUACER || COMPILE_TEST + help + SPI driver for Socionext's High speed SPI controller which provides + various operating modes for interfacing to serial peripheral devices + that use the de-facto standard SPI protocol. + + It also supports the new dual-bit and quad-bit SPI protocol. + config SPI_MXIC tristate "Macronix MX25F0A SPI controller" depends on SPI_MASTER diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index f2f78d03dc28..63dcab552bcb 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -106,6 +106,7 @@ obj-$(CONFIG_SPI_STM32_QSPI) += spi-stm32-qspi.o obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o +obj-$(CONFIG_SPI_SYNQUACER) += spi-synquacer.o obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 9f24d5f0b431..6a7d7b553d95 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -151,6 +151,7 @@ struct atmel_qspi { const struct atmel_qspi_caps *caps; u32 pending; u32 mr; + u32 scr; struct completion cmd_completion; }; @@ -382,7 +383,7 @@ static int atmel_qspi_setup(struct spi_device *spi) struct spi_controller *ctrl = spi->master; struct atmel_qspi *aq = spi_controller_get_devdata(ctrl); unsigned long src_rate; - u32 scr, scbr; + u32 scbr; if (ctrl->busy) return -EBUSY; @@ -399,13 +400,13 @@ static int atmel_qspi_setup(struct spi_device *spi) if (scbr > 0) scbr--; - scr = QSPI_SCR_SCBR(scbr); - writel_relaxed(scr, aq->regs + QSPI_SCR); + aq->scr = QSPI_SCR_SCBR(scbr); + writel_relaxed(aq->scr, aq->regs + QSPI_SCR); return 0; } -static int atmel_qspi_init(struct atmel_qspi *aq) +static void atmel_qspi_init(struct atmel_qspi *aq) { /* Reset the QSPI controller */ writel_relaxed(QSPI_CR_SWRST, aq->regs + QSPI_CR); @@ -416,8 +417,6 @@ static int atmel_qspi_init(struct atmel_qspi *aq) /* Enable the QSPI controller */ writel_relaxed(QSPI_CR_QSPIEN, aq->regs + QSPI_CR); - - return 0; } static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id) @@ -536,9 +535,7 @@ static int atmel_qspi_probe(struct platform_device *pdev) if (err) goto disable_qspick; - err = atmel_qspi_init(aq); - if (err) - goto disable_qspick; + atmel_qspi_init(aq); err = spi_register_controller(ctrl); if (err) @@ -587,7 +584,11 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev) clk_prepare_enable(aq->pclk); clk_prepare_enable(aq->qspick); - return atmel_qspi_init(aq); + atmel_qspi_init(aq); + + writel_relaxed(aq->scr, aq->regs + QSPI_SCR); + + return 0; } static SIMPLE_DEV_PM_OPS(atmel_qspi_pm_ops, atmel_qspi_suspend, diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index a5adf0d868fc..ea160f117f88 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Altera SPI driver * @@ -7,10 +8,6 @@ * Copyright (c) 2006 Ben Dooks * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/interrupt.h> diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index 7dcb14d303eb..032888344822 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Marvell Armada-3700 SPI controller driver * @@ -5,10 +6,6 @@ * * Author: Wilson Ding <dingwei@marvell.com> * Author: Romain Perier <romain.perier@free-electrons.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c index f763e14bdf12..a40bb2ef89dc 100644 --- a/drivers/spi/spi-at91-usart.c +++ b/drivers/spi/spi-at91-usart.c @@ -8,9 +8,12 @@ #include <linux/clk.h> #include <linux/delay.h> +#include <linux/dmaengine.h> +#include <linux/dma-direction.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_platform.h> #include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> @@ -59,6 +62,8 @@ #define US_INIT \ (US_MR_SPI_MASTER | US_MR_CHRL | US_MR_CLKO | US_MR_WRDBT) +#define US_DMA_MIN_BYTES 16 +#define US_DMA_TIMEOUT (msecs_to_jiffies(1000)) /* Register access macros */ #define at91_usart_spi_readl(port, reg) \ @@ -72,14 +77,19 @@ writeb_relaxed((value), (port)->regs + US_##reg) struct at91_usart_spi { + struct platform_device *mpdev; struct spi_transfer *current_transfer; void __iomem *regs; struct device *dev; struct clk *clk; + struct completion xfer_completion; + /*used in interrupt to protect data reading*/ spinlock_t lock; + phys_addr_t phybase; + int irq; unsigned int current_tx_remaining_bytes; unsigned int current_rx_remaining_bytes; @@ -88,8 +98,182 @@ struct at91_usart_spi { u32 status; bool xfer_failed; + bool use_dma; }; +static void dma_callback(void *data) +{ + struct spi_controller *ctlr = data; + struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); + + at91_usart_spi_writel(aus, IER, US_IR_RXRDY); + aus->current_rx_remaining_bytes = 0; + complete(&aus->xfer_completion); +} + +static bool at91_usart_spi_can_dma(struct spi_controller *ctrl, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct at91_usart_spi *aus = spi_master_get_devdata(ctrl); + + return aus->use_dma && xfer->len >= US_DMA_MIN_BYTES; +} + +static int at91_usart_spi_configure_dma(struct spi_controller *ctlr, + struct at91_usart_spi *aus) +{ + struct dma_slave_config slave_config; + struct device *dev = &aus->mpdev->dev; + phys_addr_t phybase = aus->phybase; + dma_cap_mask_t mask; + int err = 0; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + ctlr->dma_tx = dma_request_slave_channel_reason(dev, "tx"); + if (IS_ERR_OR_NULL(ctlr->dma_tx)) { + if (IS_ERR(ctlr->dma_tx)) { + err = PTR_ERR(ctlr->dma_tx); + goto at91_usart_spi_error_clear; + } + + dev_dbg(dev, + "DMA TX channel not available, SPI unable to use DMA\n"); + err = -EBUSY; + goto at91_usart_spi_error_clear; + } + + ctlr->dma_rx = dma_request_slave_channel_reason(dev, "rx"); + if (IS_ERR_OR_NULL(ctlr->dma_rx)) { + if (IS_ERR(ctlr->dma_rx)) { + err = PTR_ERR(ctlr->dma_rx); + goto at91_usart_spi_error; + } + + dev_dbg(dev, + "DMA RX channel not available, SPI unable to use DMA\n"); + err = -EBUSY; + goto at91_usart_spi_error; + } + + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.dst_addr = (dma_addr_t)phybase + US_THR; + slave_config.src_addr = (dma_addr_t)phybase + US_RHR; + slave_config.src_maxburst = 1; + slave_config.dst_maxburst = 1; + slave_config.device_fc = false; + + slave_config.direction = DMA_DEV_TO_MEM; + if (dmaengine_slave_config(ctlr->dma_rx, &slave_config)) { + dev_err(&ctlr->dev, + "failed to configure rx dma channel\n"); + err = -EINVAL; + goto at91_usart_spi_error; + } + + slave_config.direction = DMA_MEM_TO_DEV; + if (dmaengine_slave_config(ctlr->dma_tx, &slave_config)) { + dev_err(&ctlr->dev, + "failed to configure tx dma channel\n"); + err = -EINVAL; + goto at91_usart_spi_error; + } + + aus->use_dma = true; + return 0; + +at91_usart_spi_error: + if (!IS_ERR_OR_NULL(ctlr->dma_tx)) + dma_release_channel(ctlr->dma_tx); + if (!IS_ERR_OR_NULL(ctlr->dma_rx)) + dma_release_channel(ctlr->dma_rx); + ctlr->dma_tx = NULL; + ctlr->dma_rx = NULL; + +at91_usart_spi_error_clear: + return err; +} + +static void at91_usart_spi_release_dma(struct spi_controller *ctlr) +{ + if (ctlr->dma_rx) + dma_release_channel(ctlr->dma_rx); + if (ctlr->dma_tx) + dma_release_channel(ctlr->dma_tx); +} + +static void at91_usart_spi_stop_dma(struct spi_controller *ctlr) +{ + if (ctlr->dma_rx) + dmaengine_terminate_all(ctlr->dma_rx); + if (ctlr->dma_tx) + dmaengine_terminate_all(ctlr->dma_tx); +} + +static int at91_usart_spi_dma_transfer(struct spi_controller *ctlr, + struct spi_transfer *xfer) +{ + struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); + struct dma_chan *rxchan = ctlr->dma_rx; + struct dma_chan *txchan = ctlr->dma_tx; + struct dma_async_tx_descriptor *rxdesc; + struct dma_async_tx_descriptor *txdesc; + dma_cookie_t cookie; + + /* Disable RX interrupt */ + at91_usart_spi_writel(aus, IDR, US_IR_RXRDY); + + rxdesc = dmaengine_prep_slave_sg(rxchan, + xfer->rx_sg.sgl, + xfer->rx_sg.nents, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | + DMA_CTRL_ACK); + if (!rxdesc) + goto at91_usart_spi_err_dma; + + txdesc = dmaengine_prep_slave_sg(txchan, + xfer->tx_sg.sgl, + xfer->tx_sg.nents, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | + DMA_CTRL_ACK); + if (!txdesc) + goto at91_usart_spi_err_dma; + + rxdesc->callback = dma_callback; + rxdesc->callback_param = ctlr; + + cookie = rxdesc->tx_submit(rxdesc); + if (dma_submit_error(cookie)) + goto at91_usart_spi_err_dma; + + cookie = txdesc->tx_submit(txdesc); + if (dma_submit_error(cookie)) + goto at91_usart_spi_err_dma; + + rxchan->device->device_issue_pending(rxchan); + txchan->device->device_issue_pending(txchan); + + return 0; + +at91_usart_spi_err_dma: + /* Enable RX interrupt if something fails and fallback to PIO */ + at91_usart_spi_writel(aus, IER, US_IR_RXRDY); + at91_usart_spi_stop_dma(ctlr); + + return -ENOMEM; +} + +static unsigned long at91_usart_spi_dma_timeout(struct at91_usart_spi *aus) +{ + return wait_for_completion_timeout(&aus->xfer_completion, + US_DMA_TIMEOUT); +} + static inline u32 at91_usart_spi_tx_ready(struct at91_usart_spi *aus) { return aus->status & US_IR_TXRDY; @@ -216,6 +400,8 @@ static int at91_usart_spi_transfer_one(struct spi_controller *ctlr, struct spi_transfer *xfer) { struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); + unsigned long dma_timeout = 0; + int ret = 0; at91_usart_spi_set_xfer_speed(aus, xfer); aus->xfer_failed = false; @@ -225,8 +411,25 @@ static int at91_usart_spi_transfer_one(struct spi_controller *ctlr, while ((aus->current_tx_remaining_bytes || aus->current_rx_remaining_bytes) && !aus->xfer_failed) { - at91_usart_spi_read_status(aus); - at91_usart_spi_tx(aus); + reinit_completion(&aus->xfer_completion); + if (at91_usart_spi_can_dma(ctlr, spi, xfer) && + !ret) { + ret = at91_usart_spi_dma_transfer(ctlr, xfer); + if (ret) + continue; + + dma_timeout = at91_usart_spi_dma_timeout(aus); + + if (WARN_ON(dma_timeout == 0)) { + dev_err(&spi->dev, "DMA transfer timeout\n"); + return -EIO; + } + aus->current_tx_remaining_bytes = 0; + } else { + at91_usart_spi_read_status(aus); + at91_usart_spi_tx(aus); + } + cpu_relax(); } @@ -345,6 +548,7 @@ static int at91_usart_spi_probe(struct platform_device *pdev) controller->transfer_one = at91_usart_spi_transfer_one; controller->prepare_message = at91_usart_spi_prepare_message; controller->unprepare_message = at91_usart_spi_unprepare_message; + controller->can_dma = at91_usart_spi_can_dma; controller->cleanup = at91_usart_spi_cleanup; controller->max_speed_hz = DIV_ROUND_UP(clk_get_rate(clk), US_MIN_CLK_DIV); @@ -376,7 +580,17 @@ static int at91_usart_spi_probe(struct platform_device *pdev) aus->spi_clk = clk_get_rate(clk); at91_usart_spi_init(aus); + aus->phybase = regs->start; + + aus->mpdev = to_platform_device(pdev->dev.parent); + + ret = at91_usart_spi_configure_dma(controller, aus); + if (ret) + goto at91_usart_fail_dma; + spin_lock_init(&aus->lock); + init_completion(&aus->xfer_completion); + ret = devm_spi_register_master(&pdev->dev, controller); if (ret) goto at91_usart_fail_register_master; @@ -389,6 +603,8 @@ static int at91_usart_spi_probe(struct platform_device *pdev) return 0; at91_usart_fail_register_master: + at91_usart_spi_release_dma(controller); +at91_usart_fail_dma: clk_disable_unprepare(clk); at91_usart_spi_probe_fail: spi_master_put(controller); @@ -453,6 +669,7 @@ static int at91_usart_spi_remove(struct platform_device *pdev) struct spi_controller *ctlr = platform_get_drvdata(pdev); struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); + at91_usart_spi_release_dma(ctlr); clk_disable_unprepare(aus->clk); return 0; diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index 847f354ebef1..032a615e4ccd 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPI controller driver for the Atheros AR71XX/AR724X/AR913X SoCs * @@ -5,11 +6,6 @@ * * This driver has been based on the spi-gpio.c: * Copyright (C) 2006,2008 David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 4954f0ab1606..f00b367523cd 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Atmel AT32 and AT91 SPI Controllers * * Copyright (C) 2006 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 584bcb018a62..902bdbfedea8 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Broadcom BRCMSTB, NSP, NS2, Cygnus SPI Controllers * * Copyright 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ #include <linux/clk.h> diff --git a/drivers/spi/spi-bcm-qspi.h b/drivers/spi/spi-bcm-qspi.h index 7abfc75a3860..01aec6460108 100644 --- a/drivers/spi/spi-bcm-qspi.h +++ b/drivers/spi/spi-bcm-qspi.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ #ifndef __SPI_BCM_QSPI_H__ diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 402c1efcd762..6f243a90c844 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -13,6 +13,7 @@ #include <linux/clk.h> #include <linux/completion.h> +#include <linux/debugfs.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> @@ -64,14 +65,18 @@ #define BCM2835_SPI_FIFO_SIZE 64 #define BCM2835_SPI_FIFO_SIZE_3_4 48 -#define BCM2835_SPI_POLLING_LIMIT_US 30 -#define BCM2835_SPI_POLLING_JIFFIES 2 #define BCM2835_SPI_DMA_MIN_LENGTH 96 #define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ | SPI_NO_CS | SPI_3WIRE) #define DRV_NAME "spi-bcm2835" +/* define polling limits */ +unsigned int polling_limit_us = 30; +module_param(polling_limit_us, uint, 0664); +MODULE_PARM_DESC(polling_limit_us, + "time in us to run a transfer in polling mode\n"); + /** * struct bcm2835_spi - BCM2835 SPI controller * @regs: base address of register map @@ -88,6 +93,15 @@ * length is not a multiple of 4 (to overcome hardware limitation) * @tx_spillover: whether @tx_prologue spills over to second TX sglist entry * @dma_pending: whether a DMA transfer is in progress + * @debugfs_dir: the debugfs directory - neede to remove debugfs when + * unloading the module + * @count_transfer_polling: count of how often polling mode is used + * @count_transfer_irq: count of how often interrupt mode is used + * @count_transfer_irq_after_polling: count of how often we fall back to + * interrupt mode after starting in polling mode. + * These are counted as well in @count_transfer_polling and + * @count_transfer_irq + * @count_transfer_dma: count how often dma mode is used */ struct bcm2835_spi { void __iomem *regs; @@ -102,8 +116,55 @@ struct bcm2835_spi { int rx_prologue; unsigned int tx_spillover; unsigned int dma_pending; + + struct dentry *debugfs_dir; + u64 count_transfer_polling; + u64 count_transfer_irq; + u64 count_transfer_irq_after_polling; + u64 count_transfer_dma; }; +#if defined(CONFIG_DEBUG_FS) +static void bcm2835_debugfs_create(struct bcm2835_spi *bs, + const char *dname) +{ + char name[64]; + struct dentry *dir; + + /* get full name */ + snprintf(name, sizeof(name), "spi-bcm2835-%s", dname); + + /* the base directory */ + dir = debugfs_create_dir(name, NULL); + bs->debugfs_dir = dir; + + /* the counters */ + debugfs_create_u64("count_transfer_polling", 0444, dir, + &bs->count_transfer_polling); + debugfs_create_u64("count_transfer_irq", 0444, dir, + &bs->count_transfer_irq); + debugfs_create_u64("count_transfer_irq_after_polling", 0444, dir, + &bs->count_transfer_irq_after_polling); + debugfs_create_u64("count_transfer_dma", 0444, dir, + &bs->count_transfer_dma); +} + +static void bcm2835_debugfs_remove(struct bcm2835_spi *bs) +{ + debugfs_remove_recursive(bs->debugfs_dir); + bs->debugfs_dir = NULL; +} +#else +static void bcm2835_debugfs_create(struct bcm2835_spi *bs, + const char *dname) +{ +} + +static void bcm2835_debugfs_remove(struct bcm2835_spi *bs) +{ +} +#endif /* CONFIG_DEBUG_FS */ + static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned reg) { return readl(bs->regs + reg); @@ -248,9 +309,9 @@ static inline void bcm2835_wr_fifo_blind(struct bcm2835_spi *bs, int count) } } -static void bcm2835_spi_reset_hw(struct spi_master *master) +static void bcm2835_spi_reset_hw(struct spi_controller *ctlr) { - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); /* Disable SPI interrupts and transfer */ @@ -269,8 +330,8 @@ static void bcm2835_spi_reset_hw(struct spi_master *master) static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) { - struct spi_master *master = dev_id; - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct spi_controller *ctlr = dev_id; + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); /* @@ -292,20 +353,23 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) if (!bs->rx_len) { /* Transfer complete - reset SPI HW */ - bcm2835_spi_reset_hw(master); + bcm2835_spi_reset_hw(ctlr); /* wake up the framework */ - complete(&master->xfer_completion); + complete(&ctlr->xfer_completion); } return IRQ_HANDLED; } -static int bcm2835_spi_transfer_one_irq(struct spi_master *master, +static int bcm2835_spi_transfer_one_irq(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *tfr, u32 cs, bool fifo_empty) { - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); + + /* update usage statistics */ + bs->count_transfer_irq++; /* * Enable HW block, but with interrupts still disabled. @@ -328,7 +392,7 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master, /** * bcm2835_spi_transfer_prologue() - transfer first few bytes without DMA - * @master: SPI master + * @ctlr: SPI master controller * @tfr: SPI transfer * @bs: BCM2835 SPI controller * @cs: CS register @@ -372,7 +436,7 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master, * be transmitted in 32-bit width to ensure that the following DMA transfer can * pick up the residue in the RX FIFO in ungarbled form. */ -static void bcm2835_spi_transfer_prologue(struct spi_master *master, +static void bcm2835_spi_transfer_prologue(struct spi_controller *ctlr, struct spi_transfer *tfr, struct bcm2835_spi *bs, u32 cs) @@ -413,9 +477,9 @@ static void bcm2835_spi_transfer_prologue(struct spi_master *master, bcm2835_wr_fifo_count(bs, bs->rx_prologue); bcm2835_wait_tx_fifo_empty(bs); bcm2835_rd_fifo_count(bs, bs->rx_prologue); - bcm2835_spi_reset_hw(master); + bcm2835_spi_reset_hw(ctlr); - dma_sync_single_for_device(master->dma_rx->device->dev, + dma_sync_single_for_device(ctlr->dma_rx->device->dev, sg_dma_address(&tfr->rx_sg.sgl[0]), bs->rx_prologue, DMA_FROM_DEVICE); @@ -479,11 +543,11 @@ static void bcm2835_spi_undo_prologue(struct bcm2835_spi *bs) static void bcm2835_spi_dma_done(void *data) { - struct spi_master *master = data; - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct spi_controller *ctlr = data; + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); /* reset fifo and HW */ - bcm2835_spi_reset_hw(master); + bcm2835_spi_reset_hw(ctlr); /* and terminate tx-dma as we do not have an irq for it * because when the rx dma will terminate and this callback @@ -491,15 +555,15 @@ static void bcm2835_spi_dma_done(void *data) * situation otherwise... */ if (cmpxchg(&bs->dma_pending, true, false)) { - dmaengine_terminate_async(master->dma_tx); + dmaengine_terminate_async(ctlr->dma_tx); bcm2835_spi_undo_prologue(bs); } /* and mark as completed */; - complete(&master->xfer_completion); + complete(&ctlr->xfer_completion); } -static int bcm2835_spi_prepare_sg(struct spi_master *master, +static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr, struct spi_transfer *tfr, bool is_tx) { @@ -514,14 +578,14 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master, if (is_tx) { dir = DMA_MEM_TO_DEV; - chan = master->dma_tx; + chan = ctlr->dma_tx; nents = tfr->tx_sg.nents; sgl = tfr->tx_sg.sgl; flags = 0 /* no tx interrupt */; } else { dir = DMA_DEV_TO_MEM; - chan = master->dma_rx; + chan = ctlr->dma_rx; nents = tfr->rx_sg.nents; sgl = tfr->rx_sg.sgl; flags = DMA_PREP_INTERRUPT; @@ -534,7 +598,7 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master, /* set callback for rx */ if (!is_tx) { desc->callback = bcm2835_spi_dma_done; - desc->callback_param = master; + desc->callback_param = ctlr; } /* submit it to DMA-engine */ @@ -543,27 +607,30 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master, return dma_submit_error(cookie); } -static int bcm2835_spi_transfer_one_dma(struct spi_master *master, +static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *tfr, u32 cs) { - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); int ret; + /* update usage statistics */ + bs->count_transfer_dma++; + /* * Transfer first few bytes without DMA if length of first TX or RX * sglist entry is not a multiple of 4 bytes (hardware limitation). */ - bcm2835_spi_transfer_prologue(master, tfr, bs, cs); + bcm2835_spi_transfer_prologue(ctlr, tfr, bs, cs); /* setup tx-DMA */ - ret = bcm2835_spi_prepare_sg(master, tfr, true); + ret = bcm2835_spi_prepare_sg(ctlr, tfr, true); if (ret) goto err_reset_hw; /* start TX early */ - dma_async_issue_pending(master->dma_tx); + dma_async_issue_pending(ctlr->dma_tx); /* mark as dma pending */ bs->dma_pending = 1; @@ -579,27 +646,27 @@ static int bcm2835_spi_transfer_one_dma(struct spi_master *master, * mapping of the rx buffers still takes place * this saves 10us or more. */ - ret = bcm2835_spi_prepare_sg(master, tfr, false); + ret = bcm2835_spi_prepare_sg(ctlr, tfr, false); if (ret) { /* need to reset on errors */ - dmaengine_terminate_sync(master->dma_tx); + dmaengine_terminate_sync(ctlr->dma_tx); bs->dma_pending = false; goto err_reset_hw; } /* start rx dma late */ - dma_async_issue_pending(master->dma_rx); + dma_async_issue_pending(ctlr->dma_rx); /* wait for wakeup in framework */ return 1; err_reset_hw: - bcm2835_spi_reset_hw(master); + bcm2835_spi_reset_hw(ctlr); bcm2835_spi_undo_prologue(bs); return ret; } -static bool bcm2835_spi_can_dma(struct spi_master *master, +static bool bcm2835_spi_can_dma(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *tfr) { @@ -611,21 +678,21 @@ static bool bcm2835_spi_can_dma(struct spi_master *master, return true; } -static void bcm2835_dma_release(struct spi_master *master) +static void bcm2835_dma_release(struct spi_controller *ctlr) { - if (master->dma_tx) { - dmaengine_terminate_sync(master->dma_tx); - dma_release_channel(master->dma_tx); - master->dma_tx = NULL; + if (ctlr->dma_tx) { + dmaengine_terminate_sync(ctlr->dma_tx); + dma_release_channel(ctlr->dma_tx); + ctlr->dma_tx = NULL; } - if (master->dma_rx) { - dmaengine_terminate_sync(master->dma_rx); - dma_release_channel(master->dma_rx); - master->dma_rx = NULL; + if (ctlr->dma_rx) { + dmaengine_terminate_sync(ctlr->dma_rx); + dma_release_channel(ctlr->dma_rx); + ctlr->dma_rx = NULL; } } -static void bcm2835_dma_init(struct spi_master *master, struct device *dev) +static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev) { struct dma_slave_config slave_config; const __be32 *addr; @@ -633,7 +700,7 @@ static void bcm2835_dma_init(struct spi_master *master, struct device *dev) int ret; /* base address in dma-space */ - addr = of_get_address(master->dev.of_node, 0, NULL, NULL); + addr = of_get_address(ctlr->dev.of_node, 0, NULL, NULL); if (!addr) { dev_err(dev, "could not get DMA-register address - not using dma mode\n"); goto err; @@ -641,38 +708,36 @@ static void bcm2835_dma_init(struct spi_master *master, struct device *dev) dma_reg_base = be32_to_cpup(addr); /* get tx/rx dma */ - master->dma_tx = dma_request_slave_channel(dev, "tx"); - if (!master->dma_tx) { + ctlr->dma_tx = dma_request_slave_channel(dev, "tx"); + if (!ctlr->dma_tx) { dev_err(dev, "no tx-dma configuration found - not using dma mode\n"); goto err; } - master->dma_rx = dma_request_slave_channel(dev, "rx"); - if (!master->dma_rx) { + ctlr->dma_rx = dma_request_slave_channel(dev, "rx"); + if (!ctlr->dma_rx) { dev_err(dev, "no rx-dma configuration found - not using dma mode\n"); goto err_release; } /* configure DMAs */ - slave_config.direction = DMA_MEM_TO_DEV; slave_config.dst_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO); slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - ret = dmaengine_slave_config(master->dma_tx, &slave_config); + ret = dmaengine_slave_config(ctlr->dma_tx, &slave_config); if (ret) goto err_config; - slave_config.direction = DMA_DEV_TO_MEM; slave_config.src_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO); slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - ret = dmaengine_slave_config(master->dma_rx, &slave_config); + ret = dmaengine_slave_config(ctlr->dma_rx, &slave_config); if (ret) goto err_config; /* all went well, so set can_dma */ - master->can_dma = bcm2835_spi_can_dma; + ctlr->can_dma = bcm2835_spi_can_dma; /* need to do TX AND RX DMA, so we need dummy buffers */ - master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX; + ctlr->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; return; @@ -680,20 +745,22 @@ err_config: dev_err(dev, "issue configuring dma: %d - not using DMA mode\n", ret); err_release: - bcm2835_dma_release(master); + bcm2835_dma_release(ctlr); err: return; } -static int bcm2835_spi_transfer_one_poll(struct spi_master *master, +static int bcm2835_spi_transfer_one_poll(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *tfr, - u32 cs, - unsigned long long xfer_time_us) + u32 cs) { - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); unsigned long timeout; + /* update usage statistics */ + bs->count_transfer_polling++; + /* enable HW block without interrupts */ bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA); @@ -703,8 +770,8 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master, */ bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE); - /* set the timeout */ - timeout = jiffies + BCM2835_SPI_POLLING_JIFFIES; + /* set the timeout to at least 2 jiffies */ + timeout = jiffies + 2 + HZ * polling_limit_us / 1000000; /* loop until finished the transfer */ while (bs->rx_len) { @@ -723,25 +790,28 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master, jiffies - timeout, bs->tx_len, bs->rx_len); /* fall back to interrupt mode */ - return bcm2835_spi_transfer_one_irq(master, spi, + + /* update usage statistics */ + bs->count_transfer_irq_after_polling++; + + return bcm2835_spi_transfer_one_irq(ctlr, spi, tfr, cs, false); } } /* Transfer complete - reset SPI HW */ - bcm2835_spi_reset_hw(master); + bcm2835_spi_reset_hw(ctlr); /* and return without waiting for completion */ return 0; } -static int bcm2835_spi_transfer_one(struct spi_master *master, +static int bcm2835_spi_transfer_one(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *tfr) { - struct bcm2835_spi *bs = spi_master_get_devdata(master); - unsigned long spi_hz, clk_hz, cdiv; - unsigned long spi_used_hz; - unsigned long long xfer_time_us; + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); + unsigned long spi_hz, clk_hz, cdiv, spi_used_hz; + unsigned long hz_per_byte, byte_limit; u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); /* set clock */ @@ -782,42 +852,49 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, bs->tx_len = tfr->len; bs->rx_len = tfr->len; - /* calculate the estimated time in us the transfer runs */ - xfer_time_us = (unsigned long long)tfr->len - * 9 /* clocks/byte - SPI-HW waits 1 clock after each byte */ - * 1000000; - do_div(xfer_time_us, spi_used_hz); + /* Calculate the estimated time in us the transfer runs. Note that + * there is 1 idle clocks cycles after each byte getting transferred + * so we have 9 cycles/byte. This is used to find the number of Hz + * per byte per polling limit. E.g., we can transfer 1 byte in 30 us + * per 300,000 Hz of bus clock. + */ + hz_per_byte = polling_limit_us ? (9 * 1000000) / polling_limit_us : 0; + byte_limit = hz_per_byte ? spi_used_hz / hz_per_byte : 1; - /* for short requests run polling*/ - if (xfer_time_us <= BCM2835_SPI_POLLING_LIMIT_US) - return bcm2835_spi_transfer_one_poll(master, spi, tfr, - cs, xfer_time_us); + /* run in polling mode for short transfers */ + if (tfr->len < byte_limit) + return bcm2835_spi_transfer_one_poll(ctlr, spi, tfr, cs); - /* run in dma mode if conditions are right */ - if (master->can_dma && bcm2835_spi_can_dma(master, spi, tfr)) - return bcm2835_spi_transfer_one_dma(master, spi, tfr, cs); + /* run in dma mode if conditions are right + * Note that unlike poll or interrupt mode DMA mode does not have + * this 1 idle clock cycle pattern but runs the spi clock without gaps + */ + if (ctlr->can_dma && bcm2835_spi_can_dma(ctlr, spi, tfr)) + return bcm2835_spi_transfer_one_dma(ctlr, spi, tfr, cs); /* run in interrupt-mode */ - return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs, true); + return bcm2835_spi_transfer_one_irq(ctlr, spi, tfr, cs, true); } -static int bcm2835_spi_prepare_message(struct spi_master *master, +static int bcm2835_spi_prepare_message(struct spi_controller *ctlr, struct spi_message *msg) { struct spi_device *spi = msg->spi; - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); int ret; - /* - * DMA transfers are limited to 16 bit (0 to 65535 bytes) by the SPI HW - * due to DLEN. Split up transfers (32-bit FIFO aligned) if the limit is - * exceeded. - */ - ret = spi_split_transfers_maxsize(master, msg, 65532, - GFP_KERNEL | GFP_DMA); - if (ret) - return ret; + if (ctlr->can_dma) { + /* + * DMA transfers are limited to 16 bit (0 to 65535 bytes) by + * the SPI HW due to DLEN. Split up transfers (32-bit FIFO + * aligned) if the limit is exceeded. + */ + ret = spi_split_transfers_maxsize(ctlr, msg, 65532, + GFP_KERNEL | GFP_DMA); + if (ret) + return ret; + } cs &= ~(BCM2835_SPI_CS_CPOL | BCM2835_SPI_CS_CPHA); @@ -831,19 +908,19 @@ static int bcm2835_spi_prepare_message(struct spi_master *master, return 0; } -static void bcm2835_spi_handle_err(struct spi_master *master, +static void bcm2835_spi_handle_err(struct spi_controller *ctlr, struct spi_message *msg) { - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); /* if an error occurred and we have an active dma, then terminate */ if (cmpxchg(&bs->dma_pending, true, false)) { - dmaengine_terminate_sync(master->dma_tx); - dmaengine_terminate_sync(master->dma_rx); + dmaengine_terminate_sync(ctlr->dma_tx); + dmaengine_terminate_sync(ctlr->dma_rx); bcm2835_spi_undo_prologue(bs); } /* and reset */ - bcm2835_spi_reset_hw(master); + bcm2835_spi_reset_hw(ctlr); } static int chip_match_name(struct gpio_chip *chip, void *data) @@ -900,85 +977,88 @@ static int bcm2835_spi_setup(struct spi_device *spi) static int bcm2835_spi_probe(struct platform_device *pdev) { - struct spi_master *master; + struct spi_controller *ctlr; struct bcm2835_spi *bs; struct resource *res; int err; - master = spi_alloc_master(&pdev->dev, sizeof(*bs)); - if (!master) { - dev_err(&pdev->dev, "spi_alloc_master() failed\n"); + ctlr = spi_alloc_master(&pdev->dev, sizeof(*bs)); + if (!ctlr) return -ENOMEM; - } - platform_set_drvdata(pdev, master); + platform_set_drvdata(pdev, ctlr); - master->mode_bits = BCM2835_SPI_MODE_BITS; - master->bits_per_word_mask = SPI_BPW_MASK(8); - master->num_chipselect = 3; - master->setup = bcm2835_spi_setup; - master->transfer_one = bcm2835_spi_transfer_one; - master->handle_err = bcm2835_spi_handle_err; - master->prepare_message = bcm2835_spi_prepare_message; - master->dev.of_node = pdev->dev.of_node; + ctlr->mode_bits = BCM2835_SPI_MODE_BITS; + ctlr->bits_per_word_mask = SPI_BPW_MASK(8); + ctlr->num_chipselect = 3; + ctlr->setup = bcm2835_spi_setup; + ctlr->transfer_one = bcm2835_spi_transfer_one; + ctlr->handle_err = bcm2835_spi_handle_err; + ctlr->prepare_message = bcm2835_spi_prepare_message; + ctlr->dev.of_node = pdev->dev.of_node; - bs = spi_master_get_devdata(master); + bs = spi_controller_get_devdata(ctlr); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); bs->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(bs->regs)) { err = PTR_ERR(bs->regs); - goto out_master_put; + goto out_controller_put; } bs->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(bs->clk)) { err = PTR_ERR(bs->clk); dev_err(&pdev->dev, "could not get clk: %d\n", err); - goto out_master_put; + goto out_controller_put; } bs->irq = platform_get_irq(pdev, 0); if (bs->irq <= 0) { dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq); err = bs->irq ? bs->irq : -ENODEV; - goto out_master_put; + goto out_controller_put; } clk_prepare_enable(bs->clk); - bcm2835_dma_init(master, &pdev->dev); + bcm2835_dma_init(ctlr, &pdev->dev); /* initialise the hardware with the default polarities */ bcm2835_wr(bs, BCM2835_SPI_CS, BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0, - dev_name(&pdev->dev), master); + dev_name(&pdev->dev), ctlr); if (err) { dev_err(&pdev->dev, "could not request IRQ: %d\n", err); goto out_clk_disable; } - err = devm_spi_register_master(&pdev->dev, master); + err = devm_spi_register_controller(&pdev->dev, ctlr); if (err) { - dev_err(&pdev->dev, "could not register SPI master: %d\n", err); + dev_err(&pdev->dev, "could not register SPI controller: %d\n", + err); goto out_clk_disable; } + bcm2835_debugfs_create(bs, dev_name(&pdev->dev)); + return 0; out_clk_disable: clk_disable_unprepare(bs->clk); -out_master_put: - spi_master_put(master); +out_controller_put: + spi_controller_put(ctlr); return err; } static int bcm2835_spi_remove(struct platform_device *pdev) { - struct spi_master *master = platform_get_drvdata(pdev); - struct bcm2835_spi *bs = spi_master_get_devdata(master); + struct spi_controller *ctlr = platform_get_drvdata(pdev); + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); + + bcm2835_debugfs_remove(bs); /* Clear FIFOs, and disable the HW block */ bcm2835_wr(bs, BCM2835_SPI_CS, @@ -986,7 +1066,7 @@ static int bcm2835_spi_remove(struct platform_device *pdev) clk_disable_unprepare(bs->clk); - bcm2835_dma_release(master); + bcm2835_dma_release(ctlr); return 0; } diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c index 40dfb7f58efe..bb57035c5770 100644 --- a/drivers/spi/spi-bcm2835aux.c +++ b/drivers/spi/spi-bcm2835aux.c @@ -496,10 +496,8 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev) int err; master = spi_alloc_master(&pdev->dev, sizeof(*bs)); - if (!master) { - dev_err(&pdev->dev, "spi_alloc_master() failed\n"); + if (!master) return -ENOMEM; - } platform_set_drvdata(pdev, master); master->mode_bits = (SPI_CPOL | SPI_CS_HIGH | SPI_NO_CS); diff --git a/drivers/spi/spi-brcmstb-qspi.c b/drivers/spi/spi-brcmstb-qspi.c index c7df92e7cf6f..75e9b76dab1e 100644 --- a/drivers/spi/spi-brcmstb-qspi.c +++ b/drivers/spi/spi-brcmstb-qspi.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2016 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation (the "GPL"). - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. */ #include <linux/device.h> diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c index 065fe8744989..eb1f2142a335 100644 --- a/drivers/spi/spi-efm32.c +++ b/drivers/spi/spi-efm32.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012-2013 Uwe Kleine-Koenig for Pengutronix - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License version 2 as published by the - * Free Software Foundation. */ #include <linux/kernel.h> #include <linux/io.h> diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 81889389280b..4034e3ec0ba2 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Cirrus Logic EP93xx SPI controller. * @@ -10,10 +11,6 @@ * For more information about the SPI controller see documentation on Cirrus * Logic web site: * http://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/io.h> diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c index f8638e82e5db..00f46c816a56 100644 --- a/drivers/spi/spi-falcon.c +++ b/drivers/spi/spi-falcon.c @@ -1,7 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. * * Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com> */ diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c index ea4b1bf0fa16..f7fe9b13d122 100644 --- a/drivers/spi/spi-meson-spifc.c +++ b/drivers/spi/spi-meson-spifc.c @@ -1,9 +1,9 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for Amlogic Meson SPI flash controller (SPIFC) - * - * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Driver for Amlogic Meson SPI flash controller (SPIFC) +// +// Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> +// #include <linux/clk.h> #include <linux/delay.h> diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 10041eab36a2..45d8a7048b6c 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -123,8 +123,6 @@ static const struct mtk_spi_compatible mt8183_compat = { * supplies it. */ static const struct mtk_chip_config mtk_default_chip_info = { - .rx_mlsb = 1, - .tx_mlsb = 1, .cs_pol = 0, .sample_sel = 0, }; @@ -195,14 +193,13 @@ static int mtk_spi_prepare_message(struct spi_master *master, reg_val &= ~SPI_CMD_CPOL; /* set the mlsbx and mlsbtx */ - if (chip_config->tx_mlsb) - reg_val |= SPI_CMD_TXMSBF; - else + if (spi->mode & SPI_LSB_FIRST) { reg_val &= ~SPI_CMD_TXMSBF; - if (chip_config->rx_mlsb) - reg_val |= SPI_CMD_RXMSBF; - else reg_val &= ~SPI_CMD_RXMSBF; + } else { + reg_val |= SPI_CMD_TXMSBF; + reg_val |= SPI_CMD_RXMSBF; + } /* set the tx/rx endian */ #ifdef __LITTLE_ENDIAN @@ -599,7 +596,7 @@ static int mtk_spi_probe(struct platform_device *pdev) master->auto_runtime_pm = true; master->dev.of_node = pdev->dev.of_node; - master->mode_bits = SPI_CPOL | SPI_CPHA; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; master->set_cs = mtk_spi_set_cs; master->prepare_message = mtk_spi_prepare_message; diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c index f51a058e7678..37e2034ad4d5 100644 --- a/drivers/spi/spi-nuc900.c +++ b/drivers/spi/spi-nuc900.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2009 Nuvoton technology. * Wan ZongShun <mcuos.com@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index 085f580be7ec..bbc4ba66571f 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OpenCores tiny SPI master driver * @@ -9,10 +10,6 @@ * Copyright (c) 2006 Ben Dooks * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/interrupt.h> diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 25ea4a9e0dbc..6643ccdc2508 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Marvell Orion SPI controller driver * * Author: Shadi Ammouri <shadi@marvell.com> * Copyright (C) 2007-2008 Marvell Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/interrupt.h> diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 967d94844b30..0ea2d9a369d9 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPI_PPC4XX SPI controller driver. * @@ -10,10 +11,6 @@ * Copyright (c) 2006 Ben Dooks * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ /* diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index e5c26c1779ab..37567bc7a523 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PXA2xx SPI DMA engine support. * * Copyright (C) 2013, Intel Corporation * Author: Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index af3f37ba82c8..fc7ab4b26880 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1437,6 +1437,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { { PCI_VDEVICE(INTEL, 0x34aa), LPSS_CNL_SSP }, { PCI_VDEVICE(INTEL, 0x34ab), LPSS_CNL_SSP }, { PCI_VDEVICE(INTEL, 0x34fb), LPSS_CNL_SSP }, + /* EHL */ + { PCI_VDEVICE(INTEL, 0x4b2a), LPSS_BXT_SSP }, + { PCI_VDEVICE(INTEL, 0x4b2b), LPSS_BXT_SSP }, + { PCI_VDEVICE(INTEL, 0x4b37), LPSS_BXT_SSP }, /* APL */ { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP }, @@ -1704,6 +1708,16 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) goto out_error_dma_irq_alloc; controller->max_speed_hz = clk_get_rate(ssp->clk); + /* + * Set minimum speed for all other platforms than Intel Quark which is + * able do under 1 Hz transfers. + */ + if (!pxa25x_ssp_comp(drv_data)) + controller->min_speed_hz = + DIV_ROUND_UP(controller->max_speed_hz, 4096); + else if (!is_quark_x1000_ssp(drv_data)) + controller->min_speed_hz = + DIV_ROUND_UP(controller->max_speed_hz, 512); /* Load default SSP configuration */ pxa2xx_spi_write(drv_data, SSCR0, 0); diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index aba777b4502d..1400472bc986 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs * Copyright (C) 2013, Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef SPI_PXA2XX_H diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index f22dbb4b87a5..2f559e531100 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -273,6 +273,9 @@ static void spi_qup_read(struct spi_qup *controller, u32 *opflags) writel_relaxed(QUP_OP_IN_SERVICE_FLAG, controller->base + QUP_OPERATIONAL); + if (!remainder) + goto exit; + if (is_block_mode) { num_words = (remainder > words_per_block) ? words_per_block : remainder; @@ -302,11 +305,13 @@ static void spi_qup_read(struct spi_qup *controller, u32 *opflags) * to refresh opflags value because MAX_INPUT_DONE_FLAG may now be * present and this is used to determine if transaction is complete */ - *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL); - if (is_block_mode && *opflags & QUP_OP_MAX_INPUT_DONE_FLAG) - writel_relaxed(QUP_OP_IN_SERVICE_FLAG, - controller->base + QUP_OPERATIONAL); - +exit: + if (!remainder) { + *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL); + if (is_block_mode && *opflags & QUP_OP_MAX_INPUT_DONE_FLAG) + writel_relaxed(QUP_OP_IN_SERVICE_FLAG, + controller->base + QUP_OPERATIONAL); + } } static void spi_qup_write_to_fifo(struct spi_qup *controller, u32 num_words) @@ -354,6 +359,10 @@ static void spi_qup_write(struct spi_qup *controller) writel_relaxed(QUP_OP_OUT_SERVICE_FLAG, controller->base + QUP_OPERATIONAL); + /* make sure the interrupt is valid */ + if (!remainder) + return; + if (is_block_mode) { num_words = (remainder > words_per_block) ? words_per_block : remainder; @@ -567,10 +576,24 @@ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer, return 0; } +static bool spi_qup_data_pending(struct spi_qup *controller) +{ + unsigned int remainder_tx, remainder_rx; + + remainder_tx = DIV_ROUND_UP(spi_qup_len(controller) - + controller->tx_bytes, controller->w_size); + + remainder_rx = DIV_ROUND_UP(spi_qup_len(controller) - + controller->rx_bytes, controller->w_size); + + return remainder_tx || remainder_rx; +} + static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) { struct spi_qup *controller = dev_id; u32 opflags, qup_err, spi_err; + unsigned long flags; int error = 0; qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS); @@ -602,6 +625,11 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) error = -EIO; } + spin_lock_irqsave(&controller->lock, flags); + if (!controller->error) + controller->error = error; + spin_unlock_irqrestore(&controller->lock, flags); + if (spi_qup_is_dma_xfer(controller->mode)) { writel_relaxed(opflags, controller->base + QUP_OPERATIONAL); } else { @@ -610,10 +638,21 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) if (opflags & QUP_OP_OUT_SERVICE_FLAG) spi_qup_write(controller); + + if (!spi_qup_data_pending(controller)) + complete(&controller->done); } - if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error) + if (error) + complete(&controller->done); + + if (opflags & QUP_OP_MAX_INPUT_DONE_FLAG) { + if (!spi_qup_is_dma_xfer(controller->mode)) { + if (spi_qup_data_pending(controller)) + return IRQ_HANDLED; + } complete(&controller->done); + } return IRQ_HANDLED; } @@ -834,10 +873,6 @@ static int spi_qup_transfer_one(struct spi_master *master, else ret = spi_qup_do_pio(spi, xfer, timeout); - if (ret) - goto exit; - -exit: spi_qup_set_state(controller, QUP_STATE_RESET); spin_lock_irqsave(&controller->lock, flags); if (!ret) diff --git a/drivers/spi/spi-rb4xx.c b/drivers/spi/spi-rb4xx.c index fbbf9a188247..51f03d977ad6 100644 --- a/drivers/spi/spi-rb4xx.c +++ b/drivers/spi/spi-rb4xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPI controller driver for the Mikrotik RB4xx boards * @@ -6,11 +7,6 @@ * * This file was based on the patches for Linux 2.6.27.39 published by * MikroTik for their RouterBoard 4xx series devices. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 9b91188a85f9..2cc6d9951b52 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -417,7 +417,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs, .direction = DMA_MEM_TO_DEV, .dst_addr = rs->dma_addr_tx, .dst_addr_width = rs->n_bytes, - .dst_maxburst = rs->fifo_len / 2, + .dst_maxburst = rs->fifo_len / 4, }; dmaengine_slave_config(master->dma_tx, &txconf); @@ -518,7 +518,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs, else writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); - writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR); + writel_relaxed(rs->fifo_len / 2, rs->regs + ROCKCHIP_SPI_DMATDLR); writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR); writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR); diff --git a/drivers/spi/spi-s3c24xx-fiq.S b/drivers/spi/spi-s3c24xx-fiq.S index 059f2dc1fda2..e95d6282109e 100644 --- a/drivers/spi/spi-s3c24xx-fiq.S +++ b/drivers/spi/spi-s3c24xx-fiq.S @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* linux/drivers/spi/spi_s3c24xx_fiq.S * * Copyright 2009 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * * S3C24XX SPI - FIQ pseudo-DMA transfer code - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/linkage.h> diff --git a/drivers/spi/spi-s3c24xx-fiq.h b/drivers/spi/spi-s3c24xx-fiq.h index a5950bb25b51..7786b0ea56ec 100644 --- a/drivers/spi/spi-s3c24xx-fiq.h +++ b/drivers/spi/spi-s3c24xx-fiq.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* linux/drivers/spi/spi_s3c24xx_fiq.h * * Copyright 2009 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * * S3C24XX SPI - FIQ pseudo-DMA transfer support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /* We have R8 through R13 to play with */ diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index 4e7d1bfed7e6..48d8dff05a3a 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2006 Ben Dooks * Copyright 2006-2009 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/spinlock.h> diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 6aab7b2136db..b50bdbc27e58 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -229,7 +229,7 @@ static int sh_msiof_modify_ctr_wait(struct sh_msiof_spi_priv *p, sh_msiof_write(p, CTR, data); return readl_poll_timeout_atomic(p->mapbase + CTR, data, - (data & mask) == set, 10, 1000); + (data & mask) == set, 1, 100); } static irqreturn_t sh_msiof_spi_irq(int irq, void *data) diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c index 393701cfca3c..8f30531e1418 100644 --- a/drivers/spi/spi-sh-sci.c +++ b/drivers/spi/spi-sh-sci.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SH SCI SPI interface * @@ -6,11 +7,6 @@ * Based on S3C24XX GPIO based SPI driver, which is: * Copyright (c) 2006 Ben Dooks * Copyright (c) 2006 Simtec Electronics - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 42f8e3c6aa1f..655e4afbfb2a 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -29,7 +29,7 @@ #define CR_SSHIFT BIT(4) #define CR_DFM BIT(6) #define CR_FSEL BIT(7) -#define CR_FTHRES_MASK GENMASK(12, 8) +#define CR_FTHRES_SHIFT 8 #define CR_TEIE BIT(16) #define CR_TCIE BIT(17) #define CR_FTIE BIT(18) @@ -245,12 +245,8 @@ static int stm32_qspi_tx_dma(struct stm32_qspi *qspi, writel_relaxed(cr | CR_DMAEN, qspi->io_base + QSPI_CR); t_out = sgt.nents * STM32_COMP_TIMEOUT_MS; - if (!wait_for_completion_interruptible_timeout(&qspi->dma_completion, - msecs_to_jiffies(t_out))) - err = -ETIMEDOUT; - - if (dma_async_is_tx_complete(dma_ch, cookie, - NULL, NULL) != DMA_COMPLETE) + if (!wait_for_completion_timeout(&qspi->dma_completion, + msecs_to_jiffies(t_out))) err = -ETIMEDOUT; if (err) @@ -304,7 +300,7 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, cr = readl_relaxed(qspi->io_base + QSPI_CR); writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR); - if (!wait_for_completion_interruptible_timeout(&qspi->data_completion, + if (!wait_for_completion_timeout(&qspi->data_completion, msecs_to_jiffies(STM32_COMP_TIMEOUT_MS))) { err = -ETIMEDOUT; } else { @@ -463,7 +459,7 @@ static int stm32_qspi_setup(struct spi_device *spi) flash->presc = presc; mutex_lock(&qspi->lock); - qspi->cr_reg = FIELD_PREP(CR_FTHRES_MASK, 3) | CR_SSHIFT | CR_EN; + qspi->cr_reg = 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN; writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); /* set dcr fsize to max address */ diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c new file mode 100644 index 000000000000..f99abd85c50a --- /dev/null +++ b/drivers/spi/spi-synquacer.c @@ -0,0 +1,828 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Synquacer HSSPI controller driver +// +// Copyright (c) 2015-2018 Socionext Inc. +// Copyright (c) 2018-2019 Linaro Ltd. +// + +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/scatterlist.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/spinlock.h> +#include <linux/clk.h> + +/* HSSPI register address definitions */ +#define SYNQUACER_HSSPI_REG_MCTRL 0x00 +#define SYNQUACER_HSSPI_REG_PCC0 0x04 +#define SYNQUACER_HSSPI_REG_PCC(n) (SYNQUACER_HSSPI_REG_PCC0 + (n) * 4) +#define SYNQUACER_HSSPI_REG_TXF 0x14 +#define SYNQUACER_HSSPI_REG_TXE 0x18 +#define SYNQUACER_HSSPI_REG_TXC 0x1C +#define SYNQUACER_HSSPI_REG_RXF 0x20 +#define SYNQUACER_HSSPI_REG_RXE 0x24 +#define SYNQUACER_HSSPI_REG_RXC 0x28 +#define SYNQUACER_HSSPI_REG_FAULTF 0x2C +#define SYNQUACER_HSSPI_REG_FAULTC 0x30 +#define SYNQUACER_HSSPI_REG_DMCFG 0x34 +#define SYNQUACER_HSSPI_REG_DMSTART 0x38 +#define SYNQUACER_HSSPI_REG_DMBCC 0x3C +#define SYNQUACER_HSSPI_REG_DMSTATUS 0x40 +#define SYNQUACER_HSSPI_REG_FIFOCFG 0x4C +#define SYNQUACER_HSSPI_REG_TX_FIFO 0x50 +#define SYNQUACER_HSSPI_REG_RX_FIFO 0x90 +#define SYNQUACER_HSSPI_REG_MID 0xFC + +/* HSSPI register bit definitions */ +#define SYNQUACER_HSSPI_MCTRL_MEN BIT(0) +#define SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN BIT(1) +#define SYNQUACER_HSSPI_MCTRL_CDSS BIT(3) +#define SYNQUACER_HSSPI_MCTRL_MES BIT(4) +#define SYNQUACER_HSSPI_MCTRL_SYNCON BIT(5) + +#define SYNQUACER_HSSPI_PCC_CPHA BIT(0) +#define SYNQUACER_HSSPI_PCC_CPOL BIT(1) +#define SYNQUACER_HSSPI_PCC_ACES BIT(2) +#define SYNQUACER_HSSPI_PCC_RTM BIT(3) +#define SYNQUACER_HSSPI_PCC_SSPOL BIT(4) +#define SYNQUACER_HSSPI_PCC_SDIR BIT(7) +#define SYNQUACER_HSSPI_PCC_SENDIAN BIT(8) +#define SYNQUACER_HSSPI_PCC_SAFESYNC BIT(16) +#define SYNQUACER_HSSPI_PCC_SS2CD_SHIFT 5U +#define SYNQUACER_HSSPI_PCC_CDRS_MASK 0x7f +#define SYNQUACER_HSSPI_PCC_CDRS_SHIFT 9U + +#define SYNQUACER_HSSPI_TXF_FIFO_FULL BIT(0) +#define SYNQUACER_HSSPI_TXF_FIFO_EMPTY BIT(1) +#define SYNQUACER_HSSPI_TXF_SLAVE_RELEASED BIT(6) + +#define SYNQUACER_HSSPI_TXE_FIFO_FULL BIT(0) +#define SYNQUACER_HSSPI_TXE_FIFO_EMPTY BIT(1) +#define SYNQUACER_HSSPI_TXE_SLAVE_RELEASED BIT(6) + +#define SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD BIT(5) +#define SYNQUACER_HSSPI_RXF_SLAVE_RELEASED BIT(6) + +#define SYNQUACER_HSSPI_RXE_FIFO_MORE_THAN_THRESHOLD BIT(5) +#define SYNQUACER_HSSPI_RXE_SLAVE_RELEASED BIT(6) + +#define SYNQUACER_HSSPI_DMCFG_SSDC BIT(1) +#define SYNQUACER_HSSPI_DMCFG_MSTARTEN BIT(2) + +#define SYNQUACER_HSSPI_DMSTART_START BIT(0) +#define SYNQUACER_HSSPI_DMSTOP_STOP BIT(8) +#define SYNQUACER_HSSPI_DMPSEL_CS_MASK 0x3 +#define SYNQUACER_HSSPI_DMPSEL_CS_SHIFT 16U +#define SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT 24U +#define SYNQUACER_HSSPI_DMTRP_DATA_MASK 0x3 +#define SYNQUACER_HSSPI_DMTRP_DATA_SHIFT 26U +#define SYNQUACER_HSSPI_DMTRP_DATA_TXRX 0 +#define SYNQUACER_HSSPI_DMTRP_DATA_RX 1 +#define SYNQUACER_HSSPI_DMTRP_DATA_TX 2 + +#define SYNQUACER_HSSPI_DMSTATUS_RX_DATA_MASK 0x1f +#define SYNQUACER_HSSPI_DMSTATUS_RX_DATA_SHIFT 8U +#define SYNQUACER_HSSPI_DMSTATUS_TX_DATA_MASK 0x1f +#define SYNQUACER_HSSPI_DMSTATUS_TX_DATA_SHIFT 16U + +#define SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_MASK 0xf +#define SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT 0U +#define SYNQUACER_HSSPI_FIFOCFG_TX_THRESHOLD_MASK 0xf +#define SYNQUACER_HSSPI_FIFOCFG_TX_THRESHOLD_SHIFT 4U +#define SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK 0x3 +#define SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT 8U +#define SYNQUACER_HSSPI_FIFOCFG_RX_FLUSH BIT(11) +#define SYNQUACER_HSSPI_FIFOCFG_TX_FLUSH BIT(12) + +#define SYNQUACER_HSSPI_FIFO_DEPTH 16U +#define SYNQUACER_HSSPI_FIFO_TX_THRESHOLD 4U +#define SYNQUACER_HSSPI_FIFO_RX_THRESHOLD \ + (SYNQUACER_HSSPI_FIFO_DEPTH - SYNQUACER_HSSPI_FIFO_TX_THRESHOLD) + +#define SYNQUACER_HSSPI_TRANSFER_MODE_TX BIT(1) +#define SYNQUACER_HSSPI_TRANSFER_MODE_RX BIT(2) +#define SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC 2000U +#define SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC 1000U + +#define SYNQUACER_HSSPI_CLOCK_SRC_IHCLK 0 +#define SYNQUACER_HSSPI_CLOCK_SRC_IPCLK 1 + +#define SYNQUACER_HSSPI_NUM_CHIP_SELECT 4U +#define SYNQUACER_HSSPI_IRQ_NAME_MAX 32U + +struct synquacer_spi { + struct device *dev; + struct completion transfer_done; + unsigned int cs; + unsigned int bpw; + unsigned int mode; + unsigned int speed; + bool aces, rtm; + void *rx_buf; + const void *tx_buf; + struct clk *clk; + int clk_src_type; + void __iomem *regs; + u32 tx_words, rx_words; + unsigned int bus_width; + unsigned int transfer_mode; + char rx_irq_name[SYNQUACER_HSSPI_IRQ_NAME_MAX]; + char tx_irq_name[SYNQUACER_HSSPI_IRQ_NAME_MAX]; +}; + +static int read_fifo(struct synquacer_spi *sspi) +{ + u32 len = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTATUS); + + len = (len >> SYNQUACER_HSSPI_DMSTATUS_RX_DATA_SHIFT) & + SYNQUACER_HSSPI_DMSTATUS_RX_DATA_MASK; + len = min(len, sspi->rx_words); + + switch (sspi->bpw) { + case 8: { + u8 *buf = sspi->rx_buf; + + ioread8_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO, + buf, len); + sspi->rx_buf = buf + len; + break; + } + case 16: { + u16 *buf = sspi->rx_buf; + + ioread16_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO, + buf, len); + sspi->rx_buf = buf + len; + break; + } + case 24: + /* fallthrough, should use 32-bits access */ + case 32: { + u32 *buf = sspi->rx_buf; + + ioread32_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO, + buf, len); + sspi->rx_buf = buf + len; + break; + } + default: + return -EINVAL; + } + + sspi->rx_words -= len; + return 0; +} + +static int write_fifo(struct synquacer_spi *sspi) +{ + u32 len = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTATUS); + + len = (len >> SYNQUACER_HSSPI_DMSTATUS_TX_DATA_SHIFT) & + SYNQUACER_HSSPI_DMSTATUS_TX_DATA_MASK; + len = min(SYNQUACER_HSSPI_FIFO_DEPTH - len, + sspi->tx_words); + + switch (sspi->bpw) { + case 8: { + const u8 *buf = sspi->tx_buf; + + iowrite8_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO, + buf, len); + sspi->tx_buf = buf + len; + break; + } + case 16: { + const u16 *buf = sspi->tx_buf; + + iowrite16_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO, + buf, len); + sspi->tx_buf = buf + len; + break; + } + case 24: + /* fallthrough, should use 32-bits access */ + case 32: { + const u32 *buf = sspi->tx_buf; + + iowrite32_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO, + buf, len); + sspi->tx_buf = buf + len; + break; + } + default: + return -EINVAL; + } + + sspi->tx_words -= len; + return 0; +} + +static int synquacer_spi_config(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct synquacer_spi *sspi = spi_master_get_devdata(master); + unsigned int speed, mode, bpw, cs, bus_width, transfer_mode; + u32 rate, val, div; + + /* Full Duplex only on 1-bit wide bus */ + if (xfer->rx_buf && xfer->tx_buf && + (xfer->rx_nbits != 1 || xfer->tx_nbits != 1)) { + dev_err(sspi->dev, + "RX and TX bus widths must be 1-bit for Full-Duplex!\n"); + return -EINVAL; + } + + if (xfer->tx_buf) { + bus_width = xfer->tx_nbits; + transfer_mode = SYNQUACER_HSSPI_TRANSFER_MODE_TX; + } else { + bus_width = xfer->rx_nbits; + transfer_mode = SYNQUACER_HSSPI_TRANSFER_MODE_RX; + } + + mode = spi->mode; + cs = spi->chip_select; + speed = xfer->speed_hz; + bpw = xfer->bits_per_word; + + /* return if nothing to change */ + if (speed == sspi->speed && + bus_width == sspi->bus_width && bpw == sspi->bpw && + mode == sspi->mode && cs == sspi->cs && + transfer_mode == sspi->transfer_mode) { + return 0; + } + + sspi->transfer_mode = transfer_mode; + rate = master->max_speed_hz; + + div = DIV_ROUND_UP(rate, speed); + if (div > 254) { + dev_err(sspi->dev, "Requested rate too low (%u)\n", + sspi->speed); + return -EINVAL; + } + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_PCC(cs)); + val &= ~SYNQUACER_HSSPI_PCC_SAFESYNC; + if (bpw == 8 && (mode & (SPI_TX_DUAL | SPI_RX_DUAL)) && div < 3) + val |= SYNQUACER_HSSPI_PCC_SAFESYNC; + if (bpw == 8 && (mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 6) + val |= SYNQUACER_HSSPI_PCC_SAFESYNC; + if (bpw == 16 && (mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 3) + val |= SYNQUACER_HSSPI_PCC_SAFESYNC; + + if (mode & SPI_CPHA) + val |= SYNQUACER_HSSPI_PCC_CPHA; + else + val &= ~SYNQUACER_HSSPI_PCC_CPHA; + + if (mode & SPI_CPOL) + val |= SYNQUACER_HSSPI_PCC_CPOL; + else + val &= ~SYNQUACER_HSSPI_PCC_CPOL; + + if (mode & SPI_CS_HIGH) + val |= SYNQUACER_HSSPI_PCC_SSPOL; + else + val &= ~SYNQUACER_HSSPI_PCC_SSPOL; + + if (mode & SPI_LSB_FIRST) + val |= SYNQUACER_HSSPI_PCC_SDIR; + else + val &= ~SYNQUACER_HSSPI_PCC_SDIR; + + if (sspi->aces) + val |= SYNQUACER_HSSPI_PCC_ACES; + else + val &= ~SYNQUACER_HSSPI_PCC_ACES; + + if (sspi->rtm) + val |= SYNQUACER_HSSPI_PCC_RTM; + else + val &= ~SYNQUACER_HSSPI_PCC_RTM; + + val |= (3 << SYNQUACER_HSSPI_PCC_SS2CD_SHIFT); + val |= SYNQUACER_HSSPI_PCC_SENDIAN; + + val &= ~(SYNQUACER_HSSPI_PCC_CDRS_MASK << + SYNQUACER_HSSPI_PCC_CDRS_SHIFT); + val |= ((div >> 1) << SYNQUACER_HSSPI_PCC_CDRS_SHIFT); + + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_PCC(cs)); + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); + val &= ~(SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK << + SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT); + val |= ((bpw / 8 - 1) << SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT); + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + val &= ~(SYNQUACER_HSSPI_DMTRP_DATA_MASK << + SYNQUACER_HSSPI_DMTRP_DATA_SHIFT); + + if (xfer->rx_buf) + val |= (SYNQUACER_HSSPI_DMTRP_DATA_RX << + SYNQUACER_HSSPI_DMTRP_DATA_SHIFT); + else + val |= (SYNQUACER_HSSPI_DMTRP_DATA_TX << + SYNQUACER_HSSPI_DMTRP_DATA_SHIFT); + + val &= ~(3 << SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT); + val |= ((bus_width >> 1) << SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT); + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + + sspi->bpw = bpw; + sspi->mode = mode; + sspi->speed = speed; + sspi->cs = spi->chip_select; + sspi->bus_width = bus_width; + + return 0; +} + +static int synquacer_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct synquacer_spi *sspi = spi_master_get_devdata(master); + int ret; + int status = 0; + u32 words; + u8 bpw; + u32 val; + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + val &= ~SYNQUACER_HSSPI_DMSTOP_STOP; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); + val |= SYNQUACER_HSSPI_FIFOCFG_RX_FLUSH; + val |= SYNQUACER_HSSPI_FIFOCFG_TX_FLUSH; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); + + /* + * See if we can transfer 4-bytes as 1 word + * to maximize the FIFO buffer efficiency. + */ + bpw = xfer->bits_per_word; + if (bpw == 8 && !(xfer->len % 4) && !(spi->mode & SPI_LSB_FIRST)) + xfer->bits_per_word = 32; + + ret = synquacer_spi_config(master, spi, xfer); + + /* restore */ + xfer->bits_per_word = bpw; + + if (ret) + return ret; + + reinit_completion(&sspi->transfer_done); + + sspi->tx_buf = xfer->tx_buf; + sspi->rx_buf = xfer->rx_buf; + + switch (sspi->bpw) { + case 8: + words = xfer->len; + break; + case 16: + words = xfer->len / 2; + break; + case 24: + /* fallthrough, should use 32-bits access */ + case 32: + words = xfer->len / 4; + break; + default: + dev_err(sspi->dev, "unsupported bpw: %d\n", sspi->bpw); + return -EINVAL; + } + + if (xfer->tx_buf) + sspi->tx_words = words; + else + sspi->tx_words = 0; + + if (xfer->rx_buf) + sspi->rx_words = words; + else + sspi->rx_words = 0; + + if (xfer->tx_buf) { + status = write_fifo(sspi); + if (status < 0) { + dev_err(sspi->dev, "failed write_fifo. status: 0x%x\n", + status); + return status; + } + } + + if (xfer->rx_buf) { + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); + val &= ~(SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_MASK << + SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT); + val |= ((sspi->rx_words > SYNQUACER_HSSPI_FIFO_DEPTH ? + SYNQUACER_HSSPI_FIFO_RX_THRESHOLD : sspi->rx_words) << + SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT); + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); + } + + writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_TXC); + writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_RXC); + + /* Trigger */ + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + val |= SYNQUACER_HSSPI_DMSTART_START; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + + if (xfer->tx_buf) { + val = SYNQUACER_HSSPI_TXE_FIFO_EMPTY; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_TXE); + status = wait_for_completion_timeout(&sspi->transfer_done, + msecs_to_jiffies(SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC)); + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE); + } + + if (xfer->rx_buf) { + u32 buf[SYNQUACER_HSSPI_FIFO_DEPTH]; + + val = SYNQUACER_HSSPI_RXE_FIFO_MORE_THAN_THRESHOLD | + SYNQUACER_HSSPI_RXE_SLAVE_RELEASED; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_RXE); + status = wait_for_completion_timeout(&sspi->transfer_done, + msecs_to_jiffies(SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC)); + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE); + + /* stop RX and clean RXFIFO */ + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + val |= SYNQUACER_HSSPI_DMSTOP_STOP; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + sspi->rx_buf = buf; + sspi->rx_words = SYNQUACER_HSSPI_FIFO_DEPTH; + read_fifo(sspi); + } + + if (status < 0) { + dev_err(sspi->dev, "failed to transfer. status: 0x%x\n", + status); + return status; + } + + return 0; +} + +static void synquacer_spi_set_cs(struct spi_device *spi, bool enable) +{ + struct synquacer_spi *sspi = spi_master_get_devdata(spi->master); + u32 val; + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); + val &= ~(SYNQUACER_HSSPI_DMPSEL_CS_MASK << + SYNQUACER_HSSPI_DMPSEL_CS_SHIFT); + val |= spi->chip_select << SYNQUACER_HSSPI_DMPSEL_CS_SHIFT; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); +} + +static int synquacer_spi_wait_status_update(struct synquacer_spi *sspi, + bool enable) +{ + u32 val; + unsigned long timeout = jiffies + + msecs_to_jiffies(SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC); + + /* wait MES(Module Enable Status) is updated */ + do { + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_MCTRL) & + SYNQUACER_HSSPI_MCTRL_MES; + if (enable && val) + return 0; + if (!enable && !val) + return 0; + } while (time_before(jiffies, timeout)); + + dev_err(sspi->dev, "timeout occurs in updating Module Enable Status\n"); + return -EBUSY; +} + +static int synquacer_spi_enable(struct spi_master *master) +{ + u32 val; + int status; + struct synquacer_spi *sspi = spi_master_get_devdata(master); + + /* Disable module */ + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL); + status = synquacer_spi_wait_status_update(sspi, false); + if (status < 0) + return status; + + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE); + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE); + writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_TXC); + writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_RXC); + writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_FAULTC); + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMCFG); + val &= ~SYNQUACER_HSSPI_DMCFG_SSDC; + val &= ~SYNQUACER_HSSPI_DMCFG_MSTARTEN; + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMCFG); + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_MCTRL); + if (sspi->clk_src_type == SYNQUACER_HSSPI_CLOCK_SRC_IPCLK) + val |= SYNQUACER_HSSPI_MCTRL_CDSS; + else + val &= ~SYNQUACER_HSSPI_MCTRL_CDSS; + + val &= ~SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN; + val |= SYNQUACER_HSSPI_MCTRL_MEN; + val |= SYNQUACER_HSSPI_MCTRL_SYNCON; + + /* Enable module */ + writel(val, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL); + status = synquacer_spi_wait_status_update(sspi, true); + if (status < 0) + return status; + + return 0; +} + +static irqreturn_t sq_spi_rx_handler(int irq, void *priv) +{ + uint32_t val; + struct synquacer_spi *sspi = priv; + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_RXF); + if ((val & SYNQUACER_HSSPI_RXF_SLAVE_RELEASED) || + (val & SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD)) { + read_fifo(sspi); + + if (sspi->rx_words == 0) { + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE); + complete(&sspi->transfer_done); + } + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static irqreturn_t sq_spi_tx_handler(int irq, void *priv) +{ + uint32_t val; + struct synquacer_spi *sspi = priv; + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_TXF); + if (val & SYNQUACER_HSSPI_TXF_FIFO_EMPTY) { + if (sspi->tx_words == 0) { + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE); + complete(&sspi->transfer_done); + } else { + write_fifo(sspi); + } + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int synquacer_spi_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct spi_master *master; + struct synquacer_spi *sspi; + int ret; + int rx_irq, tx_irq; + + master = spi_alloc_master(&pdev->dev, sizeof(*sspi)); + if (!master) + return -ENOMEM; + + platform_set_drvdata(pdev, master); + + sspi = spi_master_get_devdata(master); + sspi->dev = &pdev->dev; + + init_completion(&sspi->transfer_done); + + sspi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(sspi->regs)) { + ret = PTR_ERR(sspi->regs); + goto put_spi; + } + + sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; /* Default */ + device_property_read_u32(&pdev->dev, "socionext,ihclk-rate", + &master->max_speed_hz); /* for ACPI */ + + if (dev_of_node(&pdev->dev)) { + if (device_property_match_string(&pdev->dev, + "clock-names", "iHCLK") >= 0) { + sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; + sspi->clk = devm_clk_get(sspi->dev, "iHCLK"); + } else if (device_property_match_string(&pdev->dev, + "clock-names", "iPCLK") >= 0) { + sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IPCLK; + sspi->clk = devm_clk_get(sspi->dev, "iPCLK"); + } else { + dev_err(&pdev->dev, "specified wrong clock source\n"); + ret = -EINVAL; + goto put_spi; + } + + if (IS_ERR(sspi->clk)) { + if (!(PTR_ERR(sspi->clk) == -EPROBE_DEFER)) + dev_err(&pdev->dev, "clock not found\n"); + ret = PTR_ERR(sspi->clk); + goto put_spi; + } + + ret = clk_prepare_enable(sspi->clk); + if (ret) { + dev_err(&pdev->dev, "failed to enable clock (%d)\n", + ret); + goto put_spi; + } + + master->max_speed_hz = clk_get_rate(sspi->clk); + } + + if (!master->max_speed_hz) { + dev_err(&pdev->dev, "missing clock source\n"); + return -EINVAL; + } + master->min_speed_hz = master->max_speed_hz / 254; + + sspi->aces = device_property_read_bool(&pdev->dev, + "socionext,set-aces"); + sspi->rtm = device_property_read_bool(&pdev->dev, "socionext,use-rtm"); + + master->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT; + + rx_irq = platform_get_irq(pdev, 0); + if (rx_irq <= 0) { + dev_err(&pdev->dev, "get rx_irq failed (%d)\n", rx_irq); + ret = rx_irq; + goto put_spi; + } + snprintf(sspi->rx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-rx", + dev_name(&pdev->dev)); + ret = devm_request_irq(&pdev->dev, rx_irq, sq_spi_rx_handler, + 0, sspi->rx_irq_name, sspi); + if (ret) { + dev_err(&pdev->dev, "request rx_irq failed (%d)\n", ret); + goto put_spi; + } + + tx_irq = platform_get_irq(pdev, 1); + if (tx_irq <= 0) { + dev_err(&pdev->dev, "get tx_irq failed (%d)\n", tx_irq); + ret = tx_irq; + goto put_spi; + } + snprintf(sspi->tx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-tx", + dev_name(&pdev->dev)); + ret = devm_request_irq(&pdev->dev, tx_irq, sq_spi_tx_handler, + 0, sspi->tx_irq_name, sspi); + if (ret) { + dev_err(&pdev->dev, "request tx_irq failed (%d)\n", ret); + goto put_spi; + } + + master->dev.of_node = np; + master->dev.fwnode = pdev->dev.fwnode; + master->auto_runtime_pm = true; + master->bus_num = pdev->id; + + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL | + SPI_TX_QUAD | SPI_RX_QUAD; + master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) | + SPI_BPW_MASK(16) | SPI_BPW_MASK(8); + + master->set_cs = synquacer_spi_set_cs; + master->transfer_one = synquacer_spi_transfer_one; + + ret = synquacer_spi_enable(master); + if (ret) + goto fail_enable; + + pm_runtime_set_active(sspi->dev); + pm_runtime_enable(sspi->dev); + + ret = devm_spi_register_master(sspi->dev, master); + if (ret) + goto disable_pm; + + return 0; + +disable_pm: + pm_runtime_disable(sspi->dev); +fail_enable: + clk_disable_unprepare(sspi->clk); +put_spi: + spi_master_put(master); + + return ret; +} + +static int synquacer_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct synquacer_spi *sspi = spi_master_get_devdata(master); + + pm_runtime_disable(sspi->dev); + + clk_disable_unprepare(sspi->clk); + + return 0; +} + +static int __maybe_unused synquacer_spi_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct synquacer_spi *sspi = spi_master_get_devdata(master); + int ret; + + ret = spi_master_suspend(master); + if (ret) + return ret; + + if (!pm_runtime_suspended(dev)) + clk_disable_unprepare(sspi->clk); + + return ret; +} + +static int __maybe_unused synquacer_spi_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct synquacer_spi *sspi = spi_master_get_devdata(master); + int ret; + + if (!pm_runtime_suspended(dev)) { + /* Ensure reconfigure during next xfer */ + sspi->speed = 0; + + ret = clk_prepare_enable(sspi->clk); + if (ret < 0) { + dev_err(dev, "failed to enable clk (%d)\n", + ret); + return ret; + } + + ret = synquacer_spi_enable(master); + if (ret) { + dev_err(dev, "failed to enable spi (%d)\n", ret); + return ret; + } + } + + ret = spi_master_resume(master); + if (ret < 0) + clk_disable_unprepare(sspi->clk); + + return ret; +} + +static SIMPLE_DEV_PM_OPS(synquacer_spi_pm_ops, synquacer_spi_suspend, + synquacer_spi_resume); + +static const struct of_device_id synquacer_spi_of_match[] = { + {.compatible = "socionext,synquacer-spi"}, + {} +}; +MODULE_DEVICE_TABLE(of, synquacer_spi_of_match); + +#ifdef CONFIG_ACPI +static const struct acpi_device_id synquacer_hsspi_acpi_ids[] = { + { "SCX0004" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(acpi, synquacer_hsspi_acpi_ids); +#endif + +static struct platform_driver synquacer_spi_driver = { + .driver = { + .name = "synquacer-spi", + .pm = &synquacer_spi_pm_ops, + .of_match_table = synquacer_spi_of_match, + .acpi_match_table = ACPI_PTR(synquacer_hsspi_acpi_ids), + }, + .probe = synquacer_spi_probe, + .remove = synquacer_spi_remove, +}; +module_platform_driver(synquacer_spi_driver); + +MODULE_DESCRIPTION("Socionext Synquacer HS-SPI controller driver"); +MODULE_AUTHOR("Masahisa Kojima <masahisa.kojima@linaro.org>"); +MODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index d22f4d10413f..39374c2edcf3 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -84,8 +84,10 @@ (reg = (((val) & 0x1) << ((cs) * 8 + 5)) | \ ((reg) & ~(1 << ((cs) * 8 + 5)))) #define SPI_SET_CYCLES_BETWEEN_PACKETS(reg, cs, val) \ - (reg = (((val) & 0xF) << ((cs) * 8)) | \ - ((reg) & ~(0xF << ((cs) * 8)))) + (reg = (((val) & 0x1F) << ((cs) * 8)) | \ + ((reg) & ~(0x1F << ((cs) * 8)))) +#define MAX_SETUP_HOLD_CYCLES 16 +#define MAX_INACTIVE_CYCLES 32 #define SPI_TRANS_STATUS 0x010 #define SPI_BLK_CNT(val) (((val) >> 0) & 0xFFFF) @@ -156,6 +158,11 @@ struct tegra_spi_soc_data { bool has_intr_mask_reg; }; +struct tegra_spi_client_data { + int tx_clk_tap_delay; + int rx_clk_tap_delay; +}; + struct tegra_spi_data { struct device *dev; struct spi_master *master; @@ -182,6 +189,7 @@ struct tegra_spi_data { unsigned dma_buf_size; unsigned max_buf_size; bool is_curr_dma_xfer; + bool use_hw_based_cs; struct completion rx_dma_complete; struct completion tx_dma_complete; @@ -194,6 +202,10 @@ struct tegra_spi_data { u32 command1_reg; u32 dma_control_reg; u32 def_command1_reg; + u32 def_command2_reg; + u32 spi_cs_timing1; + u32 spi_cs_timing2; + u8 last_used_cs; struct completion xfer_completion; struct spi_transfer *curr_xfer; @@ -711,14 +723,55 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi, dma_release_channel(dma_chan); } +static void tegra_spi_set_hw_cs_timing(struct spi_device *spi, u8 setup_dly, + u8 hold_dly, u8 inactive_dly) +{ + struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); + u32 setup_hold; + u32 spi_cs_timing; + u32 inactive_cycles; + u8 cs_state; + + setup_dly = min_t(u8, setup_dly, MAX_SETUP_HOLD_CYCLES); + hold_dly = min_t(u8, hold_dly, MAX_SETUP_HOLD_CYCLES); + if (setup_dly && hold_dly) { + setup_hold = SPI_SETUP_HOLD(setup_dly - 1, hold_dly - 1); + spi_cs_timing = SPI_CS_SETUP_HOLD(tspi->spi_cs_timing1, + spi->chip_select, + setup_hold); + if (tspi->spi_cs_timing1 != spi_cs_timing) { + tspi->spi_cs_timing1 = spi_cs_timing; + tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING1); + } + } + + inactive_cycles = min_t(u8, inactive_dly, MAX_INACTIVE_CYCLES); + if (inactive_cycles) + inactive_cycles--; + cs_state = inactive_cycles ? 0 : 1; + spi_cs_timing = tspi->spi_cs_timing2; + SPI_SET_CS_ACTIVE_BETWEEN_PACKETS(spi_cs_timing, spi->chip_select, + cs_state); + SPI_SET_CYCLES_BETWEEN_PACKETS(spi_cs_timing, spi->chip_select, + inactive_cycles); + if (tspi->spi_cs_timing2 != spi_cs_timing) { + tspi->spi_cs_timing2 = spi_cs_timing; + tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING2); + } +} + static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, - struct spi_transfer *t, bool is_first_of_msg) + struct spi_transfer *t, + bool is_first_of_msg, + bool is_single_xfer) { struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); + struct tegra_spi_client_data *cdata = spi->controller_data; u32 speed = t->speed_hz; u8 bits_per_word = t->bits_per_word; - u32 command1; + u32 command1, command2; int req_mode; + u32 tx_tap = 0, rx_tap = 0; if (speed != tspi->cur_speed) { clk_set_rate(tspi->clk, speed); @@ -765,13 +818,34 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, } else tegra_spi_writel(tspi, command1, SPI_COMMAND1); - command1 |= SPI_CS_SW_HW; - if (spi->mode & SPI_CS_HIGH) - command1 |= SPI_CS_SW_VAL; - else - command1 &= ~SPI_CS_SW_VAL; + /* GPIO based chip select control */ + if (spi->cs_gpiod) + gpiod_set_value(spi->cs_gpiod, 1); + + if (is_single_xfer && !(t->cs_change)) { + tspi->use_hw_based_cs = true; + command1 &= ~(SPI_CS_SW_HW | SPI_CS_SW_VAL); + } else { + tspi->use_hw_based_cs = false; + command1 |= SPI_CS_SW_HW; + if (spi->mode & SPI_CS_HIGH) + command1 |= SPI_CS_SW_VAL; + else + command1 &= ~SPI_CS_SW_VAL; + } + + if (tspi->last_used_cs != spi->chip_select) { + if (cdata && cdata->tx_clk_tap_delay) + tx_tap = cdata->tx_clk_tap_delay; + if (cdata && cdata->rx_clk_tap_delay) + rx_tap = cdata->rx_clk_tap_delay; + command2 = SPI_TX_TAP_DELAY(tx_tap) | + SPI_RX_TAP_DELAY(rx_tap); + if (command2 != tspi->def_command2_reg) + tegra_spi_writel(tspi, command2, SPI_COMMAND2); + tspi->last_used_cs = spi->chip_select; + } - tegra_spi_writel(tspi, 0, SPI_COMMAND2); } else { command1 = tspi->command1_reg; command1 &= ~SPI_BIT_LENGTH(~0); @@ -827,9 +901,42 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, return ret; } +static struct tegra_spi_client_data + *tegra_spi_parse_cdata_dt(struct spi_device *spi) +{ + struct tegra_spi_client_data *cdata; + struct device_node *slave_np; + + slave_np = spi->dev.of_node; + if (!slave_np) { + dev_dbg(&spi->dev, "device node not found\n"); + return NULL; + } + + cdata = kzalloc(sizeof(*cdata), GFP_KERNEL); + if (!cdata) + return NULL; + + of_property_read_u32(slave_np, "nvidia,tx-clk-tap-delay", + &cdata->tx_clk_tap_delay); + of_property_read_u32(slave_np, "nvidia,rx-clk-tap-delay", + &cdata->rx_clk_tap_delay); + return cdata; +} + +static void tegra_spi_cleanup(struct spi_device *spi) +{ + struct tegra_spi_client_data *cdata = spi->controller_data; + + spi->controller_data = NULL; + if (spi->dev.of_node) + kfree(cdata); +} + static int tegra_spi_setup(struct spi_device *spi) { struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); + struct tegra_spi_client_data *cdata = spi->controller_data; u32 val; unsigned long flags; int ret; @@ -840,9 +947,16 @@ static int tegra_spi_setup(struct spi_device *spi) spi->mode & SPI_CPHA ? "" : "~", spi->max_speed_hz); + if (!cdata) { + cdata = tegra_spi_parse_cdata_dt(spi); + spi->controller_data = cdata; + } + ret = pm_runtime_get_sync(tspi->dev); if (ret < 0) { dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret); + if (cdata) + tegra_spi_cleanup(spi); return ret; } @@ -853,6 +967,10 @@ static int tegra_spi_setup(struct spi_device *spi) } spin_lock_irqsave(&tspi->lock, flags); + /* GPIO based chip select control */ + if (spi->cs_gpiod) + gpiod_set_value(spi->cs_gpiod, 0); + val = tspi->def_command1_reg; if (spi->mode & SPI_CS_HIGH) val &= ~SPI_CS_POL_INACTIVE(spi->chip_select); @@ -882,11 +1000,18 @@ static void tegra_spi_transfer_end(struct spi_device *spi) struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); int cs_val = (spi->mode & SPI_CS_HIGH) ? 0 : 1; - if (cs_val) - tspi->command1_reg |= SPI_CS_SW_VAL; - else - tspi->command1_reg &= ~SPI_CS_SW_VAL; - tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1); + /* GPIO based chip select control */ + if (spi->cs_gpiod) + gpiod_set_value(spi->cs_gpiod, 0); + + if (!tspi->use_hw_based_cs) { + if (cs_val) + tspi->command1_reg |= SPI_CS_SW_VAL; + else + tspi->command1_reg &= ~SPI_CS_SW_VAL; + tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1); + } + tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1); } @@ -913,16 +1038,19 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, struct spi_device *spi = msg->spi; int ret; bool skip = false; + int single_xfer; msg->status = 0; msg->actual_length = 0; + single_xfer = list_is_singular(&msg->transfers); list_for_each_entry(xfer, &msg->transfers, transfer_list) { u32 cmd1; reinit_completion(&tspi->xfer_completion); - cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg); + cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg, + single_xfer); if (!xfer->len) { ret = 0; @@ -955,6 +1083,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); + tspi->last_used_cs = master->num_chipselect + 1; goto complete_xfer; } @@ -1188,11 +1317,14 @@ static int tegra_spi_probe(struct platform_device *pdev) master->max_speed_hz = 25000000; /* 25MHz */ /* the spi->mode bits understood by this driver: */ + master->use_gpio_descriptors = true; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_TX_DUAL | SPI_RX_DUAL | SPI_3WIRE; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); master->setup = tegra_spi_setup; + master->cleanup = tegra_spi_cleanup; master->transfer_one_message = tegra_spi_transfer_one_message; + master->set_cs_timing = tegra_spi_set_hw_cs_timing; master->num_chipselect = MAX_CHIP_SELECT; master->auto_runtime_pm = true; bus_num = of_alias_get_id(pdev->dev.of_node, "spi"); @@ -1268,6 +1400,10 @@ static int tegra_spi_probe(struct platform_device *pdev) reset_control_deassert(tspi->rst); tspi->def_command1_reg = SPI_M_S; tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1); + tspi->spi_cs_timing1 = tegra_spi_readl(tspi, SPI_CS_TIMING1); + tspi->spi_cs_timing2 = tegra_spi_readl(tspi, SPI_CS_TIMING2); + tspi->def_command2_reg = tegra_spi_readl(tspi, SPI_COMMAND2); + tspi->last_used_cs = master->num_chipselect + 1; pm_runtime_put(&pdev->dev); ret = request_threaded_irq(tspi->irq, tegra_spi_isr, tegra_spi_isr_thread, IRQF_ONESHOT, @@ -1340,6 +1476,8 @@ static int tegra_spi_resume(struct device *dev) return ret; } tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1); + tegra_spi_writel(tspi, tspi->def_command2_reg, SPI_COMMAND2); + tspi->last_used_cs = master->num_chipselect + 1; pm_runtime_put(dev); return spi_master_resume(master); diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c index c6ae775289e5..60dc69a39ace 100644 --- a/drivers/spi/spi-tle62x0.c +++ b/drivers/spi/spi-tle62x0.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Support Infineon TLE62x0 driver chips * * Copyright (c) 2007 Simtec Electronics * Ben Dooks, <ben@simtec.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index 5a6137fe172d..b32c77df5d49 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -328,7 +328,12 @@ static int uniphier_spi_transfer_one(struct spi_master *master, struct spi_transfer *t) { struct uniphier_spi_priv *priv = spi_master_get_devdata(master); - int status; + struct device *dev = master->dev.parent; + unsigned long time_left; + + /* Terminate and return success for 0 byte length transfer */ + if (!t->len) + return 0; uniphier_spi_setup_transfer(spi, t); @@ -338,13 +343,15 @@ static int uniphier_spi_transfer_one(struct spi_master *master, uniphier_spi_irq_enable(spi, SSI_IE_RCIE | SSI_IE_RORIE); - status = wait_for_completion_timeout(&priv->xfer_done, - msecs_to_jiffies(SSI_TIMEOUT_MS)); + time_left = wait_for_completion_timeout(&priv->xfer_done, + msecs_to_jiffies(SSI_TIMEOUT_MS)); uniphier_spi_irq_disable(spi, SSI_IE_RCIE | SSI_IE_RORIE); - if (status < 0) - return status; + if (!time_left) { + dev_err(dev, "transfer timeout.\n"); + return -ETIMEDOUT; + } return priv->error; } diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 63fedc49ae9c..d5f9d5fbb3e8 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Xilinx SPI controller driver (master mode only) * @@ -8,9 +9,6 @@ * Copyright (c) 2009 Intel Corporation * 2002-2007 (c) MontaVista Software, Inc. - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/spi/spi-xlp.c b/drivers/spi/spi-xlp.c index 74a01b09a8a5..1dc479fab98c 100644 --- a/drivers/spi/spi-xlp.c +++ b/drivers/spi/spi-xlp.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2003-2015 Broadcom Corporation * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 (GPL v2) - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/acpi.h> #include <linux/clk.h> diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c index 8ce04f829a80..86516eb1e143 100644 --- a/drivers/spi/spi-xtensa-xtfpga.c +++ b/drivers/spi/spi-xtensa-xtfpga.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Xtensa xtfpga SPI controller driver * * Copyright (c) 2014 Cadence Design Systems Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5e4654032bfa..91673351bcf3 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1090,6 +1090,60 @@ static int spi_transfer_wait(struct spi_controller *ctlr, return 0; } +static void _spi_transfer_delay_ns(u32 ns) +{ + if (!ns) + return; + if (ns <= 1000) { + ndelay(ns); + } else { + u32 us = DIV_ROUND_UP(ns, 1000); + + if (us <= 10) + udelay(us); + else + usleep_range(us, us + DIV_ROUND_UP(us, 10)); + } +} + +static void _spi_transfer_cs_change_delay(struct spi_message *msg, + struct spi_transfer *xfer) +{ + u32 delay = xfer->cs_change_delay; + u32 unit = xfer->cs_change_delay_unit; + u32 hz; + + /* return early on "fast" mode - for everything but USECS */ + if (!delay && unit != SPI_DELAY_UNIT_USECS) + return; + + switch (unit) { + case SPI_DELAY_UNIT_USECS: + /* for compatibility use default of 10us */ + if (!delay) + delay = 10000; + else + delay *= 1000; + break; + case SPI_DELAY_UNIT_NSECS: /* nothing to do here */ + break; + case SPI_DELAY_UNIT_SCK: + /* if there is no effective speed know, then approximate + * by underestimating with half the requested hz + */ + hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2; + delay *= DIV_ROUND_UP(1000000000, hz); + break; + default: + dev_err_once(&msg->spi->dev, + "Use of unsupported delay unit %i, using default of 10us\n", + xfer->cs_change_delay_unit); + delay = 10000; + } + /* now sleep for the requested amount of time */ + _spi_transfer_delay_ns(delay); +} + /* * spi_transfer_one_message - Default implementation of transfer_one_message() * @@ -1148,14 +1202,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, if (msg->status != -EINPROGRESS) goto out; - if (xfer->delay_usecs) { - u16 us = xfer->delay_usecs; - - if (us <= 10) - udelay(us); - else - usleep_range(us, us + DIV_ROUND_UP(us, 10)); - } + if (xfer->delay_usecs) + _spi_transfer_delay_ns(xfer->delay_usecs * 1000); if (xfer->cs_change) { if (list_is_last(&xfer->transfer_list, @@ -1163,7 +1211,7 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, keep_cs = true; } else { spi_set_cs(msg->spi, false); - udelay(10); + _spi_transfer_cs_change_delay(msg, xfer); spi_set_cs(msg->spi, true); } } @@ -1369,10 +1417,32 @@ static void spi_pump_messages(struct kthread_work *work) __spi_pump_messages(ctlr, true); } -static int spi_init_queue(struct spi_controller *ctlr) +/** + * spi_set_thread_rt - set the controller to pump at realtime priority + * @ctlr: controller to boost priority of + * + * This can be called because the controller requested realtime priority + * (by setting the ->rt value before calling spi_register_controller()) or + * because a device on the bus said that its transfers needed realtime + * priority. + * + * NOTE: at the moment if any device on a bus says it needs realtime then + * the thread will be at realtime priority for all transfers on that + * controller. If this eventually becomes a problem we may see if we can + * find a way to boost the priority only temporarily during relevant + * transfers. + */ +static void spi_set_thread_rt(struct spi_controller *ctlr) { struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; + dev_info(&ctlr->dev, + "will run message pump with realtime priority\n"); + sched_setscheduler(ctlr->kworker_task, SCHED_FIFO, ¶m); +} + +static int spi_init_queue(struct spi_controller *ctlr) +{ ctlr->running = false; ctlr->busy = false; @@ -1392,11 +1462,8 @@ static int spi_init_queue(struct spi_controller *ctlr) * request and the scheduling of the message pump thread. Without this * setting the message pump thread will remain at default priority. */ - if (ctlr->rt) { - dev_info(&ctlr->dev, - "will run message pump with realtime priority\n"); - sched_setscheduler(ctlr->kworker_task, SCHED_FIFO, ¶m); - } + if (ctlr->rt) + spi_set_thread_rt(ctlr); return 0; } @@ -1804,9 +1871,18 @@ static void of_register_spi_devices(struct spi_controller *ctlr) { } #endif #ifdef CONFIG_ACPI -static void acpi_spi_parse_apple_properties(struct spi_device *spi) +struct acpi_spi_lookup { + struct spi_controller *ctlr; + u32 max_speed_hz; + u32 mode; + int irq; + u8 bits_per_word; + u8 chip_select; +}; + +static void acpi_spi_parse_apple_properties(struct acpi_device *dev, + struct acpi_spi_lookup *lookup) { - struct acpi_device *dev = ACPI_COMPANION(&spi->dev); const union acpi_object *obj; if (!x86_apple_machine) @@ -1814,35 +1890,46 @@ static void acpi_spi_parse_apple_properties(struct spi_device *spi) if (!acpi_dev_get_property(dev, "spiSclkPeriod", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length >= 4) - spi->max_speed_hz = NSEC_PER_SEC / *(u32 *)obj->buffer.pointer; + lookup->max_speed_hz = NSEC_PER_SEC / *(u32 *)obj->buffer.pointer; if (!acpi_dev_get_property(dev, "spiWordSize", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length == 8) - spi->bits_per_word = *(u64 *)obj->buffer.pointer; + lookup->bits_per_word = *(u64 *)obj->buffer.pointer; if (!acpi_dev_get_property(dev, "spiBitOrder", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length == 8 && !*(u64 *)obj->buffer.pointer) - spi->mode |= SPI_LSB_FIRST; + lookup->mode |= SPI_LSB_FIRST; if (!acpi_dev_get_property(dev, "spiSPO", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length == 8 && *(u64 *)obj->buffer.pointer) - spi->mode |= SPI_CPOL; + lookup->mode |= SPI_CPOL; if (!acpi_dev_get_property(dev, "spiSPH", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length == 8 && *(u64 *)obj->buffer.pointer) - spi->mode |= SPI_CPHA; + lookup->mode |= SPI_CPHA; } static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) { - struct spi_device *spi = data; - struct spi_controller *ctlr = spi->controller; + struct acpi_spi_lookup *lookup = data; + struct spi_controller *ctlr = lookup->ctlr; if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { struct acpi_resource_spi_serialbus *sb; + acpi_handle parent_handle; + acpi_status status; sb = &ares->data.spi_serial_bus; if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) { + + status = acpi_get_handle(NULL, + sb->resource_source.string_ptr, + &parent_handle); + + if (ACPI_FAILURE(status) || + ACPI_HANDLE(ctlr->dev.parent) != parent_handle) + return -ENODEV; + /* * ACPI DeviceSelection numbering is handled by the * host controller driver in Windows and can vary @@ -1855,25 +1942,25 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) sb->device_selection); if (cs < 0) return cs; - spi->chip_select = cs; + lookup->chip_select = cs; } else { - spi->chip_select = sb->device_selection; + lookup->chip_select = sb->device_selection; } - spi->max_speed_hz = sb->connection_speed; + lookup->max_speed_hz = sb->connection_speed; if (sb->clock_phase == ACPI_SPI_SECOND_PHASE) - spi->mode |= SPI_CPHA; + lookup->mode |= SPI_CPHA; if (sb->clock_polarity == ACPI_SPI_START_HIGH) - spi->mode |= SPI_CPOL; + lookup->mode |= SPI_CPOL; if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH) - spi->mode |= SPI_CS_HIGH; + lookup->mode |= SPI_CS_HIGH; } - } else if (spi->irq < 0) { + } else if (lookup->irq < 0) { struct resource r; if (acpi_dev_resource_interrupt(ares, 0, &r)) - spi->irq = r.start; + lookup->irq = r.start; } /* Always tell the ACPI core to skip this resource */ @@ -1883,7 +1970,9 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, struct acpi_device *adev) { + acpi_handle parent_handle = NULL; struct list_head resource_list; + struct acpi_spi_lookup lookup = {}; struct spi_device *spi; int ret; @@ -1891,28 +1980,42 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, acpi_device_enumerated(adev)) return AE_OK; - spi = spi_alloc_device(ctlr); - if (!spi) { - dev_err(&ctlr->dev, "failed to allocate SPI device for %s\n", - dev_name(&adev->dev)); - return AE_NO_MEMORY; - } - - ACPI_COMPANION_SET(&spi->dev, adev); - spi->irq = -1; + lookup.ctlr = ctlr; + lookup.irq = -1; INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, - acpi_spi_add_resource, spi); + acpi_spi_add_resource, &lookup); acpi_dev_free_resource_list(&resource_list); - acpi_spi_parse_apple_properties(spi); + if (ret < 0) + /* found SPI in _CRS but it points to another controller */ + return AE_OK; - if (ret < 0 || !spi->max_speed_hz) { - spi_dev_put(spi); + if (!lookup.max_speed_hz && + !ACPI_FAILURE(acpi_get_parent(adev->handle, &parent_handle)) && + ACPI_HANDLE(ctlr->dev.parent) == parent_handle) { + /* Apple does not use _CRS but nested devices for SPI slaves */ + acpi_spi_parse_apple_properties(adev, &lookup); + } + + if (!lookup.max_speed_hz) return AE_OK; + + spi = spi_alloc_device(ctlr); + if (!spi) { + dev_err(&ctlr->dev, "failed to allocate SPI device for %s\n", + dev_name(&adev->dev)); + return AE_NO_MEMORY; } + ACPI_COMPANION_SET(&spi->dev, adev); + spi->max_speed_hz = lookup.max_speed_hz; + spi->mode = lookup.mode; + spi->irq = lookup.irq; + spi->bits_per_word = lookup.bits_per_word; + spi->chip_select = lookup.chip_select; + acpi_set_modalias(adev, acpi_device_hid(adev), spi->modalias, sizeof(spi->modalias)); @@ -1944,6 +2047,8 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, return acpi_register_spi_device(ctlr, adev); } +#define SPI_ACPI_ENUMERATE_MAX_DEPTH 32 + static void acpi_register_spi_devices(struct spi_controller *ctlr) { acpi_status status; @@ -1953,7 +2058,8 @@ static void acpi_register_spi_devices(struct spi_controller *ctlr) if (!handle) return; - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + SPI_ACPI_ENUMERATE_MAX_DEPTH, acpi_spi_add_device, NULL, ctlr, NULL); if (ACPI_FAILURE(status)) dev_warn(&ctlr->dev, "failed to enumerate SPI slaves\n"); @@ -2286,11 +2392,6 @@ int spi_register_controller(struct spi_controller *ctlr) if (status) return status; - /* even if it's just one always-selected device, there must - * be at least one chipselect - */ - if (ctlr->num_chipselect == 0) - return -EINVAL; if (ctlr->bus_num >= 0) { /* devices with a fixed bus num must check-in with the num */ mutex_lock(&board_lock); @@ -2361,6 +2462,13 @@ int spi_register_controller(struct spi_controller *ctlr) } } + /* + * Even if it's just one always-selected device, there must + * be at least one chipselect. + */ + if (!ctlr->num_chipselect) + return -EINVAL; + status = device_add(&ctlr->dev); if (status < 0) { /* free bus id */ @@ -2470,7 +2578,6 @@ void spi_unregister_controller(struct spi_controller *ctlr) { struct spi_controller *found; int id = ctlr->bus_num; - int dummy; /* First make sure that this controller was ever added */ mutex_lock(&board_lock); @@ -2484,7 +2591,7 @@ void spi_unregister_controller(struct spi_controller *ctlr) list_del(&ctlr->list); mutex_unlock(&board_lock); - dummy = device_for_each_child(&ctlr->dev, NULL, __unregister); + device_for_each_child(&ctlr->dev, NULL, __unregister); device_unregister(&ctlr->dev); /* free bus id */ mutex_lock(&board_lock); @@ -2633,12 +2740,9 @@ EXPORT_SYMBOL_GPL(spi_res_add); */ void spi_res_release(struct spi_controller *ctlr, struct spi_message *message) { - struct spi_res *res; - - while (!list_empty(&message->resources)) { - res = list_last_entry(&message->resources, - struct spi_res, entry); + struct spi_res *res, *tmp; + list_for_each_entry_safe_reverse(res, tmp, &message->resources, entry) { if (res->release) res->release(ctlr, message, res->data); @@ -2702,8 +2806,7 @@ struct spi_replaced_transfers *spi_replace_transfers( /* allocate the structure using spi_res */ rxfer = spi_res_alloc(msg->spi, __spi_replace_transfers_release, - insert * sizeof(struct spi_transfer) - + sizeof(struct spi_replaced_transfers) + struct_size(rxfer, inserted_transfers, insert) + extradatasize, gfp); if (!rxfer) @@ -2987,6 +3090,11 @@ int spi_setup(struct spi_device *spi) spi_set_cs(spi, false); + if (spi->rt && !spi->controller->rt) { + spi->controller->rt = true; + spi_set_thread_rt(spi->controller); + } + dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n", (int) (spi->mode & (SPI_CPOL | SPI_CPHA)), (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "", @@ -3083,6 +3191,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) */ message->frame_length = 0; list_for_each_entry(xfer, &message->transfers, transfer_list) { + xfer->effective_speed_hz = 0; message->frame_length += xfer->len; if (!xfer->bits_per_word) xfer->bits_per_word = spi->bits_per_word; @@ -3762,4 +3871,3 @@ err0: * include needing to have boardinfo data structures be much more public. */ postcore_initcall(spi_init); - diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 422bac8cc3e0..255786f2e844 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -663,6 +663,8 @@ static const struct of_device_id spidev_dt_ids[] = { { .compatible = "ge,achc" }, { .compatible = "semtech,sx1301" }, { .compatible = "lwn,bk4" }, + { .compatible = "dh,dhcom-board" }, + { .compatible = "menlo,m53cpld" }, {}, }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); diff --git a/drivers/staging/erofs/erofs_fs.h b/drivers/staging/erofs/erofs_fs.h index fa52898df006..8ddb2b3e7d39 100644 --- a/drivers/staging/erofs/erofs_fs.h +++ b/drivers/staging/erofs/erofs_fs.h @@ -17,10 +17,16 @@ #define EROFS_SUPER_MAGIC_V1 0xE0F5E1E2 #define EROFS_SUPER_OFFSET 1024 +/* + * Any bits that aren't in EROFS_ALL_REQUIREMENTS should be + * incompatible with this kernel version. + */ +#define EROFS_ALL_REQUIREMENTS 0 + struct erofs_super_block { /* 0 */__le32 magic; /* in the little endian */ /* 4 */__le32 checksum; /* crc32c(super_block) */ -/* 8 */__le32 features; +/* 8 */__le32 features; /* (aka. feature_compat) */ /* 12 */__u8 blkszbits; /* support block_size == PAGE_SIZE only */ /* 13 */__u8 reserved; @@ -34,9 +40,10 @@ struct erofs_super_block { /* 44 */__le32 xattr_blkaddr; /* 48 */__u8 uuid[16]; /* 128-bit uuid for volume */ /* 64 */__u8 volume_name[16]; /* volume name */ +/* 80 */__le32 requirements; /* (aka. feature_incompat) */ -/* 80 */__u8 reserved2[48]; /* 128 bytes */ -} __packed; +/* 84 */__u8 reserved2[44]; +} __packed; /* 128 bytes */ /* * erofs inode data mapping: diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h index c47778b3fabd..382258fc124d 100644 --- a/drivers/staging/erofs/internal.h +++ b/drivers/staging/erofs/internal.h @@ -115,6 +115,8 @@ struct erofs_sb_info { u8 uuid[16]; /* 128-bit uuid for volume */ u8 volume_name[16]; /* volume name */ + u32 requirements; + char *dev_name; unsigned int mount_opt; diff --git a/drivers/staging/erofs/super.c b/drivers/staging/erofs/super.c index f580d4ef77a1..cadbcc11702a 100644 --- a/drivers/staging/erofs/super.c +++ b/drivers/staging/erofs/super.c @@ -71,6 +71,22 @@ static void free_inode(struct inode *inode) kmem_cache_free(erofs_inode_cachep, vi); } +static bool check_layout_compatibility(struct super_block *sb, + struct erofs_super_block *layout) +{ + const unsigned int requirements = le32_to_cpu(layout->requirements); + + EROFS_SB(sb)->requirements = requirements; + + /* check if current kernel meets all mandatory requirements */ + if (requirements & (~EROFS_ALL_REQUIREMENTS)) { + errln("unidentified requirements %x, please upgrade kernel version", + requirements & ~EROFS_ALL_REQUIREMENTS); + return false; + } + return true; +} + static int superblock_read(struct super_block *sb) { struct erofs_sb_info *sbi; @@ -104,6 +120,9 @@ static int superblock_read(struct super_block *sb) goto out; } + if (!check_layout_compatibility(sb, layout)) + goto out; + sbi->blocks = le32_to_cpu(layout->blocks); sbi->meta_blkaddr = le32_to_cpu(layout->meta_blkaddr); #ifdef CONFIG_EROFS_FS_XATTR diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 9b07badf4c6c..7cbc1bdd2d8a 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -891,7 +891,9 @@ int fbtft_unregister_framebuffer(struct fb_info *fb_info) if (par->fbtftops.unregister_backlight) par->fbtftops.unregister_backlight(par); fbtft_sysfs_exit(par); - return unregister_framebuffer(fb_info); + unregister_framebuffer(fb_info); + + return 0; } EXPORT_SYMBOL(fbtft_unregister_framebuffer); diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index b6a65ee8d558..dc8c25ddb97e 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -6,7 +6,8 @@ */ #include <linux/interrupt.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/irq.h> #include <linux/workqueue.h> #include <linux/device.h> #include <linux/kernel.h> diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c index dd7fcab8e19e..e075244c602b 100644 --- a/drivers/staging/iio/cdc/ad7150.c +++ b/drivers/staging/iio/cdc/ad7150.c @@ -5,6 +5,7 @@ * Copyright 2010-2011 Analog Devices Inc. */ +#include <linux/bitfield.h> #include <linux/interrupt.h> #include <linux/device.h> #include <linux/kernel.h> @@ -130,7 +131,7 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev, { int ret; u8 threshtype; - bool adaptive; + bool thrfixed; struct ad7150_chip_info *chip = iio_priv(indio_dev); ret = i2c_smbus_read_byte_data(chip->client, AD7150_CFG); @@ -138,21 +139,23 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev, return ret; threshtype = (ret >> 5) & 0x03; - adaptive = !!(ret & 0x80); + + /*check if threshold mode is fixed or adaptive*/ + thrfixed = FIELD_GET(AD7150_CFG_FIX, ret); switch (type) { case IIO_EV_TYPE_MAG_ADAPTIVE: if (dir == IIO_EV_DIR_RISING) - return adaptive && (threshtype == 0x1); - return adaptive && (threshtype == 0x0); + return !thrfixed && (threshtype == 0x1); + return !thrfixed && (threshtype == 0x0); case IIO_EV_TYPE_THRESH_ADAPTIVE: if (dir == IIO_EV_DIR_RISING) - return adaptive && (threshtype == 0x3); - return adaptive && (threshtype == 0x2); + return !thrfixed && (threshtype == 0x3); + return !thrfixed && (threshtype == 0x2); case IIO_EV_TYPE_THRESH: if (dir == IIO_EV_DIR_RISING) - return !adaptive && (threshtype == 0x1); - return !adaptive && (threshtype == 0x0); + return thrfixed && (threshtype == 0x1); + return thrfixed && (threshtype == 0x0); default: break; } diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index f77f5eee7fc2..534d85d6c5e3 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -20,15 +20,19 @@ menuconfig STAGING_MEDIA if STAGING_MEDIA && MEDIA_SUPPORT # Please keep them in alphabetic order +source "drivers/staging/media/allegro-dvt/Kconfig" + source "drivers/staging/media/bcm2048/Kconfig" source "drivers/staging/media/davinci_vpfe/Kconfig" +source "drivers/staging/media/hantro/Kconfig" + source "drivers/staging/media/imx/Kconfig" -source "drivers/staging/media/omap4iss/Kconfig" +source "drivers/staging/media/meson/vdec/Kconfig" -source "drivers/staging/media/rockchip/vpu/Kconfig" +source "drivers/staging/media/omap4iss/Kconfig" source "drivers/staging/media/sunxi/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 99218bfc997f..c486298194da 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -1,10 +1,12 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro-dvt/ obj-$(CONFIG_I2C_BCM2048) += bcm2048/ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ +obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ obj-$(CONFIG_TEGRA_VDE) += tegra-vde/ -obj-$(CONFIG_VIDEO_ROCKCHIP_VPU) += rockchip/vpu/ +obj-$(CONFIG_VIDEO_HANTRO) += hantro/ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ obj-$(CONFIG_SOC_CAMERA) += soc_camera/ diff --git a/drivers/staging/media/allegro-dvt/Kconfig b/drivers/staging/media/allegro-dvt/Kconfig new file mode 100644 index 000000000000..6b7107d9995c --- /dev/null +++ b/drivers/staging/media/allegro-dvt/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0 +config VIDEO_ALLEGRO_DVT + tristate "Allegro DVT Video IP Core" + depends on VIDEO_DEV && VIDEO_V4L2 + depends on ARCH_ZYNQMP || COMPILE_TEST + select V4L2_MEM2MEM_DEV + select VIDEOBUF2_DMA_CONTIG + select REGMAP + select REGMAP_MMIO + help + Support for the encoder video IP core by Allegro DVT. This core is + found for example on the Xilinx ZynqMP SoC in the EV family and is + called VCU in the reference manual. + + To compile this driver as a module, choose M here: the module + will be called allegro. diff --git a/drivers/staging/media/allegro-dvt/Makefile b/drivers/staging/media/allegro-dvt/Makefile new file mode 100644 index 000000000000..80817160815c --- /dev/null +++ b/drivers/staging/media/allegro-dvt/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +allegro-objs := allegro-core.o nal-h264.o + +obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro.o diff --git a/drivers/staging/media/allegro-dvt/TODO b/drivers/staging/media/allegro-dvt/TODO new file mode 100644 index 000000000000..99e19be0e45a --- /dev/null +++ b/drivers/staging/media/allegro-dvt/TODO @@ -0,0 +1,4 @@ +TODO: + +- This driver is waiting for the stateful encoder spec and corresponding + v4l2-compliance tests to be finalized. diff --git a/drivers/staging/media/allegro-dvt/allegro-core.c b/drivers/staging/media/allegro-dvt/allegro-core.c new file mode 100644 index 000000000000..f050c7347fd5 --- /dev/null +++ b/drivers/staging/media/allegro-dvt/allegro-core.c @@ -0,0 +1,3014 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de> + * + * Allegro DVT video encoder driver + */ + +#include <linux/firmware.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/log2.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/sizes.h> +#include <linux/slab.h> +#include <linux/videodev2.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mem2mem.h> +#include <media/videobuf2-dma-contig.h> +#include <media/videobuf2-v4l2.h> + +#include "nal-h264.h" + +/* + * Support up to 4k video streams. The hardware actually supports higher + * resolutions, which are specified in PG252 June 6, 2018 (H.264/H.265 Video + * Codec Unit v1.1) Chapter 3. + */ +#define ALLEGRO_WIDTH_MIN 128 +#define ALLEGRO_WIDTH_DEFAULT 1920 +#define ALLEGRO_WIDTH_MAX 3840 +#define ALLEGRO_HEIGHT_MIN 64 +#define ALLEGRO_HEIGHT_DEFAULT 1080 +#define ALLEGRO_HEIGHT_MAX 2160 + +#define ALLEGRO_GOP_SIZE_DEFAULT 25 +#define ALLEGRO_GOP_SIZE_MAX 1000 + +/* + * MCU Control Registers + * + * The Zynq UltraScale+ Devices Register Reference documents the registers + * with an offset of 0x9000, which equals the size of the SRAM and one page + * gap. The driver handles SRAM and registers separately and, therefore, is + * oblivious of the offset. + */ +#define AL5_MCU_RESET 0x0000 +#define AL5_MCU_RESET_SOFT BIT(0) +#define AL5_MCU_RESET_REGS BIT(1) +#define AL5_MCU_RESET_MODE 0x0004 +#define AL5_MCU_RESET_MODE_SLEEP BIT(0) +#define AL5_MCU_RESET_MODE_HALT BIT(1) +#define AL5_MCU_STA 0x0008 +#define AL5_MCU_STA_SLEEP BIT(0) +#define AL5_MCU_WAKEUP 0x000c + +#define AL5_ICACHE_ADDR_OFFSET_MSB 0x0010 +#define AL5_ICACHE_ADDR_OFFSET_LSB 0x0014 +#define AL5_DCACHE_ADDR_OFFSET_MSB 0x0018 +#define AL5_DCACHE_ADDR_OFFSET_LSB 0x001c + +#define AL5_MCU_INTERRUPT 0x0100 +#define AL5_ITC_CPU_IRQ_MSK 0x0104 +#define AL5_ITC_CPU_IRQ_CLR 0x0108 +#define AL5_ITC_CPU_IRQ_STA 0x010C +#define AL5_ITC_CPU_IRQ_STA_TRIGGERED BIT(0) + +#define AXI_ADDR_OFFSET_IP 0x0208 + +/* + * The MCU accesses the system memory with a 2G offset compared to CPU + * physical addresses. + */ +#define MCU_CACHE_OFFSET SZ_2G + +/* + * The driver needs to reserve some space at the beginning of capture buffers, + * because it needs to write SPS/PPS NAL units. The encoder writes the actual + * frame data after the offset. + */ +#define ENCODER_STREAM_OFFSET SZ_64 + +#define SIZE_MACROBLOCK 16 + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-2)"); + +struct allegro_buffer { + void *vaddr; + dma_addr_t paddr; + size_t size; + struct list_head head; +}; + +struct allegro_channel; + +struct allegro_mbox { + unsigned int head; + unsigned int tail; + unsigned int data; + size_t size; + /* protect mailbox from simultaneous accesses */ + struct mutex lock; +}; + +struct allegro_dev { + struct v4l2_device v4l2_dev; + struct video_device video_dev; + struct v4l2_m2m_dev *m2m_dev; + struct platform_device *plat_dev; + + /* mutex protecting vb2_queue structure */ + struct mutex lock; + + struct regmap *regmap; + struct regmap *sram; + + struct allegro_buffer firmware; + struct allegro_buffer suballocator; + + struct completion init_complete; + + /* The mailbox interface */ + struct allegro_mbox mbox_command; + struct allegro_mbox mbox_status; + + /* + * The downstream driver limits the users to 64 users, thus I can use + * a bitfield for the user_ids that are in use. See also user_id in + * struct allegro_channel. + */ + unsigned long channel_user_ids; + struct list_head channels; +}; + +static struct regmap_config allegro_regmap_config = { + .name = "regmap", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0xfff, + .cache_type = REGCACHE_NONE, +}; + +static struct regmap_config allegro_sram_config = { + .name = "sram", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x7fff, + .cache_type = REGCACHE_NONE, +}; + +enum allegro_state { + ALLEGRO_STATE_ENCODING, + ALLEGRO_STATE_DRAIN, + ALLEGRO_STATE_WAIT_FOR_BUFFER, + ALLEGRO_STATE_STOPPED, +}; + +#define fh_to_channel(__fh) container_of(__fh, struct allegro_channel, fh) + +struct allegro_channel { + struct allegro_dev *dev; + struct v4l2_fh fh; + struct v4l2_ctrl_handler ctrl_handler; + + unsigned int width; + unsigned int height; + unsigned int stride; + + enum v4l2_colorspace colorspace; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_quantization quantization; + enum v4l2_xfer_func xfer_func; + + u32 pixelformat; + unsigned int sizeimage_raw; + unsigned int osequence; + + u32 codec; + enum v4l2_mpeg_video_h264_profile profile; + enum v4l2_mpeg_video_h264_level level; + unsigned int sizeimage_encoded; + unsigned int csequence; + + enum v4l2_mpeg_video_bitrate_mode bitrate_mode; + unsigned int bitrate; + unsigned int bitrate_peak; + unsigned int cpb_size; + unsigned int gop_size; + + struct v4l2_ctrl *mpeg_video_h264_profile; + struct v4l2_ctrl *mpeg_video_h264_level; + struct v4l2_ctrl *mpeg_video_bitrate_mode; + struct v4l2_ctrl *mpeg_video_bitrate; + struct v4l2_ctrl *mpeg_video_bitrate_peak; + struct v4l2_ctrl *mpeg_video_cpb_size; + struct v4l2_ctrl *mpeg_video_gop_size; + + /* user_id is used to identify the channel during CREATE_CHANNEL */ + /* not sure, what to set here and if this is actually required */ + int user_id; + /* channel_id is set by the mcu and used by all later commands */ + int mcu_channel_id; + + struct list_head buffers_reference; + struct list_head buffers_intermediate; + + struct list_head list; + struct completion completion; + + unsigned int error; + enum allegro_state state; +}; + +static inline int +allegro_set_state(struct allegro_channel *channel, enum allegro_state state) +{ + channel->state = state; + + return 0; +} + +static inline enum allegro_state +allegro_get_state(struct allegro_channel *channel) +{ + return channel->state; +} + +struct fw_info { + unsigned int id; + unsigned int id_codec; + char *version; + unsigned int mailbox_cmd; + unsigned int mailbox_status; + size_t mailbox_size; + size_t suballocator_size; +}; + +static const struct fw_info supported_firmware[] = { + { + .id = 18296, + .id_codec = 96272, + .version = "v2018.2", + .mailbox_cmd = 0x7800, + .mailbox_status = 0x7c00, + .mailbox_size = 0x400 - 0x8, + .suballocator_size = SZ_16M, + }, +}; + +enum mcu_msg_type { + MCU_MSG_TYPE_INIT = 0x0000, + MCU_MSG_TYPE_CREATE_CHANNEL = 0x0005, + MCU_MSG_TYPE_DESTROY_CHANNEL = 0x0006, + MCU_MSG_TYPE_ENCODE_FRAME = 0x0007, + MCU_MSG_TYPE_PUT_STREAM_BUFFER = 0x0012, + MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE = 0x000e, + MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE = 0x000f, +}; + +static const char *msg_type_name(enum mcu_msg_type type) +{ + static char buf[9]; + + switch (type) { + case MCU_MSG_TYPE_INIT: + return "INIT"; + case MCU_MSG_TYPE_CREATE_CHANNEL: + return "CREATE_CHANNEL"; + case MCU_MSG_TYPE_DESTROY_CHANNEL: + return "DESTROY_CHANNEL"; + case MCU_MSG_TYPE_ENCODE_FRAME: + return "ENCODE_FRAME"; + case MCU_MSG_TYPE_PUT_STREAM_BUFFER: + return "PUT_STREAM_BUFFER"; + case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE: + return "PUSH_BUFFER_INTERMEDIATE"; + case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE: + return "PUSH_BUFFER_REFERENCE"; + default: + snprintf(buf, sizeof(buf), "(0x%04x)", type); + return buf; + } +} + +struct mcu_msg_header { + u16 length; /* length of the body in bytes */ + u16 type; +} __attribute__ ((__packed__)); + +struct mcu_msg_init_request { + struct mcu_msg_header header; + u32 reserved0; /* maybe a unused channel id */ + u32 suballoc_dma; + u32 suballoc_size; + s32 l2_cache[3]; +} __attribute__ ((__packed__)); + +struct mcu_msg_init_response { + struct mcu_msg_header header; + u32 reserved0; +} __attribute__ ((__packed__)); + +struct mcu_msg_create_channel { + struct mcu_msg_header header; + u32 user_id; + u16 width; + u16 height; + u32 format; + u32 colorspace; + u32 src_mode; + u8 profile; + u16 constraint_set_flags; + s8 codec; + u16 level; + u16 tier; + u32 sps_param; + u32 pps_param; + + u32 enc_option; +#define AL_OPT_WPP BIT(0) +#define AL_OPT_TILE BIT(1) +#define AL_OPT_LF BIT(2) +#define AL_OPT_LF_X_SLICE BIT(3) +#define AL_OPT_LF_X_TILE BIT(4) +#define AL_OPT_SCL_LST BIT(5) +#define AL_OPT_CONST_INTRA_PRED BIT(6) +#define AL_OPT_QP_TAB_RELATIVE BIT(7) +#define AL_OPT_FIX_PREDICTOR BIT(8) +#define AL_OPT_CUSTOM_LDA BIT(9) +#define AL_OPT_ENABLE_AUTO_QP BIT(10) +#define AL_OPT_ADAPT_AUTO_QP BIT(11) +#define AL_OPT_TRANSFO_SKIP BIT(13) +#define AL_OPT_FORCE_REC BIT(15) +#define AL_OPT_FORCE_MV_OUT BIT(16) +#define AL_OPT_FORCE_MV_CLIP BIT(17) +#define AL_OPT_LOWLAT_SYNC BIT(18) +#define AL_OPT_LOWLAT_INT BIT(19) +#define AL_OPT_RDO_COST_MODE BIT(20) + + s8 beta_offset; + s8 tc_offset; + u16 reserved10; + u32 unknown11; + u32 unknown12; + u16 num_slices; + u16 prefetch_auto; + u32 prefetch_mem_offset; + u32 prefetch_mem_size; + u16 clip_hrz_range; + u16 clip_vrt_range; + u16 me_range[4]; + u8 max_cu_size; + u8 min_cu_size; + u8 max_tu_size; + u8 min_tu_size; + u8 max_transfo_depth_inter; + u8 max_transfo_depth_intra; + u16 reserved20; + u32 entropy_mode; + u32 wp_mode; + + /* rate control param */ + u32 rate_control_mode; + u32 initial_rem_delay; + u32 cpb_size; + u16 framerate; + u16 clk_ratio; + u32 target_bitrate; + u32 max_bitrate; + u16 initial_qp; + u16 min_qp; + u16 max_qp; + s16 ip_delta; + s16 pb_delta; + u16 golden_ref; + u16 golden_delta; + u16 golden_ref_frequency; + u32 rate_control_option; + + /* gop param */ + u32 gop_ctrl_mode; + u32 freq_ird; + u32 freq_lt; + u32 gdr_mode; + u32 gop_length; + u32 unknown39; + + u32 subframe_latency; + u32 lda_control_mode; +} __attribute__ ((__packed__)); + +struct mcu_msg_create_channel_response { + struct mcu_msg_header header; + u32 channel_id; + u32 user_id; + u32 options; + u32 num_core; + u32 pps_param; + u32 int_buffers_count; + u32 int_buffers_size; + u32 rec_buffers_count; + u32 rec_buffers_size; + u32 reserved; + u32 error_code; +} __attribute__ ((__packed__)); + +struct mcu_msg_destroy_channel { + struct mcu_msg_header header; + u32 channel_id; +} __attribute__ ((__packed__)); + +struct mcu_msg_destroy_channel_response { + struct mcu_msg_header header; + u32 channel_id; +} __attribute__ ((__packed__)); + +struct mcu_msg_push_buffers_internal_buffer { + u32 dma_addr; + u32 mcu_addr; + u32 size; +} __attribute__ ((__packed__)); + +struct mcu_msg_push_buffers_internal { + struct mcu_msg_header header; + u32 channel_id; + struct mcu_msg_push_buffers_internal_buffer buffer[0]; +} __attribute__ ((__packed__)); + +struct mcu_msg_put_stream_buffer { + struct mcu_msg_header header; + u32 channel_id; + u32 dma_addr; + u32 mcu_addr; + u32 size; + u32 offset; + u64 stream_id; +} __attribute__ ((__packed__)); + +struct mcu_msg_encode_frame { + struct mcu_msg_header header; + u32 channel_id; + u32 reserved; + + u32 encoding_options; +#define AL_OPT_USE_QP_TABLE BIT(0) +#define AL_OPT_FORCE_LOAD BIT(1) +#define AL_OPT_USE_L2 BIT(2) +#define AL_OPT_DISABLE_INTRA BIT(3) +#define AL_OPT_DEPENDENT_SLICES BIT(4) + + s16 pps_qp; + u16 padding; + u64 user_param; + u64 src_handle; + + u32 request_options; +#define AL_OPT_SCENE_CHANGE BIT(0) +#define AL_OPT_RESTART_GOP BIT(1) +#define AL_OPT_USE_LONG_TERM BIT(2) +#define AL_OPT_UPDATE_PARAMS BIT(3) + + /* u32 scene_change_delay (optional) */ + /* rate control param (optional) */ + /* gop param (optional) */ + u32 src_y; + u32 src_uv; + u32 stride; + u32 ep2; + u64 ep2_v; +} __attribute__ ((__packed__)); + +struct mcu_msg_encode_frame_response { + struct mcu_msg_header header; + u32 channel_id; + u64 stream_id; /* see mcu_msg_put_stream_buffer */ + u64 user_param; /* see mcu_msg_encode_frame */ + u64 src_handle; /* see mcu_msg_encode_frame */ + u16 skip; + u16 is_ref; + u32 initial_removal_delay; + u32 dpb_output_delay; + u32 size; + u32 frame_tag_size; + s32 stuffing; + s32 filler; + u16 num_column; + u16 num_row; + u16 qp; + u8 num_ref_idx_l0; + u8 num_ref_idx_l1; + u32 partition_table_offset; + s32 partition_table_size; + u32 sum_complex; + s32 tile_width[4]; + s32 tile_height[22]; + u32 error_code; + + u32 slice_type; +#define AL_ENC_SLICE_TYPE_B 0 +#define AL_ENC_SLICE_TYPE_P 1 +#define AL_ENC_SLICE_TYPE_I 2 + + u32 pic_struct; + u8 is_idr; + u8 is_first_slice; + u8 is_last_slice; + u8 reserved; + u16 pps_qp; + u16 reserved1; + u32 reserved2; +} __attribute__ ((__packed__)); + +union mcu_msg_response { + struct mcu_msg_header header; + struct mcu_msg_init_response init; + struct mcu_msg_create_channel_response create_channel; + struct mcu_msg_destroy_channel_response destroy_channel; + struct mcu_msg_encode_frame_response encode_frame; +}; + +/* Helper functions for channel and user operations */ + +static unsigned long allegro_next_user_id(struct allegro_dev *dev) +{ + if (dev->channel_user_ids == ~0UL) + return -EBUSY; + + return ffz(dev->channel_user_ids); +} + +static struct allegro_channel * +allegro_find_channel_by_user_id(struct allegro_dev *dev, + unsigned int user_id) +{ + struct allegro_channel *channel; + + list_for_each_entry(channel, &dev->channels, list) { + if (channel->user_id == user_id) + return channel; + } + + return ERR_PTR(-EINVAL); +} + +static struct allegro_channel * +allegro_find_channel_by_channel_id(struct allegro_dev *dev, + unsigned int channel_id) +{ + struct allegro_channel *channel; + + list_for_each_entry(channel, &dev->channels, list) { + if (channel->mcu_channel_id == channel_id) + return channel; + } + + return ERR_PTR(-EINVAL); +} + +static inline bool channel_exists(struct allegro_channel *channel) +{ + return channel->mcu_channel_id != -1; +} + +static unsigned int estimate_stream_size(unsigned int width, + unsigned int height) +{ + unsigned int offset = ENCODER_STREAM_OFFSET; + unsigned int num_blocks = DIV_ROUND_UP(width, SIZE_MACROBLOCK) * + DIV_ROUND_UP(height, SIZE_MACROBLOCK); + unsigned int pcm_size = SZ_256; + unsigned int partition_table = SZ_256; + + return round_up(offset + num_blocks * pcm_size + partition_table, 32); +} + +static enum v4l2_mpeg_video_h264_level +select_minimum_h264_level(unsigned int width, unsigned int height) +{ + unsigned int pic_width_in_mb = DIV_ROUND_UP(width, SIZE_MACROBLOCK); + unsigned int frame_height_in_mb = DIV_ROUND_UP(height, SIZE_MACROBLOCK); + unsigned int frame_size_in_mb = pic_width_in_mb * frame_height_in_mb; + enum v4l2_mpeg_video_h264_level level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; + + /* + * The level limits are specified in Rec. ITU-T H.264 Annex A.3.1 and + * also specify limits regarding bit rate and CBP size. Only approximate + * the levels using the frame size. + * + * Level 5.1 allows up to 4k video resolution. + */ + if (frame_size_in_mb <= 99) + level = V4L2_MPEG_VIDEO_H264_LEVEL_1_0; + else if (frame_size_in_mb <= 396) + level = V4L2_MPEG_VIDEO_H264_LEVEL_1_1; + else if (frame_size_in_mb <= 792) + level = V4L2_MPEG_VIDEO_H264_LEVEL_2_1; + else if (frame_size_in_mb <= 1620) + level = V4L2_MPEG_VIDEO_H264_LEVEL_2_2; + else if (frame_size_in_mb <= 3600) + level = V4L2_MPEG_VIDEO_H264_LEVEL_3_1; + else if (frame_size_in_mb <= 5120) + level = V4L2_MPEG_VIDEO_H264_LEVEL_3_2; + else if (frame_size_in_mb <= 8192) + level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; + else if (frame_size_in_mb <= 8704) + level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2; + else if (frame_size_in_mb <= 22080) + level = V4L2_MPEG_VIDEO_H264_LEVEL_5_0; + else + level = V4L2_MPEG_VIDEO_H264_LEVEL_5_1; + + return level; +} + +static unsigned int maximum_bitrate(enum v4l2_mpeg_video_h264_level level) +{ + switch (level) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + return 64000; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + return 128000; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + return 192000; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + return 384000; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + return 768000; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + return 2000000; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + return 4000000; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + return 4000000; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + return 10000000; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + return 14000000; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + return 20000000; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + return 20000000; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + return 50000000; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + return 50000000; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + return 135000000; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + default: + return 240000000; + } +} + +static unsigned int maximum_cpb_size(enum v4l2_mpeg_video_h264_level level) +{ + switch (level) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + return 175; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + return 350; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + return 500; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + return 1000; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + return 2000; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + return 2000; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + return 4000; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + return 4000; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + return 10000; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + return 14000; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + return 20000; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + return 25000; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + return 62500; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + return 62500; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + return 135000; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + default: + return 240000; + } +} + +static const struct fw_info * +allegro_get_firmware_info(struct allegro_dev *dev, + const struct firmware *fw, + const struct firmware *fw_codec) +{ + int i; + unsigned int id = fw->size; + unsigned int id_codec = fw_codec->size; + + for (i = 0; i < ARRAY_SIZE(supported_firmware); i++) + if (supported_firmware[i].id == id && + supported_firmware[i].id_codec == id_codec) + return &supported_firmware[i]; + + return NULL; +} + +/* + * Buffers that are used internally by the MCU. + */ + +static int allegro_alloc_buffer(struct allegro_dev *dev, + struct allegro_buffer *buffer, size_t size) +{ + buffer->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, + &buffer->paddr, GFP_KERNEL); + if (!buffer->vaddr) + return -ENOMEM; + buffer->size = size; + + return 0; +} + +static void allegro_free_buffer(struct allegro_dev *dev, + struct allegro_buffer *buffer) +{ + if (buffer->vaddr) { + dma_free_coherent(&dev->plat_dev->dev, buffer->size, + buffer->vaddr, buffer->paddr); + buffer->vaddr = NULL; + buffer->size = 0; + } +} + +/* + * Mailbox interface to send messages to the MCU. + */ + +static int allegro_mbox_init(struct allegro_dev *dev, + struct allegro_mbox *mbox, + unsigned int base, size_t size) +{ + if (!mbox) + return -EINVAL; + + mbox->head = base; + mbox->tail = base + 0x4; + mbox->data = base + 0x8; + mbox->size = size; + mutex_init(&mbox->lock); + + regmap_write(dev->sram, mbox->head, 0); + regmap_write(dev->sram, mbox->tail, 0); + + return 0; +} + +static int allegro_mbox_write(struct allegro_dev *dev, + struct allegro_mbox *mbox, void *src, size_t size) +{ + struct mcu_msg_header *header = src; + unsigned int tail; + size_t size_no_wrap; + int err = 0; + + if (!src) + return -EINVAL; + + if (size > mbox->size) { + v4l2_err(&dev->v4l2_dev, + "message (%zu bytes) to large for mailbox (%zu bytes)\n", + size, mbox->size); + return -EINVAL; + } + + if (header->length != size - sizeof(*header)) { + v4l2_err(&dev->v4l2_dev, + "invalid message length: %u bytes (expected %zu bytes)\n", + header->length, size - sizeof(*header)); + return -EINVAL; + } + + v4l2_dbg(2, debug, &dev->v4l2_dev, + "write command message: type %s, body length %d\n", + msg_type_name(header->type), header->length); + + mutex_lock(&mbox->lock); + regmap_read(dev->sram, mbox->tail, &tail); + if (tail > mbox->size) { + v4l2_err(&dev->v4l2_dev, + "invalid tail (0x%x): must be smaller than mailbox size (0x%zx)\n", + tail, mbox->size); + err = -EIO; + goto out; + } + size_no_wrap = min(size, mbox->size - (size_t)tail); + regmap_bulk_write(dev->sram, mbox->data + tail, src, size_no_wrap / 4); + regmap_bulk_write(dev->sram, mbox->data, + src + size_no_wrap, (size - size_no_wrap) / 4); + regmap_write(dev->sram, mbox->tail, (tail + size) % mbox->size); + +out: + mutex_unlock(&mbox->lock); + + return err; +} + +static ssize_t allegro_mbox_read(struct allegro_dev *dev, + struct allegro_mbox *mbox, + void *dst, size_t nbyte) +{ + struct mcu_msg_header *header; + unsigned int head; + ssize_t size; + size_t body_no_wrap; + + regmap_read(dev->sram, mbox->head, &head); + if (head > mbox->size) { + v4l2_err(&dev->v4l2_dev, + "invalid head (0x%x): must be smaller than mailbox size (0x%zx)\n", + head, mbox->size); + return -EIO; + } + + /* Assume that the header does not wrap. */ + regmap_bulk_read(dev->sram, mbox->data + head, + dst, sizeof(*header) / 4); + header = dst; + size = header->length + sizeof(*header); + if (size > mbox->size || size & 0x3) { + v4l2_err(&dev->v4l2_dev, + "invalid message length: %zu bytes (maximum %zu bytes)\n", + header->length + sizeof(*header), mbox->size); + return -EIO; + } + if (size > nbyte) { + v4l2_err(&dev->v4l2_dev, + "destination buffer too small: %zu bytes (need %zu bytes)\n", + nbyte, size); + return -EINVAL; + } + + /* + * The message might wrap within the mailbox. If the message does not + * wrap, the first read will read the entire message, otherwise the + * first read will read message until the end of the mailbox and the + * second read will read the remaining bytes from the beginning of the + * mailbox. + * + * Skip the header, as was already read to get the size of the body. + */ + body_no_wrap = min((size_t)header->length, + (size_t)(mbox->size - (head + sizeof(*header)))); + regmap_bulk_read(dev->sram, mbox->data + head + sizeof(*header), + dst + sizeof(*header), body_no_wrap / 4); + regmap_bulk_read(dev->sram, mbox->data, + dst + sizeof(*header) + body_no_wrap, + (header->length - body_no_wrap) / 4); + + regmap_write(dev->sram, mbox->head, (head + size) % mbox->size); + + v4l2_dbg(2, debug, &dev->v4l2_dev, + "read status message: type %s, body length %d\n", + msg_type_name(header->type), header->length); + + return size; +} + +static void allegro_mcu_interrupt(struct allegro_dev *dev) +{ + regmap_write(dev->regmap, AL5_MCU_INTERRUPT, BIT(0)); +} + +static void allegro_mcu_send_init(struct allegro_dev *dev, + dma_addr_t suballoc_dma, size_t suballoc_size) +{ + struct mcu_msg_init_request msg; + + memset(&msg, 0, sizeof(msg)); + + msg.header.type = MCU_MSG_TYPE_INIT; + msg.header.length = sizeof(msg) - sizeof(msg.header); + + msg.suballoc_dma = lower_32_bits(suballoc_dma) | MCU_CACHE_OFFSET; + msg.suballoc_size = suballoc_size; + + /* disable L2 cache */ + msg.l2_cache[0] = -1; + msg.l2_cache[1] = -1; + msg.l2_cache[2] = -1; + + allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg)); + allegro_mcu_interrupt(dev); +} + +static u32 v4l2_pixelformat_to_mcu_format(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_NV12: + /* AL_420_8BITS: 0x100 -> NV12, 0x88 -> 8 bit */ + return 0x100 | 0x88; + default: + return -EINVAL; + } +} + +static u32 v4l2_colorspace_to_mcu_colorspace(enum v4l2_colorspace colorspace) +{ + switch (colorspace) { + case V4L2_COLORSPACE_REC709: + return 2; + case V4L2_COLORSPACE_SMPTE170M: + return 3; + case V4L2_COLORSPACE_SMPTE240M: + return 4; + case V4L2_COLORSPACE_SRGB: + return 7; + default: + /* UNKNOWN */ + return 0; + } +} + +static s8 v4l2_pixelformat_to_mcu_codec(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_H264: + default: + return 1; + } +} + +static u8 v4l2_profile_to_mcu_profile(enum v4l2_mpeg_video_h264_profile profile) +{ + switch (profile) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + default: + return 66; + } +} + +static u16 v4l2_level_to_mcu_level(enum v4l2_mpeg_video_h264_level level) +{ + switch (level) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + return 10; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + return 11; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + return 12; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + return 13; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + return 20; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + return 21; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + return 22; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + return 30; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + return 31; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + return 32; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + return 40; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + return 41; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + return 42; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + return 50; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + default: + return 51; + } +} + +static u32 +v4l2_bitrate_mode_to_mcu_mode(enum v4l2_mpeg_video_bitrate_mode mode) +{ + switch (mode) { + case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR: + return 2; + case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR: + default: + return 1; + } +} + +static int allegro_mcu_send_create_channel(struct allegro_dev *dev, + struct allegro_channel *channel) +{ + struct mcu_msg_create_channel msg; + + memset(&msg, 0, sizeof(msg)); + + msg.header.type = MCU_MSG_TYPE_CREATE_CHANNEL; + msg.header.length = sizeof(msg) - sizeof(msg.header); + + msg.user_id = channel->user_id; + msg.width = channel->width; + msg.height = channel->height; + msg.format = v4l2_pixelformat_to_mcu_format(channel->pixelformat); + msg.colorspace = v4l2_colorspace_to_mcu_colorspace(channel->colorspace); + msg.src_mode = 0x0; + msg.profile = v4l2_profile_to_mcu_profile(channel->profile); + msg.constraint_set_flags = BIT(1); + msg.codec = v4l2_pixelformat_to_mcu_codec(channel->codec); + msg.level = v4l2_level_to_mcu_level(channel->level); + msg.tier = 0; + msg.sps_param = BIT(20) | 0x4a; + msg.pps_param = BIT(2); + msg.enc_option = AL_OPT_RDO_COST_MODE | AL_OPT_LF_X_TILE | + AL_OPT_LF_X_SLICE | AL_OPT_LF; + msg.beta_offset = -1; + msg.tc_offset = -1; + msg.num_slices = 1; + msg.me_range[0] = 8; + msg.me_range[1] = 8; + msg.me_range[2] = 16; + msg.me_range[3] = 16; + msg.max_cu_size = ilog2(SIZE_MACROBLOCK); + msg.min_cu_size = ilog2(8); + msg.max_tu_size = 2; + msg.min_tu_size = 2; + msg.max_transfo_depth_intra = 1; + msg.max_transfo_depth_inter = 1; + + msg.rate_control_mode = + v4l2_bitrate_mode_to_mcu_mode(channel->bitrate_mode); + /* Shall be ]0;cpb_size in 90 kHz units]. Use maximum value. */ + msg.initial_rem_delay = + ((channel->cpb_size * 1000) / channel->bitrate_peak) * 90000; + /* Encoder expects cpb_size in units of a 90 kHz clock. */ + msg.cpb_size = + ((channel->cpb_size * 1000) / channel->bitrate_peak) * 90000; + msg.framerate = 25; + msg.clk_ratio = 1000; + msg.target_bitrate = channel->bitrate; + msg.max_bitrate = channel->bitrate_peak; + msg.initial_qp = 25; + msg.min_qp = 10; + msg.max_qp = 51; + msg.ip_delta = -1; + msg.pb_delta = -1; + msg.golden_ref = 0; + msg.golden_delta = 2; + msg.golden_ref_frequency = 10; + msg.rate_control_option = 0x00000000; + + msg.gop_ctrl_mode = 0x00000000; + msg.freq_ird = 0x7fffffff; + msg.freq_lt = 0; + msg.gdr_mode = 0x00000000; + msg.gop_length = channel->gop_size; + msg.subframe_latency = 0x00000000; + msg.lda_control_mode = 0x700d0000; + + allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg)); + allegro_mcu_interrupt(dev); + + return 0; +} + +static int allegro_mcu_send_destroy_channel(struct allegro_dev *dev, + struct allegro_channel *channel) +{ + struct mcu_msg_destroy_channel msg; + + memset(&msg, 0, sizeof(msg)); + + msg.header.type = MCU_MSG_TYPE_DESTROY_CHANNEL; + msg.header.length = sizeof(msg) - sizeof(msg.header); + + msg.channel_id = channel->mcu_channel_id; + + allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg)); + allegro_mcu_interrupt(dev); + + return 0; +} + +static int allegro_mcu_send_put_stream_buffer(struct allegro_dev *dev, + struct allegro_channel *channel, + dma_addr_t paddr, + unsigned long size) +{ + struct mcu_msg_put_stream_buffer msg; + + memset(&msg, 0, sizeof(msg)); + + msg.header.type = MCU_MSG_TYPE_PUT_STREAM_BUFFER; + msg.header.length = sizeof(msg) - sizeof(msg.header); + + msg.channel_id = channel->mcu_channel_id; + msg.dma_addr = paddr; + msg.mcu_addr = paddr | MCU_CACHE_OFFSET; + msg.size = size; + msg.offset = ENCODER_STREAM_OFFSET; + msg.stream_id = 0; /* copied to mcu_msg_encode_frame_response */ + + allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg)); + allegro_mcu_interrupt(dev); + + return 0; +} + +static int allegro_mcu_send_encode_frame(struct allegro_dev *dev, + struct allegro_channel *channel, + dma_addr_t src_y, dma_addr_t src_uv) +{ + struct mcu_msg_encode_frame msg; + + memset(&msg, 0, sizeof(msg)); + + msg.header.type = MCU_MSG_TYPE_ENCODE_FRAME; + msg.header.length = sizeof(msg) - sizeof(msg.header); + + msg.channel_id = channel->mcu_channel_id; + msg.encoding_options = AL_OPT_FORCE_LOAD; + msg.pps_qp = 26; /* qp are relative to 26 */ + msg.user_param = 0; /* copied to mcu_msg_encode_frame_response */ + msg.src_handle = 0; /* copied to mcu_msg_encode_frame_response */ + msg.src_y = src_y; + msg.src_uv = src_uv; + msg.stride = channel->stride; + msg.ep2 = 0x0; + msg.ep2_v = msg.ep2 | MCU_CACHE_OFFSET; + + allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg)); + allegro_mcu_interrupt(dev); + + return 0; +} + +static int allegro_mcu_wait_for_init_timeout(struct allegro_dev *dev, + unsigned long timeout_ms) +{ + unsigned long tmo; + + tmo = wait_for_completion_timeout(&dev->init_complete, + msecs_to_jiffies(timeout_ms)); + if (tmo == 0) + return -ETIMEDOUT; + + reinit_completion(&dev->init_complete); + return 0; +} + +static int allegro_mcu_push_buffer_internal(struct allegro_channel *channel, + enum mcu_msg_type type) +{ + struct allegro_dev *dev = channel->dev; + struct mcu_msg_push_buffers_internal *msg; + struct mcu_msg_push_buffers_internal_buffer *buffer; + unsigned int num_buffers = 0; + size_t size; + struct allegro_buffer *al_buffer; + struct list_head *list; + int err; + + switch (type) { + case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE: + list = &channel->buffers_reference; + break; + case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE: + list = &channel->buffers_intermediate; + break; + default: + return -EINVAL; + } + + list_for_each_entry(al_buffer, list, head) + num_buffers++; + size = struct_size(msg, buffer, num_buffers); + + msg = kmalloc(size, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->header.length = size - sizeof(msg->header); + msg->header.type = type; + msg->channel_id = channel->mcu_channel_id; + + buffer = msg->buffer; + list_for_each_entry(al_buffer, list, head) { + buffer->dma_addr = lower_32_bits(al_buffer->paddr); + buffer->mcu_addr = + lower_32_bits(al_buffer->paddr) | MCU_CACHE_OFFSET; + buffer->size = al_buffer->size; + buffer++; + } + + err = allegro_mbox_write(dev, &dev->mbox_command, msg, size); + if (err) + goto out; + allegro_mcu_interrupt(dev); + +out: + kfree(msg); + return err; +} + +static int allegro_mcu_push_buffer_intermediate(struct allegro_channel *channel) +{ + enum mcu_msg_type type = MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE; + + return allegro_mcu_push_buffer_internal(channel, type); +} + +static int allegro_mcu_push_buffer_reference(struct allegro_channel *channel) +{ + enum mcu_msg_type type = MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE; + + return allegro_mcu_push_buffer_internal(channel, type); +} + +static int allocate_buffers_internal(struct allegro_channel *channel, + struct list_head *list, + size_t n, size_t size) +{ + struct allegro_dev *dev = channel->dev; + unsigned int i; + int err; + struct allegro_buffer *buffer, *tmp; + + for (i = 0; i < n; i++) { + buffer = kmalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) { + err = -ENOMEM; + goto err; + } + INIT_LIST_HEAD(&buffer->head); + + err = allegro_alloc_buffer(dev, buffer, size); + if (err) + goto err; + list_add(&buffer->head, list); + } + + return 0; + +err: + list_for_each_entry_safe(buffer, tmp, list, head) { + list_del(&buffer->head); + allegro_free_buffer(dev, buffer); + kfree(buffer); + } + return err; +} + +static void destroy_buffers_internal(struct allegro_channel *channel, + struct list_head *list) +{ + struct allegro_dev *dev = channel->dev; + struct allegro_buffer *buffer, *tmp; + + list_for_each_entry_safe(buffer, tmp, list, head) { + list_del(&buffer->head); + allegro_free_buffer(dev, buffer); + kfree(buffer); + } +} + +static void destroy_reference_buffers(struct allegro_channel *channel) +{ + return destroy_buffers_internal(channel, &channel->buffers_reference); +} + +static void destroy_intermediate_buffers(struct allegro_channel *channel) +{ + return destroy_buffers_internal(channel, + &channel->buffers_intermediate); +} + +static int allocate_intermediate_buffers(struct allegro_channel *channel, + size_t n, size_t size) +{ + return allocate_buffers_internal(channel, + &channel->buffers_intermediate, + n, size); +} + +static int allocate_reference_buffers(struct allegro_channel *channel, + size_t n, size_t size) +{ + return allocate_buffers_internal(channel, + &channel->buffers_reference, + n, PAGE_ALIGN(size)); +} + +static ssize_t allegro_h264_write_sps(struct allegro_channel *channel, + void *dest, size_t n) +{ + struct allegro_dev *dev = channel->dev; + struct nal_h264_sps *sps; + ssize_t size; + unsigned int size_mb = SIZE_MACROBLOCK; + /* Calculation of crop units in Rec. ITU-T H.264 (04/2017) p. 76 */ + unsigned int crop_unit_x = 2; + unsigned int crop_unit_y = 2; + + sps = kzalloc(sizeof(*sps), GFP_KERNEL); + if (!sps) + return -ENOMEM; + + sps->profile_idc = nal_h264_profile_from_v4l2(channel->profile); + sps->constraint_set0_flag = 0; + sps->constraint_set1_flag = 1; + sps->constraint_set2_flag = 0; + sps->constraint_set3_flag = 0; + sps->constraint_set4_flag = 0; + sps->constraint_set5_flag = 0; + sps->level_idc = nal_h264_level_from_v4l2(channel->level); + sps->seq_parameter_set_id = 0; + sps->log2_max_frame_num_minus4 = 0; + sps->pic_order_cnt_type = 0; + sps->log2_max_pic_order_cnt_lsb_minus4 = 6; + sps->max_num_ref_frames = 3; + sps->gaps_in_frame_num_value_allowed_flag = 0; + sps->pic_width_in_mbs_minus1 = + DIV_ROUND_UP(channel->width, size_mb) - 1; + sps->pic_height_in_map_units_minus1 = + DIV_ROUND_UP(channel->height, size_mb) - 1; + sps->frame_mbs_only_flag = 1; + sps->mb_adaptive_frame_field_flag = 0; + sps->direct_8x8_inference_flag = 1; + sps->frame_cropping_flag = + (channel->width % size_mb) || (channel->height % size_mb); + if (sps->frame_cropping_flag) { + sps->crop_left = 0; + sps->crop_right = (round_up(channel->width, size_mb) - channel->width) / crop_unit_x; + sps->crop_top = 0; + sps->crop_bottom = (round_up(channel->height, size_mb) - channel->height) / crop_unit_y; + } + sps->vui_parameters_present_flag = 1; + sps->vui.aspect_ratio_info_present_flag = 0; + sps->vui.overscan_info_present_flag = 0; + sps->vui.video_signal_type_present_flag = 1; + sps->vui.video_format = 1; + sps->vui.video_full_range_flag = 0; + sps->vui.colour_description_present_flag = 1; + sps->vui.colour_primaries = 5; + sps->vui.transfer_characteristics = 5; + sps->vui.matrix_coefficients = 5; + sps->vui.chroma_loc_info_present_flag = 1; + sps->vui.chroma_sample_loc_type_top_field = 0; + sps->vui.chroma_sample_loc_type_bottom_field = 0; + sps->vui.timing_info_present_flag = 1; + sps->vui.num_units_in_tick = 1; + sps->vui.time_scale = 50; + sps->vui.fixed_frame_rate_flag = 1; + sps->vui.nal_hrd_parameters_present_flag = 0; + sps->vui.vcl_hrd_parameters_present_flag = 1; + sps->vui.vcl_hrd_parameters.cpb_cnt_minus1 = 0; + sps->vui.vcl_hrd_parameters.bit_rate_scale = 0; + sps->vui.vcl_hrd_parameters.cpb_size_scale = 1; + /* See Rec. ITU-T H.264 (04/2017) p. 410 E-53 */ + sps->vui.vcl_hrd_parameters.bit_rate_value_minus1[0] = + channel->bitrate_peak / (1 << (6 + sps->vui.vcl_hrd_parameters.bit_rate_scale)) - 1; + /* See Rec. ITU-T H.264 (04/2017) p. 410 E-54 */ + sps->vui.vcl_hrd_parameters.cpb_size_value_minus1[0] = + (channel->cpb_size * 1000) / (1 << (4 + sps->vui.vcl_hrd_parameters.cpb_size_scale)) - 1; + sps->vui.vcl_hrd_parameters.cbr_flag[0] = 1; + sps->vui.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1 = 31; + sps->vui.vcl_hrd_parameters.cpb_removal_delay_length_minus1 = 31; + sps->vui.vcl_hrd_parameters.dpb_output_delay_length_minus1 = 31; + sps->vui.vcl_hrd_parameters.time_offset_length = 0; + sps->vui.low_delay_hrd_flag = 0; + sps->vui.pic_struct_present_flag = 1; + sps->vui.bitstream_restriction_flag = 0; + + size = nal_h264_write_sps(&dev->plat_dev->dev, dest, n, sps); + + kfree(sps); + + return size; +} + +static ssize_t allegro_h264_write_pps(struct allegro_channel *channel, + void *dest, size_t n) +{ + struct allegro_dev *dev = channel->dev; + struct nal_h264_pps *pps; + ssize_t size; + + pps = kzalloc(sizeof(*pps), GFP_KERNEL); + if (!pps) + return -ENOMEM; + + pps->pic_parameter_set_id = 0; + pps->seq_parameter_set_id = 0; + pps->entropy_coding_mode_flag = 0; + pps->bottom_field_pic_order_in_frame_present_flag = 0; + pps->num_slice_groups_minus1 = 0; + pps->num_ref_idx_l0_default_active_minus1 = 2; + pps->num_ref_idx_l1_default_active_minus1 = 2; + pps->weighted_pred_flag = 0; + pps->weighted_bipred_idc = 0; + pps->pic_init_qp_minus26 = 0; + pps->pic_init_qs_minus26 = 0; + pps->chroma_qp_index_offset = 0; + pps->deblocking_filter_control_present_flag = 1; + pps->constrained_intra_pred_flag = 0; + pps->redundant_pic_cnt_present_flag = 0; + pps->transform_8x8_mode_flag = 0; + pps->pic_scaling_matrix_present_flag = 0; + pps->second_chroma_qp_index_offset = 0; + + size = nal_h264_write_pps(&dev->plat_dev->dev, dest, n, pps); + + kfree(pps); + + return size; +} + +static bool allegro_channel_is_at_eos(struct allegro_channel *channel) +{ + bool is_at_eos = false; + + switch (allegro_get_state(channel)) { + case ALLEGRO_STATE_STOPPED: + is_at_eos = true; + break; + case ALLEGRO_STATE_DRAIN: + case ALLEGRO_STATE_WAIT_FOR_BUFFER: + if (v4l2_m2m_num_src_bufs_ready(channel->fh.m2m_ctx) == 0) + is_at_eos = true; + break; + default: + break; + } + + return is_at_eos; +} + +static void allegro_channel_buf_done(struct allegro_channel *channel, + struct vb2_v4l2_buffer *buf, + enum vb2_buffer_state state) +{ + const struct v4l2_event eos_event = { + .type = V4L2_EVENT_EOS + }; + + if (allegro_channel_is_at_eos(channel)) { + buf->flags |= V4L2_BUF_FLAG_LAST; + v4l2_event_queue_fh(&channel->fh, &eos_event); + + allegro_set_state(channel, ALLEGRO_STATE_STOPPED); + } + + v4l2_m2m_buf_done(buf, state); +} + +static void allegro_channel_finish_frame(struct allegro_channel *channel, + struct mcu_msg_encode_frame_response *msg) +{ + struct allegro_dev *dev = channel->dev; + struct vb2_v4l2_buffer *src_buf; + struct vb2_v4l2_buffer *dst_buf; + struct { + u32 offset; + u32 size; + } *partition; + enum vb2_buffer_state state = VB2_BUF_STATE_ERROR; + char *curr; + ssize_t len; + ssize_t free; + + src_buf = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx); + + dst_buf = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx); + dst_buf->sequence = channel->csequence++; + + if (msg->error_code) { + v4l2_err(&dev->v4l2_dev, + "channel %d: error while encoding frame: %x\n", + channel->mcu_channel_id, msg->error_code); + goto err; + } + + if (msg->partition_table_size != 1) { + v4l2_warn(&dev->v4l2_dev, + "channel %d: only handling first partition table entry (%d entries)\n", + channel->mcu_channel_id, msg->partition_table_size); + } + + if (msg->partition_table_offset + + msg->partition_table_size * sizeof(*partition) > + vb2_plane_size(&dst_buf->vb2_buf, 0)) { + v4l2_err(&dev->v4l2_dev, + "channel %d: partition table outside of dst_buf\n", + channel->mcu_channel_id); + goto err; + } + + partition = + vb2_plane_vaddr(&dst_buf->vb2_buf, 0) + msg->partition_table_offset; + if (partition->offset + partition->size > + vb2_plane_size(&dst_buf->vb2_buf, 0)) { + v4l2_err(&dev->v4l2_dev, + "channel %d: encoded frame is outside of dst_buf (offset 0x%x, size 0x%x)\n", + channel->mcu_channel_id, partition->offset, + partition->size); + goto err; + } + + v4l2_dbg(2, debug, &dev->v4l2_dev, + "channel %d: encoded frame of size %d is at offset 0x%x\n", + channel->mcu_channel_id, partition->size, partition->offset); + + /* + * The payload must include the data before the partition offset, + * because we will put the sps and pps data there. + */ + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, + partition->offset + partition->size); + + curr = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); + free = partition->offset; + if (msg->is_idr) { + len = allegro_h264_write_sps(channel, curr, free); + if (len < 0) { + v4l2_err(&dev->v4l2_dev, + "not enough space for sequence parameter set: %zd left\n", + free); + goto err; + } + curr += len; + free -= len; + v4l2_dbg(1, debug, &dev->v4l2_dev, + "channel %d: wrote %zd byte SPS nal unit\n", + channel->mcu_channel_id, len); + } + + if (msg->slice_type == AL_ENC_SLICE_TYPE_I) { + len = allegro_h264_write_pps(channel, curr, free); + if (len < 0) { + v4l2_err(&dev->v4l2_dev, + "not enough space for picture parameter set: %zd left\n", + free); + goto err; + } + curr += len; + free -= len; + v4l2_dbg(1, debug, &dev->v4l2_dev, + "channel %d: wrote %zd byte PPS nal unit\n", + channel->mcu_channel_id, len); + } + + len = nal_h264_write_filler(&dev->plat_dev->dev, curr, free); + if (len < 0) { + v4l2_err(&dev->v4l2_dev, + "failed to write %zd filler data\n", free); + goto err; + } + curr += len; + free -= len; + v4l2_dbg(2, debug, &dev->v4l2_dev, + "channel %d: wrote %zd bytes filler nal unit\n", + channel->mcu_channel_id, len); + + if (free != 0) { + v4l2_err(&dev->v4l2_dev, + "non-VCL NAL units do not fill space until VCL NAL unit: %zd bytes left\n", + free); + goto err; + } + + state = VB2_BUF_STATE_DONE; + + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); + if (msg->is_idr) + dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; + else + dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; + + v4l2_dbg(1, debug, &dev->v4l2_dev, + "channel %d: encoded frame #%03d (%s%s, %d bytes)\n", + channel->mcu_channel_id, + dst_buf->sequence, + msg->is_idr ? "IDR, " : "", + msg->slice_type == AL_ENC_SLICE_TYPE_I ? "I slice" : + msg->slice_type == AL_ENC_SLICE_TYPE_P ? "P slice" : "unknown", + partition->size); + +err: + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + + allegro_channel_buf_done(channel, dst_buf, state); + + v4l2_m2m_job_finish(dev->m2m_dev, channel->fh.m2m_ctx); +} + +static int allegro_handle_init(struct allegro_dev *dev, + struct mcu_msg_init_response *msg) +{ + complete(&dev->init_complete); + + return 0; +} + +static int +allegro_handle_create_channel(struct allegro_dev *dev, + struct mcu_msg_create_channel_response *msg) +{ + struct allegro_channel *channel; + int err = 0; + + channel = allegro_find_channel_by_user_id(dev, msg->user_id); + if (IS_ERR(channel)) { + v4l2_warn(&dev->v4l2_dev, + "received %s for unknown user %d\n", + msg_type_name(msg->header.type), + msg->user_id); + return -EINVAL; + } + + if (msg->error_code) { + v4l2_err(&dev->v4l2_dev, + "user %d: mcu failed to create channel: error %x\n", + channel->user_id, msg->error_code); + err = -EIO; + goto out; + } + + channel->mcu_channel_id = msg->channel_id; + v4l2_dbg(1, debug, &dev->v4l2_dev, + "user %d: channel has channel id %d\n", + channel->user_id, channel->mcu_channel_id); + + v4l2_dbg(1, debug, &dev->v4l2_dev, + "channel %d: intermediate buffers: %d x %d bytes\n", + channel->mcu_channel_id, + msg->int_buffers_count, msg->int_buffers_size); + err = allocate_intermediate_buffers(channel, msg->int_buffers_count, + msg->int_buffers_size); + if (err) { + v4l2_err(&dev->v4l2_dev, + "channel %d: failed to allocate intermediate buffers\n", + channel->mcu_channel_id); + goto out; + } + err = allegro_mcu_push_buffer_intermediate(channel); + if (err) + goto out; + + v4l2_dbg(1, debug, &dev->v4l2_dev, + "channel %d: reference buffers: %d x %d bytes\n", + channel->mcu_channel_id, + msg->rec_buffers_count, msg->rec_buffers_size); + err = allocate_reference_buffers(channel, msg->rec_buffers_count, + msg->rec_buffers_size); + if (err) { + v4l2_err(&dev->v4l2_dev, + "channel %d: failed to allocate reference buffers\n", + channel->mcu_channel_id); + goto out; + } + err = allegro_mcu_push_buffer_reference(channel); + if (err) + goto out; + +out: + channel->error = err; + complete(&channel->completion); + + /* Handled successfully, error is passed via channel->error */ + return 0; +} + +static int +allegro_handle_destroy_channel(struct allegro_dev *dev, + struct mcu_msg_destroy_channel_response *msg) +{ + struct allegro_channel *channel; + + channel = allegro_find_channel_by_channel_id(dev, msg->channel_id); + if (IS_ERR(channel)) { + v4l2_err(&dev->v4l2_dev, + "received %s for unknown channel %d\n", + msg_type_name(msg->header.type), + msg->channel_id); + return -EINVAL; + } + + v4l2_dbg(2, debug, &dev->v4l2_dev, + "user %d: vcu destroyed channel %d\n", + channel->user_id, channel->mcu_channel_id); + complete(&channel->completion); + + return 0; +} + +static int +allegro_handle_encode_frame(struct allegro_dev *dev, + struct mcu_msg_encode_frame_response *msg) +{ + struct allegro_channel *channel; + + channel = allegro_find_channel_by_channel_id(dev, msg->channel_id); + if (IS_ERR(channel)) { + v4l2_err(&dev->v4l2_dev, + "received %s for unknown channel %d\n", + msg_type_name(msg->header.type), + msg->channel_id); + return -EINVAL; + } + + allegro_channel_finish_frame(channel, msg); + + return 0; +} + +static int allegro_receive_message(struct allegro_dev *dev) +{ + union mcu_msg_response *msg; + ssize_t size; + int err = 0; + + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + size = allegro_mbox_read(dev, &dev->mbox_status, msg, sizeof(*msg)); + if (size < sizeof(msg->header)) { + v4l2_err(&dev->v4l2_dev, + "invalid mbox message (%zd): must be at least %zu\n", + size, sizeof(msg->header)); + err = -EINVAL; + goto out; + } + + switch (msg->header.type) { + case MCU_MSG_TYPE_INIT: + err = allegro_handle_init(dev, &msg->init); + break; + case MCU_MSG_TYPE_CREATE_CHANNEL: + err = allegro_handle_create_channel(dev, &msg->create_channel); + break; + case MCU_MSG_TYPE_DESTROY_CHANNEL: + err = allegro_handle_destroy_channel(dev, + &msg->destroy_channel); + break; + case MCU_MSG_TYPE_ENCODE_FRAME: + err = allegro_handle_encode_frame(dev, &msg->encode_frame); + break; + default: + v4l2_warn(&dev->v4l2_dev, + "%s: unknown message %s\n", + __func__, msg_type_name(msg->header.type)); + err = -EINVAL; + break; + } + +out: + kfree(msg); + + return err; +} + +static irqreturn_t allegro_hardirq(int irq, void *data) +{ + struct allegro_dev *dev = data; + unsigned int status; + + regmap_read(dev->regmap, AL5_ITC_CPU_IRQ_STA, &status); + if (!(status & AL5_ITC_CPU_IRQ_STA_TRIGGERED)) + return IRQ_NONE; + + regmap_write(dev->regmap, AL5_ITC_CPU_IRQ_CLR, status); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t allegro_irq_thread(int irq, void *data) +{ + struct allegro_dev *dev = data; + + allegro_receive_message(dev); + + return IRQ_HANDLED; +} + +static void allegro_copy_firmware(struct allegro_dev *dev, + const u8 * const buf, size_t size) +{ + int err = 0; + + v4l2_dbg(1, debug, &dev->v4l2_dev, + "copy mcu firmware (%zu B) to SRAM\n", size); + err = regmap_bulk_write(dev->sram, 0x0, buf, size / 4); + if (err) + v4l2_err(&dev->v4l2_dev, + "failed to copy firmware: %d\n", err); +} + +static void allegro_copy_fw_codec(struct allegro_dev *dev, + const u8 * const buf, size_t size) +{ + int err; + dma_addr_t icache_offset, dcache_offset; + + /* + * The downstream allocates 600 KB for the codec firmware to have some + * extra space for "possible extensions." My tests were fine with + * allocating just enough memory for the actual firmware, but I am not + * sure that the firmware really does not use the remaining space. + */ + err = allegro_alloc_buffer(dev, &dev->firmware, size); + if (err) { + v4l2_err(&dev->v4l2_dev, + "failed to allocate %zu bytes for firmware\n", size); + return; + } + + v4l2_dbg(1, debug, &dev->v4l2_dev, + "copy codec firmware (%zd B) to phys %pad\n", + size, &dev->firmware.paddr); + memcpy(dev->firmware.vaddr, buf, size); + + regmap_write(dev->regmap, AXI_ADDR_OFFSET_IP, + upper_32_bits(dev->firmware.paddr)); + + icache_offset = dev->firmware.paddr - MCU_CACHE_OFFSET; + v4l2_dbg(2, debug, &dev->v4l2_dev, + "icache_offset: msb = 0x%x, lsb = 0x%x\n", + upper_32_bits(icache_offset), lower_32_bits(icache_offset)); + regmap_write(dev->regmap, AL5_ICACHE_ADDR_OFFSET_MSB, + upper_32_bits(icache_offset)); + regmap_write(dev->regmap, AL5_ICACHE_ADDR_OFFSET_LSB, + lower_32_bits(icache_offset)); + + dcache_offset = + (dev->firmware.paddr & 0xffffffff00000000ULL) - MCU_CACHE_OFFSET; + v4l2_dbg(2, debug, &dev->v4l2_dev, + "dcache_offset: msb = 0x%x, lsb = 0x%x\n", + upper_32_bits(dcache_offset), lower_32_bits(dcache_offset)); + regmap_write(dev->regmap, AL5_DCACHE_ADDR_OFFSET_MSB, + upper_32_bits(dcache_offset)); + regmap_write(dev->regmap, AL5_DCACHE_ADDR_OFFSET_LSB, + lower_32_bits(dcache_offset)); +} + +static void allegro_free_fw_codec(struct allegro_dev *dev) +{ + allegro_free_buffer(dev, &dev->firmware); +} + +/* + * Control functions for the MCU + */ + +static int allegro_mcu_enable_interrupts(struct allegro_dev *dev) +{ + return regmap_write(dev->regmap, AL5_ITC_CPU_IRQ_MSK, BIT(0)); +} + +static int allegro_mcu_disable_interrupts(struct allegro_dev *dev) +{ + return regmap_write(dev->regmap, AL5_ITC_CPU_IRQ_MSK, 0); +} + +static int allegro_mcu_wait_for_sleep(struct allegro_dev *dev) +{ + unsigned long timeout; + unsigned int status; + + timeout = jiffies + msecs_to_jiffies(100); + while (regmap_read(dev->regmap, AL5_MCU_STA, &status) == 0 && + status != AL5_MCU_STA_SLEEP) { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + cpu_relax(); + } + + return 0; +} + +static int allegro_mcu_start(struct allegro_dev *dev) +{ + unsigned long timeout; + unsigned int status; + int err; + + err = regmap_write(dev->regmap, AL5_MCU_WAKEUP, BIT(0)); + if (err) + return err; + + timeout = jiffies + msecs_to_jiffies(100); + while (regmap_read(dev->regmap, AL5_MCU_STA, &status) == 0 && + status == AL5_MCU_STA_SLEEP) { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + cpu_relax(); + } + + err = regmap_write(dev->regmap, AL5_MCU_WAKEUP, 0); + if (err) + return err; + + return 0; +} + +static int allegro_mcu_reset(struct allegro_dev *dev) +{ + int err; + + err = regmap_write(dev->regmap, + AL5_MCU_RESET_MODE, AL5_MCU_RESET_MODE_SLEEP); + if (err < 0) + return err; + + err = regmap_write(dev->regmap, AL5_MCU_RESET, AL5_MCU_RESET_SOFT); + if (err < 0) + return err; + + return allegro_mcu_wait_for_sleep(dev); +} + +static void allegro_destroy_channel(struct allegro_channel *channel) +{ + struct allegro_dev *dev = channel->dev; + unsigned long timeout; + + if (channel_exists(channel)) { + reinit_completion(&channel->completion); + allegro_mcu_send_destroy_channel(dev, channel); + timeout = wait_for_completion_timeout(&channel->completion, + msecs_to_jiffies(5000)); + if (timeout == 0) + v4l2_warn(&dev->v4l2_dev, + "channel %d: timeout while destroying\n", + channel->mcu_channel_id); + + channel->mcu_channel_id = -1; + } + + destroy_intermediate_buffers(channel); + destroy_reference_buffers(channel); + + v4l2_ctrl_grab(channel->mpeg_video_h264_profile, false); + v4l2_ctrl_grab(channel->mpeg_video_h264_level, false); + v4l2_ctrl_grab(channel->mpeg_video_bitrate_mode, false); + v4l2_ctrl_grab(channel->mpeg_video_bitrate, false); + v4l2_ctrl_grab(channel->mpeg_video_bitrate_peak, false); + v4l2_ctrl_grab(channel->mpeg_video_cpb_size, false); + v4l2_ctrl_grab(channel->mpeg_video_gop_size, false); + + if (channel->user_id != -1) { + clear_bit(channel->user_id, &dev->channel_user_ids); + channel->user_id = -1; + } +} + +/* + * Create the MCU channel + * + * After the channel has been created, the picture size, format, colorspace + * and framerate are fixed. Also the codec, profile, bitrate, etc. cannot be + * changed anymore. + * + * The channel can be created only once. The MCU will accept source buffers + * and stream buffers only after a channel has been created. + */ +static int allegro_create_channel(struct allegro_channel *channel) +{ + struct allegro_dev *dev = channel->dev; + unsigned long timeout; + enum v4l2_mpeg_video_h264_level min_level; + + if (channel_exists(channel)) { + v4l2_warn(&dev->v4l2_dev, + "channel already exists\n"); + return 0; + } + + channel->user_id = allegro_next_user_id(dev); + if (channel->user_id < 0) { + v4l2_err(&dev->v4l2_dev, + "no free channels available\n"); + return -EBUSY; + } + set_bit(channel->user_id, &dev->channel_user_ids); + + v4l2_dbg(1, debug, &dev->v4l2_dev, + "user %d: creating channel (%4.4s, %dx%d@%d)\n", + channel->user_id, + (char *)&channel->codec, channel->width, channel->height, 25); + + min_level = select_minimum_h264_level(channel->width, channel->height); + if (channel->level < min_level) { + v4l2_warn(&dev->v4l2_dev, + "user %d: selected Level %s too low: increasing to Level %s\n", + channel->user_id, + v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL)[channel->level], + v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL)[min_level]); + channel->level = min_level; + } + + v4l2_ctrl_grab(channel->mpeg_video_h264_profile, true); + v4l2_ctrl_grab(channel->mpeg_video_h264_level, true); + v4l2_ctrl_grab(channel->mpeg_video_bitrate_mode, true); + v4l2_ctrl_grab(channel->mpeg_video_bitrate, true); + v4l2_ctrl_grab(channel->mpeg_video_bitrate_peak, true); + v4l2_ctrl_grab(channel->mpeg_video_cpb_size, true); + v4l2_ctrl_grab(channel->mpeg_video_gop_size, true); + + reinit_completion(&channel->completion); + allegro_mcu_send_create_channel(dev, channel); + timeout = wait_for_completion_timeout(&channel->completion, + msecs_to_jiffies(5000)); + if (timeout == 0) + channel->error = -ETIMEDOUT; + if (channel->error) + goto err; + + v4l2_dbg(1, debug, &dev->v4l2_dev, + "channel %d: accepting buffers\n", + channel->mcu_channel_id); + + return 0; + +err: + allegro_destroy_channel(channel); + + return channel->error; +} + +static void allegro_set_default_params(struct allegro_channel *channel) +{ + channel->width = ALLEGRO_WIDTH_DEFAULT; + channel->height = ALLEGRO_HEIGHT_DEFAULT; + channel->stride = round_up(channel->width, 32); + + channel->colorspace = V4L2_COLORSPACE_REC709; + channel->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + channel->quantization = V4L2_QUANTIZATION_DEFAULT; + channel->xfer_func = V4L2_XFER_FUNC_DEFAULT; + + channel->pixelformat = V4L2_PIX_FMT_NV12; + channel->sizeimage_raw = channel->stride * channel->height * 3 / 2; + + channel->codec = V4L2_PIX_FMT_H264; + channel->profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; + channel->level = + select_minimum_h264_level(channel->width, channel->height); + channel->sizeimage_encoded = + estimate_stream_size(channel->width, channel->height); + + channel->bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; + channel->bitrate = maximum_bitrate(channel->level); + channel->bitrate_peak = maximum_bitrate(channel->level); + channel->cpb_size = maximum_cpb_size(channel->level); + channel->gop_size = ALLEGRO_GOP_SIZE_DEFAULT; +} + +static int allegro_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct allegro_channel *channel = vb2_get_drv_priv(vq); + struct allegro_dev *dev = channel->dev; + + v4l2_dbg(2, debug, &dev->v4l2_dev, + "%s: queue setup[%s]: nplanes = %d\n", + V4L2_TYPE_IS_OUTPUT(vq->type) ? "output" : "capture", + *nplanes == 0 ? "REQBUFS" : "CREATE_BUFS", *nplanes); + + if (*nplanes != 0) { + if (V4L2_TYPE_IS_OUTPUT(vq->type)) { + if (sizes[0] < channel->sizeimage_raw) + return -EINVAL; + } else { + if (sizes[0] < channel->sizeimage_encoded) + return -EINVAL; + } + } else { + *nplanes = 1; + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + sizes[0] = channel->sizeimage_raw; + else + sizes[0] = channel->sizeimage_encoded; + } + + return 0; +} + +static int allegro_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct allegro_channel *channel = vb2_get_drv_priv(vb->vb2_queue); + struct allegro_dev *dev = channel->dev; + + if (allegro_get_state(channel) == ALLEGRO_STATE_DRAIN && + V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) + return -EBUSY; + + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { + if (vbuf->field == V4L2_FIELD_ANY) + vbuf->field = V4L2_FIELD_NONE; + if (vbuf->field != V4L2_FIELD_NONE) { + v4l2_err(&dev->v4l2_dev, + "channel %d: unsupported field\n", + channel->mcu_channel_id); + return -EINVAL; + } + } + + return 0; +} + +static void allegro_buf_queue(struct vb2_buffer *vb) +{ + struct allegro_channel *channel = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + if (allegro_get_state(channel) == ALLEGRO_STATE_WAIT_FOR_BUFFER && + vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + allegro_channel_buf_done(channel, vbuf, VB2_BUF_STATE_DONE); + return; + } + + v4l2_m2m_buf_queue(channel->fh.m2m_ctx, vbuf); +} + +static int allegro_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct allegro_channel *channel = vb2_get_drv_priv(q); + struct allegro_dev *dev = channel->dev; + + v4l2_dbg(2, debug, &dev->v4l2_dev, + "%s: start streaming\n", + V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture"); + + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + channel->osequence = 0; + allegro_set_state(channel, ALLEGRO_STATE_ENCODING); + } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + channel->csequence = 0; + } + + return 0; +} + +static void allegro_stop_streaming(struct vb2_queue *q) +{ + struct allegro_channel *channel = vb2_get_drv_priv(q); + struct allegro_dev *dev = channel->dev; + struct vb2_v4l2_buffer *buffer; + + v4l2_dbg(2, debug, &dev->v4l2_dev, + "%s: stop streaming\n", + V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture"); + + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + allegro_set_state(channel, ALLEGRO_STATE_STOPPED); + while ((buffer = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx))) + v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_ERROR); + } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + allegro_destroy_channel(channel); + while ((buffer = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx))) + v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_ERROR); + } +} + +static const struct vb2_ops allegro_queue_ops = { + .queue_setup = allegro_queue_setup, + .buf_prepare = allegro_buf_prepare, + .buf_queue = allegro_buf_queue, + .start_streaming = allegro_start_streaming, + .stop_streaming = allegro_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int allegro_queue_init(void *priv, + struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + int err; + struct allegro_channel *channel = priv; + + src_vq->dev = &channel->dev->plat_dev->dev; + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->drv_priv = channel; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->ops = &allegro_queue_ops; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->lock = &channel->dev->lock; + err = vb2_queue_init(src_vq); + if (err) + return err; + + dst_vq->dev = &channel->dev->plat_dev->dev; + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->drv_priv = channel; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->ops = &allegro_queue_ops; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->lock = &channel->dev->lock; + err = vb2_queue_init(dst_vq); + if (err) + return err; + + return 0; +} + +static int allegro_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct allegro_channel *channel = container_of(ctrl->handler, + struct allegro_channel, + ctrl_handler); + struct allegro_dev *dev = channel->dev; + + v4l2_dbg(1, debug, &dev->v4l2_dev, + "s_ctrl: %s = %d\n", v4l2_ctrl_get_name(ctrl->id), ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + channel->level = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + channel->bitrate_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + channel->bitrate = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + channel->bitrate_peak = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: + channel->cpb_size = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + channel->gop_size = ctrl->val; + break; + } + + return 0; +} + +static const struct v4l2_ctrl_ops allegro_ctrl_ops = { + .s_ctrl = allegro_s_ctrl, +}; + +static int allegro_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct allegro_dev *dev = video_get_drvdata(vdev); + struct allegro_channel *channel = NULL; + struct v4l2_ctrl_handler *handler; + u64 mask; + + channel = kzalloc(sizeof(*channel), GFP_KERNEL); + if (!channel) + return -ENOMEM; + + v4l2_fh_init(&channel->fh, vdev); + file->private_data = &channel->fh; + v4l2_fh_add(&channel->fh); + + init_completion(&channel->completion); + + channel->dev = dev; + + allegro_set_default_params(channel); + + handler = &channel->ctrl_handler; + v4l2_ctrl_handler_init(handler, 0); + channel->mpeg_video_h264_profile = v4l2_ctrl_new_std_menu(handler, + &allegro_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE); + mask = 1 << V4L2_MPEG_VIDEO_H264_LEVEL_1B; + channel->mpeg_video_h264_level = v4l2_ctrl_new_std_menu(handler, + &allegro_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + V4L2_MPEG_VIDEO_H264_LEVEL_5_1, mask, + V4L2_MPEG_VIDEO_H264_LEVEL_5_1); + channel->mpeg_video_bitrate_mode = v4l2_ctrl_new_std_menu(handler, + &allegro_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, + channel->bitrate_mode); + channel->mpeg_video_bitrate = v4l2_ctrl_new_std(handler, + &allegro_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE, + 0, maximum_bitrate(V4L2_MPEG_VIDEO_H264_LEVEL_5_1), + 1, channel->bitrate); + channel->mpeg_video_bitrate_peak = v4l2_ctrl_new_std(handler, + &allegro_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + 0, maximum_bitrate(V4L2_MPEG_VIDEO_H264_LEVEL_5_1), + 1, channel->bitrate_peak); + channel->mpeg_video_cpb_size = v4l2_ctrl_new_std(handler, + &allegro_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, + 0, maximum_cpb_size(V4L2_MPEG_VIDEO_H264_LEVEL_5_1), + 1, channel->cpb_size); + channel->mpeg_video_gop_size = v4l2_ctrl_new_std(handler, + &allegro_ctrl_ops, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + 0, ALLEGRO_GOP_SIZE_MAX, + 1, channel->gop_size); + v4l2_ctrl_new_std(handler, + &allegro_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 1, 32, + 1, 1); + channel->fh.ctrl_handler = handler; + + channel->mcu_channel_id = -1; + channel->user_id = -1; + + INIT_LIST_HEAD(&channel->buffers_reference); + INIT_LIST_HEAD(&channel->buffers_intermediate); + + list_add(&channel->list, &dev->channels); + + channel->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, channel, + allegro_queue_init); + + return 0; +} + +static int allegro_release(struct file *file) +{ + struct allegro_channel *channel = fh_to_channel(file->private_data); + + v4l2_m2m_ctx_release(channel->fh.m2m_ctx); + + list_del(&channel->list); + + v4l2_ctrl_handler_free(&channel->ctrl_handler); + + v4l2_fh_del(&channel->fh); + v4l2_fh_exit(&channel->fh); + + kfree(channel); + + return 0; +} + +static int allegro_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct video_device *vdev = video_devdata(file); + struct allegro_dev *dev = video_get_drvdata(vdev); + + strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strscpy(cap->card, "Allegro DVT Video Encoder", sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(&dev->plat_dev->dev)); + + return 0; +} + +static int allegro_enum_fmt_vid(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + if (f->index) + return -EINVAL; + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + f->pixelformat = V4L2_PIX_FMT_NV12; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + f->pixelformat = V4L2_PIX_FMT_H264; + break; + default: + return -EINVAL; + } + return 0; +} + +static int allegro_g_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct allegro_channel *channel = fh_to_channel(fh); + + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.width = channel->width; + f->fmt.pix.height = channel->height; + + f->fmt.pix.colorspace = channel->colorspace; + f->fmt.pix.ycbcr_enc = channel->ycbcr_enc; + f->fmt.pix.quantization = channel->quantization; + f->fmt.pix.xfer_func = channel->xfer_func; + + f->fmt.pix.pixelformat = channel->codec; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = channel->sizeimage_encoded; + + return 0; +} + +static int allegro_try_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + f->fmt.pix.field = V4L2_FIELD_NONE; + + f->fmt.pix.width = clamp_t(__u32, f->fmt.pix.width, + ALLEGRO_WIDTH_MIN, ALLEGRO_WIDTH_MAX); + f->fmt.pix.height = clamp_t(__u32, f->fmt.pix.height, + ALLEGRO_HEIGHT_MIN, ALLEGRO_HEIGHT_MAX); + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = + estimate_stream_size(f->fmt.pix.width, f->fmt.pix.height); + + return 0; +} + +static int allegro_g_fmt_vid_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct allegro_channel *channel = fh_to_channel(fh); + + f->fmt.pix.field = V4L2_FIELD_NONE; + + f->fmt.pix.width = channel->width; + f->fmt.pix.height = channel->height; + + f->fmt.pix.colorspace = channel->colorspace; + f->fmt.pix.ycbcr_enc = channel->ycbcr_enc; + f->fmt.pix.quantization = channel->quantization; + f->fmt.pix.xfer_func = channel->xfer_func; + + f->fmt.pix.pixelformat = channel->pixelformat; + f->fmt.pix.bytesperline = channel->stride; + f->fmt.pix.sizeimage = channel->sizeimage_raw; + + return 0; +} + +static int allegro_try_fmt_vid_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + f->fmt.pix.field = V4L2_FIELD_NONE; + + /* + * The firmware of the Allegro codec handles the padding internally + * and expects the visual frame size when configuring a channel. + * Therefore, unlike other encoder drivers, this driver does not round + * up the width and height to macroblock alignment and does not + * implement the selection api. + */ + f->fmt.pix.width = clamp_t(__u32, f->fmt.pix.width, + ALLEGRO_WIDTH_MIN, ALLEGRO_WIDTH_MAX); + f->fmt.pix.height = clamp_t(__u32, f->fmt.pix.height, + ALLEGRO_HEIGHT_MIN, ALLEGRO_HEIGHT_MAX); + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12; + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 32); + f->fmt.pix.sizeimage = + f->fmt.pix.bytesperline * f->fmt.pix.height * 3 / 2; + + return 0; +} + +static int allegro_s_fmt_vid_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct allegro_channel *channel = fh_to_channel(fh); + int err; + + err = allegro_try_fmt_vid_out(file, fh, f); + if (err) + return err; + + channel->width = f->fmt.pix.width; + channel->height = f->fmt.pix.height; + channel->stride = f->fmt.pix.bytesperline; + channel->sizeimage_raw = f->fmt.pix.sizeimage; + + channel->colorspace = f->fmt.pix.colorspace; + channel->ycbcr_enc = f->fmt.pix.ycbcr_enc; + channel->quantization = f->fmt.pix.quantization; + channel->xfer_func = f->fmt.pix.xfer_func; + + channel->level = + select_minimum_h264_level(channel->width, channel->height); + channel->sizeimage_encoded = + estimate_stream_size(channel->width, channel->height); + + return 0; +} + +static int allegro_channel_cmd_stop(struct allegro_channel *channel) +{ + struct allegro_dev *dev = channel->dev; + struct vb2_v4l2_buffer *dst_buf; + + switch (allegro_get_state(channel)) { + case ALLEGRO_STATE_DRAIN: + case ALLEGRO_STATE_WAIT_FOR_BUFFER: + return -EBUSY; + case ALLEGRO_STATE_ENCODING: + allegro_set_state(channel, ALLEGRO_STATE_DRAIN); + break; + default: + return 0; + } + + /* If there are output buffers, they must be encoded */ + if (v4l2_m2m_num_src_bufs_ready(channel->fh.m2m_ctx) != 0) { + v4l2_dbg(1, debug, &dev->v4l2_dev, + "channel %d: CMD_STOP: continue encoding src buffers\n", + channel->mcu_channel_id); + return 0; + } + + /* If there are capture buffers, use it to signal EOS */ + dst_buf = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx); + if (dst_buf) { + v4l2_dbg(1, debug, &dev->v4l2_dev, + "channel %d: CMD_STOP: signaling EOS\n", + channel->mcu_channel_id); + allegro_channel_buf_done(channel, dst_buf, VB2_BUF_STATE_DONE); + return 0; + } + + /* + * If there are no capture buffers, we need to wait for the next + * buffer to signal EOS. + */ + v4l2_dbg(1, debug, &dev->v4l2_dev, + "channel %d: CMD_STOP: wait for CAPTURE buffer to signal EOS\n", + channel->mcu_channel_id); + allegro_set_state(channel, ALLEGRO_STATE_WAIT_FOR_BUFFER); + + return 0; +} + +static int allegro_channel_cmd_start(struct allegro_channel *channel) +{ + switch (allegro_get_state(channel)) { + case ALLEGRO_STATE_DRAIN: + case ALLEGRO_STATE_WAIT_FOR_BUFFER: + return -EBUSY; + case ALLEGRO_STATE_STOPPED: + allegro_set_state(channel, ALLEGRO_STATE_ENCODING); + break; + default: + return 0; + } + + return 0; +} + +static int allegro_encoder_cmd(struct file *file, void *fh, + struct v4l2_encoder_cmd *cmd) +{ + struct allegro_channel *channel = fh_to_channel(fh); + int err; + + err = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd); + if (err) + return err; + + switch (cmd->cmd) { + case V4L2_ENC_CMD_STOP: + err = allegro_channel_cmd_stop(channel); + break; + case V4L2_ENC_CMD_START: + err = allegro_channel_cmd_start(channel); + break; + default: + err = -EINVAL; + break; + } + + return err; +} + +static int allegro_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + switch (fsize->pixel_format) { + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_NV12: + break; + default: + return -EINVAL; + } + + if (fsize->index) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise.min_width = ALLEGRO_WIDTH_MIN; + fsize->stepwise.max_width = ALLEGRO_WIDTH_MAX; + fsize->stepwise.step_width = 1; + fsize->stepwise.min_height = ALLEGRO_HEIGHT_MIN; + fsize->stepwise.max_height = ALLEGRO_HEIGHT_MAX; + fsize->stepwise.step_height = 1; + + return 0; +} + +static int allegro_ioctl_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct v4l2_fh *fh = file->private_data; + struct allegro_channel *channel = fh_to_channel(fh); + int err; + + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + err = allegro_create_channel(channel); + if (err) + return err; + } + + return v4l2_m2m_streamon(file, fh->m2m_ctx, type); +} + +static int allegro_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 0, NULL); + default: + return v4l2_ctrl_subscribe_event(fh, sub); + } +} + +static const struct v4l2_ioctl_ops allegro_ioctl_ops = { + .vidioc_querycap = allegro_querycap, + .vidioc_enum_fmt_vid_cap = allegro_enum_fmt_vid, + .vidioc_enum_fmt_vid_out = allegro_enum_fmt_vid, + .vidioc_g_fmt_vid_cap = allegro_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = allegro_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = allegro_try_fmt_vid_cap, + .vidioc_g_fmt_vid_out = allegro_g_fmt_vid_out, + .vidioc_try_fmt_vid_out = allegro_try_fmt_vid_out, + .vidioc_s_fmt_vid_out = allegro_s_fmt_vid_out, + + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + + .vidioc_streamon = allegro_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, + .vidioc_encoder_cmd = allegro_encoder_cmd, + .vidioc_enum_framesizes = allegro_enum_framesizes, + + .vidioc_subscribe_event = allegro_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static const struct v4l2_file_operations allegro_fops = { + .owner = THIS_MODULE, + .open = allegro_open, + .release = allegro_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static int allegro_register_device(struct allegro_dev *dev) +{ + struct video_device *video_dev = &dev->video_dev; + + strscpy(video_dev->name, "allegro", sizeof(video_dev->name)); + video_dev->fops = &allegro_fops; + video_dev->ioctl_ops = &allegro_ioctl_ops; + video_dev->release = video_device_release_empty; + video_dev->lock = &dev->lock; + video_dev->v4l2_dev = &dev->v4l2_dev; + video_dev->vfl_dir = VFL_DIR_M2M; + video_dev->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; + video_set_drvdata(video_dev, dev); + + return video_register_device(video_dev, VFL_TYPE_GRABBER, 0); +} + +static void allegro_device_run(void *priv) +{ + struct allegro_channel *channel = priv; + struct allegro_dev *dev = channel->dev; + struct vb2_v4l2_buffer *src_buf; + struct vb2_v4l2_buffer *dst_buf; + dma_addr_t src_y; + dma_addr_t src_uv; + dma_addr_t dst_addr; + unsigned long dst_size; + + dst_buf = v4l2_m2m_next_dst_buf(channel->fh.m2m_ctx); + dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + dst_size = vb2_plane_size(&dst_buf->vb2_buf, 0); + allegro_mcu_send_put_stream_buffer(dev, channel, dst_addr, dst_size); + + src_buf = v4l2_m2m_next_src_buf(channel->fh.m2m_ctx); + src_buf->sequence = channel->osequence++; + + src_y = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + src_uv = src_y + (channel->stride * channel->height); + allegro_mcu_send_encode_frame(dev, channel, src_y, src_uv); +} + +static const struct v4l2_m2m_ops allegro_m2m_ops = { + .device_run = allegro_device_run, +}; + +static int allegro_mcu_hw_init(struct allegro_dev *dev, + const struct fw_info *info) +{ + int err; + + allegro_mbox_init(dev, &dev->mbox_command, + info->mailbox_cmd, info->mailbox_size); + allegro_mbox_init(dev, &dev->mbox_status, + info->mailbox_status, info->mailbox_size); + + allegro_mcu_enable_interrupts(dev); + + /* The mcu sends INIT after reset. */ + allegro_mcu_start(dev); + err = allegro_mcu_wait_for_init_timeout(dev, 5000); + if (err < 0) { + v4l2_err(&dev->v4l2_dev, + "mcu did not send INIT after reset\n"); + err = -EIO; + goto err_disable_interrupts; + } + + err = allegro_alloc_buffer(dev, &dev->suballocator, + info->suballocator_size); + if (err) { + v4l2_err(&dev->v4l2_dev, + "failed to allocate %zu bytes for suballocator\n", + info->suballocator_size); + goto err_reset_mcu; + } + + allegro_mcu_send_init(dev, dev->suballocator.paddr, + dev->suballocator.size); + err = allegro_mcu_wait_for_init_timeout(dev, 5000); + if (err < 0) { + v4l2_err(&dev->v4l2_dev, + "mcu failed to configure sub-allocator\n"); + err = -EIO; + goto err_free_suballocator; + } + + return 0; + +err_free_suballocator: + allegro_free_buffer(dev, &dev->suballocator); +err_reset_mcu: + allegro_mcu_reset(dev); +err_disable_interrupts: + allegro_mcu_disable_interrupts(dev); + + return err; +} + +static int allegro_mcu_hw_deinit(struct allegro_dev *dev) +{ + int err; + + err = allegro_mcu_reset(dev); + if (err) + v4l2_warn(&dev->v4l2_dev, + "mcu failed to enter sleep state\n"); + + err = allegro_mcu_disable_interrupts(dev); + if (err) + v4l2_warn(&dev->v4l2_dev, + "failed to disable interrupts\n"); + + allegro_free_buffer(dev, &dev->suballocator); + + return 0; +} + +static void allegro_fw_callback(const struct firmware *fw, void *context) +{ + struct allegro_dev *dev = context; + const char *fw_codec_name = "al5e.fw"; + const struct firmware *fw_codec; + int err; + const struct fw_info *info; + + if (!fw) + return; + + v4l2_dbg(1, debug, &dev->v4l2_dev, + "requesting codec firmware '%s'\n", fw_codec_name); + err = request_firmware(&fw_codec, fw_codec_name, &dev->plat_dev->dev); + if (err) + goto err_release_firmware; + + info = allegro_get_firmware_info(dev, fw, fw_codec); + if (!info) { + v4l2_err(&dev->v4l2_dev, "firmware is not supported\n"); + goto err_release_firmware_codec; + } + + v4l2_info(&dev->v4l2_dev, + "using mcu firmware version '%s'\n", info->version); + + /* Ensure that the mcu is sleeping at the reset vector */ + err = allegro_mcu_reset(dev); + if (err) { + v4l2_err(&dev->v4l2_dev, "failed to reset mcu\n"); + goto err_release_firmware_codec; + } + + allegro_copy_firmware(dev, fw->data, fw->size); + allegro_copy_fw_codec(dev, fw_codec->data, fw_codec->size); + + err = allegro_mcu_hw_init(dev, info); + if (err) { + v4l2_err(&dev->v4l2_dev, "failed to initialize mcu\n"); + goto err_free_fw_codec; + } + + dev->m2m_dev = v4l2_m2m_init(&allegro_m2m_ops); + if (IS_ERR(dev->m2m_dev)) { + v4l2_err(&dev->v4l2_dev, "failed to init mem2mem device\n"); + goto err_mcu_hw_deinit; + } + + err = allegro_register_device(dev); + if (err) { + v4l2_err(&dev->v4l2_dev, "failed to register video device\n"); + goto err_m2m_release; + } + + v4l2_dbg(1, debug, &dev->v4l2_dev, + "allegro codec registered as /dev/video%d\n", + dev->video_dev.num); + + release_firmware(fw_codec); + release_firmware(fw); + + return; + +err_m2m_release: + v4l2_m2m_release(dev->m2m_dev); + dev->m2m_dev = NULL; +err_mcu_hw_deinit: + allegro_mcu_hw_deinit(dev); +err_free_fw_codec: + allegro_free_fw_codec(dev); +err_release_firmware_codec: + release_firmware(fw_codec); +err_release_firmware: + release_firmware(fw); +} + +static int allegro_firmware_request_nowait(struct allegro_dev *dev) +{ + const char *fw = "al5e_b.fw"; + + v4l2_dbg(1, debug, &dev->v4l2_dev, + "requesting firmware '%s'\n", fw); + return request_firmware_nowait(THIS_MODULE, true, fw, + &dev->plat_dev->dev, GFP_KERNEL, dev, + allegro_fw_callback); +} + +static int allegro_probe(struct platform_device *pdev) +{ + struct allegro_dev *dev; + struct resource *res, *sram_res; + int ret; + int irq; + void __iomem *regs, *sram_regs; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + dev->plat_dev = pdev; + init_completion(&dev->init_complete); + INIT_LIST_HEAD(&dev->channels); + + mutex_init(&dev->lock); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + if (!res) { + dev_err(&pdev->dev, + "regs resource missing from device tree\n"); + return -EINVAL; + } + regs = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); + if (IS_ERR(regs)) { + dev_err(&pdev->dev, "failed to map registers\n"); + return PTR_ERR(regs); + } + dev->regmap = devm_regmap_init_mmio(&pdev->dev, regs, + &allegro_regmap_config); + if (IS_ERR(dev->regmap)) { + dev_err(&pdev->dev, "failed to init regmap\n"); + return PTR_ERR(dev->regmap); + } + + sram_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); + if (!sram_res) { + dev_err(&pdev->dev, + "sram resource missing from device tree\n"); + return -EINVAL; + } + sram_regs = devm_ioremap_nocache(&pdev->dev, + sram_res->start, + resource_size(sram_res)); + if (IS_ERR(sram_regs)) { + dev_err(&pdev->dev, "failed to map sram\n"); + return PTR_ERR(sram_regs); + } + dev->sram = devm_regmap_init_mmio(&pdev->dev, sram_regs, + &allegro_sram_config); + if (IS_ERR(dev->sram)) { + dev_err(&pdev->dev, "failed to init sram\n"); + return PTR_ERR(dev->sram); + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get irq resource\n"); + return irq; + } + ret = devm_request_threaded_irq(&pdev->dev, irq, + allegro_hardirq, + allegro_irq_thread, + IRQF_SHARED, dev_name(&pdev->dev), dev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to request irq: %d\n", ret); + return ret; + } + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) + return ret; + + platform_set_drvdata(pdev, dev); + + ret = allegro_firmware_request_nowait(dev); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, + "failed to request firmware: %d\n", ret); + return ret; + } + + return 0; +} + +static int allegro_remove(struct platform_device *pdev) +{ + struct allegro_dev *dev = platform_get_drvdata(pdev); + + video_unregister_device(&dev->video_dev); + if (dev->m2m_dev) + v4l2_m2m_release(dev->m2m_dev); + allegro_mcu_hw_deinit(dev); + allegro_free_fw_codec(dev); + + v4l2_device_unregister(&dev->v4l2_dev); + + return 0; +} + +static const struct of_device_id allegro_dt_ids[] = { + { .compatible = "allegro,al5e-1.1" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, allegro_dt_ids); + +static struct platform_driver allegro_driver = { + .probe = allegro_probe, + .remove = allegro_remove, + .driver = { + .name = "allegro", + .of_match_table = of_match_ptr(allegro_dt_ids), + }, +}; + +module_platform_driver(allegro_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michael Tretter <kernel@pengutronix.de>"); +MODULE_DESCRIPTION("Allegro DVT encoder driver"); diff --git a/drivers/staging/media/allegro-dvt/nal-h264.c b/drivers/staging/media/allegro-dvt/nal-h264.c new file mode 100644 index 000000000000..4e14b77851e1 --- /dev/null +++ b/drivers/staging/media/allegro-dvt/nal-h264.c @@ -0,0 +1,1001 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de> + * + * Convert NAL units between raw byte sequence payloads (RBSP) and C structs + * + * The conversion is defined in "ITU-T Rec. H.264 (04/2017) Advanced video + * coding for generic audiovisual services". Decoder drivers may use the + * parser to parse RBSP from encoded streams and configure the hardware, if + * the hardware is not able to parse RBSP itself. Encoder drivers may use the + * generator to generate the RBSP for SPS/PPS nal units and add them to the + * encoded stream if the hardware does not generate the units. + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/v4l2-controls.h> + +#include <linux/device.h> +#include <linux/export.h> +#include <linux/log2.h> + +#include "nal-h264.h" + +/* + * See Rec. ITU-T H.264 (04/2017) Table 7-1 – NAL unit type codes, syntax + * element categories, and NAL unit type classes + */ +enum nal_unit_type { + SEQUENCE_PARAMETER_SET = 7, + PICTURE_PARAMETER_SET = 8, + FILLER_DATA = 12, +}; + +struct rbsp; + +struct nal_h264_ops { + int (*rbsp_bit)(struct rbsp *rbsp, int *val); + int (*rbsp_bits)(struct rbsp *rbsp, int n, unsigned int *val); + int (*rbsp_uev)(struct rbsp *rbsp, unsigned int *val); + int (*rbsp_sev)(struct rbsp *rbsp, int *val); +}; + +/** + * struct rbsp - State object for handling a raw byte sequence payload + * @data: pointer to the data of the rbsp + * @size: maximum size of the data of the rbsp + * @pos: current bit position inside the rbsp + * @num_consecutive_zeros: number of zeros before @pos + * @ops: per datatype functions for interacting with the rbsp + * @error: an error occurred while handling the rbsp + * + * This struct is passed around the various parsing functions and tracks the + * current position within the raw byte sequence payload. + * + * The @ops field allows to separate the operation, i.e., reading/writing a + * value from/to that rbsp, from the structure of the NAL unit. This allows to + * have a single function for iterating the NAL unit, while @ops has function + * pointers for handling each type in the rbsp. + */ +struct rbsp { + u8 *data; + size_t size; + unsigned int pos; + unsigned int num_consecutive_zeros; + struct nal_h264_ops *ops; + int error; +}; + +static void rbsp_init(struct rbsp *rbsp, void *addr, size_t size, + struct nal_h264_ops *ops) +{ + if (!rbsp) + return; + + rbsp->data = addr; + rbsp->size = size; + rbsp->pos = 0; + rbsp->ops = ops; + rbsp->error = 0; +} + +/** + * nal_h264_profile_from_v4l2() - Get profile_idc for v4l2 h264 profile + * @profile: the profile as &enum v4l2_mpeg_video_h264_profile + * + * Convert the &enum v4l2_mpeg_video_h264_profile to profile_idc as specified + * in Rec. ITU-T H.264 (04/2017) A.2. + * + * Return: the profile_idc for the passed level + */ +int nal_h264_profile_from_v4l2(enum v4l2_mpeg_video_h264_profile profile) +{ + switch (profile) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + return 66; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + return 77; + case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: + return 88; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + return 100; + default: + return -EINVAL; + } +} + +/** + * nal_h264_level_from_v4l2() - Get level_idc for v4l2 h264 level + * @level: the level as &enum v4l2_mpeg_video_h264_level + * + * Convert the &enum v4l2_mpeg_video_h264_level to level_idc as specified in + * Rec. ITU-T H.264 (04/2017) A.3.2. + * + * Return: the level_idc for the passed level + */ +int nal_h264_level_from_v4l2(enum v4l2_mpeg_video_h264_level level) +{ + switch (level) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + return 10; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + return 9; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + return 11; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + return 12; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + return 13; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + return 20; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + return 21; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + return 22; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + return 30; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + return 31; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + return 32; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + return 40; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + return 41; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + return 42; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + return 50; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + return 51; + default: + return -EINVAL; + } +} + +static int rbsp_read_bits(struct rbsp *rbsp, int n, unsigned int *value); +static int rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int value); + +/* + * When reading or writing, the emulation_prevention_three_byte is detected + * only when the 2 one bits need to be inserted. Therefore, we are not + * actually adding the 0x3 byte, but the 2 one bits and the six 0 bits of the + * next byte. + */ +#define EMULATION_PREVENTION_THREE_BYTE (0x3 << 6) + +static int add_emulation_prevention_three_byte(struct rbsp *rbsp) +{ + rbsp->num_consecutive_zeros = 0; + rbsp_write_bits(rbsp, 8, EMULATION_PREVENTION_THREE_BYTE); + + return 0; +} + +static int discard_emulation_prevention_three_byte(struct rbsp *rbsp) +{ + unsigned int tmp = 0; + + rbsp->num_consecutive_zeros = 0; + rbsp_read_bits(rbsp, 8, &tmp); + if (tmp != EMULATION_PREVENTION_THREE_BYTE) + return -EINVAL; + + return 0; +} + +static inline int rbsp_read_bit(struct rbsp *rbsp) +{ + int shift; + int ofs; + int bit; + int err; + + if (rbsp->num_consecutive_zeros == 22) { + err = discard_emulation_prevention_three_byte(rbsp); + if (err) + return err; + } + + shift = 7 - (rbsp->pos % 8); + ofs = rbsp->pos / 8; + if (ofs >= rbsp->size) + return -EINVAL; + + bit = (rbsp->data[ofs] >> shift) & 1; + + rbsp->pos++; + + if (bit == 1 || + (rbsp->num_consecutive_zeros < 7 && (rbsp->pos % 8 == 0))) + rbsp->num_consecutive_zeros = 0; + else + rbsp->num_consecutive_zeros++; + + return bit; +} + +static inline int rbsp_write_bit(struct rbsp *rbsp, bool value) +{ + int shift; + int ofs; + + if (rbsp->num_consecutive_zeros == 22) + add_emulation_prevention_three_byte(rbsp); + + shift = 7 - (rbsp->pos % 8); + ofs = rbsp->pos / 8; + if (ofs >= rbsp->size) + return -EINVAL; + + rbsp->data[ofs] &= ~(1 << shift); + rbsp->data[ofs] |= value << shift; + + rbsp->pos++; + + if (value == 1 || + (rbsp->num_consecutive_zeros < 7 && (rbsp->pos % 8 == 0))) { + rbsp->num_consecutive_zeros = 0; + } else { + rbsp->num_consecutive_zeros++; + } + + return 0; +} + +static inline int rbsp_read_bits(struct rbsp *rbsp, int n, unsigned int *value) +{ + int i; + int bit; + unsigned int tmp = 0; + + if (n > 8 * sizeof(*value)) + return -EINVAL; + + for (i = n; i > 0; i--) { + bit = rbsp_read_bit(rbsp); + if (bit < 0) + return bit; + tmp |= bit << (i - 1); + } + + if (value) + *value = tmp; + + return 0; +} + +static int rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int value) +{ + int ret; + + if (n > 8 * sizeof(value)) + return -EINVAL; + + while (n--) { + ret = rbsp_write_bit(rbsp, (value >> n) & 1); + if (ret) + return ret; + } + + return 0; +} + +static int rbsp_read_uev(struct rbsp *rbsp, unsigned int *value) +{ + int leading_zero_bits = 0; + unsigned int tmp = 0; + int ret; + + while ((ret = rbsp_read_bit(rbsp)) == 0) + leading_zero_bits++; + if (ret < 0) + return ret; + + if (leading_zero_bits > 0) { + ret = rbsp_read_bits(rbsp, leading_zero_bits, &tmp); + if (ret) + return ret; + } + + if (value) + *value = (1 << leading_zero_bits) - 1 + tmp; + + return 0; +} + +static int rbsp_write_uev(struct rbsp *rbsp, unsigned int *value) +{ + int ret; + int leading_zero_bits; + + if (!value) + return -EINVAL; + + leading_zero_bits = ilog2(*value + 1); + + ret = rbsp_write_bits(rbsp, leading_zero_bits, 0); + if (ret) + return ret; + + return rbsp_write_bits(rbsp, leading_zero_bits + 1, *value + 1); +} + +static int rbsp_read_sev(struct rbsp *rbsp, int *value) +{ + int ret; + unsigned int tmp; + + ret = rbsp_read_uev(rbsp, &tmp); + if (ret) + return ret; + + if (value) { + if (tmp & 1) + *value = (tmp + 1) / 2; + else + *value = -(tmp / 2); + } + + return 0; +} + +static int rbsp_write_sev(struct rbsp *rbsp, int *value) +{ + unsigned int tmp; + + if (!value) + return -EINVAL; + + if (*value > 0) + tmp = (2 * (*value)) | 1; + else + tmp = -2 * (*value); + + return rbsp_write_uev(rbsp, &tmp); +} + +static int __rbsp_write_bit(struct rbsp *rbsp, int *value) +{ + return rbsp_write_bit(rbsp, *value); +} + +static int __rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int *value) +{ + return rbsp_write_bits(rbsp, n, *value); +} + +static struct nal_h264_ops write = { + .rbsp_bit = __rbsp_write_bit, + .rbsp_bits = __rbsp_write_bits, + .rbsp_uev = rbsp_write_uev, + .rbsp_sev = rbsp_write_sev, +}; + +static int __rbsp_read_bit(struct rbsp *rbsp, int *value) +{ + int tmp = rbsp_read_bit(rbsp); + + if (tmp < 0) + return tmp; + *value = tmp; + + return 0; +} + +static struct nal_h264_ops read = { + .rbsp_bit = __rbsp_read_bit, + .rbsp_bits = rbsp_read_bits, + .rbsp_uev = rbsp_read_uev, + .rbsp_sev = rbsp_read_sev, +}; + +static inline void rbsp_bit(struct rbsp *rbsp, int *value) +{ + if (rbsp->error) + return; + rbsp->error = rbsp->ops->rbsp_bit(rbsp, value); +} + +static inline void rbsp_bits(struct rbsp *rbsp, int n, int *value) +{ + if (rbsp->error) + return; + rbsp->error = rbsp->ops->rbsp_bits(rbsp, n, value); +} + +static inline void rbsp_uev(struct rbsp *rbsp, unsigned int *value) +{ + if (rbsp->error) + return; + rbsp->error = rbsp->ops->rbsp_uev(rbsp, value); +} + +static inline void rbsp_sev(struct rbsp *rbsp, int *value) +{ + if (rbsp->error) + return; + rbsp->error = rbsp->ops->rbsp_sev(rbsp, value); +} + +static void nal_h264_rbsp_trailing_bits(struct rbsp *rbsp) +{ + unsigned int rbsp_stop_one_bit = 1; + unsigned int rbsp_alignment_zero_bit = 0; + + rbsp_bit(rbsp, &rbsp_stop_one_bit); + rbsp_bits(rbsp, round_up(rbsp->pos, 8) - rbsp->pos, + &rbsp_alignment_zero_bit); +} + +static void nal_h264_write_start_code_prefix(struct rbsp *rbsp) +{ + u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8); + int i = 4; + + if (DIV_ROUND_UP(rbsp->pos, 8) + i > rbsp->size) { + rbsp->error = -EINVAL; + return; + } + + p[0] = 0x00; + p[1] = 0x00; + p[2] = 0x00; + p[3] = 0x01; + + rbsp->pos += i * 8; +} + +static void nal_h264_read_start_code_prefix(struct rbsp *rbsp) +{ + u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8); + int i = 4; + + if (DIV_ROUND_UP(rbsp->pos, 8) + i > rbsp->size) { + rbsp->error = -EINVAL; + return; + } + + if (p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x00 || p[3] != 0x01) { + rbsp->error = -EINVAL; + return; + } + + rbsp->pos += i * 8; +} + +static void nal_h264_write_filler_data(struct rbsp *rbsp) +{ + u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8); + int i; + + /* Keep 1 byte extra for terminating the NAL unit */ + i = rbsp->size - DIV_ROUND_UP(rbsp->pos, 8) - 1; + memset(p, 0xff, i); + rbsp->pos += i * 8; +} + +static void nal_h264_read_filler_data(struct rbsp *rbsp) +{ + u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8); + + while (*p == 0xff) { + if (DIV_ROUND_UP(rbsp->pos, 8) > rbsp->size) { + rbsp->error = -EINVAL; + return; + } + + p++; + rbsp->pos += 8; + } +} + +static void nal_h264_rbsp_hrd_parameters(struct rbsp *rbsp, + struct nal_h264_hrd_parameters *hrd) +{ + unsigned int i; + + if (!hrd) { + rbsp->error = -EINVAL; + return; + } + + rbsp_uev(rbsp, &hrd->cpb_cnt_minus1); + rbsp_bits(rbsp, 4, &hrd->bit_rate_scale); + rbsp_bits(rbsp, 4, &hrd->cpb_size_scale); + + for (i = 0; i <= hrd->cpb_cnt_minus1; i++) { + rbsp_uev(rbsp, &hrd->bit_rate_value_minus1[i]); + rbsp_uev(rbsp, &hrd->cpb_size_value_minus1[i]); + rbsp_bit(rbsp, &hrd->cbr_flag[i]); + } + + rbsp_bits(rbsp, 5, &hrd->initial_cpb_removal_delay_length_minus1); + rbsp_bits(rbsp, 5, &hrd->cpb_removal_delay_length_minus1); + rbsp_bits(rbsp, 5, &hrd->dpb_output_delay_length_minus1); + rbsp_bits(rbsp, 5, &hrd->time_offset_length); +} + +static void nal_h264_rbsp_vui_parameters(struct rbsp *rbsp, + struct nal_h264_vui_parameters *vui) +{ + if (!vui) { + rbsp->error = -EINVAL; + return; + } + + rbsp_bit(rbsp, &vui->aspect_ratio_info_present_flag); + if (vui->aspect_ratio_info_present_flag) { + rbsp_bits(rbsp, 8, &vui->aspect_ratio_idc); + if (vui->aspect_ratio_idc == 255) { + rbsp_bits(rbsp, 16, &vui->sar_width); + rbsp_bits(rbsp, 16, &vui->sar_height); + } + } + + rbsp_bit(rbsp, &vui->overscan_info_present_flag); + if (vui->overscan_info_present_flag) + rbsp_bit(rbsp, &vui->overscan_appropriate_flag); + + rbsp_bit(rbsp, &vui->video_signal_type_present_flag); + if (vui->video_signal_type_present_flag) { + rbsp_bits(rbsp, 3, &vui->video_format); + rbsp_bit(rbsp, &vui->video_full_range_flag); + + rbsp_bit(rbsp, &vui->colour_description_present_flag); + if (vui->colour_description_present_flag) { + rbsp_bits(rbsp, 8, &vui->colour_primaries); + rbsp_bits(rbsp, 8, &vui->transfer_characteristics); + rbsp_bits(rbsp, 8, &vui->matrix_coefficients); + } + } + + rbsp_bit(rbsp, &vui->chroma_loc_info_present_flag); + if (vui->chroma_loc_info_present_flag) { + rbsp_uev(rbsp, &vui->chroma_sample_loc_type_top_field); + rbsp_uev(rbsp, &vui->chroma_sample_loc_type_bottom_field); + } + + rbsp_bit(rbsp, &vui->timing_info_present_flag); + if (vui->timing_info_present_flag) { + rbsp_bits(rbsp, 32, &vui->num_units_in_tick); + rbsp_bits(rbsp, 32, &vui->time_scale); + rbsp_bit(rbsp, &vui->fixed_frame_rate_flag); + } + + rbsp_bit(rbsp, &vui->nal_hrd_parameters_present_flag); + if (vui->nal_hrd_parameters_present_flag) + nal_h264_rbsp_hrd_parameters(rbsp, &vui->nal_hrd_parameters); + + rbsp_bit(rbsp, &vui->vcl_hrd_parameters_present_flag); + if (vui->vcl_hrd_parameters_present_flag) + nal_h264_rbsp_hrd_parameters(rbsp, &vui->vcl_hrd_parameters); + + if (vui->nal_hrd_parameters_present_flag || + vui->vcl_hrd_parameters_present_flag) + rbsp_bit(rbsp, &vui->low_delay_hrd_flag); + + rbsp_bit(rbsp, &vui->pic_struct_present_flag); + + rbsp_bit(rbsp, &vui->bitstream_restriction_flag); + if (vui->bitstream_restriction_flag) { + rbsp_bit(rbsp, &vui->motion_vectors_over_pic_boundaries_flag); + rbsp_uev(rbsp, &vui->max_bytes_per_pic_denom); + rbsp_uev(rbsp, &vui->max_bits_per_mb_denom); + rbsp_uev(rbsp, &vui->log2_max_mv_length_horizontal); + rbsp_uev(rbsp, &vui->log21_max_mv_length_vertical); + rbsp_uev(rbsp, &vui->max_num_reorder_frames); + rbsp_uev(rbsp, &vui->max_dec_frame_buffering); + } +} + +static void nal_h264_rbsp_sps(struct rbsp *rbsp, struct nal_h264_sps *sps) +{ + unsigned int i; + + if (!sps) { + rbsp->error = -EINVAL; + return; + } + + rbsp_bits(rbsp, 8, &sps->profile_idc); + rbsp_bit(rbsp, &sps->constraint_set0_flag); + rbsp_bit(rbsp, &sps->constraint_set1_flag); + rbsp_bit(rbsp, &sps->constraint_set2_flag); + rbsp_bit(rbsp, &sps->constraint_set3_flag); + rbsp_bit(rbsp, &sps->constraint_set4_flag); + rbsp_bit(rbsp, &sps->constraint_set5_flag); + rbsp_bits(rbsp, 2, &sps->reserved_zero_2bits); + rbsp_bits(rbsp, 8, &sps->level_idc); + + rbsp_uev(rbsp, &sps->seq_parameter_set_id); + + if (sps->profile_idc == 100 || sps->profile_idc == 110 || + sps->profile_idc == 122 || sps->profile_idc == 244 || + sps->profile_idc == 44 || sps->profile_idc == 83 || + sps->profile_idc == 86 || sps->profile_idc == 118 || + sps->profile_idc == 128 || sps->profile_idc == 138 || + sps->profile_idc == 139 || sps->profile_idc == 134 || + sps->profile_idc == 135) { + rbsp_uev(rbsp, &sps->chroma_format_idc); + + if (sps->chroma_format_idc == 3) + rbsp_bit(rbsp, &sps->separate_colour_plane_flag); + rbsp_uev(rbsp, &sps->bit_depth_luma_minus8); + rbsp_uev(rbsp, &sps->bit_depth_chroma_minus8); + rbsp_bit(rbsp, &sps->qpprime_y_zero_transform_bypass_flag); + rbsp_bit(rbsp, &sps->seq_scaling_matrix_present_flag); + if (sps->seq_scaling_matrix_present_flag) + rbsp->error = -EINVAL; + } + + rbsp_uev(rbsp, &sps->log2_max_frame_num_minus4); + + rbsp_uev(rbsp, &sps->pic_order_cnt_type); + switch (sps->pic_order_cnt_type) { + case 0: + rbsp_uev(rbsp, &sps->log2_max_pic_order_cnt_lsb_minus4); + break; + case 1: + rbsp_bit(rbsp, &sps->delta_pic_order_always_zero_flag); + rbsp_sev(rbsp, &sps->offset_for_non_ref_pic); + rbsp_sev(rbsp, &sps->offset_for_top_to_bottom_field); + + rbsp_uev(rbsp, &sps->num_ref_frames_in_pic_order_cnt_cycle); + for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++) + rbsp_sev(rbsp, &sps->offset_for_ref_frame[i]); + break; + default: + rbsp->error = -EINVAL; + break; + } + + rbsp_uev(rbsp, &sps->max_num_ref_frames); + rbsp_bit(rbsp, &sps->gaps_in_frame_num_value_allowed_flag); + rbsp_uev(rbsp, &sps->pic_width_in_mbs_minus1); + rbsp_uev(rbsp, &sps->pic_height_in_map_units_minus1); + + rbsp_bit(rbsp, &sps->frame_mbs_only_flag); + if (!sps->frame_mbs_only_flag) + rbsp_bit(rbsp, &sps->mb_adaptive_frame_field_flag); + + rbsp_bit(rbsp, &sps->direct_8x8_inference_flag); + + rbsp_bit(rbsp, &sps->frame_cropping_flag); + if (sps->frame_cropping_flag) { + rbsp_uev(rbsp, &sps->crop_left); + rbsp_uev(rbsp, &sps->crop_right); + rbsp_uev(rbsp, &sps->crop_top); + rbsp_uev(rbsp, &sps->crop_bottom); + } + + rbsp_bit(rbsp, &sps->vui_parameters_present_flag); + if (sps->vui_parameters_present_flag) + nal_h264_rbsp_vui_parameters(rbsp, &sps->vui); +} + +static void nal_h264_rbsp_pps(struct rbsp *rbsp, struct nal_h264_pps *pps) +{ + int i; + + rbsp_uev(rbsp, &pps->pic_parameter_set_id); + rbsp_uev(rbsp, &pps->seq_parameter_set_id); + rbsp_bit(rbsp, &pps->entropy_coding_mode_flag); + rbsp_bit(rbsp, &pps->bottom_field_pic_order_in_frame_present_flag); + rbsp_uev(rbsp, &pps->num_slice_groups_minus1); + if (pps->num_slice_groups_minus1 > 0) { + rbsp_uev(rbsp, &pps->slice_group_map_type); + switch (pps->slice_group_map_type) { + case 0: + for (i = 0; i < pps->num_slice_groups_minus1; i++) + rbsp_uev(rbsp, &pps->run_length_minus1[i]); + break; + case 2: + for (i = 0; i < pps->num_slice_groups_minus1; i++) { + rbsp_uev(rbsp, &pps->top_left[i]); + rbsp_uev(rbsp, &pps->bottom_right[i]); + } + break; + case 3: case 4: case 5: + rbsp_bit(rbsp, &pps->slice_group_change_direction_flag); + rbsp_uev(rbsp, &pps->slice_group_change_rate_minus1); + break; + case 6: + rbsp_uev(rbsp, &pps->pic_size_in_map_units_minus1); + for (i = 0; i < pps->pic_size_in_map_units_minus1; i++) + rbsp_bits(rbsp, + order_base_2(pps->num_slice_groups_minus1 + 1), + &pps->slice_group_id[i]); + break; + default: + break; + } + } + rbsp_uev(rbsp, &pps->num_ref_idx_l0_default_active_minus1); + rbsp_uev(rbsp, &pps->num_ref_idx_l1_default_active_minus1); + rbsp_bit(rbsp, &pps->weighted_pred_flag); + rbsp_bits(rbsp, 2, &pps->weighted_bipred_idc); + rbsp_sev(rbsp, &pps->pic_init_qp_minus26); + rbsp_sev(rbsp, &pps->pic_init_qs_minus26); + rbsp_sev(rbsp, &pps->chroma_qp_index_offset); + rbsp_bit(rbsp, &pps->deblocking_filter_control_present_flag); + rbsp_bit(rbsp, &pps->constrained_intra_pred_flag); + rbsp_bit(rbsp, &pps->redundant_pic_cnt_present_flag); + if (/* more_rbsp_data() */ false) { + rbsp_bit(rbsp, &pps->transform_8x8_mode_flag); + rbsp_bit(rbsp, &pps->pic_scaling_matrix_present_flag); + if (pps->pic_scaling_matrix_present_flag) + rbsp->error = -EINVAL; + rbsp_sev(rbsp, &pps->second_chroma_qp_index_offset); + } +} + +/** + * nal_h264_write_sps() - Write SPS NAL unit into RBSP format + * @dev: device pointer + * @dest: the buffer that is filled with RBSP data + * @n: maximum size of @dest in bytes + * @sps: &struct nal_h264_sps to convert to RBSP + * + * Convert @sps to RBSP data and write it into @dest. + * + * The size of the SPS NAL unit is not known in advance and this function will + * fail, if @dest does not hold sufficient space for the SPS NAL unit. + * + * Return: number of bytes written to @dest or negative error code + */ +ssize_t nal_h264_write_sps(const struct device *dev, + void *dest, size_t n, struct nal_h264_sps *sps) +{ + struct rbsp rbsp; + unsigned int forbidden_zero_bit = 0; + unsigned int nal_ref_idc = 0; + unsigned int nal_unit_type = SEQUENCE_PARAMETER_SET; + + if (!dest) + return -EINVAL; + + rbsp_init(&rbsp, dest, n, &write); + + nal_h264_write_start_code_prefix(&rbsp); + + rbsp_bit(&rbsp, &forbidden_zero_bit); + rbsp_bits(&rbsp, 2, &nal_ref_idc); + rbsp_bits(&rbsp, 5, &nal_unit_type); + + nal_h264_rbsp_sps(&rbsp, sps); + + nal_h264_rbsp_trailing_bits(&rbsp); + + if (rbsp.error) + return rbsp.error; + + return DIV_ROUND_UP(rbsp.pos, 8); +} +EXPORT_SYMBOL_GPL(nal_h264_write_sps); + +/** + * nal_h264_read_sps() - Read SPS NAL unit from RBSP format + * @dev: device pointer + * @sps: the &struct nal_h264_sps to fill from the RBSP data + * @src: the buffer that contains the RBSP data + * @n: size of @src in bytes + * + * Read RBSP data from @src and use it to fill @sps. + * + * Return: number of bytes read from @src or negative error code + */ +ssize_t nal_h264_read_sps(const struct device *dev, + struct nal_h264_sps *sps, void *src, size_t n) +{ + struct rbsp rbsp; + unsigned int forbidden_zero_bit; + unsigned int nal_ref_idc; + unsigned int nal_unit_type; + + if (!src) + return -EINVAL; + + rbsp_init(&rbsp, src, n, &read); + + nal_h264_read_start_code_prefix(&rbsp); + + rbsp_bit(&rbsp, &forbidden_zero_bit); + rbsp_bits(&rbsp, 2, &nal_ref_idc); + rbsp_bits(&rbsp, 5, &nal_unit_type); + + if (rbsp.error || + forbidden_zero_bit != 0 || + nal_ref_idc != 0 || + nal_unit_type != SEQUENCE_PARAMETER_SET) + return -EINVAL; + + nal_h264_rbsp_sps(&rbsp, sps); + + nal_h264_rbsp_trailing_bits(&rbsp); + + if (rbsp.error) + return rbsp.error; + + return DIV_ROUND_UP(rbsp.pos, 8); +} +EXPORT_SYMBOL_GPL(nal_h264_read_sps); + +/** + * nal_h264_write_pps() - Write PPS NAL unit into RBSP format + * @dev: device pointer + * @dest: the buffer that is filled with RBSP data + * @n: maximum size of @dest in bytes + * @pps: &struct nal_h264_pps to convert to RBSP + * + * Convert @pps to RBSP data and write it into @dest. + * + * The size of the PPS NAL unit is not known in advance and this function will + * fail, if @dest does not hold sufficient space for the PPS NAL unit. + * + * Return: number of bytes written to @dest or negative error code + */ +ssize_t nal_h264_write_pps(const struct device *dev, + void *dest, size_t n, struct nal_h264_pps *pps) +{ + struct rbsp rbsp; + unsigned int forbidden_zero_bit = 0; + unsigned int nal_ref_idc = 0; + unsigned int nal_unit_type = PICTURE_PARAMETER_SET; + + if (!dest) + return -EINVAL; + + rbsp_init(&rbsp, dest, n, &write); + + nal_h264_write_start_code_prefix(&rbsp); + + /* NAL unit header */ + rbsp_bit(&rbsp, &forbidden_zero_bit); + rbsp_bits(&rbsp, 2, &nal_ref_idc); + rbsp_bits(&rbsp, 5, &nal_unit_type); + + nal_h264_rbsp_pps(&rbsp, pps); + + nal_h264_rbsp_trailing_bits(&rbsp); + + if (rbsp.error) + return rbsp.error; + + return DIV_ROUND_UP(rbsp.pos, 8); +} +EXPORT_SYMBOL_GPL(nal_h264_write_pps); + +/** + * nal_h264_read_pps() - Read PPS NAL unit from RBSP format + * @dev: device pointer + * @pps: the &struct nal_h264_pps to fill from the RBSP data + * @src: the buffer that contains the RBSP data + * @n: size of @src in bytes + * + * Read RBSP data from @src and use it to fill @pps. + * + * Return: number of bytes read from @src or negative error code + */ +ssize_t nal_h264_read_pps(const struct device *dev, + struct nal_h264_pps *pps, void *src, size_t n) +{ + struct rbsp rbsp; + + if (!src) + return -EINVAL; + + rbsp_init(&rbsp, src, n, &read); + + nal_h264_read_start_code_prefix(&rbsp); + + /* NAL unit header */ + rbsp.pos += 8; + + nal_h264_rbsp_pps(&rbsp, pps); + + nal_h264_rbsp_trailing_bits(&rbsp); + + if (rbsp.error) + return rbsp.error; + + return DIV_ROUND_UP(rbsp.pos, 8); +} +EXPORT_SYMBOL_GPL(nal_h264_read_pps); + +/** + * nal_h264_write_filler() - Write filler data RBSP + * @dev: device pointer + * @dest: buffer to fill with filler data + * @n: size of the buffer to fill with filler data + * + * Write a filler data RBSP to @dest with a size of @n bytes and return the + * number of written filler data bytes. + * + * Use this function to generate dummy data in an RBSP data stream that can be + * safely ignored by h264 decoders. + * + * The RBSP format of the filler data is specified in Rec. ITU-T H.264 + * (04/2017) 7.3.2.7 Filler data RBSP syntax. + * + * Return: number of filler data bytes (including marker) or negative error + */ +ssize_t nal_h264_write_filler(const struct device *dev, void *dest, size_t n) +{ + struct rbsp rbsp; + unsigned int forbidden_zero_bit = 0; + unsigned int nal_ref_idc = 0; + unsigned int nal_unit_type = FILLER_DATA; + + if (!dest) + return -EINVAL; + + rbsp_init(&rbsp, dest, n, &write); + + nal_h264_write_start_code_prefix(&rbsp); + + rbsp_bit(&rbsp, &forbidden_zero_bit); + rbsp_bits(&rbsp, 2, &nal_ref_idc); + rbsp_bits(&rbsp, 5, &nal_unit_type); + + nal_h264_write_filler_data(&rbsp); + + nal_h264_rbsp_trailing_bits(&rbsp); + + return DIV_ROUND_UP(rbsp.pos, 8); +} +EXPORT_SYMBOL_GPL(nal_h264_write_filler); + +/** + * nal_h264_read_filler() - Read filler data RBSP + * @dev: device pointer + * @src: buffer with RBSP data that is read + * @n: maximum size of src that shall be read + * + * Read a filler data RBSP from @src up to a maximum size of @n bytes and + * return the size of the filler data in bytes including the marker. + * + * This function is used to parse filler data and skip the respective bytes in + * the RBSP data. + * + * The RBSP format of the filler data is specified in Rec. ITU-T H.264 + * (04/2017) 7.3.2.7 Filler data RBSP syntax. + * + * Return: number of filler data bytes (including marker) or negative error + */ +ssize_t nal_h264_read_filler(const struct device *dev, void *src, size_t n) +{ + struct rbsp rbsp; + unsigned int forbidden_zero_bit; + unsigned int nal_ref_idc; + unsigned int nal_unit_type; + + if (!src) + return -EINVAL; + + rbsp_init(&rbsp, src, n, &read); + + nal_h264_read_start_code_prefix(&rbsp); + + rbsp_bit(&rbsp, &forbidden_zero_bit); + rbsp_bits(&rbsp, 2, &nal_ref_idc); + rbsp_bits(&rbsp, 5, &nal_unit_type); + + if (rbsp.error) + return rbsp.error; + if (forbidden_zero_bit != 0 || + nal_ref_idc != 0 || + nal_unit_type != FILLER_DATA) + return -EINVAL; + + nal_h264_read_filler_data(&rbsp); + nal_h264_rbsp_trailing_bits(&rbsp); + + if (rbsp.error) + return rbsp.error; + + return DIV_ROUND_UP(rbsp.pos, 8); +} +EXPORT_SYMBOL_GPL(nal_h264_read_filler); diff --git a/drivers/staging/media/allegro-dvt/nal-h264.h b/drivers/staging/media/allegro-dvt/nal-h264.h new file mode 100644 index 000000000000..2ba7cbced7a5 --- /dev/null +++ b/drivers/staging/media/allegro-dvt/nal-h264.h @@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de> + * + * Convert NAL units between raw byte sequence payloads (RBSP) and C structs. + */ + +#ifndef __NAL_H264_H__ +#define __NAL_H264_H__ + +#include <linux/kernel.h> +#include <linux/types.h> + +/** + * struct nal_h264_hdr_parameters - HDR parameters + * + * C struct representation of the sequence parameter set NAL unit as defined by + * Rec. ITU-T H.264 (04/2017) E.1.2 HRD parameters syntax. + */ +struct nal_h264_hrd_parameters { + unsigned int cpb_cnt_minus1; + unsigned int bit_rate_scale; + unsigned int cpb_size_scale; + struct { + int bit_rate_value_minus1[16]; + int cpb_size_value_minus1[16]; + unsigned int cbr_flag[16]; + }; + unsigned int initial_cpb_removal_delay_length_minus1; + unsigned int cpb_removal_delay_length_minus1; + unsigned int dpb_output_delay_length_minus1; + unsigned int time_offset_length; +}; + +/** + * struct nal_h264_vui_parameters - VUI parameters + * + * C struct representation of the VUI parameters as defined by Rec. ITU-T + * H.264 (04/2017) E.1.1 VUI parameters syntax. + */ +struct nal_h264_vui_parameters { + unsigned int aspect_ratio_info_present_flag; + struct { + unsigned int aspect_ratio_idc; + unsigned int sar_width; + unsigned int sar_height; + }; + unsigned int overscan_info_present_flag; + unsigned int overscan_appropriate_flag; + unsigned int video_signal_type_present_flag; + struct { + unsigned int video_format; + unsigned int video_full_range_flag; + unsigned int colour_description_present_flag; + struct { + unsigned int colour_primaries; + unsigned int transfer_characteristics; + unsigned int matrix_coefficients; + }; + }; + unsigned int chroma_loc_info_present_flag; + struct { + unsigned int chroma_sample_loc_type_top_field; + unsigned int chroma_sample_loc_type_bottom_field; + }; + unsigned int timing_info_present_flag; + struct { + unsigned int num_units_in_tick; + unsigned int time_scale; + unsigned int fixed_frame_rate_flag; + }; + unsigned int nal_hrd_parameters_present_flag; + struct nal_h264_hrd_parameters nal_hrd_parameters; + unsigned int vcl_hrd_parameters_present_flag; + struct nal_h264_hrd_parameters vcl_hrd_parameters; + unsigned int low_delay_hrd_flag; + unsigned int pic_struct_present_flag; + unsigned int bitstream_restriction_flag; + struct { + unsigned int motion_vectors_over_pic_boundaries_flag; + unsigned int max_bytes_per_pic_denom; + unsigned int max_bits_per_mb_denom; + unsigned int log2_max_mv_length_horizontal; + unsigned int log21_max_mv_length_vertical; + unsigned int max_num_reorder_frames; + unsigned int max_dec_frame_buffering; + }; +}; + +/** + * struct nal_h264_sps - Sequence parameter set + * + * C struct representation of the sequence parameter set NAL unit as defined by + * Rec. ITU-T H.264 (04/2017) 7.3.2.1.1 Sequence parameter set data syntax. + */ +struct nal_h264_sps { + unsigned int profile_idc; + unsigned int constraint_set0_flag; + unsigned int constraint_set1_flag; + unsigned int constraint_set2_flag; + unsigned int constraint_set3_flag; + unsigned int constraint_set4_flag; + unsigned int constraint_set5_flag; + unsigned int reserved_zero_2bits; + unsigned int level_idc; + unsigned int seq_parameter_set_id; + struct { + unsigned int chroma_format_idc; + unsigned int separate_colour_plane_flag; + unsigned int bit_depth_luma_minus8; + unsigned int bit_depth_chroma_minus8; + unsigned int qpprime_y_zero_transform_bypass_flag; + unsigned int seq_scaling_matrix_present_flag; + }; + unsigned int log2_max_frame_num_minus4; + unsigned int pic_order_cnt_type; + union { + unsigned int log2_max_pic_order_cnt_lsb_minus4; + struct { + unsigned int delta_pic_order_always_zero_flag; + int offset_for_non_ref_pic; + int offset_for_top_to_bottom_field; + unsigned int num_ref_frames_in_pic_order_cnt_cycle; + int offset_for_ref_frame[255]; + }; + }; + unsigned int max_num_ref_frames; + unsigned int gaps_in_frame_num_value_allowed_flag; + unsigned int pic_width_in_mbs_minus1; + unsigned int pic_height_in_map_units_minus1; + unsigned int frame_mbs_only_flag; + unsigned int mb_adaptive_frame_field_flag; + unsigned int direct_8x8_inference_flag; + unsigned int frame_cropping_flag; + struct { + unsigned int crop_left; + unsigned int crop_right; + unsigned int crop_top; + unsigned int crop_bottom; + }; + unsigned int vui_parameters_present_flag; + struct nal_h264_vui_parameters vui; +}; + +/** + * struct nal_h264_pps - Picture parameter set + * + * C struct representation of the picture parameter set NAL unit as defined by + * Rec. ITU-T H.264 (04/2017) 7.3.2.2 Picture parameter set RBSP syntax. + */ +struct nal_h264_pps { + unsigned int pic_parameter_set_id; + unsigned int seq_parameter_set_id; + unsigned int entropy_coding_mode_flag; + unsigned int bottom_field_pic_order_in_frame_present_flag; + unsigned int num_slice_groups_minus1; + unsigned int slice_group_map_type; + union { + unsigned int run_length_minus1[8]; + struct { + unsigned int top_left[8]; + unsigned int bottom_right[8]; + }; + struct { + unsigned int slice_group_change_direction_flag; + unsigned int slice_group_change_rate_minus1; + }; + struct { + unsigned int pic_size_in_map_units_minus1; + unsigned int slice_group_id[8]; + }; + }; + unsigned int num_ref_idx_l0_default_active_minus1; + unsigned int num_ref_idx_l1_default_active_minus1; + unsigned int weighted_pred_flag; + unsigned int weighted_bipred_idc; + int pic_init_qp_minus26; + int pic_init_qs_minus26; + int chroma_qp_index_offset; + unsigned int deblocking_filter_control_present_flag; + unsigned int constrained_intra_pred_flag; + unsigned int redundant_pic_cnt_present_flag; + struct { + unsigned int transform_8x8_mode_flag; + unsigned int pic_scaling_matrix_present_flag; + int second_chroma_qp_index_offset; + }; +}; + +int nal_h264_profile_from_v4l2(enum v4l2_mpeg_video_h264_profile profile); +int nal_h264_level_from_v4l2(enum v4l2_mpeg_video_h264_level level); + +ssize_t nal_h264_write_sps(const struct device *dev, + void *dest, size_t n, struct nal_h264_sps *sps); +ssize_t nal_h264_read_sps(const struct device *dev, + struct nal_h264_sps *sps, void *src, size_t n); +void nal_h264_print_sps(const struct device *dev, struct nal_h264_sps *sps); + +ssize_t nal_h264_write_pps(const struct device *dev, + void *dest, size_t n, struct nal_h264_pps *pps); +ssize_t nal_h264_read_pps(const struct device *dev, + struct nal_h264_pps *pps, void *src, size_t n); +void nal_h264_print_pps(const struct device *dev, struct nal_h264_pps *pps); + +ssize_t nal_h264_write_filler(const struct device *dev, void *dest, size_t n); +ssize_t nal_h264_read_filler(const struct device *dev, void *src, size_t n); + +#endif /* __NAL_H264_H__ */ diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index 09903ffb13ba..2c60a1fb6350 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c @@ -2310,11 +2310,6 @@ static int bcm2048_vidioc_querycap(struct file *file, void *priv, strscpy(capability->card, BCM2048_DRIVER_CARD, sizeof(capability->card)); snprintf(capability->bus_info, 32, "I2C: 0x%X", bdev->client->addr); - capability->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | - V4L2_CAP_HW_FREQ_SEEK; - capability->capabilities = capability->device_caps | - V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -2570,6 +2565,8 @@ static const struct video_device bcm2048_viddev_template = { .name = BCM2048_DRIVER_NAME, .release = video_device_release_empty, .ioctl_ops = &bcm2048_ioctl_ops, + .device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | + V4L2_CAP_HW_FREQ_SEEK, }; /* diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c index 30e2edc0cec5..52397ad0e3e2 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c +++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c @@ -1251,10 +1251,10 @@ static int ipipe_s_config(struct v4l2_subdev *sd, struct vpfe_ipipe_config *cfg) struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); unsigned int i; int rval = 0; + struct ipipe_module_params *params; for (i = 0; i < ARRAY_SIZE(ipipe_modules); i++) { const struct ipipe_module_if *module_if; - struct ipipe_module_params *params; void *from, *to; size_t size; @@ -1265,25 +1265,30 @@ static int ipipe_s_config(struct v4l2_subdev *sd, struct vpfe_ipipe_config *cfg) from = *(void **)((void *)cfg + module_if->config_offset); params = kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; to = (void *)params + module_if->param_offset; size = module_if->param_size; if (to && from && size) { if (copy_from_user(to, (void __user *)from, size)) { rval = -EFAULT; - break; + goto error_free; } rval = module_if->set(ipipe, to); if (rval) - goto error; + goto error_free; } else if (to && !from && size) { rval = module_if->set(ipipe, NULL); if (rval) - goto error; + goto error_free; } kfree(params); } -error: + return rval; + +error_free: + kfree(params); return rval; } @@ -1772,7 +1777,7 @@ vpfe_ipipe_init(struct vpfe_ipipe_device *ipipe, struct platform_device *pdev) struct media_pad *pads = &ipipe->pads[0]; struct v4l2_subdev *sd = &ipipe->subdev; struct media_entity *me = &sd->entity; - struct resource *res, *memres; + struct resource *res, *res2, *memres; res = platform_get_resource(pdev, IORESOURCE_MEM, 4); if (!res) @@ -1786,11 +1791,11 @@ vpfe_ipipe_init(struct vpfe_ipipe_device *ipipe, struct platform_device *pdev) if (!ipipe->base_addr) goto error_release; - res = platform_get_resource(pdev, IORESOURCE_MEM, 6); - if (!res) + res2 = platform_get_resource(pdev, IORESOURCE_MEM, 6); + if (!res2) goto error_unmap; - ipipe->isp5_base_addr = ioremap_nocache(res->start, - resource_size(res)); + ipipe->isp5_base_addr = ioremap_nocache(res2->start, + resource_size(res2)); if (!ipipe->isp5_base_addr) goto error_unmap; diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c index 46fd8184fc77..05a997f7aa5d 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_isif.c +++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c @@ -816,7 +816,7 @@ isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc) /* Correct whole line or partial */ if (vdfc->corr_whole_line) - val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT; + val |= BIT(ISIF_VDFC_CORR_WHOLE_LN_SHIFT); /* level shift value */ val |= (vdfc->def_level_shift & ISIF_VDFC_LEVEL_SHFT_MASK) << @@ -844,7 +844,7 @@ isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc) val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL); /* set DFCMARST and set DFCMWR */ - val |= 1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT; + val |= BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); val |= 1; isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL); @@ -875,7 +875,7 @@ isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc) } val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL); /* clear DFCMARST and set DFCMWR */ - val &= ~(1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT); + val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); val |= 1; isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL); @@ -1135,7 +1135,7 @@ static int isif_config_raw(struct v4l2_subdev *sd, int mode) isif_write(isif->isif_cfg.base_addr, val, CGAMMAWD); /* Configure DPCM compression settings */ if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10DPCM8) { - val = 1 << ISIF_DPCM_EN_SHIFT; + val = BIT(ISIF_DPCM_EN_SHIFT); val |= (params->dpcm_predictor & ISIF_DPCM_PREDICTOR_MASK) << ISIF_DPCM_PREDICTOR_SHIFT; } diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c index 57b93605bc58..9dc28ffe38d5 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c @@ -158,7 +158,7 @@ static irqreturn_t vpfe_isr(int irq, void *dev_id) { struct vpfe_device *vpfe_dev = dev_id; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_isr\n"); + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__); vpfe_isif_buffer_isr(&vpfe_dev->vpfe_isif); vpfe_resizer_buffer_isr(&vpfe_dev->vpfe_resizer); return IRQ_HANDLED; @@ -169,7 +169,7 @@ static irqreturn_t vpfe_vdint1_isr(int irq, void *dev_id) { struct vpfe_device *vpfe_dev = dev_id; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_vdint1_isr\n"); + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__); vpfe_isif_vidint1_isr(&vpfe_dev->vpfe_isif); return IRQ_HANDLED; } @@ -179,7 +179,7 @@ static irqreturn_t vpfe_imp_dma_isr(int irq, void *dev_id) { struct vpfe_device *vpfe_dev = dev_id; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_imp_dma_isr\n"); + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__); vpfe_ipipeif_ss_buffer_isr(&vpfe_dev->vpfe_ipipeif); vpfe_resizer_dma_isr(&vpfe_dev->vpfe_resizer); return IRQ_HANDLED; @@ -691,7 +691,7 @@ static int vpfe_remove(struct platform_device *pdev) { struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); - v4l2_info(pdev->dev.driver, "vpfe_remove\n"); + v4l2_info(pdev->dev.driver, "%s\n", __func__); kzfree(vpfe_dev->sd); vpfe_detach_irq(vpfe_dev); diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c index 510202a3b091..ab6bc452d9f6 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c @@ -419,6 +419,9 @@ static int vpfe_open(struct file *file) /* If decoder is not initialized. initialize it */ if (!video->initialized && vpfe_update_pipe_state(video)) { mutex_unlock(&video->lock); + v4l2_fh_del(&handle->vfh); + v4l2_fh_exit(&handle->vfh); + kfree(handle); return -ENODEV; } /* Increment device users counter */ @@ -609,10 +612,6 @@ static int vpfe_querycap(struct file *file, void *priv, v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n"); - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - else - cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; strscpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); @@ -1625,6 +1624,11 @@ int vpfe_video_register(struct vpfe_video_device *video, video->video_dev.v4l2_dev = vdev; + if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + video->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE; + else + video->video_dev.device_caps = V4L2_CAP_VIDEO_OUTPUT; + video->video_dev.device_caps |= V4L2_CAP_STREAMING; ret = video_register_device(&video->video_dev, VFL_TYPE_GRABBER, -1); if (ret < 0) pr_err("%s: could not register video device (%d)\n", diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/staging/media/hantro/Kconfig new file mode 100644 index 000000000000..be133bbaa68a --- /dev/null +++ b/drivers/staging/media/hantro/Kconfig @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0 +config VIDEO_HANTRO + tristate "Hantro VPU driver" + depends on ARCH_ROCKCHIP || COMPILE_TEST + depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on MEDIA_CONTROLLER_REQUEST_API + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_VMALLOC + select V4L2_MEM2MEM_DEV + help + Support for the Hantro IP based Video Processing Unit present on + Rockchip SoC, which accelerates video and image encoding and + decoding. + To compile this driver as a module, choose M here: the module + will be called hantro-vpu. + +config VIDEO_HANTRO_ROCKCHIP + bool "Hantro VPU Rockchip support" + depends on VIDEO_HANTRO + depends on ARCH_ROCKCHIP || COMPILE_TEST + default y + help + Enable support for RK3288 and RK3399 SoCs. diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile new file mode 100644 index 000000000000..1584acdbf4a3 --- /dev/null +++ b/drivers/staging/media/hantro/Makefile @@ -0,0 +1,15 @@ +obj-$(CONFIG_VIDEO_HANTRO) += hantro-vpu.o + +hantro-vpu-y += \ + hantro_drv.o \ + hantro_v4l2.o \ + hantro_h1_jpeg_enc.o \ + hantro_g1_mpeg2_dec.o \ + rk3399_vpu_hw_jpeg_enc.o \ + rk3399_vpu_hw_mpeg2_dec.o \ + hantro_jpeg.o \ + hantro_mpeg2.o + +hantro-vpu-$(CONFIG_VIDEO_HANTRO_ROCKCHIP) += \ + rk3288_vpu_hw.o \ + rk3399_vpu_hw.o diff --git a/drivers/staging/media/rockchip/vpu/TODO b/drivers/staging/media/hantro/TODO index fa0c94057007..fa0c94057007 100644 --- a/drivers/staging/media/rockchip/vpu/TODO +++ b/drivers/staging/media/hantro/TODO diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h new file mode 100644 index 000000000000..62dcca9ff19c --- /dev/null +++ b/drivers/staging/media/hantro/hantro.h @@ -0,0 +1,351 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Hantro VPU codec driver + * + * Copyright 2018 Google LLC. + * Tomasz Figa <tfiga@chromium.org> + * + * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + */ + +#ifndef HANTRO_H_ +#define HANTRO_H_ + +#include <linux/platform_device.h> +#include <linux/videodev2.h> +#include <linux/wait.h> +#include <linux/clk.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "hantro_hw.h" + +#define MPEG2_MB_DIM 16 +#define MPEG2_MB_WIDTH(w) DIV_ROUND_UP(w, MPEG2_MB_DIM) +#define MPEG2_MB_HEIGHT(h) DIV_ROUND_UP(h, MPEG2_MB_DIM) + +#define JPEG_MB_DIM 16 +#define JPEG_MB_WIDTH(w) DIV_ROUND_UP(w, JPEG_MB_DIM) +#define JPEG_MB_HEIGHT(h) DIV_ROUND_UP(h, JPEG_MB_DIM) + +struct hantro_ctx; +struct hantro_codec_ops; + +#define HANTRO_JPEG_ENCODER BIT(0) +#define HANTRO_ENCODERS 0x0000ffff + +#define HANTRO_MPEG2_DECODER BIT(16) +#define HANTRO_DECODERS 0xffff0000 + +/** + * struct hantro_irq - irq handler and name + * + * @name: irq name for device tree lookup + * @handler: interrupt handler + */ +struct hantro_irq { + const char *name; + irqreturn_t (*handler)(int irq, void *priv); +}; + +/** + * struct hantro_variant - information about VPU hardware variant + * + * @enc_offset: Offset from VPU base to encoder registers. + * @dec_offset: Offset from VPU base to decoder registers. + * @enc_fmts: Encoder formats. + * @num_enc_fmts: Number of encoder formats. + * @dec_fmts: Decoder formats. + * @num_dec_fmts: Number of decoder formats. + * @codec: Supported codecs + * @codec_ops: Codec ops. + * @init: Initialize hardware. + * @runtime_resume: reenable hardware after power gating + * @irqs: array of irq names and interrupt handlers + * @num_irqs: number of irqs in the array + * @clk_names: array of clock names + * @num_clocks: number of clocks in the array + * @reg_names: array of register range names + * @num_regs: number of register range names in the array + */ +struct hantro_variant { + unsigned int enc_offset; + unsigned int dec_offset; + const struct hantro_fmt *enc_fmts; + unsigned int num_enc_fmts; + const struct hantro_fmt *dec_fmts; + unsigned int num_dec_fmts; + unsigned int codec; + const struct hantro_codec_ops *codec_ops; + int (*init)(struct hantro_dev *vpu); + int (*runtime_resume)(struct hantro_dev *vpu); + const struct hantro_irq *irqs; + int num_irqs; + const char * const *clk_names; + int num_clocks; + const char * const *reg_names; + int num_regs; +}; + +/** + * enum hantro_codec_mode - codec operating mode. + * @HANTRO_MODE_NONE: No operating mode. Used for RAW video formats. + * @HANTRO_MODE_JPEG_ENC: JPEG encoder. + * @HANTRO_MODE_MPEG2_DEC: MPEG-2 decoder. + */ +enum hantro_codec_mode { + HANTRO_MODE_NONE = -1, + HANTRO_MODE_JPEG_ENC, + HANTRO_MODE_MPEG2_DEC, +}; + +/* + * struct hantro_ctrl - helper type to declare supported controls + * @id: V4L2 control ID (V4L2_CID_xxx) + * @codec: codec id this control belong to (HANTRO_JPEG_ENCODER, etc.) + * @cfg: control configuration + */ +struct hantro_ctrl { + unsigned int id; + unsigned int codec; + struct v4l2_ctrl_config cfg; +}; + +/* + * struct hantro_func - Hantro VPU functionality + * + * @id: processing functionality ID (can be + * %MEDIA_ENT_F_PROC_VIDEO_ENCODER or + * %MEDIA_ENT_F_PROC_VIDEO_DECODER) + * @vdev: &struct video_device that exposes the encoder or + * decoder functionality + * @source_pad: &struct media_pad with the source pad. + * @sink: &struct media_entity pointer with the sink entity + * @sink_pad: &struct media_pad with the sink pad. + * @proc: &struct media_entity pointer with the M2M device itself. + * @proc_pads: &struct media_pad with the @proc pads. + * @intf_devnode: &struct media_intf devnode pointer with the interface + * with controls the M2M device. + * + * Contains everything needed to attach the video device to the media device. + */ +struct hantro_func { + unsigned int id; + struct video_device vdev; + struct media_pad source_pad; + struct media_entity sink; + struct media_pad sink_pad; + struct media_entity proc; + struct media_pad proc_pads[2]; + struct media_intf_devnode *intf_devnode; +}; + +static inline struct hantro_func * +hantro_vdev_to_func(struct video_device *vdev) +{ + return container_of(vdev, struct hantro_func, vdev); +} + +/** + * struct hantro_dev - driver data + * @v4l2_dev: V4L2 device to register video devices for. + * @m2m_dev: mem2mem device associated to this device. + * @mdev: media device associated to this device. + * @encoder: encoder functionality. + * @decoder: decoder functionality. + * @pdev: Pointer to VPU platform device. + * @dev: Pointer to device for convenient logging using + * dev_ macros. + * @clocks: Array of clock handles. + * @reg_bases: Mapped addresses of VPU registers. + * @enc_base: Mapped address of VPU encoder register for convenience. + * @dec_base: Mapped address of VPU decoder register for convenience. + * @ctrl_base: Mapped address of VPU control block. + * @vpu_mutex: Mutex to synchronize V4L2 calls. + * @irqlock: Spinlock to synchronize access to data structures + * shared with interrupt handlers. + * @variant: Hardware variant-specific parameters. + * @watchdog_work: Delayed work for hardware timeout handling. + */ +struct hantro_dev { + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *m2m_dev; + struct media_device mdev; + struct hantro_func *encoder; + struct hantro_func *decoder; + struct platform_device *pdev; + struct device *dev; + struct clk_bulk_data *clocks; + void __iomem **reg_bases; + void __iomem *enc_base; + void __iomem *dec_base; + void __iomem *ctrl_base; + + struct mutex vpu_mutex; /* video_device lock */ + spinlock_t irqlock; + const struct hantro_variant *variant; + struct delayed_work watchdog_work; +}; + +/** + * struct hantro_ctx - Context (instance) private data. + * + * @dev: VPU driver data to which the context belongs. + * @fh: V4L2 file handler. + * + * @sequence_cap: Sequence counter for capture queue + * @sequence_out: Sequence counter for output queue + * + * @vpu_src_fmt: Descriptor of active source format. + * @src_fmt: V4L2 pixel format of active source format. + * @vpu_dst_fmt: Descriptor of active destination format. + * @dst_fmt: V4L2 pixel format of active destination format. + * + * @ctrl_handler: Control handler used to register controls. + * @jpeg_quality: User-specified JPEG compression quality. + * + * @buf_finish: Buffer finish. This depends on encoder or decoder + * context, and it's called right before + * calling v4l2_m2m_job_finish. + * @codec_ops: Set of operations related to codec mode. + * @jpeg_enc: JPEG-encoding context. + * @mpeg2_dec: MPEG-2-decoding context. + */ +struct hantro_ctx { + struct hantro_dev *dev; + struct v4l2_fh fh; + + u32 sequence_cap; + u32 sequence_out; + + const struct hantro_fmt *vpu_src_fmt; + struct v4l2_pix_format_mplane src_fmt; + const struct hantro_fmt *vpu_dst_fmt; + struct v4l2_pix_format_mplane dst_fmt; + + struct v4l2_ctrl_handler ctrl_handler; + int jpeg_quality; + + int (*buf_finish)(struct hantro_ctx *ctx, + struct vb2_buffer *buf, + unsigned int bytesused); + + const struct hantro_codec_ops *codec_ops; + + /* Specific for particular codec modes. */ + union { + struct hantro_jpeg_enc_hw_ctx jpeg_enc; + struct hantro_mpeg2_dec_hw_ctx mpeg2_dec; + }; +}; + +/** + * struct hantro_fmt - information about supported video formats. + * @name: Human readable name of the format. + * @fourcc: FourCC code of the format. See V4L2_PIX_FMT_*. + * @codec_mode: Codec mode related to this format. See + * enum hantro_codec_mode. + * @header_size: Optional header size. Currently used by JPEG encoder. + * @max_depth: Maximum depth, for bitstream formats + * @enc_fmt: Format identifier for encoder registers. + * @frmsize: Supported range of frame sizes (only for bitstream formats). + */ +struct hantro_fmt { + char *name; + u32 fourcc; + enum hantro_codec_mode codec_mode; + int header_size; + int max_depth; + enum hantro_enc_fmt enc_fmt; + struct v4l2_frmsize_stepwise frmsize; +}; + +/* Logging helpers */ + +/** + * debug - Module parameter to control level of debugging messages. + * + * Level of debugging messages can be controlled by bits of + * module parameter called "debug". Meaning of particular + * bits is as follows: + * + * bit 0 - global information: mode, size, init, release + * bit 1 - each run start/result information + * bit 2 - contents of small controls from userspace + * bit 3 - contents of big controls from userspace + * bit 4 - detail fmt, ctrl, buffer q/dq information + * bit 5 - detail function enter/leave trace information + * bit 6 - register write/read information + */ +extern int hantro_debug; + +#define vpu_debug(level, fmt, args...) \ + do { \ + if (hantro_debug & BIT(level)) \ + pr_info("%s:%d: " fmt, \ + __func__, __LINE__, ##args); \ + } while (0) + +#define vpu_err(fmt, args...) \ + pr_err("%s:%d: " fmt, __func__, __LINE__, ##args) + +/* Structure access helpers. */ +static inline struct hantro_ctx *fh_to_ctx(struct v4l2_fh *fh) +{ + return container_of(fh, struct hantro_ctx, fh); +} + +/* Register accessors. */ +static inline void vepu_write_relaxed(struct hantro_dev *vpu, + u32 val, u32 reg) +{ + vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); + writel_relaxed(val, vpu->enc_base + reg); +} + +static inline void vepu_write(struct hantro_dev *vpu, u32 val, u32 reg) +{ + vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); + writel(val, vpu->enc_base + reg); +} + +static inline u32 vepu_read(struct hantro_dev *vpu, u32 reg) +{ + u32 val = readl(vpu->enc_base + reg); + + vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); + return val; +} + +static inline void vdpu_write_relaxed(struct hantro_dev *vpu, + u32 val, u32 reg) +{ + vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); + writel_relaxed(val, vpu->dec_base + reg); +} + +static inline void vdpu_write(struct hantro_dev *vpu, u32 val, u32 reg) +{ + vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); + writel(val, vpu->dec_base + reg); +} + +static inline u32 vdpu_read(struct hantro_dev *vpu, u32 reg) +{ + u32 val = readl(vpu->dec_base + reg); + + vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); + return val; +} + +bool hantro_is_encoder_ctx(const struct hantro_ctx *ctx); + +void *hantro_get_ctrl(struct hantro_ctx *ctx, u32 id); +dma_addr_t hantro_get_ref(struct vb2_queue *q, u64 ts); + +#endif /* HANTRO_H_ */ diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c new file mode 100644 index 000000000000..c3665f0e87a2 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -0,0 +1,876 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Collabora, Ltd. + * Copyright 2018 Google LLC. + * Tomasz Figa <tfiga@chromium.org> + * + * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/videodev2.h> +#include <linux/workqueue.h> +#include <media/v4l2-event.h> +#include <media/v4l2-mem2mem.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-vmalloc.h> + +#include "hantro_v4l2.h" +#include "hantro.h" +#include "hantro_hw.h" + +#define DRIVER_NAME "hantro-vpu" + +int hantro_debug; +module_param_named(debug, hantro_debug, int, 0644); +MODULE_PARM_DESC(debug, + "Debug level - higher value produces more verbose messages"); + +void *hantro_get_ctrl(struct hantro_ctx *ctx, u32 id) +{ + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_find(&ctx->ctrl_handler, id); + return ctrl ? ctrl->p_cur.p : NULL; +} + +dma_addr_t hantro_get_ref(struct vb2_queue *q, u64 ts) +{ + struct vb2_buffer *buf; + int index; + + index = vb2_find_timestamp(q, ts, 0); + if (index < 0) + return 0; + buf = vb2_get_buffer(q, index); + return vb2_dma_contig_plane_dma_addr(buf, 0); +} + +static int +hantro_enc_buf_finish(struct hantro_ctx *ctx, struct vb2_buffer *buf, + unsigned int bytesused) +{ + size_t avail_size; + + avail_size = vb2_plane_size(buf, 0) - ctx->vpu_dst_fmt->header_size; + if (bytesused > avail_size) + return -EINVAL; + /* + * The bounce buffer is only for the JPEG encoder. + * TODO: Rework the JPEG encoder to eliminate the need + * for a bounce buffer. + */ + if (ctx->jpeg_enc.bounce_buffer.cpu) { + memcpy(vb2_plane_vaddr(buf, 0) + + ctx->vpu_dst_fmt->header_size, + ctx->jpeg_enc.bounce_buffer.cpu, bytesused); + } + buf->planes[0].bytesused = + ctx->vpu_dst_fmt->header_size + bytesused; + return 0; +} + +static int +hantro_dec_buf_finish(struct hantro_ctx *ctx, struct vb2_buffer *buf, + unsigned int bytesused) +{ + /* For decoders set bytesused as per the output picture. */ + buf->planes[0].bytesused = ctx->dst_fmt.plane_fmt[0].sizeimage; + return 0; +} + +static void hantro_job_finish(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + unsigned int bytesused, + enum vb2_buffer_state result) +{ + struct vb2_v4l2_buffer *src, *dst; + int ret; + + pm_runtime_mark_last_busy(vpu->dev); + pm_runtime_put_autosuspend(vpu->dev); + clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks); + + src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + if (WARN_ON(!src)) + return; + if (WARN_ON(!dst)) + return; + + src->sequence = ctx->sequence_out++; + dst->sequence = ctx->sequence_cap++; + + v4l2_m2m_buf_copy_metadata(src, dst, true); + + ret = ctx->buf_finish(ctx, &dst->vb2_buf, bytesused); + if (ret) + result = VB2_BUF_STATE_ERROR; + + v4l2_m2m_buf_done(src, result); + v4l2_m2m_buf_done(dst, result); + + v4l2_m2m_job_finish(vpu->m2m_dev, ctx->fh.m2m_ctx); +} + +void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, + enum vb2_buffer_state result) +{ + struct hantro_ctx *ctx = + v4l2_m2m_get_curr_priv(vpu->m2m_dev); + + /* + * If cancel_delayed_work returns false + * the timeout expired. The watchdog is running, + * and will take care of finishing the job. + */ + if (cancel_delayed_work(&vpu->watchdog_work)) + hantro_job_finish(vpu, ctx, bytesused, result); +} + +void hantro_watchdog(struct work_struct *work) +{ + struct hantro_dev *vpu; + struct hantro_ctx *ctx; + + vpu = container_of(to_delayed_work(work), + struct hantro_dev, watchdog_work); + ctx = v4l2_m2m_get_curr_priv(vpu->m2m_dev); + if (ctx) { + vpu_err("frame processing timed out!\n"); + ctx->codec_ops->reset(ctx); + hantro_job_finish(vpu, ctx, 0, VB2_BUF_STATE_ERROR); + } +} + +static void device_run(void *priv) +{ + struct hantro_ctx *ctx = priv; + int ret; + + ret = clk_bulk_enable(ctx->dev->variant->num_clocks, ctx->dev->clocks); + if (ret) + goto err_cancel_job; + ret = pm_runtime_get_sync(ctx->dev->dev); + if (ret < 0) + goto err_cancel_job; + + ctx->codec_ops->run(ctx); + return; + +err_cancel_job: + hantro_job_finish(ctx->dev, ctx, 0, VB2_BUF_STATE_ERROR); +} + +bool hantro_is_encoder_ctx(const struct hantro_ctx *ctx) +{ + return ctx->buf_finish == hantro_enc_buf_finish; +} + +static struct v4l2_m2m_ops vpu_m2m_ops = { + .device_run = device_run, +}; + +static int +queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + struct hantro_ctx *ctx = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->ops = &hantro_queue_ops; + src_vq->mem_ops = &vb2_dma_contig_memops; + + /* + * Driver does mostly sequential access, so sacrifice TLB efficiency + * for faster allocation. Also, no CPU access on the source queue, + * so no kernel mapping needed. + */ + src_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES | + DMA_ATTR_NO_KERNEL_MAPPING; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->dev->vpu_mutex; + src_vq->dev = ctx->dev->v4l2_dev.dev; + src_vq->supports_requests = true; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + /* + * When encoding, the CAPTURE queue doesn't need dma memory, + * as the CPU needs to create the JPEG frames, from the + * hardware-produced JPEG payload. + * + * For the DMA destination buffer, we use a bounce buffer. + */ + if (hantro_is_encoder_ctx(ctx)) { + dst_vq->mem_ops = &vb2_vmalloc_memops; + } else { + dst_vq->bidirectional = true; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES | + DMA_ATTR_NO_KERNEL_MAPPING; + } + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->ops = &hantro_queue_ops; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->dev->vpu_mutex; + dst_vq->dev = ctx->dev->v4l2_dev.dev; + + return vb2_queue_init(dst_vq); +} + +static int hantro_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct hantro_ctx *ctx; + + ctx = container_of(ctrl->handler, + struct hantro_ctx, ctrl_handler); + + vpu_debug(1, "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + ctx->jpeg_quality = ctrl->val; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops hantro_ctrl_ops = { + .s_ctrl = hantro_s_ctrl, +}; + +static struct hantro_ctrl controls[] = { + { + .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, + .codec = HANTRO_JPEG_ENCODER, + .cfg = { + .min = 5, + .max = 100, + .step = 1, + .def = 50, + }, + }, { + .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, + .codec = HANTRO_MPEG2_DECODER, + .cfg = { + .elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params), + }, + }, { + .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, + .codec = HANTRO_MPEG2_DECODER, + .cfg = { + .elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization), + }, + }, +}; + +static int hantro_ctrls_setup(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + int allowed_codecs) +{ + int i, num_ctrls = ARRAY_SIZE(controls); + + v4l2_ctrl_handler_init(&ctx->ctrl_handler, num_ctrls); + + for (i = 0; i < num_ctrls; i++) { + if (!(allowed_codecs & controls[i].codec)) + continue; + if (!controls[i].cfg.elem_size) { + v4l2_ctrl_new_std(&ctx->ctrl_handler, + &hantro_ctrl_ops, + controls[i].id, controls[i].cfg.min, + controls[i].cfg.max, + controls[i].cfg.step, + controls[i].cfg.def); + } else { + controls[i].cfg.id = controls[i].id; + v4l2_ctrl_new_custom(&ctx->ctrl_handler, + &controls[i].cfg, NULL); + } + + if (ctx->ctrl_handler.error) { + vpu_err("Adding control (%d) failed %d\n", + controls[i].id, + ctx->ctrl_handler.error); + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + return ctx->ctrl_handler.error; + } + } + return v4l2_ctrl_handler_setup(&ctx->ctrl_handler); +} + +/* + * V4L2 file operations. + */ + +static int hantro_open(struct file *filp) +{ + struct hantro_dev *vpu = video_drvdata(filp); + struct video_device *vdev = video_devdata(filp); + struct hantro_func *func = hantro_vdev_to_func(vdev); + struct hantro_ctx *ctx; + int allowed_codecs, ret; + + /* + * We do not need any extra locking here, because we operate only + * on local data here, except reading few fields from dev, which + * do not change through device's lifetime (which is guaranteed by + * reference on module from open()) and V4L2 internal objects (such + * as vdev and ctx->fh), which have proper locking done in respective + * helper functions used here. + */ + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->dev = vpu; + if (func->id == MEDIA_ENT_F_PROC_VIDEO_ENCODER) { + allowed_codecs = vpu->variant->codec & HANTRO_ENCODERS; + ctx->buf_finish = hantro_enc_buf_finish; + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx, + queue_init); + } else if (func->id == MEDIA_ENT_F_PROC_VIDEO_DECODER) { + allowed_codecs = vpu->variant->codec & HANTRO_DECODERS; + ctx->buf_finish = hantro_dec_buf_finish; + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx, + queue_init); + } else { + ctx->fh.m2m_ctx = ERR_PTR(-ENODEV); + } + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + kfree(ctx); + return ret; + } + + v4l2_fh_init(&ctx->fh, vdev); + filp->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + hantro_reset_fmts(ctx); + + ret = hantro_ctrls_setup(vpu, ctx, allowed_codecs); + if (ret) { + vpu_err("Failed to set up controls\n"); + goto err_fh_free; + } + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + + return 0; + +err_fh_free: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + return ret; +} + +static int hantro_release(struct file *filp) +{ + struct hantro_ctx *ctx = + container_of(filp->private_data, struct hantro_ctx, fh); + + /* + * No need for extra locking because this was the last reference + * to this file. + */ + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + kfree(ctx); + + return 0; +} + +static const struct v4l2_file_operations hantro_fops = { + .owner = THIS_MODULE, + .open = hantro_open, + .release = hantro_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static const struct of_device_id of_hantro_match[] = { +#ifdef CONFIG_VIDEO_HANTRO_ROCKCHIP + { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, + { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, +#endif + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_hantro_match); + +static int hantro_register_entity(struct media_device *mdev, + struct media_entity *entity, + const char *entity_name, + struct media_pad *pads, int num_pads, + int function, struct video_device *vdev) +{ + char *name; + int ret; + + entity->obj_type = MEDIA_ENTITY_TYPE_BASE; + if (function == MEDIA_ENT_F_IO_V4L) { + entity->info.dev.major = VIDEO_MAJOR; + entity->info.dev.minor = vdev->minor; + } + + name = devm_kasprintf(mdev->dev, GFP_KERNEL, "%s-%s", vdev->name, + entity_name); + if (!name) + return -ENOMEM; + + entity->name = name; + entity->function = function; + + ret = media_entity_pads_init(entity, num_pads, pads); + if (ret) + return ret; + + ret = media_device_register_entity(mdev, entity); + if (ret) + return ret; + + return 0; +} + +static int hantro_attach_func(struct hantro_dev *vpu, + struct hantro_func *func) +{ + struct media_device *mdev = &vpu->mdev; + struct media_link *link; + int ret; + + /* Create the three encoder entities with their pads */ + func->source_pad.flags = MEDIA_PAD_FL_SOURCE; + ret = hantro_register_entity(mdev, &func->vdev.entity, "source", + &func->source_pad, 1, MEDIA_ENT_F_IO_V4L, + &func->vdev); + if (ret) + return ret; + + func->proc_pads[0].flags = MEDIA_PAD_FL_SINK; + func->proc_pads[1].flags = MEDIA_PAD_FL_SOURCE; + ret = hantro_register_entity(mdev, &func->proc, "proc", + func->proc_pads, 2, func->id, + &func->vdev); + if (ret) + goto err_rel_entity0; + + func->sink_pad.flags = MEDIA_PAD_FL_SINK; + ret = hantro_register_entity(mdev, &func->sink, "sink", + &func->sink_pad, 1, MEDIA_ENT_F_IO_V4L, + &func->vdev); + if (ret) + goto err_rel_entity1; + + /* Connect the three entities */ + ret = media_create_pad_link(&func->vdev.entity, 0, &func->proc, 1, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) + goto err_rel_entity2; + + ret = media_create_pad_link(&func->proc, 0, &func->sink, 0, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) + goto err_rm_links0; + + /* Create video interface */ + func->intf_devnode = media_devnode_create(mdev, MEDIA_INTF_T_V4L_VIDEO, + 0, VIDEO_MAJOR, + func->vdev.minor); + if (!func->intf_devnode) { + ret = -ENOMEM; + goto err_rm_links1; + } + + /* Connect the two DMA engines to the interface */ + link = media_create_intf_link(&func->vdev.entity, + &func->intf_devnode->intf, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (!link) { + ret = -ENOMEM; + goto err_rm_devnode; + } + + link = media_create_intf_link(&func->sink, &func->intf_devnode->intf, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (!link) { + ret = -ENOMEM; + goto err_rm_devnode; + } + return 0; + +err_rm_devnode: + media_devnode_remove(func->intf_devnode); + +err_rm_links1: + media_entity_remove_links(&func->sink); + +err_rm_links0: + media_entity_remove_links(&func->proc); + media_entity_remove_links(&func->vdev.entity); + +err_rel_entity2: + media_device_unregister_entity(&func->sink); + +err_rel_entity1: + media_device_unregister_entity(&func->proc); + +err_rel_entity0: + media_device_unregister_entity(&func->vdev.entity); + return ret; +} + +static void hantro_detach_func(struct hantro_func *func) +{ + media_devnode_remove(func->intf_devnode); + media_entity_remove_links(&func->sink); + media_entity_remove_links(&func->proc); + media_entity_remove_links(&func->vdev.entity); + media_device_unregister_entity(&func->sink); + media_device_unregister_entity(&func->proc); + media_device_unregister_entity(&func->vdev.entity); +} + +static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid) +{ + const struct of_device_id *match; + struct hantro_func *func; + struct video_device *vfd; + int ret; + + match = of_match_node(of_hantro_match, vpu->dev->of_node); + func = devm_kzalloc(vpu->dev, sizeof(*func), GFP_KERNEL); + if (!func) { + v4l2_err(&vpu->v4l2_dev, "Failed to allocate video device\n"); + return -ENOMEM; + } + + func->id = funcid; + + vfd = &func->vdev; + vfd->fops = &hantro_fops; + vfd->release = video_device_release_empty; + vfd->lock = &vpu->vpu_mutex; + vfd->v4l2_dev = &vpu->v4l2_dev; + vfd->vfl_dir = VFL_DIR_M2M; + vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; + vfd->ioctl_ops = &hantro_ioctl_ops; + snprintf(vfd->name, sizeof(vfd->name), "%s-%s", match->compatible, + funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER ? "enc" : "dec"); + + if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER) + vpu->encoder = func; + else + vpu->decoder = func; + + video_set_drvdata(vfd, vpu); + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); + if (ret) { + v4l2_err(&vpu->v4l2_dev, "Failed to register video device\n"); + return ret; + } + + ret = hantro_attach_func(vpu, func); + if (ret) { + v4l2_err(&vpu->v4l2_dev, + "Failed to attach functionality to the media device\n"); + goto err_unreg_dev; + } + + v4l2_info(&vpu->v4l2_dev, "registered %s as /dev/video%d\n", vfd->name, + vfd->num); + + return 0; + +err_unreg_dev: + video_unregister_device(vfd); + return ret; +} + +static int hantro_add_enc_func(struct hantro_dev *vpu) +{ + if (!vpu->variant->enc_fmts) + return 0; + + return hantro_add_func(vpu, MEDIA_ENT_F_PROC_VIDEO_ENCODER); +} + +static int hantro_add_dec_func(struct hantro_dev *vpu) +{ + if (!vpu->variant->dec_fmts) + return 0; + + return hantro_add_func(vpu, MEDIA_ENT_F_PROC_VIDEO_DECODER); +} + +static void hantro_remove_func(struct hantro_dev *vpu, + unsigned int funcid) +{ + struct hantro_func *func; + + if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER) + func = vpu->encoder; + else + func = vpu->decoder; + + if (!func) + return; + + hantro_detach_func(func); + video_unregister_device(&func->vdev); +} + +static void hantro_remove_enc_func(struct hantro_dev *vpu) +{ + hantro_remove_func(vpu, MEDIA_ENT_F_PROC_VIDEO_ENCODER); +} + +static void hantro_remove_dec_func(struct hantro_dev *vpu) +{ + hantro_remove_func(vpu, MEDIA_ENT_F_PROC_VIDEO_DECODER); +} + +static const struct media_device_ops hantro_m2m_media_ops = { + .req_validate = vb2_request_validate, + .req_queue = v4l2_m2m_request_queue, +}; + +static int hantro_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct hantro_dev *vpu; + struct resource *res; + int num_bases; + int i, ret; + + vpu = devm_kzalloc(&pdev->dev, sizeof(*vpu), GFP_KERNEL); + if (!vpu) + return -ENOMEM; + + vpu->dev = &pdev->dev; + vpu->pdev = pdev; + mutex_init(&vpu->vpu_mutex); + spin_lock_init(&vpu->irqlock); + + match = of_match_node(of_hantro_match, pdev->dev.of_node); + vpu->variant = match->data; + + INIT_DELAYED_WORK(&vpu->watchdog_work, hantro_watchdog); + + vpu->clocks = devm_kcalloc(&pdev->dev, vpu->variant->num_clocks, + sizeof(*vpu->clocks), GFP_KERNEL); + if (!vpu->clocks) + return -ENOMEM; + + for (i = 0; i < vpu->variant->num_clocks; i++) + vpu->clocks[i].id = vpu->variant->clk_names[i]; + ret = devm_clk_bulk_get(&pdev->dev, vpu->variant->num_clocks, + vpu->clocks); + if (ret) + return ret; + + num_bases = vpu->variant->num_regs ?: 1; + vpu->reg_bases = devm_kcalloc(&pdev->dev, num_bases, + sizeof(*vpu->reg_bases), GFP_KERNEL); + if (!vpu->reg_bases) + return -ENOMEM; + + for (i = 0; i < num_bases; i++) { + res = vpu->variant->reg_names ? + platform_get_resource_byname(vpu->pdev, IORESOURCE_MEM, + vpu->variant->reg_names[i]) : + platform_get_resource(vpu->pdev, IORESOURCE_MEM, 0); + vpu->reg_bases[i] = devm_ioremap_resource(vpu->dev, res); + if (IS_ERR(vpu->reg_bases[i])) + return PTR_ERR(vpu->reg_bases[i]); + } + vpu->enc_base = vpu->reg_bases[0] + vpu->variant->enc_offset; + vpu->dec_base = vpu->reg_bases[0] + vpu->variant->dec_offset; + + ret = dma_set_coherent_mask(vpu->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(vpu->dev, "Could not set DMA coherent mask.\n"); + return ret; + } + + for (i = 0; i < vpu->variant->num_irqs; i++) { + const char *irq_name = vpu->variant->irqs[i].name; + int irq; + + if (!vpu->variant->irqs[i].handler) + continue; + + irq = platform_get_irq_byname(vpu->pdev, irq_name); + if (irq <= 0) { + dev_err(vpu->dev, "Could not get %s IRQ.\n", irq_name); + return -ENXIO; + } + + ret = devm_request_irq(vpu->dev, irq, + vpu->variant->irqs[i].handler, 0, + dev_name(vpu->dev), vpu); + if (ret) { + dev_err(vpu->dev, "Could not request %s IRQ.\n", + irq_name); + return ret; + } + } + + ret = vpu->variant->init(vpu); + if (ret) { + dev_err(&pdev->dev, "Failed to init VPU hardware\n"); + return ret; + } + + pm_runtime_set_autosuspend_delay(vpu->dev, 100); + pm_runtime_use_autosuspend(vpu->dev); + pm_runtime_enable(vpu->dev); + + ret = clk_bulk_prepare(vpu->variant->num_clocks, vpu->clocks); + if (ret) { + dev_err(&pdev->dev, "Failed to prepare clocks\n"); + return ret; + } + + ret = v4l2_device_register(&pdev->dev, &vpu->v4l2_dev); + if (ret) { + dev_err(&pdev->dev, "Failed to register v4l2 device\n"); + goto err_clk_unprepare; + } + platform_set_drvdata(pdev, vpu); + + vpu->m2m_dev = v4l2_m2m_init(&vpu_m2m_ops); + if (IS_ERR(vpu->m2m_dev)) { + v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(vpu->m2m_dev); + goto err_v4l2_unreg; + } + + vpu->mdev.dev = vpu->dev; + strscpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model)); + strscpy(vpu->mdev.bus_info, "platform: " DRIVER_NAME, + sizeof(vpu->mdev.model)); + media_device_init(&vpu->mdev); + vpu->mdev.ops = &hantro_m2m_media_ops; + vpu->v4l2_dev.mdev = &vpu->mdev; + + ret = hantro_add_enc_func(vpu); + if (ret) { + dev_err(&pdev->dev, "Failed to register encoder\n"); + goto err_m2m_rel; + } + + ret = hantro_add_dec_func(vpu); + if (ret) { + dev_err(&pdev->dev, "Failed to register decoder\n"); + goto err_rm_enc_func; + } + + ret = media_device_register(&vpu->mdev); + if (ret) { + v4l2_err(&vpu->v4l2_dev, "Failed to register mem2mem media device\n"); + goto err_rm_dec_func; + } + + return 0; + +err_rm_dec_func: + hantro_remove_dec_func(vpu); +err_rm_enc_func: + hantro_remove_enc_func(vpu); +err_m2m_rel: + media_device_cleanup(&vpu->mdev); + v4l2_m2m_release(vpu->m2m_dev); +err_v4l2_unreg: + v4l2_device_unregister(&vpu->v4l2_dev); +err_clk_unprepare: + clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks); + pm_runtime_dont_use_autosuspend(vpu->dev); + pm_runtime_disable(vpu->dev); + return ret; +} + +static int hantro_remove(struct platform_device *pdev) +{ + struct hantro_dev *vpu = platform_get_drvdata(pdev); + + v4l2_info(&vpu->v4l2_dev, "Removing %s\n", pdev->name); + + media_device_unregister(&vpu->mdev); + hantro_remove_dec_func(vpu); + hantro_remove_enc_func(vpu); + media_device_cleanup(&vpu->mdev); + v4l2_m2m_release(vpu->m2m_dev); + v4l2_device_unregister(&vpu->v4l2_dev); + clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks); + pm_runtime_dont_use_autosuspend(vpu->dev); + pm_runtime_disable(vpu->dev); + return 0; +} + +#ifdef CONFIG_PM +static int hantro_runtime_resume(struct device *dev) +{ + struct hantro_dev *vpu = dev_get_drvdata(dev); + + if (vpu->variant->runtime_resume) + return vpu->variant->runtime_resume(vpu); + + return 0; +} +#endif + +static const struct dev_pm_ops hantro_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(NULL, hantro_runtime_resume, NULL) +}; + +static struct platform_driver hantro_driver = { + .probe = hantro_probe, + .remove = hantro_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(of_hantro_match), + .pm = &hantro_pm_ops, + }, +}; +module_platform_driver(hantro_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Alpha Lin <Alpha.Lin@Rock-Chips.com>"); +MODULE_AUTHOR("Tomasz Figa <tfiga@chromium.org>"); +MODULE_AUTHOR("Ezequiel Garcia <ezequiel@collabora.com>"); +MODULE_DESCRIPTION("Hantro VPU codec driver"); diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c new file mode 100644 index 000000000000..e592c1b66375 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + */ + +#include <asm/unaligned.h> +#include <linux/bitfield.h> +#include <media/v4l2-mem2mem.h> +#include "hantro.h" +#include "hantro_hw.h" + +#define G1_SWREG(nr) ((nr) * 4) + +#define G1_REG_RLC_VLC_BASE G1_SWREG(12) +#define G1_REG_DEC_OUT_BASE G1_SWREG(13) +#define G1_REG_REFER0_BASE G1_SWREG(14) +#define G1_REG_REFER1_BASE G1_SWREG(15) +#define G1_REG_REFER2_BASE G1_SWREG(16) +#define G1_REG_REFER3_BASE G1_SWREG(17) +#define G1_REG_QTABLE_BASE G1_SWREG(40) +#define G1_REG_DEC_E(v) ((v) ? BIT(0) : 0) + +#define G1_REG_DEC_AXI_RD_ID(v) (((v) << 24) & GENMASK(31, 24)) +#define G1_REG_DEC_TIMEOUT_E(v) ((v) ? BIT(23) : 0) +#define G1_REG_DEC_STRSWAP32_E(v) ((v) ? BIT(22) : 0) +#define G1_REG_DEC_STRENDIAN_E(v) ((v) ? BIT(21) : 0) +#define G1_REG_DEC_INSWAP32_E(v) ((v) ? BIT(20) : 0) +#define G1_REG_DEC_OUTSWAP32_E(v) ((v) ? BIT(19) : 0) +#define G1_REG_DEC_DATA_DISC_E(v) ((v) ? BIT(18) : 0) +#define G1_REG_DEC_LATENCY(v) (((v) << 11) & GENMASK(16, 11)) +#define G1_REG_DEC_CLK_GATE_E(v) ((v) ? BIT(10) : 0) +#define G1_REG_DEC_IN_ENDIAN(v) ((v) ? BIT(9) : 0) +#define G1_REG_DEC_OUT_ENDIAN(v) ((v) ? BIT(8) : 0) +#define G1_REG_DEC_ADV_PRE_DIS(v) ((v) ? BIT(6) : 0) +#define G1_REG_DEC_SCMD_DIS(v) ((v) ? BIT(5) : 0) +#define G1_REG_DEC_MAX_BURST(v) (((v) << 0) & GENMASK(4, 0)) + +#define G1_REG_DEC_MODE(v) (((v) << 28) & GENMASK(31, 28)) +#define G1_REG_RLC_MODE_E(v) ((v) ? BIT(27) : 0) +#define G1_REG_PIC_INTERLACE_E(v) ((v) ? BIT(23) : 0) +#define G1_REG_PIC_FIELDMODE_E(v) ((v) ? BIT(22) : 0) +#define G1_REG_PIC_B_E(v) ((v) ? BIT(21) : 0) +#define G1_REG_PIC_INTER_E(v) ((v) ? BIT(20) : 0) +#define G1_REG_PIC_TOPFIELD_E(v) ((v) ? BIT(19) : 0) +#define G1_REG_FWD_INTERLACE_E(v) ((v) ? BIT(18) : 0) +#define G1_REG_FILTERING_DIS(v) ((v) ? BIT(14) : 0) +#define G1_REG_WRITE_MVS_E(v) ((v) ? BIT(12) : 0) +#define G1_REG_DEC_AXI_WR_ID(v) (((v) << 0) & GENMASK(7, 0)) + +#define G1_REG_PIC_MB_WIDTH(v) (((v) << 23) & GENMASK(31, 23)) +#define G1_REG_PIC_MB_HEIGHT_P(v) (((v) << 11) & GENMASK(18, 11)) +#define G1_REG_ALT_SCAN_E(v) ((v) ? BIT(6) : 0) +#define G1_REG_TOPFIELDFIRST_E(v) ((v) ? BIT(5) : 0) + +#define G1_REG_STRM_START_BIT(v) (((v) << 26) & GENMASK(31, 26)) +#define G1_REG_QSCALE_TYPE(v) ((v) ? BIT(24) : 0) +#define G1_REG_CON_MV_E(v) ((v) ? BIT(4) : 0) +#define G1_REG_INTRA_DC_PREC(v) (((v) << 2) & GENMASK(3, 2)) +#define G1_REG_INTRA_VLC_TAB(v) ((v) ? BIT(1) : 0) +#define G1_REG_FRAME_PRED_DCT(v) ((v) ? BIT(0) : 0) + +#define G1_REG_INIT_QP(v) (((v) << 25) & GENMASK(30, 25)) +#define G1_REG_STREAM_LEN(v) (((v) << 0) & GENMASK(23, 0)) + +#define G1_REG_ALT_SCAN_FLAG_E(v) ((v) ? BIT(19) : 0) +#define G1_REG_FCODE_FWD_HOR(v) (((v) << 15) & GENMASK(18, 15)) +#define G1_REG_FCODE_FWD_VER(v) (((v) << 11) & GENMASK(14, 11)) +#define G1_REG_FCODE_BWD_HOR(v) (((v) << 7) & GENMASK(10, 7)) +#define G1_REG_FCODE_BWD_VER(v) (((v) << 3) & GENMASK(6, 3)) +#define G1_REG_MV_ACCURACY_FWD(v) ((v) ? BIT(2) : 0) +#define G1_REG_MV_ACCURACY_BWD(v) ((v) ? BIT(1) : 0) + +#define G1_REG_STARTMB_X(v) (((v) << 23) & GENMASK(31, 23)) +#define G1_REG_STARTMB_Y(v) (((v) << 15) & GENMASK(22, 15)) + +#define G1_REG_APF_THRESHOLD(v) (((v) << 0) & GENMASK(13, 0)) + +#define PICT_TOP_FIELD 1 +#define PICT_BOTTOM_FIELD 2 +#define PICT_FRAME 3 + +static void +hantro_g1_mpeg2_dec_set_quantization(struct hantro_dev *vpu, + struct hantro_ctx *ctx) +{ + struct v4l2_ctrl_mpeg2_quantization *quantization; + + quantization = hantro_get_ctrl(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); + hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, + quantization); + vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, + G1_REG_QTABLE_BASE); +} + +static void +hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, + struct vb2_buffer *src_buf, + struct vb2_buffer *dst_buf, + const struct v4l2_mpeg2_sequence *sequence, + const struct v4l2_mpeg2_picture *picture, + const struct v4l2_ctrl_mpeg2_slice_params *slice_params) +{ + dma_addr_t forward_addr = 0, backward_addr = 0; + dma_addr_t current_addr, addr; + struct vb2_queue *vq; + + vq = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx); + + switch (picture->picture_coding_type) { + case V4L2_MPEG2_PICTURE_CODING_TYPE_B: + backward_addr = hantro_get_ref(vq, + slice_params->backward_ref_ts); + /* fall-through */ + case V4L2_MPEG2_PICTURE_CODING_TYPE_P: + forward_addr = hantro_get_ref(vq, + slice_params->forward_ref_ts); + } + + /* Source bitstream buffer */ + addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + vdpu_write_relaxed(vpu, addr, G1_REG_RLC_VLC_BASE); + + /* Destination frame buffer */ + addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + current_addr = addr; + + if (picture->picture_structure == PICT_BOTTOM_FIELD) + addr += ALIGN(ctx->dst_fmt.width, 16); + vdpu_write_relaxed(vpu, addr, G1_REG_DEC_OUT_BASE); + + if (!forward_addr) + forward_addr = current_addr; + if (!backward_addr) + backward_addr = current_addr; + + /* Set forward ref frame (top/bottom field) */ + if (picture->picture_structure == PICT_FRAME || + picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B || + (picture->picture_structure == PICT_TOP_FIELD && + picture->top_field_first) || + (picture->picture_structure == PICT_BOTTOM_FIELD && + !picture->top_field_first)) { + vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER0_BASE); + vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER1_BASE); + } else if (picture->picture_structure == PICT_TOP_FIELD) { + vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER0_BASE); + vdpu_write_relaxed(vpu, current_addr, G1_REG_REFER1_BASE); + } else if (picture->picture_structure == PICT_BOTTOM_FIELD) { + vdpu_write_relaxed(vpu, current_addr, G1_REG_REFER0_BASE); + vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER1_BASE); + } + + /* Set backward ref frame (top/bottom field) */ + vdpu_write_relaxed(vpu, backward_addr, G1_REG_REFER2_BASE); + vdpu_write_relaxed(vpu, backward_addr, G1_REG_REFER3_BASE); +} + +void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + const struct v4l2_ctrl_mpeg2_slice_params *slice_params; + const struct v4l2_mpeg2_sequence *sequence; + const struct v4l2_mpeg2_picture *picture; + u32 reg; + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + /* Apply request controls if any */ + v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, + &ctx->ctrl_handler); + + slice_params = hantro_get_ctrl(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); + sequence = &slice_params->sequence; + picture = &slice_params->picture; + + reg = G1_REG_DEC_AXI_RD_ID(0) | + G1_REG_DEC_TIMEOUT_E(1) | + G1_REG_DEC_STRSWAP32_E(1) | + G1_REG_DEC_STRENDIAN_E(1) | + G1_REG_DEC_INSWAP32_E(1) | + G1_REG_DEC_OUTSWAP32_E(1) | + G1_REG_DEC_DATA_DISC_E(0) | + G1_REG_DEC_LATENCY(0) | + G1_REG_DEC_CLK_GATE_E(1) | + G1_REG_DEC_IN_ENDIAN(1) | + G1_REG_DEC_OUT_ENDIAN(1) | + G1_REG_DEC_ADV_PRE_DIS(0) | + G1_REG_DEC_SCMD_DIS(0) | + G1_REG_DEC_MAX_BURST(16); + vdpu_write_relaxed(vpu, reg, G1_SWREG(2)); + + reg = G1_REG_DEC_MODE(5) | + G1_REG_RLC_MODE_E(0) | + G1_REG_PIC_INTERLACE_E(!sequence->progressive_sequence) | + G1_REG_PIC_FIELDMODE_E(picture->picture_structure != PICT_FRAME) | + G1_REG_PIC_B_E(picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B) | + G1_REG_PIC_INTER_E(picture->picture_coding_type != V4L2_MPEG2_PICTURE_CODING_TYPE_I) | + G1_REG_PIC_TOPFIELD_E(picture->picture_structure == PICT_TOP_FIELD) | + G1_REG_FWD_INTERLACE_E(0) | + G1_REG_FILTERING_DIS(1) | + G1_REG_WRITE_MVS_E(0) | + G1_REG_DEC_AXI_WR_ID(0); + vdpu_write_relaxed(vpu, reg, G1_SWREG(3)); + + reg = G1_REG_PIC_MB_WIDTH(MPEG2_MB_WIDTH(ctx->dst_fmt.width)) | + G1_REG_PIC_MB_HEIGHT_P(MPEG2_MB_HEIGHT(ctx->dst_fmt.height)) | + G1_REG_ALT_SCAN_E(picture->alternate_scan) | + G1_REG_TOPFIELDFIRST_E(picture->top_field_first); + vdpu_write_relaxed(vpu, reg, G1_SWREG(4)); + + reg = G1_REG_STRM_START_BIT(slice_params->data_bit_offset) | + G1_REG_QSCALE_TYPE(picture->q_scale_type) | + G1_REG_CON_MV_E(picture->concealment_motion_vectors) | + G1_REG_INTRA_DC_PREC(picture->intra_dc_precision) | + G1_REG_INTRA_VLC_TAB(picture->intra_vlc_format) | + G1_REG_FRAME_PRED_DCT(picture->frame_pred_frame_dct); + vdpu_write_relaxed(vpu, reg, G1_SWREG(5)); + + reg = G1_REG_INIT_QP(1) | + G1_REG_STREAM_LEN(slice_params->bit_size >> 3); + vdpu_write_relaxed(vpu, reg, G1_SWREG(6)); + + reg = G1_REG_ALT_SCAN_FLAG_E(picture->alternate_scan) | + G1_REG_FCODE_FWD_HOR(picture->f_code[0][0]) | + G1_REG_FCODE_FWD_VER(picture->f_code[0][1]) | + G1_REG_FCODE_BWD_HOR(picture->f_code[1][0]) | + G1_REG_FCODE_BWD_VER(picture->f_code[1][1]) | + G1_REG_MV_ACCURACY_FWD(1) | + G1_REG_MV_ACCURACY_BWD(1); + vdpu_write_relaxed(vpu, reg, G1_SWREG(18)); + + reg = G1_REG_STARTMB_X(0) | + G1_REG_STARTMB_Y(0); + vdpu_write_relaxed(vpu, reg, G1_SWREG(48)); + + reg = G1_REG_APF_THRESHOLD(8); + vdpu_write_relaxed(vpu, reg, G1_SWREG(55)); + + hantro_g1_mpeg2_dec_set_quantization(vpu, ctx); + + hantro_g1_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, + &dst_buf->vb2_buf, + sequence, picture, slice_params); + + /* Controls no longer in-use, we can complete them */ + v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req, + &ctx->ctrl_handler); + + /* Kick the watchdog and start decoding */ + schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + + reg = G1_REG_DEC_E(1); + vdpu_write(vpu, reg, G1_SWREG(1)); +} diff --git a/drivers/staging/media/hantro/hantro_g1_regs.h b/drivers/staging/media/hantro/hantro_g1_regs.h new file mode 100644 index 000000000000..5c0ea7994336 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_g1_regs.h @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Hantro VPU codec driver + * + * Copyright 2018 Google LLC. + * Tomasz Figa <tfiga@chromium.org> + */ + +#ifndef HANTRO_G1_REGS_H_ +#define HANTRO_G1_REGS_H_ + +/* Decoder registers. */ +#define G1_REG_INTERRUPT 0x004 +#define G1_REG_INTERRUPT_DEC_PIC_INF BIT(24) +#define G1_REG_INTERRUPT_DEC_TIMEOUT BIT(18) +#define G1_REG_INTERRUPT_DEC_SLICE_INT BIT(17) +#define G1_REG_INTERRUPT_DEC_ERROR_INT BIT(16) +#define G1_REG_INTERRUPT_DEC_ASO_INT BIT(15) +#define G1_REG_INTERRUPT_DEC_BUFFER_INT BIT(14) +#define G1_REG_INTERRUPT_DEC_BUS_INT BIT(13) +#define G1_REG_INTERRUPT_DEC_RDY_INT BIT(12) +#define G1_REG_INTERRUPT_DEC_IRQ BIT(8) +#define G1_REG_INTERRUPT_DEC_IRQ_DIS BIT(4) +#define G1_REG_INTERRUPT_DEC_E BIT(0) +#define G1_REG_CONFIG 0x008 +#define G1_REG_CONFIG_DEC_AXI_RD_ID(x) (((x) & 0xff) << 24) +#define G1_REG_CONFIG_DEC_TIMEOUT_E BIT(23) +#define G1_REG_CONFIG_DEC_STRSWAP32_E BIT(22) +#define G1_REG_CONFIG_DEC_STRENDIAN_E BIT(21) +#define G1_REG_CONFIG_DEC_INSWAP32_E BIT(20) +#define G1_REG_CONFIG_DEC_OUTSWAP32_E BIT(19) +#define G1_REG_CONFIG_DEC_DATA_DISC_E BIT(18) +#define G1_REG_CONFIG_TILED_MODE_MSB BIT(17) +#define G1_REG_CONFIG_DEC_OUT_TILED_E BIT(17) +#define G1_REG_CONFIG_DEC_LATENCY(x) (((x) & 0x3f) << 11) +#define G1_REG_CONFIG_DEC_CLK_GATE_E BIT(10) +#define G1_REG_CONFIG_DEC_IN_ENDIAN BIT(9) +#define G1_REG_CONFIG_DEC_OUT_ENDIAN BIT(8) +#define G1_REG_CONFIG_PRIORITY_MODE(x) (((x) & 0x7) << 5) +#define G1_REG_CONFIG_TILED_MODE_LSB BIT(7) +#define G1_REG_CONFIG_DEC_ADV_PRE_DIS BIT(6) +#define G1_REG_CONFIG_DEC_SCMD_DIS BIT(5) +#define G1_REG_CONFIG_DEC_MAX_BURST(x) (((x) & 0x1f) << 0) +#define G1_REG_DEC_CTRL0 0x00c +#define G1_REG_DEC_CTRL0_DEC_MODE(x) (((x) & 0xf) << 28) +#define G1_REG_DEC_CTRL0_RLC_MODE_E BIT(27) +#define G1_REG_DEC_CTRL0_SKIP_MODE BIT(26) +#define G1_REG_DEC_CTRL0_DIVX3_E BIT(25) +#define G1_REG_DEC_CTRL0_PJPEG_E BIT(24) +#define G1_REG_DEC_CTRL0_PIC_INTERLACE_E BIT(23) +#define G1_REG_DEC_CTRL0_PIC_FIELDMODE_E BIT(22) +#define G1_REG_DEC_CTRL0_PIC_B_E BIT(21) +#define G1_REG_DEC_CTRL0_PIC_INTER_E BIT(20) +#define G1_REG_DEC_CTRL0_PIC_TOPFIELD_E BIT(19) +#define G1_REG_DEC_CTRL0_FWD_INTERLACE_E BIT(18) +#define G1_REG_DEC_CTRL0_SORENSON_E BIT(17) +#define G1_REG_DEC_CTRL0_REF_TOPFIELD_E BIT(16) +#define G1_REG_DEC_CTRL0_DEC_OUT_DIS BIT(15) +#define G1_REG_DEC_CTRL0_FILTERING_DIS BIT(14) +#define G1_REG_DEC_CTRL0_WEBP_E BIT(13) +#define G1_REG_DEC_CTRL0_MVC_E BIT(13) +#define G1_REG_DEC_CTRL0_PIC_FIXED_QUANT BIT(13) +#define G1_REG_DEC_CTRL0_WRITE_MVS_E BIT(12) +#define G1_REG_DEC_CTRL0_REFTOPFIRST_E BIT(11) +#define G1_REG_DEC_CTRL0_SEQ_MBAFF_E BIT(10) +#define G1_REG_DEC_CTRL0_PICORD_COUNT_E BIT(9) +#define G1_REG_DEC_CTRL0_DEC_AHB_HLOCK_E BIT(8) +#define G1_REG_DEC_CTRL0_DEC_AXI_WR_ID(x) (((x) & 0xff) << 0) +#define G1_REG_DEC_CTRL1 0x010 +#define G1_REG_DEC_CTRL1_PIC_MB_WIDTH(x) (((x) & 0x1ff) << 23) +#define G1_REG_DEC_CTRL1_MB_WIDTH_OFF(x) (((x) & 0xf) << 19) +#define G1_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(x) (((x) & 0xff) << 11) +#define G1_REG_DEC_CTRL1_MB_HEIGHT_OFF(x) (((x) & 0xf) << 7) +#define G1_REG_DEC_CTRL1_ALT_SCAN_E BIT(6) +#define G1_REG_DEC_CTRL1_TOPFIELDFIRST_E BIT(5) +#define G1_REG_DEC_CTRL1_REF_FRAMES(x) (((x) & 0x1f) << 0) +#define G1_REG_DEC_CTRL1_PIC_MB_W_EXT(x) (((x) & 0x7) << 3) +#define G1_REG_DEC_CTRL1_PIC_MB_H_EXT(x) (((x) & 0x7) << 0) +#define G1_REG_DEC_CTRL1_PIC_REFER_FLAG BIT(0) +#define G1_REG_DEC_CTRL2 0x014 +#define G1_REG_DEC_CTRL2_STRM_START_BIT(x) (((x) & 0x3f) << 26) +#define G1_REG_DEC_CTRL2_SYNC_MARKER_E BIT(25) +#define G1_REG_DEC_CTRL2_TYPE1_QUANT_E BIT(24) +#define G1_REG_DEC_CTRL2_CH_QP_OFFSET(x) (((x) & 0x1f) << 19) +#define G1_REG_DEC_CTRL2_CH_QP_OFFSET2(x) (((x) & 0x1f) << 14) +#define G1_REG_DEC_CTRL2_FIELDPIC_FLAG_E BIT(0) +#define G1_REG_DEC_CTRL2_INTRADC_VLC_THR(x) (((x) & 0x7) << 16) +#define G1_REG_DEC_CTRL2_VOP_TIME_INCR(x) (((x) & 0xffff) << 0) +#define G1_REG_DEC_CTRL2_DQ_PROFILE BIT(24) +#define G1_REG_DEC_CTRL2_DQBI_LEVEL BIT(23) +#define G1_REG_DEC_CTRL2_RANGE_RED_FRM_E BIT(22) +#define G1_REG_DEC_CTRL2_FAST_UVMC_E BIT(20) +#define G1_REG_DEC_CTRL2_TRANSDCTAB BIT(17) +#define G1_REG_DEC_CTRL2_TRANSACFRM(x) (((x) & 0x3) << 15) +#define G1_REG_DEC_CTRL2_TRANSACFRM2(x) (((x) & 0x3) << 13) +#define G1_REG_DEC_CTRL2_MB_MODE_TAB(x) (((x) & 0x7) << 10) +#define G1_REG_DEC_CTRL2_MVTAB(x) (((x) & 0x7) << 7) +#define G1_REG_DEC_CTRL2_CBPTAB(x) (((x) & 0x7) << 4) +#define G1_REG_DEC_CTRL2_2MV_BLK_PAT_TAB(x) (((x) & 0x3) << 2) +#define G1_REG_DEC_CTRL2_4MV_BLK_PAT_TAB(x) (((x) & 0x3) << 0) +#define G1_REG_DEC_CTRL2_QSCALE_TYPE BIT(24) +#define G1_REG_DEC_CTRL2_CON_MV_E BIT(4) +#define G1_REG_DEC_CTRL2_INTRA_DC_PREC(x) (((x) & 0x3) << 2) +#define G1_REG_DEC_CTRL2_INTRA_VLC_TAB BIT(1) +#define G1_REG_DEC_CTRL2_FRAME_PRED_DCT BIT(0) +#define G1_REG_DEC_CTRL2_JPEG_QTABLES(x) (((x) & 0x3) << 11) +#define G1_REG_DEC_CTRL2_JPEG_MODE(x) (((x) & 0x7) << 8) +#define G1_REG_DEC_CTRL2_JPEG_FILRIGHT_E BIT(7) +#define G1_REG_DEC_CTRL2_JPEG_STREAM_ALL BIT(6) +#define G1_REG_DEC_CTRL2_CR_AC_VLCTABLE BIT(5) +#define G1_REG_DEC_CTRL2_CB_AC_VLCTABLE BIT(4) +#define G1_REG_DEC_CTRL2_CR_DC_VLCTABLE BIT(3) +#define G1_REG_DEC_CTRL2_CB_DC_VLCTABLE BIT(2) +#define G1_REG_DEC_CTRL2_CR_DC_VLCTABLE3 BIT(1) +#define G1_REG_DEC_CTRL2_CB_DC_VLCTABLE3 BIT(0) +#define G1_REG_DEC_CTRL2_STRM1_START_BIT(x) (((x) & 0x3f) << 18) +#define G1_REG_DEC_CTRL2_HUFFMAN_E BIT(17) +#define G1_REG_DEC_CTRL2_MULTISTREAM_E BIT(16) +#define G1_REG_DEC_CTRL2_BOOLEAN_VALUE(x) (((x) & 0xff) << 8) +#define G1_REG_DEC_CTRL2_BOOLEAN_RANGE(x) (((x) & 0xff) << 0) +#define G1_REG_DEC_CTRL2_ALPHA_OFFSET(x) (((x) & 0x1f) << 5) +#define G1_REG_DEC_CTRL2_BETA_OFFSET(x) (((x) & 0x1f) << 0) +#define G1_REG_DEC_CTRL3 0x018 +#define G1_REG_DEC_CTRL3_START_CODE_E BIT(31) +#define G1_REG_DEC_CTRL3_INIT_QP(x) (((x) & 0x3f) << 25) +#define G1_REG_DEC_CTRL3_CH_8PIX_ILEAV_E BIT(24) +#define G1_REG_DEC_CTRL3_STREAM_LEN_EXT(x) (((x) & 0xff) << 24) +#define G1_REG_DEC_CTRL3_STREAM_LEN(x) (((x) & 0xffffff) << 0) +#define G1_REG_DEC_CTRL4 0x01c +#define G1_REG_DEC_CTRL4_CABAC_E BIT(31) +#define G1_REG_DEC_CTRL4_BLACKWHITE_E BIT(30) +#define G1_REG_DEC_CTRL4_DIR_8X8_INFER_E BIT(29) +#define G1_REG_DEC_CTRL4_WEIGHT_PRED_E BIT(28) +#define G1_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(x) (((x) & 0x3) << 26) +#define G1_REG_DEC_CTRL4_AVS_H264_H_EXT BIT(25) +#define G1_REG_DEC_CTRL4_FRAMENUM_LEN(x) (((x) & 0x1f) << 16) +#define G1_REG_DEC_CTRL4_FRAMENUM(x) (((x) & 0xffff) << 0) +#define G1_REG_DEC_CTRL4_BITPLANE0_E BIT(31) +#define G1_REG_DEC_CTRL4_BITPLANE1_E BIT(30) +#define G1_REG_DEC_CTRL4_BITPLANE2_E BIT(29) +#define G1_REG_DEC_CTRL4_ALT_PQUANT(x) (((x) & 0x1f) << 24) +#define G1_REG_DEC_CTRL4_DQ_EDGES(x) (((x) & 0xf) << 20) +#define G1_REG_DEC_CTRL4_TTMBF BIT(19) +#define G1_REG_DEC_CTRL4_PQINDEX(x) (((x) & 0x1f) << 14) +#define G1_REG_DEC_CTRL4_VC1_HEIGHT_EXT BIT(13) +#define G1_REG_DEC_CTRL4_BILIN_MC_E BIT(12) +#define G1_REG_DEC_CTRL4_UNIQP_E BIT(11) +#define G1_REG_DEC_CTRL4_HALFQP_E BIT(10) +#define G1_REG_DEC_CTRL4_TTFRM(x) (((x) & 0x3) << 8) +#define G1_REG_DEC_CTRL4_2ND_BYTE_EMUL_E BIT(7) +#define G1_REG_DEC_CTRL4_DQUANT_E BIT(6) +#define G1_REG_DEC_CTRL4_VC1_ADV_E BIT(5) +#define G1_REG_DEC_CTRL4_PJPEG_FILDOWN_E BIT(26) +#define G1_REG_DEC_CTRL4_PJPEG_WDIV8 BIT(25) +#define G1_REG_DEC_CTRL4_PJPEG_HDIV8 BIT(24) +#define G1_REG_DEC_CTRL4_PJPEG_AH(x) (((x) & 0xf) << 20) +#define G1_REG_DEC_CTRL4_PJPEG_AL(x) (((x) & 0xf) << 16) +#define G1_REG_DEC_CTRL4_PJPEG_SS(x) (((x) & 0xff) << 8) +#define G1_REG_DEC_CTRL4_PJPEG_SE(x) (((x) & 0xff) << 0) +#define G1_REG_DEC_CTRL4_DCT1_START_BIT(x) (((x) & 0x3f) << 26) +#define G1_REG_DEC_CTRL4_DCT2_START_BIT(x) (((x) & 0x3f) << 20) +#define G1_REG_DEC_CTRL4_CH_MV_RES BIT(13) +#define G1_REG_DEC_CTRL4_INIT_DC_MATCH0(x) (((x) & 0x7) << 9) +#define G1_REG_DEC_CTRL4_INIT_DC_MATCH1(x) (((x) & 0x7) << 6) +#define G1_REG_DEC_CTRL4_VP7_VERSION BIT(5) +#define G1_REG_DEC_CTRL5 0x020 +#define G1_REG_DEC_CTRL5_CONST_INTRA_E BIT(31) +#define G1_REG_DEC_CTRL5_FILT_CTRL_PRES BIT(30) +#define G1_REG_DEC_CTRL5_RDPIC_CNT_PRES BIT(29) +#define G1_REG_DEC_CTRL5_8X8TRANS_FLAG_E BIT(28) +#define G1_REG_DEC_CTRL5_REFPIC_MK_LEN(x) (((x) & 0x7ff) << 17) +#define G1_REG_DEC_CTRL5_IDR_PIC_E BIT(16) +#define G1_REG_DEC_CTRL5_IDR_PIC_ID(x) (((x) & 0xffff) << 0) +#define G1_REG_DEC_CTRL5_MV_SCALEFACTOR(x) (((x) & 0xff) << 24) +#define G1_REG_DEC_CTRL5_REF_DIST_FWD(x) (((x) & 0x1f) << 19) +#define G1_REG_DEC_CTRL5_REF_DIST_BWD(x) (((x) & 0x1f) << 14) +#define G1_REG_DEC_CTRL5_LOOP_FILT_LIMIT(x) (((x) & 0xf) << 14) +#define G1_REG_DEC_CTRL5_VARIANCE_TEST_E BIT(13) +#define G1_REG_DEC_CTRL5_MV_THRESHOLD(x) (((x) & 0x7) << 10) +#define G1_REG_DEC_CTRL5_VAR_THRESHOLD(x) (((x) & 0x3ff) << 0) +#define G1_REG_DEC_CTRL5_DIVX_IDCT_E BIT(8) +#define G1_REG_DEC_CTRL5_DIVX3_SLICE_SIZE(x) (((x) & 0xff) << 0) +#define G1_REG_DEC_CTRL5_PJPEG_REST_FREQ(x) (((x) & 0xffff) << 0) +#define G1_REG_DEC_CTRL5_RV_PROFILE(x) (((x) & 0x3) << 30) +#define G1_REG_DEC_CTRL5_RV_OSV_QUANT(x) (((x) & 0x3) << 28) +#define G1_REG_DEC_CTRL5_RV_FWD_SCALE(x) (((x) & 0x3fff) << 14) +#define G1_REG_DEC_CTRL5_RV_BWD_SCALE(x) (((x) & 0x3fff) << 0) +#define G1_REG_DEC_CTRL5_INIT_DC_COMP0(x) (((x) & 0xffff) << 16) +#define G1_REG_DEC_CTRL5_INIT_DC_COMP1(x) (((x) & 0xffff) << 0) +#define G1_REG_DEC_CTRL6 0x024 +#define G1_REG_DEC_CTRL6_PPS_ID(x) (((x) & 0xff) << 24) +#define G1_REG_DEC_CTRL6_REFIDX1_ACTIVE(x) (((x) & 0x1f) << 19) +#define G1_REG_DEC_CTRL6_REFIDX0_ACTIVE(x) (((x) & 0x1f) << 14) +#define G1_REG_DEC_CTRL6_POC_LENGTH(x) (((x) & 0xff) << 0) +#define G1_REG_DEC_CTRL6_ICOMP0_E BIT(24) +#define G1_REG_DEC_CTRL6_ISCALE0(x) (((x) & 0xff) << 16) +#define G1_REG_DEC_CTRL6_ISHIFT0(x) (((x) & 0xffff) << 0) +#define G1_REG_DEC_CTRL6_STREAM1_LEN(x) (((x) & 0xffffff) << 0) +#define G1_REG_DEC_CTRL6_PIC_SLICE_AM(x) (((x) & 0x1fff) << 0) +#define G1_REG_DEC_CTRL6_COEFFS_PART_AM(x) (((x) & 0xf) << 24) +#define G1_REG_FWD_PIC(i) (0x028 + ((i) * 0x4)) +#define G1_REG_FWD_PIC_PINIT_RLIST_F5(x) (((x) & 0x1f) << 25) +#define G1_REG_FWD_PIC_PINIT_RLIST_F4(x) (((x) & 0x1f) << 20) +#define G1_REG_FWD_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 15) +#define G1_REG_FWD_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 10) +#define G1_REG_FWD_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 5) +#define G1_REG_FWD_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 0) +#define G1_REG_FWD_PIC1_ICOMP1_E BIT(24) +#define G1_REG_FWD_PIC1_ISCALE1(x) (((x) & 0xff) << 16) +#define G1_REG_FWD_PIC1_ISHIFT1(x) (((x) & 0xffff) << 0) +#define G1_REG_FWD_PIC1_SEGMENT_BASE(x) ((x) << 0) +#define G1_REG_FWD_PIC1_SEGMENT_UPD_E BIT(1) +#define G1_REG_FWD_PIC1_SEGMENT_E BIT(0) +#define G1_REG_DEC_CTRL7 0x02c +#define G1_REG_DEC_CTRL7_PINIT_RLIST_F15(x) (((x) & 0x1f) << 25) +#define G1_REG_DEC_CTRL7_PINIT_RLIST_F14(x) (((x) & 0x1f) << 20) +#define G1_REG_DEC_CTRL7_PINIT_RLIST_F13(x) (((x) & 0x1f) << 15) +#define G1_REG_DEC_CTRL7_PINIT_RLIST_F12(x) (((x) & 0x1f) << 10) +#define G1_REG_DEC_CTRL7_PINIT_RLIST_F11(x) (((x) & 0x1f) << 5) +#define G1_REG_DEC_CTRL7_PINIT_RLIST_F10(x) (((x) & 0x1f) << 0) +#define G1_REG_DEC_CTRL7_ICOMP2_E BIT(24) +#define G1_REG_DEC_CTRL7_ISCALE2(x) (((x) & 0xff) << 16) +#define G1_REG_DEC_CTRL7_ISHIFT2(x) (((x) & 0xffff) << 0) +#define G1_REG_DEC_CTRL7_DCT3_START_BIT(x) (((x) & 0x3f) << 24) +#define G1_REG_DEC_CTRL7_DCT4_START_BIT(x) (((x) & 0x3f) << 18) +#define G1_REG_DEC_CTRL7_DCT5_START_BIT(x) (((x) & 0x3f) << 12) +#define G1_REG_DEC_CTRL7_DCT6_START_BIT(x) (((x) & 0x3f) << 6) +#define G1_REG_DEC_CTRL7_DCT7_START_BIT(x) (((x) & 0x3f) << 0) +#define G1_REG_ADDR_STR 0x030 +#define G1_REG_ADDR_DST 0x034 +#define G1_REG_ADDR_REF(i) (0x038 + ((i) * 0x4)) +#define G1_REG_ADDR_REF_FIELD_E BIT(1) +#define G1_REG_ADDR_REF_TOPC_E BIT(0) +#define G1_REG_REF_PIC(i) (0x078 + ((i) * 0x4)) +#define G1_REG_REF_PIC_FILT_TYPE_E BIT(31) +#define G1_REG_REF_PIC_FILT_SHARPNESS(x) (((x) & 0x7) << 28) +#define G1_REG_REF_PIC_MB_ADJ_0(x) (((x) & 0x7f) << 21) +#define G1_REG_REF_PIC_MB_ADJ_1(x) (((x) & 0x7f) << 14) +#define G1_REG_REF_PIC_MB_ADJ_2(x) (((x) & 0x7f) << 7) +#define G1_REG_REF_PIC_MB_ADJ_3(x) (((x) & 0x7f) << 0) +#define G1_REG_REF_PIC_REFER1_NBR(x) (((x) & 0xffff) << 16) +#define G1_REG_REF_PIC_REFER0_NBR(x) (((x) & 0xffff) << 0) +#define G1_REG_REF_PIC_LF_LEVEL_0(x) (((x) & 0x3f) << 18) +#define G1_REG_REF_PIC_LF_LEVEL_1(x) (((x) & 0x3f) << 12) +#define G1_REG_REF_PIC_LF_LEVEL_2(x) (((x) & 0x3f) << 6) +#define G1_REG_REF_PIC_LF_LEVEL_3(x) (((x) & 0x3f) << 0) +#define G1_REG_REF_PIC_QUANT_DELTA_0(x) (((x) & 0x1f) << 27) +#define G1_REG_REF_PIC_QUANT_DELTA_1(x) (((x) & 0x1f) << 22) +#define G1_REG_REF_PIC_QUANT_0(x) (((x) & 0x7ff) << 11) +#define G1_REG_REF_PIC_QUANT_1(x) (((x) & 0x7ff) << 0) +#define G1_REG_LT_REF 0x098 +#define G1_REG_VALID_REF 0x09c +#define G1_REG_ADDR_QTABLE 0x0a0 +#define G1_REG_ADDR_DIR_MV 0x0a4 +#define G1_REG_BD_REF_PIC(i) (0x0a8 + ((i) * 0x4)) +#define G1_REG_BD_REF_PIC_BINIT_RLIST_B2(x) (((x) & 0x1f) << 25) +#define G1_REG_BD_REF_PIC_BINIT_RLIST_F2(x) (((x) & 0x1f) << 20) +#define G1_REG_BD_REF_PIC_BINIT_RLIST_B1(x) (((x) & 0x1f) << 15) +#define G1_REG_BD_REF_PIC_BINIT_RLIST_F1(x) (((x) & 0x1f) << 10) +#define G1_REG_BD_REF_PIC_BINIT_RLIST_B0(x) (((x) & 0x1f) << 5) +#define G1_REG_BD_REF_PIC_BINIT_RLIST_F0(x) (((x) & 0x1f) << 0) +#define G1_REG_BD_REF_PIC_PRED_TAP_2_M1(x) (((x) & 0x3) << 10) +#define G1_REG_BD_REF_PIC_PRED_TAP_2_4(x) (((x) & 0x3) << 8) +#define G1_REG_BD_REF_PIC_PRED_TAP_4_M1(x) (((x) & 0x3) << 6) +#define G1_REG_BD_REF_PIC_PRED_TAP_4_4(x) (((x) & 0x3) << 4) +#define G1_REG_BD_REF_PIC_PRED_TAP_6_M1(x) (((x) & 0x3) << 2) +#define G1_REG_BD_REF_PIC_PRED_TAP_6_4(x) (((x) & 0x3) << 0) +#define G1_REG_BD_REF_PIC_QUANT_DELTA_2(x) (((x) & 0x1f) << 27) +#define G1_REG_BD_REF_PIC_QUANT_DELTA_3(x) (((x) & 0x1f) << 22) +#define G1_REG_BD_REF_PIC_QUANT_2(x) (((x) & 0x7ff) << 11) +#define G1_REG_BD_REF_PIC_QUANT_3(x) (((x) & 0x7ff) << 0) +#define G1_REG_BD_P_REF_PIC 0x0bc +#define G1_REG_BD_P_REF_PIC_QUANT_DELTA_4(x) (((x) & 0x1f) << 27) +#define G1_REG_BD_P_REF_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 25) +#define G1_REG_BD_P_REF_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 20) +#define G1_REG_BD_P_REF_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 15) +#define G1_REG_BD_P_REF_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 10) +#define G1_REG_BD_P_REF_PIC_BINIT_RLIST_B15(x) (((x) & 0x1f) << 5) +#define G1_REG_BD_P_REF_PIC_BINIT_RLIST_F15(x) (((x) & 0x1f) << 0) +#define G1_REG_ERR_CONC 0x0c0 +#define G1_REG_ERR_CONC_STARTMB_X(x) (((x) & 0x1ff) << 23) +#define G1_REG_ERR_CONC_STARTMB_Y(x) (((x) & 0xff) << 15) +#define G1_REG_PRED_FLT 0x0c4 +#define G1_REG_PRED_FLT_PRED_BC_TAP_0_0(x) (((x) & 0x3ff) << 22) +#define G1_REG_PRED_FLT_PRED_BC_TAP_0_1(x) (((x) & 0x3ff) << 12) +#define G1_REG_PRED_FLT_PRED_BC_TAP_0_2(x) (((x) & 0x3ff) << 2) +#define G1_REG_REF_BUF_CTRL 0x0cc +#define G1_REG_REF_BUF_CTRL_REFBU_E BIT(31) +#define G1_REG_REF_BUF_CTRL_REFBU_THR(x) (((x) & 0xfff) << 19) +#define G1_REG_REF_BUF_CTRL_REFBU_PICID(x) (((x) & 0x1f) << 14) +#define G1_REG_REF_BUF_CTRL_REFBU_EVAL_E BIT(13) +#define G1_REG_REF_BUF_CTRL_REFBU_FPARMOD_E BIT(12) +#define G1_REG_REF_BUF_CTRL_REFBU_Y_OFFSET(x) (((x) & 0x1ff) << 0) +#define G1_REG_REF_BUF_CTRL2 0x0dc +#define G1_REG_REF_BUF_CTRL2_REFBU2_BUF_E BIT(31) +#define G1_REG_REF_BUF_CTRL2_REFBU2_THR(x) (((x) & 0xfff) << 19) +#define G1_REG_REF_BUF_CTRL2_REFBU2_PICID(x) (((x) & 0x1f) << 14) +#define G1_REG_REF_BUF_CTRL2_APF_THRESHOLD(x) (((x) & 0x3fff) << 0) +#define G1_REG_SOFT_RESET 0x194 + +#endif /* HANTRO_G1_REGS_H_ */ diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c new file mode 100644 index 000000000000..0c1e3043dc7e --- /dev/null +++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + */ + +#include <asm/unaligned.h> +#include <media/v4l2-mem2mem.h> +#include "hantro_jpeg.h" +#include "hantro.h" +#include "hantro_v4l2.h" +#include "hantro_hw.h" +#include "hantro_h1_regs.h" + +#define H1_JPEG_QUANT_TABLE_COUNT 16 + +static void hantro_h1_set_src_img_ctrl(struct hantro_dev *vpu, + struct hantro_ctx *ctx) +{ + struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; + u32 reg; + + reg = H1_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width) + | H1_REG_IN_IMG_CTRL_OVRFLR_D4(0) + | H1_REG_IN_IMG_CTRL_OVRFLB_D4(0) + | H1_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); + vepu_write_relaxed(vpu, reg, H1_REG_IN_IMG_CTRL); +} + +static void hantro_h1_jpeg_enc_set_buffers(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + struct vb2_buffer *src_buf) +{ + struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; + dma_addr_t src[3]; + + WARN_ON(pix_fmt->num_planes > 3); + + vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.dma, + H1_REG_ADDR_OUTPUT_STREAM); + vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.size, + H1_REG_STR_BUF_LIMIT); + + if (pix_fmt->num_planes == 1) { + src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); + /* single plane formats we supported are all interlaced */ + vepu_write_relaxed(vpu, src[0], H1_REG_ADDR_IN_PLANE_0); + } else if (pix_fmt->num_planes == 2) { + src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); + src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); + vepu_write_relaxed(vpu, src[0], H1_REG_ADDR_IN_PLANE_0); + vepu_write_relaxed(vpu, src[1], H1_REG_ADDR_IN_PLANE_1); + } else { + src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); + src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); + src[2] = vb2_dma_contig_plane_dma_addr(src_buf, 2); + vepu_write_relaxed(vpu, src[0], H1_REG_ADDR_IN_PLANE_0); + vepu_write_relaxed(vpu, src[1], H1_REG_ADDR_IN_PLANE_1); + vepu_write_relaxed(vpu, src[2], H1_REG_ADDR_IN_PLANE_2); + } +} + +static void +hantro_h1_jpeg_enc_set_qtable(struct hantro_dev *vpu, + unsigned char *luma_qtable, + unsigned char *chroma_qtable) +{ + u32 reg, i; + + for (i = 0; i < H1_JPEG_QUANT_TABLE_COUNT; i++) { + reg = get_unaligned_be32(&luma_qtable[i]); + vepu_write_relaxed(vpu, reg, H1_REG_JPEG_LUMA_QUAT(i)); + + reg = get_unaligned_be32(&chroma_qtable[i]); + vepu_write_relaxed(vpu, reg, H1_REG_JPEG_CHROMA_QUAT(i)); + } +} + +void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct hantro_jpeg_ctx jpeg_ctx; + u32 reg; + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + memset(&jpeg_ctx, 0, sizeof(jpeg_ctx)); + jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); + jpeg_ctx.width = ctx->dst_fmt.width; + jpeg_ctx.height = ctx->dst_fmt.height; + jpeg_ctx.quality = ctx->jpeg_quality; + hantro_jpeg_header_assemble(&jpeg_ctx); + + /* Switch to JPEG encoder mode before writing registers */ + vepu_write_relaxed(vpu, H1_REG_ENC_CTRL_ENC_MODE_JPEG, + H1_REG_ENC_CTRL); + + hantro_h1_set_src_img_ctrl(vpu, ctx); + hantro_h1_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf); + hantro_h1_jpeg_enc_set_qtable(vpu, + hantro_jpeg_get_qtable(&jpeg_ctx, 0), + hantro_jpeg_get_qtable(&jpeg_ctx, 1)); + + reg = H1_REG_AXI_CTRL_OUTPUT_SWAP16 + | H1_REG_AXI_CTRL_INPUT_SWAP16 + | H1_REG_AXI_CTRL_BURST_LEN(16) + | H1_REG_AXI_CTRL_OUTPUT_SWAP32 + | H1_REG_AXI_CTRL_INPUT_SWAP32 + | H1_REG_AXI_CTRL_OUTPUT_SWAP8 + | H1_REG_AXI_CTRL_INPUT_SWAP8; + /* Make sure that all registers are written at this point. */ + vepu_write(vpu, reg, H1_REG_AXI_CTRL); + + reg = H1_REG_ENC_CTRL_WIDTH(JPEG_MB_WIDTH(ctx->src_fmt.width)) + | H1_REG_ENC_CTRL_HEIGHT(JPEG_MB_HEIGHT(ctx->src_fmt.height)) + | H1_REG_ENC_CTRL_ENC_MODE_JPEG + | H1_REG_ENC_PIC_INTRA + | H1_REG_ENC_CTRL_EN_BIT; + /* Kick the watchdog and start encoding */ + schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + vepu_write(vpu, reg, H1_REG_ENC_CTRL); +} diff --git a/drivers/staging/media/hantro/hantro_h1_regs.h b/drivers/staging/media/hantro/hantro_h1_regs.h new file mode 100644 index 000000000000..d6e9825bb5c7 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_h1_regs.h @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Hantro VPU codec driver + * + * Copyright 2018 Google LLC. + * Tomasz Figa <tfiga@chromium.org> + */ + +#ifndef HANTRO_H1_REGS_H_ +#define HANTRO_H1_REGS_H_ + +/* Encoder registers. */ +#define H1_REG_INTERRUPT 0x004 +#define H1_REG_INTERRUPT_FRAME_RDY BIT(2) +#define H1_REG_INTERRUPT_DIS_BIT BIT(1) +#define H1_REG_INTERRUPT_BIT BIT(0) +#define H1_REG_AXI_CTRL 0x008 +#define H1_REG_AXI_CTRL_OUTPUT_SWAP16 BIT(15) +#define H1_REG_AXI_CTRL_INPUT_SWAP16 BIT(14) +#define H1_REG_AXI_CTRL_BURST_LEN(x) ((x) << 8) +#define H1_REG_AXI_CTRL_GATE_BIT BIT(4) +#define H1_REG_AXI_CTRL_OUTPUT_SWAP32 BIT(3) +#define H1_REG_AXI_CTRL_INPUT_SWAP32 BIT(2) +#define H1_REG_AXI_CTRL_OUTPUT_SWAP8 BIT(1) +#define H1_REG_AXI_CTRL_INPUT_SWAP8 BIT(0) +#define H1_REG_ADDR_OUTPUT_STREAM 0x014 +#define H1_REG_ADDR_OUTPUT_CTRL 0x018 +#define H1_REG_ADDR_REF_LUMA 0x01c +#define H1_REG_ADDR_REF_CHROMA 0x020 +#define H1_REG_ADDR_REC_LUMA 0x024 +#define H1_REG_ADDR_REC_CHROMA 0x028 +#define H1_REG_ADDR_IN_PLANE_0 0x02c +#define H1_REG_ADDR_IN_PLANE_1 0x030 +#define H1_REG_ADDR_IN_PLANE_2 0x034 +#define H1_REG_ENC_CTRL 0x038 +#define H1_REG_ENC_CTRL_TIMEOUT_EN BIT(31) +#define H1_REG_ENC_CTRL_NAL_MODE_BIT BIT(29) +#define H1_REG_ENC_CTRL_WIDTH(w) ((w) << 19) +#define H1_REG_ENC_CTRL_HEIGHT(h) ((h) << 10) +#define H1_REG_ENC_PIC_INTER (0x0 << 3) +#define H1_REG_ENC_PIC_INTRA (0x1 << 3) +#define H1_REG_ENC_PIC_MVCINTER (0x2 << 3) +#define H1_REG_ENC_CTRL_ENC_MODE_H264 (0x3 << 1) +#define H1_REG_ENC_CTRL_ENC_MODE_JPEG (0x2 << 1) +#define H1_REG_ENC_CTRL_ENC_MODE_VP8 (0x1 << 1) +#define H1_REG_ENC_CTRL_EN_BIT BIT(0) +#define H1_REG_IN_IMG_CTRL 0x03c +#define H1_REG_IN_IMG_CTRL_ROW_LEN(x) ((x) << 12) +#define H1_REG_IN_IMG_CTRL_OVRFLR_D4(x) ((x) << 10) +#define H1_REG_IN_IMG_CTRL_OVRFLB_D4(x) ((x) << 6) +#define H1_REG_IN_IMG_CTRL_FMT(x) ((x) << 2) +#define H1_REG_ENC_CTRL0 0x040 +#define H1_REG_ENC_CTRL0_INIT_QP(x) ((x) << 26) +#define H1_REG_ENC_CTRL0_SLICE_ALPHA(x) ((x) << 22) +#define H1_REG_ENC_CTRL0_SLICE_BETA(x) ((x) << 18) +#define H1_REG_ENC_CTRL0_CHROMA_QP_OFFSET(x) ((x) << 13) +#define H1_REG_ENC_CTRL0_FILTER_DIS(x) ((x) << 5) +#define H1_REG_ENC_CTRL0_IDR_PICID(x) ((x) << 1) +#define H1_REG_ENC_CTRL0_CONSTR_INTRA_PRED BIT(0) +#define H1_REG_ENC_CTRL1 0x044 +#define H1_REG_ENC_CTRL1_PPS_ID(x) ((x) << 24) +#define H1_REG_ENC_CTRL1_INTRA_PRED_MODE(x) ((x) << 16) +#define H1_REG_ENC_CTRL1_FRAME_NUM(x) ((x)) +#define H1_REG_ENC_CTRL2 0x048 +#define H1_REG_ENC_CTRL2_DEBLOCKING_FILETER_MODE(x) ((x) << 30) +#define H1_REG_ENC_CTRL2_H264_SLICE_SIZE(x) ((x) << 23) +#define H1_REG_ENC_CTRL2_DISABLE_QUARTER_PIXMV BIT(22) +#define H1_REG_ENC_CTRL2_TRANS8X8_MODE_EN BIT(21) +#define H1_REG_ENC_CTRL2_CABAC_INIT_IDC(x) ((x) << 19) +#define H1_REG_ENC_CTRL2_ENTROPY_CODING_MODE BIT(18) +#define H1_REG_ENC_CTRL2_H264_INTER4X4_MODE BIT(17) +#define H1_REG_ENC_CTRL2_H264_STREAM_MODE BIT(16) +#define H1_REG_ENC_CTRL2_INTRA16X16_MODE(x) ((x)) +#define H1_REG_ENC_CTRL3 0x04c +#define H1_REG_ENC_CTRL3_MUTIMV_EN BIT(30) +#define H1_REG_ENC_CTRL3_MV_PENALTY_1_4P(x) ((x) << 20) +#define H1_REG_ENC_CTRL3_MV_PENALTY_4P(x) ((x) << 10) +#define H1_REG_ENC_CTRL3_MV_PENALTY_1P(x) ((x)) +#define H1_REG_ENC_CTRL4 0x050 +#define H1_REG_ENC_CTRL4_MV_PENALTY_16X8_8X16(x) ((x) << 20) +#define H1_REG_ENC_CTRL4_MV_PENALTY_8X8(x) ((x) << 10) +#define H1_REG_ENC_CTRL4_8X4_4X8(x) ((x)) +#define H1_REG_ENC_CTRL5 0x054 +#define H1_REG_ENC_CTRL5_MACROBLOCK_PENALTY(x) ((x) << 24) +#define H1_REG_ENC_CTRL5_COMPLETE_SLICES(x) ((x) << 16) +#define H1_REG_ENC_CTRL5_INTER_MODE(x) ((x)) +#define H1_REG_STR_HDR_REM_MSB 0x058 +#define H1_REG_STR_HDR_REM_LSB 0x05c +#define H1_REG_STR_BUF_LIMIT 0x060 +#define H1_REG_MAD_CTRL 0x064 +#define H1_REG_MAD_CTRL_QP_ADJUST(x) ((x) << 28) +#define H1_REG_MAD_CTRL_MAD_THREDHOLD(x) ((x) << 22) +#define H1_REG_MAD_CTRL_QP_SUM_DIV2(x) ((x)) +#define H1_REG_ADDR_VP8_PROB_CNT 0x068 +#define H1_REG_QP_VAL 0x06c +#define H1_REG_QP_VAL_LUM(x) ((x) << 26) +#define H1_REG_QP_VAL_MAX(x) ((x) << 20) +#define H1_REG_QP_VAL_MIN(x) ((x) << 14) +#define H1_REG_QP_VAL_CHECKPOINT_DISTAN(x) ((x)) +#define H1_REG_VP8_QP_VAL(i) (0x06c + ((i) * 0x4)) +#define H1_REG_CHECKPOINT(i) (0x070 + ((i) * 0x4)) +#define H1_REG_CHECKPOINT_CHECK0(x) (((x) & 0xffff)) +#define H1_REG_CHECKPOINT_CHECK1(x) (((x) & 0xffff) << 16) +#define H1_REG_CHECKPOINT_RESULT(x) ((((x) >> (16 - 16 \ + * (i & 1))) & 0xffff) \ + * 32) +#define H1_REG_CHKPT_WORD_ERR(i) (0x084 + ((i) * 0x4)) +#define H1_REG_CHKPT_WORD_ERR_CHK0(x) (((x) & 0xffff)) +#define H1_REG_CHKPT_WORD_ERR_CHK1(x) (((x) & 0xffff) << 16) +#define H1_REG_VP8_BOOL_ENC 0x08c +#define H1_REG_CHKPT_DELTA_QP 0x090 +#define H1_REG_CHKPT_DELTA_QP_CHK0(x) (((x) & 0x0f) << 0) +#define H1_REG_CHKPT_DELTA_QP_CHK1(x) (((x) & 0x0f) << 4) +#define H1_REG_CHKPT_DELTA_QP_CHK2(x) (((x) & 0x0f) << 8) +#define H1_REG_CHKPT_DELTA_QP_CHK3(x) (((x) & 0x0f) << 12) +#define H1_REG_CHKPT_DELTA_QP_CHK4(x) (((x) & 0x0f) << 16) +#define H1_REG_CHKPT_DELTA_QP_CHK5(x) (((x) & 0x0f) << 20) +#define H1_REG_CHKPT_DELTA_QP_CHK6(x) (((x) & 0x0f) << 24) +#define H1_REG_VP8_CTRL0 0x090 +#define H1_REG_RLC_CTRL 0x094 +#define H1_REG_RLC_CTRL_STR_OFFS_SHIFT 23 +#define H1_REG_RLC_CTRL_STR_OFFS_MASK (0x3f << 23) +#define H1_REG_RLC_CTRL_RLC_SUM(x) ((x)) +#define H1_REG_MB_CTRL 0x098 +#define H1_REG_MB_CNT_OUT(x) (((x) & 0xffff)) +#define H1_REG_MB_CNT_SET(x) (((x) & 0xffff) << 16) +#define H1_REG_ADDR_NEXT_PIC 0x09c +#define H1_REG_JPEG_LUMA_QUAT(i) (0x100 + ((i) * 0x4)) +#define H1_REG_JPEG_CHROMA_QUAT(i) (0x140 + ((i) * 0x4)) +#define H1_REG_STABILIZATION_OUTPUT 0x0A0 +#define H1_REG_ADDR_CABAC_TBL 0x0cc +#define H1_REG_ADDR_MV_OUT 0x0d0 +#define H1_REG_RGB_YUV_COEFF(i) (0x0d4 + ((i) * 0x4)) +#define H1_REG_RGB_MASK_MSB 0x0dc +#define H1_REG_INTRA_AREA_CTRL 0x0e0 +#define H1_REG_CIR_INTRA_CTRL 0x0e4 +#define H1_REG_INTRA_SLICE_BITMAP(i) (0x0e8 + ((i) * 0x4)) +#define H1_REG_ADDR_VP8_DCT_PART(i) (0x0e8 + ((i) * 0x4)) +#define H1_REG_FIRST_ROI_AREA 0x0f0 +#define H1_REG_SECOND_ROI_AREA 0x0f4 +#define H1_REG_MVC_CTRL 0x0f8 +#define H1_REG_MVC_CTRL_MV16X16_FAVOR(x) ((x) << 28) +#define H1_REG_VP8_INTRA_PENALTY(i) (0x100 + ((i) * 0x4)) +#define H1_REG_ADDR_VP8_SEG_MAP 0x11c +#define H1_REG_VP8_SEG_QP(i) (0x120 + ((i) * 0x4)) +#define H1_REG_DMV_4P_1P_PENALTY(i) (0x180 + ((i) * 0x4)) +#define H1_REG_DMV_4P_1P_PENALTY_BIT(x, i) ((x) << (i) * 8) +#define H1_REG_DMV_QPEL_PENALTY(i) (0x200 + ((i) * 0x4)) +#define H1_REG_DMV_QPEL_PENALTY_BIT(x, i) ((x) << (i) * 8) +#define H1_REG_VP8_CTRL1 0x280 +#define H1_REG_VP8_BIT_COST_GOLDEN 0x284 +#define H1_REG_VP8_LOOP_FLT_DELTA(i) (0x288 + ((i) * 0x4)) + +#endif /* HANTRO_H1_REGS_H_ */ diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h new file mode 100644 index 000000000000..3c361c2e9b88 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Hantro VPU codec driver + * + * Copyright 2018 Google LLC. + * Tomasz Figa <tfiga@chromium.org> + */ + +#ifndef HANTRO_HW_H_ +#define HANTRO_HW_H_ + +#include <linux/interrupt.h> +#include <linux/v4l2-controls.h> +#include <media/mpeg2-ctrls.h> +#include <media/videobuf2-core.h> + +struct hantro_dev; +struct hantro_ctx; +struct hantro_buf; +struct hantro_variant; + +/** + * struct hantro_aux_buf - auxiliary DMA buffer for hardware data + * @cpu: CPU pointer to the buffer. + * @dma: DMA address of the buffer. + * @size: Size of the buffer. + */ +struct hantro_aux_buf { + void *cpu; + dma_addr_t dma; + size_t size; +}; + +/** + * struct hantro_jpeg_enc_hw_ctx + * @bounce_buffer: Bounce buffer + */ +struct hantro_jpeg_enc_hw_ctx { + struct hantro_aux_buf bounce_buffer; +}; + +/** + * struct hantro_mpeg2_dec_hw_ctx + * @qtable: Quantization table + */ +struct hantro_mpeg2_dec_hw_ctx { + struct hantro_aux_buf qtable; +}; + +/** + * struct hantro_codec_ops - codec mode specific operations + * + * @init: If needed, can be used for initialization. + * Optional and called from process context. + * @exit: If needed, can be used to undo the .init phase. + * Optional and called from process context. + * @run: Start single {en,de)coding job. Called from atomic context + * to indicate that a pair of buffers is ready and the hardware + * should be programmed and started. + * @done: Read back processing results and additional data from hardware. + * @reset: Reset the hardware in case of a timeout. + */ +struct hantro_codec_ops { + int (*init)(struct hantro_ctx *ctx); + void (*exit)(struct hantro_ctx *ctx); + void (*run)(struct hantro_ctx *ctx); + void (*done)(struct hantro_ctx *ctx, enum vb2_buffer_state); + void (*reset)(struct hantro_ctx *ctx); +}; + +/** + * enum hantro_enc_fmt - source format ID for hardware registers. + */ +enum hantro_enc_fmt { + RK3288_VPU_ENC_FMT_YUV420P = 0, + RK3288_VPU_ENC_FMT_YUV420SP = 1, + RK3288_VPU_ENC_FMT_YUYV422 = 2, + RK3288_VPU_ENC_FMT_UYVY422 = 3, +}; + +extern const struct hantro_variant rk3399_vpu_variant; +extern const struct hantro_variant rk3328_vpu_variant; +extern const struct hantro_variant rk3288_vpu_variant; + +void hantro_watchdog(struct work_struct *work); +void hantro_run(struct hantro_ctx *ctx); +void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, + enum vb2_buffer_state result); + +void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx); +void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx); +int hantro_jpeg_enc_init(struct hantro_ctx *ctx); +void hantro_jpeg_enc_exit(struct hantro_ctx *ctx); + +void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx); +void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx); +void hantro_mpeg2_dec_copy_qtable(u8 *qtable, + const struct v4l2_ctrl_mpeg2_quantization *ctrl); +int hantro_mpeg2_dec_init(struct hantro_ctx *ctx); +void hantro_mpeg2_dec_exit(struct hantro_ctx *ctx); + +#endif /* HANTRO_HW_H_ */ diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.c b/drivers/staging/media/hantro/hantro_jpeg.c index 0ff0badc1f7a..125eb41f2ede 100644 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.c +++ b/drivers/staging/media/hantro/hantro_jpeg.c @@ -6,9 +6,11 @@ * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr) * Copyright (C) 2014 Philipp Zabel, Pengutronix */ +#include <linux/dma-mapping.h> #include <linux/kernel.h> #include <linux/string.h> -#include "rockchip_vpu_jpeg.h" +#include "hantro_jpeg.h" +#include "hantro.h" #define LUMA_QUANT_OFF 7 #define CHROMA_QUANT_OFF 72 @@ -116,7 +118,7 @@ static const unsigned char chroma_ac_table[] = { * and we'll use fixed offsets to change the width, height * quantization tables, etc. */ -static const unsigned char rockchip_vpu_jpeg_header[JPEG_HEADER_SIZE] = { +static const unsigned char hantro_jpeg_header[JPEG_HEADER_SIZE] = { /* SOI */ 0xff, 0xd8, @@ -260,19 +262,19 @@ static void jpeg_set_quality(unsigned char *buffer, int quality) } unsigned char * -rockchip_vpu_jpeg_get_qtable(struct rockchip_vpu_jpeg_ctx *ctx, int index) +hantro_jpeg_get_qtable(struct hantro_jpeg_ctx *ctx, int index) { if (index == 0) return ctx->buffer + LUMA_QUANT_OFF; return ctx->buffer + CHROMA_QUANT_OFF; } -void rockchip_vpu_jpeg_header_assemble(struct rockchip_vpu_jpeg_ctx *ctx) +void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx) { char *buf = ctx->buffer; - memcpy(buf, rockchip_vpu_jpeg_header, - sizeof(rockchip_vpu_jpeg_header)); + memcpy(buf, hantro_jpeg_header, + sizeof(hantro_jpeg_header)); buf[HEIGHT_OFF + 0] = ctx->height >> 8; buf[HEIGHT_OFF + 1] = ctx->height; @@ -288,3 +290,30 @@ void rockchip_vpu_jpeg_header_assemble(struct rockchip_vpu_jpeg_ctx *ctx) jpeg_set_quality(buf, ctx->quality); } + +int hantro_jpeg_enc_init(struct hantro_ctx *ctx) +{ + ctx->jpeg_enc.bounce_buffer.size = + ctx->dst_fmt.plane_fmt[0].sizeimage - + ctx->vpu_dst_fmt->header_size; + + ctx->jpeg_enc.bounce_buffer.cpu = + dma_alloc_attrs(ctx->dev->dev, + ctx->jpeg_enc.bounce_buffer.size, + &ctx->jpeg_enc.bounce_buffer.dma, + GFP_KERNEL, + DMA_ATTR_ALLOC_SINGLE_PAGES); + if (!ctx->jpeg_enc.bounce_buffer.cpu) + return -ENOMEM; + + return 0; +} + +void hantro_jpeg_enc_exit(struct hantro_ctx *ctx) +{ + dma_free_attrs(ctx->dev->dev, + ctx->jpeg_enc.bounce_buffer.size, + ctx->jpeg_enc.bounce_buffer.cpu, + ctx->jpeg_enc.bounce_buffer.dma, + DMA_ATTR_ALLOC_SINGLE_PAGES); +} diff --git a/drivers/staging/media/hantro/hantro_jpeg.h b/drivers/staging/media/hantro/hantro_jpeg.h new file mode 100644 index 000000000000..9e8397c71388 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_jpeg.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#define JPEG_HEADER_SIZE 601 + +struct hantro_jpeg_ctx { + int width; + int height; + int quality; + unsigned char *buffer; +}; + +unsigned char *hantro_jpeg_get_qtable(struct hantro_jpeg_ctx *ctx, int index); +void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx); diff --git a/drivers/staging/media/hantro/hantro_mpeg2.c b/drivers/staging/media/hantro/hantro_mpeg2.c new file mode 100644 index 000000000000..1d334e6fcd06 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_mpeg2.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + */ + +#include "hantro.h" + +static const u8 zigzag[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +void hantro_mpeg2_dec_copy_qtable(u8 *qtable, + const struct v4l2_ctrl_mpeg2_quantization *ctrl) +{ + int i, n; + + if (!qtable || !ctrl) + return; + + for (i = 0; i < ARRAY_SIZE(zigzag); i++) { + n = zigzag[i]; + qtable[n + 0] = ctrl->intra_quantiser_matrix[i]; + qtable[n + 64] = ctrl->non_intra_quantiser_matrix[i]; + qtable[n + 128] = ctrl->chroma_intra_quantiser_matrix[i]; + qtable[n + 192] = ctrl->chroma_non_intra_quantiser_matrix[i]; + } +} + +int hantro_mpeg2_dec_init(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + ctx->mpeg2_dec.qtable.size = ARRAY_SIZE(zigzag) * 4; + ctx->mpeg2_dec.qtable.cpu = + dma_alloc_coherent(vpu->dev, + ctx->mpeg2_dec.qtable.size, + &ctx->mpeg2_dec.qtable.dma, + GFP_KERNEL); + if (!ctx->mpeg2_dec.qtable.cpu) + return -ENOMEM; + return 0; +} + +void hantro_mpeg2_dec_exit(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + dma_free_coherent(vpu->dev, + ctx->mpeg2_dec.qtable.size, + ctx->mpeg2_dec.qtable.cpu, + ctx->mpeg2_dec.qtable.dma); +} diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c new file mode 100644 index 000000000000..68f45ee66821 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_v4l2.c @@ -0,0 +1,686 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Collabora, Ltd. + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Alpha Lin <Alpha.Lin@rock-chips.com> + * Jeffy Chen <jeffy.chen@rock-chips.com> + * + * Copyright 2018 Google LLC. + * Tomasz Figa <tfiga@chromium.org> + * + * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. + * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. + */ + +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/videodev2.h> +#include <linux/workqueue.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> +#include <media/v4l2-mem2mem.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-sg.h> + +#include "hantro.h" +#include "hantro_hw.h" +#include "hantro_v4l2.h" + +static const struct hantro_fmt * +hantro_get_formats(const struct hantro_ctx *ctx, unsigned int *num_fmts) +{ + const struct hantro_fmt *formats; + + if (hantro_is_encoder_ctx(ctx)) { + formats = ctx->dev->variant->enc_fmts; + *num_fmts = ctx->dev->variant->num_enc_fmts; + } else { + formats = ctx->dev->variant->dec_fmts; + *num_fmts = ctx->dev->variant->num_dec_fmts; + } + + return formats; +} + +static const struct hantro_fmt * +hantro_find_format(const struct hantro_fmt *formats, unsigned int num_fmts, + u32 fourcc) +{ + unsigned int i; + + for (i = 0; i < num_fmts; i++) + if (formats[i].fourcc == fourcc) + return &formats[i]; + return NULL; +} + +static const struct hantro_fmt * +hantro_get_default_fmt(const struct hantro_fmt *formats, unsigned int num_fmts, + bool bitstream) +{ + unsigned int i; + + for (i = 0; i < num_fmts; i++) { + if (bitstream == (formats[i].codec_mode != + HANTRO_MODE_NONE)) + return &formats[i]; + } + return NULL; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct hantro_dev *vpu = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver)); + strscpy(cap->card, vdev->name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s", + vpu->dev->driver->name); + return 0; +} + +static int vidioc_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct hantro_ctx *ctx = fh_to_ctx(priv); + const struct hantro_fmt *formats, *fmt; + unsigned int num_fmts; + + if (fsize->index != 0) { + vpu_debug(0, "invalid frame size index (expected 0, got %d)\n", + fsize->index); + return -EINVAL; + } + + formats = hantro_get_formats(ctx, &num_fmts); + fmt = hantro_find_format(formats, num_fmts, fsize->pixel_format); + if (!fmt) { + vpu_debug(0, "unsupported bitstream format (%08x)\n", + fsize->pixel_format); + return -EINVAL; + } + + /* This only makes sense for coded formats */ + if (fmt->codec_mode == HANTRO_MODE_NONE) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise = fmt->frmsize; + + return 0; +} + +static int vidioc_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f, bool capture) + +{ + struct hantro_ctx *ctx = fh_to_ctx(priv); + const struct hantro_fmt *fmt, *formats; + unsigned int num_fmts, i, j = 0; + bool skip_mode_none; + + /* + * When dealing with an encoder: + * - on the capture side we want to filter out all MODE_NONE formats. + * - on the output side we want to filter out all formats that are + * not MODE_NONE. + * When dealing with a decoder: + * - on the capture side we want to filter out all formats that are + * not MODE_NONE. + * - on the output side we want to filter out all MODE_NONE formats. + */ + skip_mode_none = capture == hantro_is_encoder_ctx(ctx); + + formats = hantro_get_formats(ctx, &num_fmts); + for (i = 0; i < num_fmts; i++) { + bool mode_none = formats[i].codec_mode == HANTRO_MODE_NONE; + + if (skip_mode_none == mode_none) + continue; + if (j == f->index) { + fmt = &formats[i]; + f->pixelformat = fmt->fourcc; + return 0; + } + ++j; + } + return -EINVAL; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt(file, priv, f, true); +} + +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt(file, priv, f, false); +} + +static int vidioc_g_fmt_out_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct hantro_ctx *ctx = fh_to_ctx(priv); + + vpu_debug(4, "f->type = %d\n", f->type); + + *pix_mp = ctx->src_fmt; + + return 0; +} + +static int vidioc_g_fmt_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct hantro_ctx *ctx = fh_to_ctx(priv); + + vpu_debug(4, "f->type = %d\n", f->type); + + *pix_mp = ctx->dst_fmt; + + return 0; +} + +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f, + bool capture) +{ + struct hantro_ctx *ctx = fh_to_ctx(priv); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + const struct hantro_fmt *formats, *fmt, *vpu_fmt; + unsigned int num_fmts; + bool coded; + + coded = capture == hantro_is_encoder_ctx(ctx); + + vpu_debug(4, "trying format %c%c%c%c\n", + (pix_mp->pixelformat & 0x7f), + (pix_mp->pixelformat >> 8) & 0x7f, + (pix_mp->pixelformat >> 16) & 0x7f, + (pix_mp->pixelformat >> 24) & 0x7f); + + formats = hantro_get_formats(ctx, &num_fmts); + fmt = hantro_find_format(formats, num_fmts, pix_mp->pixelformat); + if (!fmt) { + fmt = hantro_get_default_fmt(formats, num_fmts, coded); + f->fmt.pix_mp.pixelformat = fmt->fourcc; + } + + if (coded) { + pix_mp->num_planes = 1; + vpu_fmt = fmt; + } else if (hantro_is_encoder_ctx(ctx)) { + vpu_fmt = ctx->vpu_dst_fmt; + } else { + vpu_fmt = ctx->vpu_src_fmt; + /* + * Width/height on the CAPTURE end of a decoder are ignored and + * replaced by the OUTPUT ones. + */ + pix_mp->width = ctx->src_fmt.width; + pix_mp->height = ctx->src_fmt.height; + } + + pix_mp->field = V4L2_FIELD_NONE; + + v4l2_apply_frmsize_constraints(&pix_mp->width, &pix_mp->height, + &vpu_fmt->frmsize); + + if (!coded) { + /* Fill remaining fields */ + v4l2_fill_pixfmt_mp(pix_mp, fmt->fourcc, pix_mp->width, + pix_mp->height); + } else if (!pix_mp->plane_fmt[0].sizeimage) { + /* + * For coded formats the application can specify + * sizeimage. If the application passes a zero sizeimage, + * let's default to the maximum frame size. + */ + pix_mp->plane_fmt[0].sizeimage = fmt->header_size + + pix_mp->width * pix_mp->height * fmt->max_depth; + } + + return 0; +} + +static int vidioc_try_fmt_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + return vidioc_try_fmt(file, priv, f, true); +} + +static int vidioc_try_fmt_out_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + return vidioc_try_fmt(file, priv, f, false); +} + +static void +hantro_reset_fmt(struct v4l2_pix_format_mplane *fmt, + const struct hantro_fmt *vpu_fmt) +{ + memset(fmt, 0, sizeof(*fmt)); + + fmt->pixelformat = vpu_fmt->fourcc; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_JPEG, + fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->quantization = V4L2_QUANTIZATION_DEFAULT; + fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; +} + +static void +hantro_reset_encoded_fmt(struct hantro_ctx *ctx) +{ + const struct hantro_fmt *vpu_fmt, *formats; + struct v4l2_pix_format_mplane *fmt; + unsigned int num_fmts; + + formats = hantro_get_formats(ctx, &num_fmts); + vpu_fmt = hantro_get_default_fmt(formats, num_fmts, true); + + if (hantro_is_encoder_ctx(ctx)) { + ctx->vpu_dst_fmt = vpu_fmt; + fmt = &ctx->dst_fmt; + } else { + ctx->vpu_src_fmt = vpu_fmt; + fmt = &ctx->src_fmt; + } + + hantro_reset_fmt(fmt, vpu_fmt); + fmt->num_planes = 1; + fmt->width = vpu_fmt->frmsize.min_width; + fmt->height = vpu_fmt->frmsize.min_height; + fmt->plane_fmt[0].sizeimage = vpu_fmt->header_size + + fmt->width * fmt->height * vpu_fmt->max_depth; +} + +static void +hantro_reset_raw_fmt(struct hantro_ctx *ctx) +{ + const struct hantro_fmt *raw_vpu_fmt, *formats; + struct v4l2_pix_format_mplane *raw_fmt, *encoded_fmt; + unsigned int num_fmts; + + formats = hantro_get_formats(ctx, &num_fmts); + raw_vpu_fmt = hantro_get_default_fmt(formats, num_fmts, false); + + if (hantro_is_encoder_ctx(ctx)) { + ctx->vpu_src_fmt = raw_vpu_fmt; + raw_fmt = &ctx->src_fmt; + encoded_fmt = &ctx->dst_fmt; + } else { + ctx->vpu_dst_fmt = raw_vpu_fmt; + raw_fmt = &ctx->dst_fmt; + encoded_fmt = &ctx->src_fmt; + } + + hantro_reset_fmt(raw_fmt, raw_vpu_fmt); + v4l2_fill_pixfmt_mp(raw_fmt, raw_vpu_fmt->fourcc, + encoded_fmt->width, + encoded_fmt->height); +} + +void hantro_reset_fmts(struct hantro_ctx *ctx) +{ + hantro_reset_encoded_fmt(ctx); + hantro_reset_raw_fmt(ctx); +} + +static void +hantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc) +{ + switch (fourcc) { + case V4L2_PIX_FMT_JPEG: + ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = false; + break; + case V4L2_PIX_FMT_MPEG2_SLICE: + ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true; + break; + default: + break; + } +} + +static int +vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct hantro_ctx *ctx = fh_to_ctx(priv); + const struct hantro_fmt *formats; + unsigned int num_fmts; + struct vb2_queue *vq; + int ret; + + /* Change not allowed if queue is busy. */ + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (vb2_is_busy(vq)) + return -EBUSY; + + if (!hantro_is_encoder_ctx(ctx)) { + struct vb2_queue *peer_vq; + + /* + * Since format change on the OUTPUT queue will reset + * the CAPTURE queue, we can't allow doing so + * when the CAPTURE queue has buffers allocated. + */ + peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (vb2_is_busy(peer_vq)) + return -EBUSY; + } + + ret = vidioc_try_fmt_out_mplane(file, priv, f); + if (ret) + return ret; + + formats = hantro_get_formats(ctx, &num_fmts); + ctx->vpu_src_fmt = hantro_find_format(formats, num_fmts, + pix_mp->pixelformat); + ctx->src_fmt = *pix_mp; + + /* + * Current raw format might have become invalid with newly + * selected codec, so reset it to default just to be safe and + * keep internal driver state sane. User is mandated to set + * the raw format again after we return, so we don't need + * anything smarter. + * Note that hantro_reset_raw_fmt() also propagates size + * changes to the raw format. + */ + if (!hantro_is_encoder_ctx(ctx)) + hantro_reset_raw_fmt(ctx); + + /* Colorimetry information are always propagated. */ + ctx->dst_fmt.colorspace = pix_mp->colorspace; + ctx->dst_fmt.ycbcr_enc = pix_mp->ycbcr_enc; + ctx->dst_fmt.xfer_func = pix_mp->xfer_func; + ctx->dst_fmt.quantization = pix_mp->quantization; + + hantro_update_requires_request(ctx, pix_mp->pixelformat); + + vpu_debug(0, "OUTPUT codec mode: %d\n", ctx->vpu_src_fmt->codec_mode); + vpu_debug(0, "fmt - w: %d, h: %d\n", + pix_mp->width, pix_mp->height); + return 0; +} + +static int vidioc_s_fmt_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct hantro_ctx *ctx = fh_to_ctx(priv); + const struct hantro_fmt *formats; + struct vb2_queue *vq; + unsigned int num_fmts; + int ret; + + /* Change not allowed if queue is busy. */ + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (vb2_is_busy(vq)) + return -EBUSY; + + if (hantro_is_encoder_ctx(ctx)) { + struct vb2_queue *peer_vq; + + /* + * Since format change on the CAPTURE queue will reset + * the OUTPUT queue, we can't allow doing so + * when the OUTPUT queue has buffers allocated. + */ + peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (vb2_is_busy(peer_vq) && + (pix_mp->pixelformat != ctx->dst_fmt.pixelformat || + pix_mp->height != ctx->dst_fmt.height || + pix_mp->width != ctx->dst_fmt.width)) + return -EBUSY; + } + + ret = vidioc_try_fmt_cap_mplane(file, priv, f); + if (ret) + return ret; + + formats = hantro_get_formats(ctx, &num_fmts); + ctx->vpu_dst_fmt = hantro_find_format(formats, num_fmts, + pix_mp->pixelformat); + ctx->dst_fmt = *pix_mp; + + /* + * Current raw format might have become invalid with newly + * selected codec, so reset it to default just to be safe and + * keep internal driver state sane. User is mandated to set + * the raw format again after we return, so we don't need + * anything smarter. + * Note that hantro_reset_raw_fmt() also propagates size + * changes to the raw format. + */ + if (hantro_is_encoder_ctx(ctx)) + hantro_reset_raw_fmt(ctx); + + /* Colorimetry information are always propagated. */ + ctx->src_fmt.colorspace = pix_mp->colorspace; + ctx->src_fmt.ycbcr_enc = pix_mp->ycbcr_enc; + ctx->src_fmt.xfer_func = pix_mp->xfer_func; + ctx->src_fmt.quantization = pix_mp->quantization; + + vpu_debug(0, "CAPTURE codec mode: %d\n", ctx->vpu_dst_fmt->codec_mode); + vpu_debug(0, "fmt - w: %d, h: %d\n", + pix_mp->width, pix_mp->height); + + hantro_update_requires_request(ctx, pix_mp->pixelformat); + + return 0; +} + +const struct v4l2_ioctl_ops hantro_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_framesizes = vidioc_enum_framesizes, + + .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_cap_mplane, + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_out_mplane, + .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_out_mplane, + .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap_mplane, + .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_out_mplane, + .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_cap_mplane, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, +}; + +static int +hantro_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct hantro_ctx *ctx = vb2_get_drv_priv(vq); + struct v4l2_pix_format_mplane *pixfmt; + int i; + + switch (vq->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + pixfmt = &ctx->dst_fmt; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + pixfmt = &ctx->src_fmt; + break; + default: + vpu_err("invalid queue type: %d\n", vq->type); + return -EINVAL; + } + + if (*num_planes) { + if (*num_planes != pixfmt->num_planes) + return -EINVAL; + for (i = 0; i < pixfmt->num_planes; ++i) + if (sizes[i] < pixfmt->plane_fmt[i].sizeimage) + return -EINVAL; + return 0; + } + + *num_planes = pixfmt->num_planes; + for (i = 0; i < pixfmt->num_planes; ++i) + sizes[i] = pixfmt->plane_fmt[i].sizeimage; + return 0; +} + +static int +hantro_buf_plane_check(struct vb2_buffer *vb, const struct hantro_fmt *vpu_fmt, + struct v4l2_pix_format_mplane *pixfmt) +{ + unsigned int sz; + int i; + + for (i = 0; i < pixfmt->num_planes; ++i) { + sz = pixfmt->plane_fmt[i].sizeimage; + vpu_debug(4, "plane %d size: %ld, sizeimage: %u\n", + i, vb2_plane_size(vb, i), sz); + if (vb2_plane_size(vb, i) < sz) { + vpu_err("plane %d is too small for output\n", i); + return -EINVAL; + } + } + return 0; +} + +static int hantro_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct hantro_ctx *ctx = vb2_get_drv_priv(vq); + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + return hantro_buf_plane_check(vb, ctx->vpu_src_fmt, + &ctx->src_fmt); + + return hantro_buf_plane_check(vb, ctx->vpu_dst_fmt, &ctx->dst_fmt); +} + +static void hantro_buf_queue(struct vb2_buffer *vb) +{ + struct hantro_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static bool hantro_vq_is_coded(struct vb2_queue *q) +{ + struct hantro_ctx *ctx = vb2_get_drv_priv(q); + + return hantro_is_encoder_ctx(ctx) != V4L2_TYPE_IS_OUTPUT(q->type); +} + +static int hantro_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct hantro_ctx *ctx = vb2_get_drv_priv(q); + int ret = 0; + + if (V4L2_TYPE_IS_OUTPUT(q->type)) + ctx->sequence_out = 0; + else + ctx->sequence_cap = 0; + + if (hantro_vq_is_coded(q)) { + enum hantro_codec_mode codec_mode; + + if (V4L2_TYPE_IS_OUTPUT(q->type)) + codec_mode = ctx->vpu_src_fmt->codec_mode; + else + codec_mode = ctx->vpu_dst_fmt->codec_mode; + + vpu_debug(4, "Codec mode = %d\n", codec_mode); + ctx->codec_ops = &ctx->dev->variant->codec_ops[codec_mode]; + if (ctx->codec_ops->init) + ret = ctx->codec_ops->init(ctx); + } + + return ret; +} + +static void +hantro_return_bufs(struct vb2_queue *q, + struct vb2_v4l2_buffer *(*buf_remove)(struct v4l2_m2m_ctx *)) +{ + struct hantro_ctx *ctx = vb2_get_drv_priv(q); + + for (;;) { + struct vb2_v4l2_buffer *vbuf; + + vbuf = buf_remove(ctx->fh.m2m_ctx); + if (!vbuf) + break; + v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, + &ctx->ctrl_handler); + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + } +} + +static void hantro_stop_streaming(struct vb2_queue *q) +{ + struct hantro_ctx *ctx = vb2_get_drv_priv(q); + + if (hantro_vq_is_coded(q)) { + if (ctx->codec_ops && ctx->codec_ops->exit) + ctx->codec_ops->exit(ctx); + } + + /* + * The mem2mem framework calls v4l2_m2m_cancel_job before + * .stop_streaming, so there isn't any job running and + * it is safe to return all the buffers. + */ + if (V4L2_TYPE_IS_OUTPUT(q->type)) + hantro_return_bufs(q, v4l2_m2m_src_buf_remove); + else + hantro_return_bufs(q, v4l2_m2m_dst_buf_remove); +} + +static void hantro_buf_request_complete(struct vb2_buffer *vb) +{ + struct hantro_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->ctrl_handler); +} + +static int hantro_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + vbuf->field = V4L2_FIELD_NONE; + return 0; +} + +const struct vb2_ops hantro_queue_ops = { + .queue_setup = hantro_queue_setup, + .buf_prepare = hantro_buf_prepare, + .buf_queue = hantro_buf_queue, + .buf_out_validate = hantro_buf_out_validate, + .buf_request_complete = hantro_buf_request_complete, + .start_streaming = hantro_start_streaming, + .stop_streaming = hantro_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; diff --git a/drivers/staging/media/hantro/hantro_v4l2.h b/drivers/staging/media/hantro/hantro_v4l2.h new file mode 100644 index 000000000000..18bc682c8556 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_v4l2.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Alpha Lin <Alpha.Lin@rock-chips.com> + * Jeffy Chen <jeffy.chen@rock-chips.com> + * + * Copyright 2018 Google LLC. + * Tomasz Figa <tfiga@chromium.org> + * + * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + */ + +#ifndef HANTRO_V4L2_H_ +#define HANTRO_V4L2_H_ + +#include "hantro.h" + +extern const struct v4l2_ioctl_ops hantro_ioctl_ops; +extern const struct vb2_ops hantro_queue_ops; + +void hantro_reset_fmts(struct hantro_ctx *ctx); + +#endif /* HANTRO_V4L2_H_ */ diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c new file mode 100644 index 000000000000..bcacc4f51093 --- /dev/null +++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Jeffy Chen <jeffy.chen@rock-chips.com> + */ + +#include <linux/clk.h> + +#include "hantro.h" +#include "hantro_jpeg.h" +#include "hantro_g1_regs.h" +#include "hantro_h1_regs.h" + +#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000) + +/* + * Supported formats. + */ + +static const struct hantro_fmt rk3288_vpu_enc_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_YUV420M, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422, + }, + { + .fourcc = V4L2_PIX_FMT_UYVY, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422, + }, + { + .fourcc = V4L2_PIX_FMT_JPEG, + .codec_mode = HANTRO_MODE_JPEG_ENC, + .max_depth = 2, + .header_size = JPEG_HEADER_SIZE, + .frmsize = { + .min_width = 96, + .max_width = 8192, + .step_width = JPEG_MB_DIM, + .min_height = 32, + .max_height = 8192, + .step_height = JPEG_MB_DIM, + }, + }, +}; + +static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .codec_mode = HANTRO_MODE_NONE, + }, + { + .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, + .codec_mode = HANTRO_MODE_MPEG2_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 1920, + .step_width = MPEG2_MB_DIM, + .min_height = 48, + .max_height = 1088, + .step_height = MPEG2_MB_DIM, + }, + }, +}; + +static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id) +{ + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; + u32 status, bytesused; + + status = vepu_read(vpu, H1_REG_INTERRUPT); + bytesused = vepu_read(vpu, H1_REG_STR_BUF_LIMIT) / 8; + state = (status & H1_REG_INTERRUPT_FRAME_RDY) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vepu_write(vpu, 0, H1_REG_INTERRUPT); + vepu_write(vpu, 0, H1_REG_AXI_CTRL); + + hantro_irq_done(vpu, bytesused, state); + + return IRQ_HANDLED; +} + +static irqreturn_t rk3288_vdpu_irq(int irq, void *dev_id) +{ + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; + u32 status; + + status = vdpu_read(vpu, G1_REG_INTERRUPT); + state = (status & G1_REG_INTERRUPT_DEC_RDY_INT) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vdpu_write(vpu, 0, G1_REG_INTERRUPT); + vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); + + hantro_irq_done(vpu, 0, state); + + return IRQ_HANDLED; +} + +static int rk3288_vpu_hw_init(struct hantro_dev *vpu) +{ + /* Bump ACLK to max. possible freq. to improve performance. */ + clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ); + return 0; +} + +static void rk3288_vpu_enc_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + vepu_write(vpu, H1_REG_INTERRUPT_DIS_BIT, H1_REG_INTERRUPT); + vepu_write(vpu, 0, H1_REG_ENC_CTRL); + vepu_write(vpu, 0, H1_REG_AXI_CTRL); +} + +static void rk3288_vpu_dec_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + vdpu_write(vpu, G1_REG_INTERRUPT_DEC_IRQ_DIS, G1_REG_INTERRUPT); + vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); + vdpu_write(vpu, 1, G1_REG_SOFT_RESET); +} + +/* + * Supported codec ops. + */ + +static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = { + [HANTRO_MODE_JPEG_ENC] = { + .run = hantro_h1_jpeg_enc_run, + .reset = rk3288_vpu_enc_reset, + .init = hantro_jpeg_enc_init, + .exit = hantro_jpeg_enc_exit, + }, + [HANTRO_MODE_MPEG2_DEC] = { + .run = hantro_g1_mpeg2_dec_run, + .reset = rk3288_vpu_dec_reset, + .init = hantro_mpeg2_dec_init, + .exit = hantro_mpeg2_dec_exit, + }, +}; + +/* + * VPU variant. + */ + +static const struct hantro_irq rk3288_irqs[] = { + { "vepu", rk3288_vepu_irq }, + { "vdpu", rk3288_vdpu_irq }, +}; + +static const char * const rk3288_clk_names[] = { + "aclk", "hclk" +}; + +const struct hantro_variant rk3288_vpu_variant = { + .enc_offset = 0x0, + .enc_fmts = rk3288_vpu_enc_fmts, + .num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts), + .dec_offset = 0x400, + .dec_fmts = rk3288_vpu_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(rk3288_vpu_dec_fmts), + .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER, + .codec_ops = rk3288_vpu_codec_ops, + .irqs = rk3288_irqs, + .num_irqs = ARRAY_SIZE(rk3288_irqs), + .init = rk3288_vpu_hw_init, + .clk_names = rk3288_clk_names, + .num_clocks = ARRAY_SIZE(rk3288_clk_names) +}; diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c new file mode 100644 index 000000000000..5718f8063542 --- /dev/null +++ b/drivers/staging/media/hantro/rk3399_vpu_hw.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Jeffy Chen <jeffy.chen@rock-chips.com> + */ + +#include <linux/clk.h> + +#include "hantro.h" +#include "hantro_jpeg.h" +#include "rk3399_vpu_regs.h" + +#define RK3399_ACLK_MAX_FREQ (400 * 1000 * 1000) + +/* + * Supported formats. + */ + +static const struct hantro_fmt rk3399_vpu_enc_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_YUV420M, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422, + }, + { + .fourcc = V4L2_PIX_FMT_UYVY, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422, + }, + { + .fourcc = V4L2_PIX_FMT_JPEG, + .codec_mode = HANTRO_MODE_JPEG_ENC, + .max_depth = 2, + .header_size = JPEG_HEADER_SIZE, + .frmsize = { + .min_width = 96, + .max_width = 8192, + .step_width = JPEG_MB_DIM, + .min_height = 32, + .max_height = 8192, + .step_height = JPEG_MB_DIM, + }, + }, +}; + +static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .codec_mode = HANTRO_MODE_NONE, + }, + { + .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, + .codec_mode = HANTRO_MODE_MPEG2_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 1920, + .step_width = MPEG2_MB_DIM, + .min_height = 48, + .max_height = 1088, + .step_height = MPEG2_MB_DIM, + }, + }, +}; + +static irqreturn_t rk3399_vepu_irq(int irq, void *dev_id) +{ + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; + u32 status, bytesused; + + status = vepu_read(vpu, VEPU_REG_INTERRUPT); + bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8; + state = (status & VEPU_REG_INTERRUPT_FRAME_READY) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vepu_write(vpu, 0, VEPU_REG_INTERRUPT); + vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); + + hantro_irq_done(vpu, bytesused, state); + + return IRQ_HANDLED; +} + +static irqreturn_t rk3399_vdpu_irq(int irq, void *dev_id) +{ + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; + u32 status; + + status = vdpu_read(vpu, VDPU_REG_INTERRUPT); + state = (status & VDPU_REG_INTERRUPT_DEC_IRQ) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vdpu_write(vpu, 0, VDPU_REG_INTERRUPT); + vdpu_write(vpu, 0, VDPU_REG_AXI_CTRL); + + hantro_irq_done(vpu, 0, state); + + return IRQ_HANDLED; +} + +static int rk3399_vpu_hw_init(struct hantro_dev *vpu) +{ + /* Bump ACLK to max. possible freq. to improve performance. */ + clk_set_rate(vpu->clocks[0].clk, RK3399_ACLK_MAX_FREQ); + return 0; +} + +static void rk3399_vpu_enc_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT); + vepu_write(vpu, 0, VEPU_REG_ENCODE_START); + vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); +} + +static void rk3399_vpu_dec_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_IRQ_DIS, VDPU_REG_INTERRUPT); + vdpu_write(vpu, 0, VDPU_REG_EN_FLAGS); + vdpu_write(vpu, 1, VDPU_REG_SOFT_RESET); +} + +/* + * Supported codec ops. + */ + +static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = { + [HANTRO_MODE_JPEG_ENC] = { + .run = rk3399_vpu_jpeg_enc_run, + .reset = rk3399_vpu_enc_reset, + .init = hantro_jpeg_enc_init, + .exit = hantro_jpeg_enc_exit, + }, + [HANTRO_MODE_MPEG2_DEC] = { + .run = rk3399_vpu_mpeg2_dec_run, + .reset = rk3399_vpu_dec_reset, + .init = hantro_mpeg2_dec_init, + .exit = hantro_mpeg2_dec_exit, + }, +}; + +/* + * VPU variant. + */ + +static const struct hantro_irq rk3399_irqs[] = { + { "vepu", rk3399_vepu_irq }, + { "vdpu", rk3399_vdpu_irq }, +}; + +static const char * const rk3399_clk_names[] = { + "aclk", "hclk" +}; + +const struct hantro_variant rk3399_vpu_variant = { + .enc_offset = 0x0, + .enc_fmts = rk3399_vpu_enc_fmts, + .num_enc_fmts = ARRAY_SIZE(rk3399_vpu_enc_fmts), + .dec_offset = 0x400, + .dec_fmts = rk3399_vpu_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), + .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER, + .codec_ops = rk3399_vpu_codec_ops, + .irqs = rk3399_irqs, + .num_irqs = ARRAY_SIZE(rk3399_irqs), + .init = rk3399_vpu_hw_init, + .clk_names = rk3399_clk_names, + .num_clocks = ARRAY_SIZE(rk3399_clk_names) +}; diff --git a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_jpeg_enc.c b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c index 3d438797692e..ae66354d2d93 100644 --- a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_jpeg_enc.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Rockchip VPU codec driver + * Hantro VPU codec driver * * Copyright (C) 2018 Rockchip Electronics Co., Ltd. * @@ -25,16 +25,16 @@ #include <asm/unaligned.h> #include <media/v4l2-mem2mem.h> -#include "rockchip_vpu_jpeg.h" -#include "rockchip_vpu.h" -#include "rockchip_vpu_common.h" -#include "rockchip_vpu_hw.h" +#include "hantro_jpeg.h" +#include "hantro.h" +#include "hantro_v4l2.h" +#include "hantro_hw.h" #include "rk3399_vpu_regs.h" #define VEPU_JPEG_QUANT_TABLE_COUNT 16 -static void rk3399_vpu_set_src_img_ctrl(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx) +static void rk3399_vpu_set_src_img_ctrl(struct hantro_dev *vpu, + struct hantro_ctx *ctx) { struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; u32 reg; @@ -60,8 +60,8 @@ static void rk3399_vpu_set_src_img_ctrl(struct rockchip_vpu_dev *vpu, vepu_write_relaxed(vpu, reg, VEPU_REG_ENC_CTRL1); } -static void rk3399_vpu_jpeg_enc_set_buffers(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx, +static void rk3399_vpu_jpeg_enc_set_buffers(struct hantro_dev *vpu, + struct hantro_ctx *ctx, struct vb2_buffer *src_buf) { struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; @@ -69,9 +69,9 @@ static void rk3399_vpu_jpeg_enc_set_buffers(struct rockchip_vpu_dev *vpu, WARN_ON(pix_fmt->num_planes > 3); - vepu_write_relaxed(vpu, ctx->bounce_dma_addr, + vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.dma, VEPU_REG_ADDR_OUTPUT_STREAM); - vepu_write_relaxed(vpu, ctx->bounce_size, + vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.size, VEPU_REG_STR_BUF_LIMIT); if (pix_fmt->num_planes == 1) { @@ -93,7 +93,7 @@ static void rk3399_vpu_jpeg_enc_set_buffers(struct rockchip_vpu_dev *vpu, } static void -rk3399_vpu_jpeg_enc_set_qtable(struct rockchip_vpu_dev *vpu, +rk3399_vpu_jpeg_enc_set_qtable(struct hantro_dev *vpu, unsigned char *luma_qtable, unsigned char *chroma_qtable) { @@ -108,22 +108,26 @@ rk3399_vpu_jpeg_enc_set_qtable(struct rockchip_vpu_dev *vpu, } } -void rk3399_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx) +void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx) { - struct rockchip_vpu_dev *vpu = ctx->dev; + struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; - struct rockchip_vpu_jpeg_ctx jpeg_ctx; + struct hantro_jpeg_ctx jpeg_ctx; + struct media_request *src_req; u32 reg; src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + src_req = src_buf->vb2_buf.req_obj.req; + v4l2_ctrl_request_setup(src_req, &ctx->ctrl_handler); + memset(&jpeg_ctx, 0, sizeof(jpeg_ctx)); jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); jpeg_ctx.width = ctx->dst_fmt.width; jpeg_ctx.height = ctx->dst_fmt.height; jpeg_ctx.quality = ctx->jpeg_quality; - rockchip_vpu_jpeg_header_assemble(&jpeg_ctx); + hantro_jpeg_header_assemble(&jpeg_ctx); /* Switch to JPEG encoder mode before writing registers */ vepu_write_relaxed(vpu, VEPU_REG_ENCODE_FORMAT_JPEG, @@ -132,8 +136,8 @@ void rk3399_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx) rk3399_vpu_set_src_img_ctrl(vpu, ctx); rk3399_vpu_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf); rk3399_vpu_jpeg_enc_set_qtable(vpu, - rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 0), - rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 1)); + hantro_jpeg_get_qtable(&jpeg_ctx, 0), + hantro_jpeg_get_qtable(&jpeg_ctx, 1)); reg = VEPU_REG_OUTPUT_SWAP32 | VEPU_REG_OUTPUT_SWAP16 @@ -153,6 +157,8 @@ void rk3399_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx) | VEPU_REG_ENCODE_FORMAT_JPEG | VEPU_REG_ENCODE_ENABLE; + v4l2_ctrl_request_complete(src_req, &ctx->ctrl_handler); + /* Kick the watchdog and start encoding */ schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); vepu_write(vpu, reg, VEPU_REG_ENCODE_START); diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c new file mode 100644 index 000000000000..8685bddfbcab --- /dev/null +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + */ + +#include <asm/unaligned.h> +#include <linux/bitfield.h> +#include <media/v4l2-mem2mem.h> +#include "hantro.h" +#include "hantro_hw.h" + +#define VDPU_SWREG(nr) ((nr) * 4) + +#define VDPU_REG_DEC_OUT_BASE VDPU_SWREG(63) +#define VDPU_REG_RLC_VLC_BASE VDPU_SWREG(64) +#define VDPU_REG_QTABLE_BASE VDPU_SWREG(61) +#define VDPU_REG_REFER0_BASE VDPU_SWREG(131) +#define VDPU_REG_REFER2_BASE VDPU_SWREG(134) +#define VDPU_REG_REFER3_BASE VDPU_SWREG(135) +#define VDPU_REG_REFER1_BASE VDPU_SWREG(148) +#define VDPU_REG_DEC_E(v) ((v) ? BIT(0) : 0) + +#define VDPU_REG_DEC_ADV_PRE_DIS(v) ((v) ? BIT(11) : 0) +#define VDPU_REG_DEC_SCMD_DIS(v) ((v) ? BIT(10) : 0) +#define VDPU_REG_FILTERING_DIS(v) ((v) ? BIT(8) : 0) +#define VDPU_REG_DEC_LATENCY(v) (((v) << 1) & GENMASK(6, 1)) + +#define VDPU_REG_INIT_QP(v) (((v) << 25) & GENMASK(30, 25)) +#define VDPU_REG_STREAM_LEN(v) (((v) << 0) & GENMASK(23, 0)) + +#define VDPU_REG_APF_THRESHOLD(v) (((v) << 17) & GENMASK(30, 17)) +#define VDPU_REG_STARTMB_X(v) (((v) << 8) & GENMASK(16, 8)) +#define VDPU_REG_STARTMB_Y(v) (((v) << 0) & GENMASK(7, 0)) + +#define VDPU_REG_DEC_MODE(v) (((v) << 0) & GENMASK(3, 0)) + +#define VDPU_REG_DEC_STRENDIAN_E(v) ((v) ? BIT(5) : 0) +#define VDPU_REG_DEC_STRSWAP32_E(v) ((v) ? BIT(4) : 0) +#define VDPU_REG_DEC_OUTSWAP32_E(v) ((v) ? BIT(3) : 0) +#define VDPU_REG_DEC_INSWAP32_E(v) ((v) ? BIT(2) : 0) +#define VDPU_REG_DEC_OUT_ENDIAN(v) ((v) ? BIT(1) : 0) +#define VDPU_REG_DEC_IN_ENDIAN(v) ((v) ? BIT(0) : 0) + +#define VDPU_REG_DEC_DATA_DISC_E(v) ((v) ? BIT(22) : 0) +#define VDPU_REG_DEC_MAX_BURST(v) (((v) << 16) & GENMASK(20, 16)) +#define VDPU_REG_DEC_AXI_WR_ID(v) (((v) << 8) & GENMASK(15, 8)) +#define VDPU_REG_DEC_AXI_RD_ID(v) (((v) << 0) & GENMASK(7, 0)) + +#define VDPU_REG_RLC_MODE_E(v) ((v) ? BIT(20) : 0) +#define VDPU_REG_PIC_INTERLACE_E(v) ((v) ? BIT(17) : 0) +#define VDPU_REG_PIC_FIELDMODE_E(v) ((v) ? BIT(16) : 0) +#define VDPU_REG_PIC_B_E(v) ((v) ? BIT(15) : 0) +#define VDPU_REG_PIC_INTER_E(v) ((v) ? BIT(14) : 0) +#define VDPU_REG_PIC_TOPFIELD_E(v) ((v) ? BIT(13) : 0) +#define VDPU_REG_FWD_INTERLACE_E(v) ((v) ? BIT(12) : 0) +#define VDPU_REG_WRITE_MVS_E(v) ((v) ? BIT(10) : 0) +#define VDPU_REG_DEC_TIMEOUT_E(v) ((v) ? BIT(5) : 0) +#define VDPU_REG_DEC_CLK_GATE_E(v) ((v) ? BIT(4) : 0) + +#define VDPU_REG_PIC_MB_WIDTH(v) (((v) << 23) & GENMASK(31, 23)) +#define VDPU_REG_PIC_MB_HEIGHT_P(v) (((v) << 11) & GENMASK(18, 11)) +#define VDPU_REG_ALT_SCAN_E(v) ((v) ? BIT(6) : 0) +#define VDPU_REG_TOPFIELDFIRST_E(v) ((v) ? BIT(5) : 0) + +#define VDPU_REG_STRM_START_BIT(v) (((v) << 26) & GENMASK(31, 26)) +#define VDPU_REG_QSCALE_TYPE(v) ((v) ? BIT(24) : 0) +#define VDPU_REG_CON_MV_E(v) ((v) ? BIT(4) : 0) +#define VDPU_REG_INTRA_DC_PREC(v) (((v) << 2) & GENMASK(3, 2)) +#define VDPU_REG_INTRA_VLC_TAB(v) ((v) ? BIT(1) : 0) +#define VDPU_REG_FRAME_PRED_DCT(v) ((v) ? BIT(0) : 0) + +#define VDPU_REG_ALT_SCAN_FLAG_E(v) ((v) ? BIT(19) : 0) +#define VDPU_REG_FCODE_FWD_HOR(v) (((v) << 15) & GENMASK(18, 15)) +#define VDPU_REG_FCODE_FWD_VER(v) (((v) << 11) & GENMASK(14, 11)) +#define VDPU_REG_FCODE_BWD_HOR(v) (((v) << 7) & GENMASK(10, 7)) +#define VDPU_REG_FCODE_BWD_VER(v) (((v) << 3) & GENMASK(6, 3)) +#define VDPU_REG_MV_ACCURACY_FWD(v) ((v) ? BIT(2) : 0) +#define VDPU_REG_MV_ACCURACY_BWD(v) ((v) ? BIT(1) : 0) + +#define PICT_TOP_FIELD 1 +#define PICT_BOTTOM_FIELD 2 +#define PICT_FRAME 3 + +static void +rk3399_vpu_mpeg2_dec_set_quantization(struct hantro_dev *vpu, + struct hantro_ctx *ctx) +{ + struct v4l2_ctrl_mpeg2_quantization *quantization; + + quantization = hantro_get_ctrl(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); + hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, quantization); + vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, + VDPU_REG_QTABLE_BASE); +} + +static void +rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + struct vb2_buffer *src_buf, + struct vb2_buffer *dst_buf, + const struct v4l2_mpeg2_sequence *sequence, + const struct v4l2_mpeg2_picture *picture, + const struct v4l2_ctrl_mpeg2_slice_params *slice_params) +{ + dma_addr_t forward_addr = 0, backward_addr = 0; + dma_addr_t current_addr, addr; + struct vb2_queue *vq; + + vq = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx); + + switch (picture->picture_coding_type) { + case V4L2_MPEG2_PICTURE_CODING_TYPE_B: + backward_addr = hantro_get_ref(vq, + slice_params->backward_ref_ts); + /* fall-through */ + case V4L2_MPEG2_PICTURE_CODING_TYPE_P: + forward_addr = hantro_get_ref(vq, + slice_params->forward_ref_ts); + } + + /* Source bitstream buffer */ + addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + vdpu_write_relaxed(vpu, addr, VDPU_REG_RLC_VLC_BASE); + + /* Destination frame buffer */ + addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + current_addr = addr; + + if (picture->picture_structure == PICT_BOTTOM_FIELD) + addr += ALIGN(ctx->dst_fmt.width, 16); + vdpu_write_relaxed(vpu, addr, VDPU_REG_DEC_OUT_BASE); + + if (!forward_addr) + forward_addr = current_addr; + if (!backward_addr) + backward_addr = current_addr; + + /* Set forward ref frame (top/bottom field) */ + if (picture->picture_structure == PICT_FRAME || + picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B || + (picture->picture_structure == PICT_TOP_FIELD && + picture->top_field_first) || + (picture->picture_structure == PICT_BOTTOM_FIELD && + !picture->top_field_first)) { + vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE); + vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE); + } else if (picture->picture_structure == PICT_TOP_FIELD) { + vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE); + vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER1_BASE); + } else if (picture->picture_structure == PICT_BOTTOM_FIELD) { + vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER0_BASE); + vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE); + } + + /* Set backward ref frame (top/bottom field) */ + vdpu_write_relaxed(vpu, backward_addr, VDPU_REG_REFER2_BASE); + vdpu_write_relaxed(vpu, backward_addr, VDPU_REG_REFER3_BASE); +} + +void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + const struct v4l2_ctrl_mpeg2_slice_params *slice_params; + const struct v4l2_mpeg2_sequence *sequence; + const struct v4l2_mpeg2_picture *picture; + u32 reg; + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + /* Apply request controls if any */ + v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, + &ctx->ctrl_handler); + + slice_params = hantro_get_ctrl(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); + sequence = &slice_params->sequence; + picture = &slice_params->picture; + + reg = VDPU_REG_DEC_ADV_PRE_DIS(0) | + VDPU_REG_DEC_SCMD_DIS(0) | + VDPU_REG_FILTERING_DIS(1) | + VDPU_REG_DEC_LATENCY(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(50)); + + reg = VDPU_REG_INIT_QP(1) | + VDPU_REG_STREAM_LEN(slice_params->bit_size >> 3); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(51)); + + reg = VDPU_REG_APF_THRESHOLD(8) | + VDPU_REG_STARTMB_X(0) | + VDPU_REG_STARTMB_Y(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(52)); + + reg = VDPU_REG_DEC_MODE(5); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(53)); + + reg = VDPU_REG_DEC_STRENDIAN_E(1) | + VDPU_REG_DEC_STRSWAP32_E(1) | + VDPU_REG_DEC_OUTSWAP32_E(1) | + VDPU_REG_DEC_INSWAP32_E(1) | + VDPU_REG_DEC_OUT_ENDIAN(1) | + VDPU_REG_DEC_IN_ENDIAN(1); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(54)); + + reg = VDPU_REG_DEC_DATA_DISC_E(0) | + VDPU_REG_DEC_MAX_BURST(16) | + VDPU_REG_DEC_AXI_WR_ID(0) | + VDPU_REG_DEC_AXI_RD_ID(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(56)); + + reg = VDPU_REG_RLC_MODE_E(0) | + VDPU_REG_PIC_INTERLACE_E(!sequence->progressive_sequence) | + VDPU_REG_PIC_FIELDMODE_E(picture->picture_structure != PICT_FRAME) | + VDPU_REG_PIC_B_E(picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B) | + VDPU_REG_PIC_INTER_E(picture->picture_coding_type != V4L2_MPEG2_PICTURE_CODING_TYPE_I) | + VDPU_REG_PIC_TOPFIELD_E(picture->picture_structure == PICT_TOP_FIELD) | + VDPU_REG_FWD_INTERLACE_E(0) | + VDPU_REG_WRITE_MVS_E(0) | + VDPU_REG_DEC_TIMEOUT_E(1) | + VDPU_REG_DEC_CLK_GATE_E(1); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(57)); + + reg = VDPU_REG_PIC_MB_WIDTH(MPEG2_MB_WIDTH(ctx->dst_fmt.width)) | + VDPU_REG_PIC_MB_HEIGHT_P(MPEG2_MB_HEIGHT(ctx->dst_fmt.height)) | + VDPU_REG_ALT_SCAN_E(picture->alternate_scan) | + VDPU_REG_TOPFIELDFIRST_E(picture->top_field_first); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(120)); + + reg = VDPU_REG_STRM_START_BIT(slice_params->data_bit_offset) | + VDPU_REG_QSCALE_TYPE(picture->q_scale_type) | + VDPU_REG_CON_MV_E(picture->concealment_motion_vectors) | + VDPU_REG_INTRA_DC_PREC(picture->intra_dc_precision) | + VDPU_REG_INTRA_VLC_TAB(picture->intra_vlc_format) | + VDPU_REG_FRAME_PRED_DCT(picture->frame_pred_frame_dct); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(122)); + + reg = VDPU_REG_ALT_SCAN_FLAG_E(picture->alternate_scan) | + VDPU_REG_FCODE_FWD_HOR(picture->f_code[0][0]) | + VDPU_REG_FCODE_FWD_VER(picture->f_code[0][1]) | + VDPU_REG_FCODE_BWD_HOR(picture->f_code[1][0]) | + VDPU_REG_FCODE_BWD_VER(picture->f_code[1][1]) | + VDPU_REG_MV_ACCURACY_FWD(1) | + VDPU_REG_MV_ACCURACY_BWD(1); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(136)); + + rk3399_vpu_mpeg2_dec_set_quantization(vpu, ctx); + + rk3399_vpu_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, + &dst_buf->vb2_buf, + sequence, picture, slice_params); + + /* Controls no longer in-use, we can complete them */ + v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req, + &ctx->ctrl_handler); + + /* Kick the watchdog and start decoding */ + schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + + reg = vdpu_read(vpu, VDPU_SWREG(57)) | VDPU_REG_DEC_E(1); + vdpu_write(vpu, reg, VDPU_SWREG(57)); +} diff --git a/drivers/staging/media/rockchip/vpu/rk3399_vpu_regs.h b/drivers/staging/media/hantro/rk3399_vpu_regs.h index fbe294177ec9..88d096920f30 100644 --- a/drivers/staging/media/rockchip/vpu/rk3399_vpu_regs.h +++ b/drivers/staging/media/hantro/rk3399_vpu_regs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Rockchip VPU codec driver + * Hantro VPU codec driver * * Copyright (C) 2018 Rockchip Electronics Co., Ltd. * Alpha Lin <alpha.lin@rock-chips.com> diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile index d2d909a36239..aa6c4b4ad37e 100644 --- a/drivers/staging/media/imx/Makefile +++ b/drivers/staging/media/imx/Makefile @@ -1,16 +1,16 @@ # SPDX-License-Identifier: GPL-2.0 -imx-media-objs := imx-media-dev.o imx-media-internal-sd.o imx-media-of.o -imx-media-objs += imx-media-dev-common.o -imx-media-common-objs := imx-media-utils.o imx-media-fim.o -imx-media-ic-objs := imx-ic-common.o imx-ic-prp.o imx-ic-prpencvf.o +imx6-media-objs := imx-media-dev.o imx-media-internal-sd.o \ + imx-ic-common.o imx-ic-prp.o imx-ic-prpencvf.o imx-media-vdic.o -obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media.o +imx-media-common-objs := imx-media-capture.o imx-media-dev-common.o \ + imx-media-of.o imx-media-utils.o + +imx6-media-csi-objs := imx-media-csi.o imx-media-fim.o + +obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx6-media.o obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-common.o -obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-capture.o -obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-vdic.o -obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-ic.o -obj-$(CONFIG_VIDEO_IMX_CSI) += imx-media-csi.o +obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-media-csi.o obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-mipi-csi2.o obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o diff --git a/drivers/staging/media/imx/imx-ic-common.c b/drivers/staging/media/imx/imx-ic-common.c index 18cd4cb92431..6df1ffb53895 100644 --- a/drivers/staging/media/imx/imx-ic-common.c +++ b/drivers/staging/media/imx/imx-ic-common.c @@ -4,8 +4,6 @@ * * Copyright (c) 2014-2016 Mentor Graphics Inc. */ -#include <linux/module.h> -#include <linux/platform_device.h> #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> #include "imx-media.h" @@ -20,23 +18,23 @@ static struct imx_ic_ops *ic_ops[IC_NUM_OPS] = { [IC_TASK_VIEWFINDER] = &imx_ic_prpencvf_ops, }; -static int imx_ic_probe(struct platform_device *pdev) +struct v4l2_subdev *imx_media_ic_register(struct v4l2_device *v4l2_dev, + struct device *ipu_dev, + struct ipu_soc *ipu, + u32 grp_id) { - struct imx_media_ipu_internal_sd_pdata *pdata; struct imx_ic_priv *priv; int ret; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(ipu_dev, sizeof(*priv), GFP_KERNEL); if (!priv) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - platform_set_drvdata(pdev, &priv->sd); - priv->dev = &pdev->dev; + priv->ipu_dev = ipu_dev; + priv->ipu = ipu; - /* get our ipu_id, grp_id and IC task id */ - pdata = priv->dev->platform_data; - priv->ipu_id = pdata->ipu_id; - switch (pdata->grp_id) { + /* get our IC task id */ + switch (grp_id) { case IMX_MEDIA_GRP_ID_IPU_IC_PRP: priv->task_id = IC_TASK_PRP; break; @@ -47,7 +45,7 @@ static int imx_ic_probe(struct platform_device *pdev) priv->task_id = IC_TASK_VIEWFINDER; break; default: - return -EINVAL; + return ERR_PTR(-EINVAL); } v4l2_subdev_init(&priv->sd, ic_ops[priv->task_id]->subdev_ops); @@ -55,55 +53,35 @@ static int imx_ic_probe(struct platform_device *pdev) priv->sd.internal_ops = ic_ops[priv->task_id]->internal_ops; priv->sd.entity.ops = ic_ops[priv->task_id]->entity_ops; priv->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; - priv->sd.dev = &pdev->dev; - priv->sd.owner = THIS_MODULE; + priv->sd.owner = ipu_dev->driver->owner; priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; - priv->sd.grp_id = pdata->grp_id; - strscpy(priv->sd.name, pdata->sd_name, sizeof(priv->sd.name)); + priv->sd.grp_id = grp_id; + imx_media_grp_id_to_sd_name(priv->sd.name, sizeof(priv->sd.name), + priv->sd.grp_id, ipu_get_num(ipu)); ret = ic_ops[priv->task_id]->init(priv); if (ret) - return ret; + return ERR_PTR(ret); - ret = v4l2_async_register_subdev(&priv->sd); - if (ret) + ret = v4l2_device_register_subdev(v4l2_dev, &priv->sd); + if (ret) { ic_ops[priv->task_id]->remove(priv); + return ERR_PTR(ret); + } - return ret; + return &priv->sd; } -static int imx_ic_remove(struct platform_device *pdev) +int imx_media_ic_unregister(struct v4l2_subdev *sd) { - struct v4l2_subdev *sd = platform_get_drvdata(pdev); struct imx_ic_priv *priv = container_of(sd, struct imx_ic_priv, sd); v4l2_info(sd, "Removing\n"); ic_ops[priv->task_id]->remove(priv); - v4l2_async_unregister_subdev(sd); + v4l2_device_unregister_subdev(sd); media_entity_cleanup(&sd->entity); return 0; } - -static const struct platform_device_id imx_ic_ids[] = { - { .name = "imx-ipuv3-ic" }, - { }, -}; -MODULE_DEVICE_TABLE(platform, imx_ic_ids); - -static struct platform_driver imx_ic_driver = { - .probe = imx_ic_probe, - .remove = imx_ic_remove, - .id_table = imx_ic_ids, - .driver = { - .name = "imx-ipuv3-ic", - }, -}; -module_platform_driver(imx_ic_driver); - -MODULE_DESCRIPTION("i.MX IC subdev driver"); -MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx-ipuv3-ic"); diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c index 10ffe00f1a54..5b4af3cfe670 100644 --- a/drivers/staging/media/imx/imx-ic-prp.c +++ b/drivers/staging/media/imx/imx-ic-prp.c @@ -35,16 +35,12 @@ #define S_ALIGN 1 /* multiple of 2 */ struct prp_priv { - struct imx_media_dev *md; struct imx_ic_priv *ic_priv; struct media_pad pad[PRP_NUM_PADS]; /* lock to protect all members below */ struct mutex lock; - /* IPU units we require */ - struct ipu_soc *ipu; - struct v4l2_subdev *src_sd; struct v4l2_subdev *sink_sd_prpenc; struct v4l2_subdev *sink_sd_prpvf; @@ -62,7 +58,7 @@ static inline struct prp_priv *sd_to_priv(struct v4l2_subdev *sd) { struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd); - return ic_priv->prp_priv; + return ic_priv->task_priv; } static int prp_start(struct prp_priv *priv) @@ -70,12 +66,10 @@ static int prp_start(struct prp_priv *priv) struct imx_ic_priv *ic_priv = priv->ic_priv; bool src_is_vdic; - priv->ipu = priv->md->ipu[ic_priv->ipu_id]; - /* set IC to receive from CSI or VDI depending on source */ src_is_vdic = !!(priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC); - ipu_set_ic_src_mux(priv->ipu, priv->csi_id, src_is_vdic); + ipu_set_ic_src_mux(ic_priv->ipu, priv->csi_id, src_is_vdic); return 0; } @@ -216,12 +210,12 @@ static int prp_link_setup(struct media_entity *entity, { struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd); - struct prp_priv *priv = ic_priv->prp_priv; + struct prp_priv *priv = ic_priv->task_priv; struct v4l2_subdev *remote_sd; int ret = 0; - dev_dbg(ic_priv->dev, "link setup %s -> %s", remote->entity->name, - local->entity->name); + dev_dbg(ic_priv->ipu_dev, "%s: link setup %s -> %s", + ic_priv->sd.name, remote->entity->name, local->entity->name); remote_sd = media_entity_to_v4l2_subdev(remote->entity); @@ -295,7 +289,7 @@ static int prp_link_validate(struct v4l2_subdev *sd, struct v4l2_subdev_format *sink_fmt) { struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd); - struct prp_priv *priv = ic_priv->prp_priv; + struct prp_priv *priv = ic_priv->task_priv; struct v4l2_subdev *csi; int ret; @@ -304,8 +298,8 @@ static int prp_link_validate(struct v4l2_subdev *sd, if (ret) return ret; - csi = imx_media_find_upstream_subdev(priv->md, &ic_priv->sd.entity, - IMX_MEDIA_GRP_ID_IPU_CSI); + csi = imx_media_pipeline_subdev(&ic_priv->sd.entity, + IMX_MEDIA_GRP_ID_IPU_CSI, true); if (IS_ERR(csi)) csi = NULL; @@ -351,7 +345,7 @@ out: static int prp_s_stream(struct v4l2_subdev *sd, int enable) { struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd); - struct prp_priv *priv = ic_priv->prp_priv; + struct prp_priv *priv = ic_priv->task_priv; int ret = 0; mutex_lock(&priv->lock); @@ -368,7 +362,8 @@ static int prp_s_stream(struct v4l2_subdev *sd, int enable) if (priv->stream_count != !enable) goto update_count; - dev_dbg(ic_priv->dev, "stream %s\n", enable ? "ON" : "OFF"); + dev_dbg(ic_priv->ipu_dev, "%s: stream %s\n", sd->name, + enable ? "ON" : "OFF"); if (enable) ret = prp_start(priv); @@ -440,9 +435,6 @@ static int prp_registered(struct v4l2_subdev *sd) int i, ret; u32 code; - /* get media device */ - priv->md = dev_get_drvdata(sd->v4l2_dev->dev); - for (i = 0; i < PRP_NUM_PADS; i++) { priv->pad[i].flags = (i == PRP_SINK_PAD) ? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; @@ -494,12 +486,12 @@ static int prp_init(struct imx_ic_priv *ic_priv) { struct prp_priv *priv; - priv = devm_kzalloc(ic_priv->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; mutex_init(&priv->lock); - ic_priv->prp_priv = priv; + ic_priv->task_priv = priv; priv->ic_priv = ic_priv; return 0; @@ -507,7 +499,7 @@ static int prp_init(struct imx_ic_priv *ic_priv) static void prp_remove(struct imx_ic_priv *ic_priv) { - struct prp_priv *priv = ic_priv->prp_priv; + struct prp_priv *priv = ic_priv->task_priv; mutex_destroy(&priv->lock); } diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c index 64037b0a8387..82bba68c554e 100644 --- a/drivers/staging/media/imx/imx-ic-prpencvf.c +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c @@ -50,7 +50,6 @@ #define S_ALIGN 1 /* multiple of 2 */ struct prp_priv { - struct imx_media_dev *md; struct imx_ic_priv *ic_priv; struct media_pad pad[PRPENCVF_NUM_PADS]; /* the video device at output pad */ @@ -60,7 +59,6 @@ struct prp_priv { struct mutex lock; /* IPU units we require */ - struct ipu_soc *ipu; struct ipu_ic *ic; struct ipuv3_channel *out_ch; struct ipuv3_channel *rot_in_ch; @@ -156,9 +154,7 @@ static int prp_get_ipu_resources(struct prp_priv *priv) struct ipuv3_channel *out_ch, *rot_in_ch, *rot_out_ch; int ret, task = ic_priv->task_id; - priv->ipu = priv->md->ipu[ic_priv->ipu_id]; - - ic = ipu_ic_get(priv->ipu, task); + ic = ipu_ic_get(ic_priv->ipu, task); if (IS_ERR(ic)) { v4l2_err(&ic_priv->sd, "failed to get IC\n"); ret = PTR_ERR(ic); @@ -166,7 +162,7 @@ static int prp_get_ipu_resources(struct prp_priv *priv) } priv->ic = ic; - out_ch = ipu_idmac_get(priv->ipu, prp_channel[task].out_ch); + out_ch = ipu_idmac_get(ic_priv->ipu, prp_channel[task].out_ch); if (IS_ERR(out_ch)) { v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n", prp_channel[task].out_ch); @@ -175,7 +171,7 @@ static int prp_get_ipu_resources(struct prp_priv *priv) } priv->out_ch = out_ch; - rot_in_ch = ipu_idmac_get(priv->ipu, prp_channel[task].rot_in_ch); + rot_in_ch = ipu_idmac_get(ic_priv->ipu, prp_channel[task].rot_in_ch); if (IS_ERR(rot_in_ch)) { v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n", prp_channel[task].rot_in_ch); @@ -184,7 +180,7 @@ static int prp_get_ipu_resources(struct prp_priv *priv) } priv->rot_in_ch = rot_in_ch; - rot_out_ch = ipu_idmac_get(priv->ipu, prp_channel[task].rot_out_ch); + rot_out_ch = ipu_idmac_get(ic_priv->ipu, prp_channel[task].rot_out_ch); if (IS_ERR(rot_out_ch)) { v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n", prp_channel[task].rot_out_ch); @@ -464,13 +460,13 @@ static int prp_setup_rotation(struct prp_priv *priv) incc = priv->cc[PRPENCVF_SINK_PAD]; outcc = vdev->cc; - ret = imx_media_alloc_dma_buf(priv->md, &priv->rot_buf[0], + ret = imx_media_alloc_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[0], outfmt->sizeimage); if (ret) { v4l2_err(&ic_priv->sd, "failed to alloc rot_buf[0], %d\n", ret); return ret; } - ret = imx_media_alloc_dma_buf(priv->md, &priv->rot_buf[1], + ret = imx_media_alloc_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[1], outfmt->sizeimage); if (ret) { v4l2_err(&ic_priv->sd, "failed to alloc rot_buf[1], %d\n", ret); @@ -543,14 +539,16 @@ static int prp_setup_rotation(struct prp_priv *priv) unsetup_vb2: prp_unsetup_vb2_buf(priv, VB2_BUF_STATE_QUEUED); free_rot1: - imx_media_free_dma_buf(priv->md, &priv->rot_buf[1]); + imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[1]); free_rot0: - imx_media_free_dma_buf(priv->md, &priv->rot_buf[0]); + imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[0]); return ret; } static void prp_unsetup_rotation(struct prp_priv *priv) { + struct imx_ic_priv *ic_priv = priv->ic_priv; + ipu_ic_task_disable(priv->ic); ipu_idmac_disable_channel(priv->out_ch); @@ -561,8 +559,8 @@ static void prp_unsetup_rotation(struct prp_priv *priv) ipu_ic_disable(priv->ic); - imx_media_free_dma_buf(priv->md, &priv->rot_buf[0]); - imx_media_free_dma_buf(priv->md, &priv->rot_buf[1]); + imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[0]); + imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[1]); } static int prp_setup_norotation(struct prp_priv *priv) @@ -602,7 +600,7 @@ static int prp_setup_norotation(struct prp_priv *priv) ipu_cpmem_dump(priv->out_ch); ipu_ic_dump(priv->ic); - ipu_dump(priv->ipu); + ipu_dump(ic_priv->ipu); ipu_ic_enable(priv->ic); @@ -654,7 +652,7 @@ static int prp_start(struct prp_priv *priv) outfmt = &vdev->fmt.fmt.pix; - ret = imx_media_alloc_dma_buf(priv->md, &priv->underrun_buf, + ret = imx_media_alloc_dma_buf(ic_priv->ipu_dev, &priv->underrun_buf, outfmt->sizeimage); if (ret) goto out_put_ipu; @@ -674,10 +672,10 @@ static int prp_start(struct prp_priv *priv) if (ret) goto out_free_underrun; - priv->nfb4eof_irq = ipu_idmac_channel_irq(priv->ipu, + priv->nfb4eof_irq = ipu_idmac_channel_irq(ic_priv->ipu, priv->out_ch, IPU_IRQ_NFB4EOF); - ret = devm_request_irq(ic_priv->dev, priv->nfb4eof_irq, + ret = devm_request_irq(ic_priv->ipu_dev, priv->nfb4eof_irq, prp_nfb4eof_interrupt, 0, "imx-ic-prp-nfb4eof", priv); if (ret) { @@ -688,12 +686,12 @@ static int prp_start(struct prp_priv *priv) if (ipu_rot_mode_is_irt(priv->rot_mode)) priv->eof_irq = ipu_idmac_channel_irq( - priv->ipu, priv->rot_out_ch, IPU_IRQ_EOF); + ic_priv->ipu, priv->rot_out_ch, IPU_IRQ_EOF); else priv->eof_irq = ipu_idmac_channel_irq( - priv->ipu, priv->out_ch, IPU_IRQ_EOF); + ic_priv->ipu, priv->out_ch, IPU_IRQ_EOF); - ret = devm_request_irq(ic_priv->dev, priv->eof_irq, + ret = devm_request_irq(ic_priv->ipu_dev, priv->eof_irq, prp_eof_interrupt, 0, "imx-ic-prp-eof", priv); if (ret) { @@ -718,13 +716,13 @@ static int prp_start(struct prp_priv *priv) return 0; out_free_eof_irq: - devm_free_irq(ic_priv->dev, priv->eof_irq, priv); + devm_free_irq(ic_priv->ipu_dev, priv->eof_irq, priv); out_free_nfb4eof_irq: - devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv); + devm_free_irq(ic_priv->ipu_dev, priv->nfb4eof_irq, priv); out_unsetup: prp_unsetup(priv, VB2_BUF_STATE_QUEUED); out_free_underrun: - imx_media_free_dma_buf(priv->md, &priv->underrun_buf); + imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->underrun_buf); out_put_ipu: prp_put_ipu_resources(priv); return ret; @@ -756,12 +754,12 @@ static void prp_stop(struct prp_priv *priv) v4l2_warn(&ic_priv->sd, "upstream stream off failed: %d\n", ret); - devm_free_irq(ic_priv->dev, priv->eof_irq, priv); - devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv); + devm_free_irq(ic_priv->ipu_dev, priv->eof_irq, priv); + devm_free_irq(ic_priv->ipu_dev, priv->nfb4eof_irq, priv); prp_unsetup(priv, VB2_BUF_STATE_ERROR); - imx_media_free_dma_buf(priv->md, &priv->underrun_buf); + imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->underrun_buf); /* cancel the EOF timeout timer */ del_timer_sync(&priv->eof_timeout_timer); @@ -904,11 +902,8 @@ static int prp_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *sdformat) { struct prp_priv *priv = sd_to_priv(sd); - struct imx_media_video_dev *vdev = priv->vdev; const struct imx_media_pixfmt *cc; - struct v4l2_pix_format vdev_fmt; struct v4l2_mbus_framefmt *fmt; - struct v4l2_rect vdev_compose; int ret = 0; if (sdformat->pad >= PRPENCVF_NUM_PADS) @@ -944,19 +939,9 @@ static int prp_set_fmt(struct v4l2_subdev *sd, priv->cc[PRPENCVF_SRC_PAD] = outcc; } - if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) - goto out; - - priv->cc[sdformat->pad] = cc; + if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) + priv->cc[sdformat->pad] = cc; - /* propagate output pad format to capture device */ - imx_media_mbus_fmt_to_pix_fmt(&vdev_fmt, &vdev_compose, - &priv->format_mbus[PRPENCVF_SRC_PAD], - priv->cc[PRPENCVF_SRC_PAD]); - mutex_unlock(&priv->lock); - imx_media_capture_device_set_format(vdev, &vdev_fmt, &vdev_compose); - - return 0; out: mutex_unlock(&priv->lock); return ret; @@ -1011,8 +996,8 @@ static int prp_link_setup(struct media_entity *entity, struct v4l2_subdev *remote_sd; int ret = 0; - dev_dbg(ic_priv->dev, "link setup %s -> %s", remote->entity->name, - local->entity->name); + dev_dbg(ic_priv->ipu_dev, "%s: link setup %s -> %s", + ic_priv->sd.name, remote->entity->name, local->entity->name); mutex_lock(&priv->lock); @@ -1178,7 +1163,8 @@ static int prp_s_stream(struct v4l2_subdev *sd, int enable) if (priv->stream_count != !enable) goto update_count; - dev_dbg(ic_priv->dev, "stream %s\n", enable ? "ON" : "OFF"); + dev_dbg(ic_priv->ipu_dev, "%s: stream %s\n", sd->name, + enable ? "ON" : "OFF"); if (enable) ret = prp_start(priv); @@ -1241,9 +1227,6 @@ static int prp_registered(struct v4l2_subdev *sd) int i, ret; u32 code; - /* get media device */ - priv->md = dev_get_drvdata(sd->v4l2_dev->dev); - for (i = 0; i < PRPENCVF_NUM_PADS; i++) { priv->pad[i].flags = (i == PRPENCVF_SINK_PAD) ? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; @@ -1266,14 +1249,10 @@ static int prp_registered(struct v4l2_subdev *sd) if (ret) return ret; - ret = imx_media_capture_device_register(priv->md, priv->vdev); + ret = imx_media_capture_device_register(priv->vdev); if (ret) return ret; - ret = imx_media_add_video_device(priv->md, priv->vdev); - if (ret) - goto unreg; - ret = prp_init_controls(priv); if (ret) goto unreg; @@ -1325,7 +1304,7 @@ static int prp_init(struct imx_ic_priv *ic_priv) { struct prp_priv *priv; - priv = devm_kzalloc(ic_priv->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -1335,7 +1314,8 @@ static int prp_init(struct imx_ic_priv *ic_priv) spin_lock_init(&priv->irqlock); timer_setup(&priv->eof_timeout_timer, prp_eof_timeout, 0); - priv->vdev = imx_media_capture_device_init(&ic_priv->sd, + priv->vdev = imx_media_capture_device_init(ic_priv->ipu_dev, + &ic_priv->sd, PRPENCVF_SRC_PAD); if (IS_ERR(priv->vdev)) return PTR_ERR(priv->vdev); diff --git a/drivers/staging/media/imx/imx-ic.h b/drivers/staging/media/imx/imx-ic.h index 0dbcf2a7ab5f..587c191c3eab 100644 --- a/drivers/staging/media/imx/imx-ic.h +++ b/drivers/staging/media/imx/imx-ic.h @@ -10,11 +10,10 @@ #include <media/v4l2-subdev.h> struct imx_ic_priv { - struct device *dev; + struct device *ipu_dev; + struct ipu_soc *ipu; struct v4l2_subdev sd; - int ipu_id; int task_id; - void *prp_priv; void *task_priv; }; @@ -29,6 +28,5 @@ struct imx_ic_ops { extern struct imx_ic_ops imx_ic_prp_ops; extern struct imx_ic_ops imx_ic_prpencvf_ops; -extern struct imx_ic_ops imx_ic_pp_ops; #endif diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c index 9430c835c434..b33a07bc9105 100644 --- a/drivers/staging/media/imx/imx-media-capture.c +++ b/drivers/staging/media/imx/imx-media-capture.c @@ -202,6 +202,7 @@ static int capture_g_fmt_vid_cap(struct file *file, void *fh, static int __capture_try_fmt_vid_cap(struct capture_priv *priv, struct v4l2_subdev_format *fmt_src, struct v4l2_format *f, + const struct imx_media_pixfmt **retcc, struct v4l2_rect *compose) { const struct imx_media_pixfmt *cc, *cc_src; @@ -242,8 +243,17 @@ static int __capture_try_fmt_vid_cap(struct capture_priv *priv, } } - imx_media_mbus_fmt_to_pix_fmt(&f->fmt.pix, compose, - &fmt_src->format, cc); + imx_media_mbus_fmt_to_pix_fmt(&f->fmt.pix, &fmt_src->format, cc); + + if (retcc) + *retcc = cc; + + if (compose) { + compose->left = 0; + compose->top = 0; + compose->width = fmt_src->format.width; + compose->height = fmt_src->format.height; + } return 0; } @@ -261,7 +271,7 @@ static int capture_try_fmt_vid_cap(struct file *file, void *fh, if (ret) return ret; - return __capture_try_fmt_vid_cap(priv, &fmt_src, f, NULL); + return __capture_try_fmt_vid_cap(priv, &fmt_src, f, NULL, NULL); } static int capture_s_fmt_vid_cap(struct file *file, void *fh, @@ -269,7 +279,6 @@ static int capture_s_fmt_vid_cap(struct file *file, void *fh, { struct capture_priv *priv = video_drvdata(file); struct v4l2_subdev_format fmt_src; - struct v4l2_rect compose; int ret; if (vb2_is_busy(&priv->q)) { @@ -283,14 +292,12 @@ static int capture_s_fmt_vid_cap(struct file *file, void *fh, if (ret) return ret; - ret = __capture_try_fmt_vid_cap(priv, &fmt_src, f, &compose); + ret = __capture_try_fmt_vid_cap(priv, &fmt_src, f, &priv->vdev.cc, + &priv->vdev.compose); if (ret) return ret; priv->vdev.fmt.fmt.pix = f->fmt.pix; - priv->vdev.cc = imx_media_find_format(f->fmt.pix.pixelformat, - CS_SEL_ANY, true); - priv->vdev.compose = compose; return 0; } @@ -520,6 +527,33 @@ static void capture_buf_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&priv->q_lock, flags); } +static int capture_validate_fmt(struct capture_priv *priv) +{ + struct v4l2_subdev_format fmt_src; + const struct imx_media_pixfmt *cc; + struct v4l2_rect compose; + struct v4l2_format f; + int ret; + + fmt_src.pad = priv->src_sd_pad; + fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(priv->src_sd, pad, get_fmt, NULL, &fmt_src); + if (ret) + return ret; + + v4l2_fill_pix_format(&f.fmt.pix, &fmt_src.format); + + ret = __capture_try_fmt_vid_cap(priv, &fmt_src, &f, &cc, &compose); + if (ret) + return ret; + + return (priv->vdev.fmt.fmt.pix.width != f.fmt.pix.width || + priv->vdev.fmt.fmt.pix.height != f.fmt.pix.height || + priv->vdev.cc->cs != cc->cs || + priv->vdev.compose.width != compose.width || + priv->vdev.compose.height != compose.height) ? -EINVAL : 0; +} + static int capture_start_streaming(struct vb2_queue *vq, unsigned int count) { struct capture_priv *priv = vb2_get_drv_priv(vq); @@ -527,6 +561,12 @@ static int capture_start_streaming(struct vb2_queue *vq, unsigned int count) unsigned long flags; int ret; + ret = capture_validate_fmt(priv); + if (ret) { + v4l2_err(priv->src_sd, "capture format not valid\n"); + goto return_bufs; + } + ret = imx_media_pipeline_set_stream(priv->md, &priv->src_sd->entity, true); if (ret) { @@ -614,7 +654,6 @@ static int capture_release(struct file *file) struct capture_priv *priv = video_drvdata(file); struct video_device *vfd = priv->vdev.vfd; struct vb2_queue *vq = &priv->q; - int ret = 0; mutex_lock(&priv->mutex); @@ -627,7 +666,7 @@ static int capture_release(struct file *file) v4l2_fh_release(file); mutex_unlock(&priv->mutex); - return ret; + return 0; } static const struct v4l2_file_operations capture_fops = { @@ -649,21 +688,6 @@ static struct video_device capture_videodev = { .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING, }; -void imx_media_capture_device_set_format(struct imx_media_video_dev *vdev, - const struct v4l2_pix_format *pix, - const struct v4l2_rect *compose) -{ - struct capture_priv *priv = to_capture_priv(vdev); - - mutex_lock(&priv->mutex); - priv->vdev.fmt.fmt.pix = *pix; - priv->vdev.cc = imx_media_find_format(pix->pixelformat, CS_SEL_ANY, - true); - priv->vdev.compose = *compose; - mutex_unlock(&priv->mutex); -} -EXPORT_SYMBOL_GPL(imx_media_capture_device_set_format); - struct imx_media_buffer * imx_media_capture_device_next_buf(struct imx_media_video_dev *vdev) { @@ -701,19 +725,20 @@ void imx_media_capture_device_error(struct imx_media_video_dev *vdev) } EXPORT_SYMBOL_GPL(imx_media_capture_device_error); -int imx_media_capture_device_register(struct imx_media_dev *md, - struct imx_media_video_dev *vdev) +int imx_media_capture_device_register(struct imx_media_video_dev *vdev) { struct capture_priv *priv = to_capture_priv(vdev); struct v4l2_subdev *sd = priv->src_sd; + struct v4l2_device *v4l2_dev = sd->v4l2_dev; struct video_device *vfd = vdev->vfd; struct vb2_queue *vq = &priv->q; struct v4l2_subdev_format fmt_src; int ret; - priv->md = md; + /* get media device */ + priv->md = container_of(v4l2_dev->mdev, struct imx_media_dev, md); - vfd->v4l2_dev = sd->v4l2_dev; + vfd->v4l2_dev = v4l2_dev; ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); if (ret) { @@ -765,8 +790,10 @@ int imx_media_capture_device_register(struct imx_media_dev *md, } vdev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - imx_media_mbus_fmt_to_pix_fmt(&vdev->fmt.fmt.pix, &vdev->compose, + imx_media_mbus_fmt_to_pix_fmt(&vdev->fmt.fmt.pix, &fmt_src.format, NULL); + vdev->compose.width = fmt_src.format.width; + vdev->compose.height = fmt_src.format.height; vdev->cc = imx_media_find_format(vdev->fmt.fmt.pix.pixelformat, CS_SEL_ANY, false); @@ -775,6 +802,9 @@ int imx_media_capture_device_register(struct imx_media_dev *md, vfd->ctrl_handler = &priv->ctrl_hdlr; + /* add vdev to the video device list */ + imx_media_add_video_device(priv->md, vdev); + return 0; unreg: video_unregister_device(vfd); @@ -799,18 +829,19 @@ void imx_media_capture_device_unregister(struct imx_media_video_dev *vdev) EXPORT_SYMBOL_GPL(imx_media_capture_device_unregister); struct imx_media_video_dev * -imx_media_capture_device_init(struct v4l2_subdev *src_sd, int pad) +imx_media_capture_device_init(struct device *dev, struct v4l2_subdev *src_sd, + int pad) { struct capture_priv *priv; struct video_device *vfd; - priv = devm_kzalloc(src_sd->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return ERR_PTR(-ENOMEM); priv->src_sd = src_sd; priv->src_sd_pad = pad; - priv->dev = src_sd->dev; + priv->dev = dev; mutex_init(&priv->mutex); spin_lock_init(&priv->q_lock); diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 1d248aca40a9..0eeb0db6d83f 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -56,7 +56,6 @@ struct csi_skip_desc { struct csi_priv { struct device *dev; struct ipu_soc *ipu; - struct imx_media_dev *md; struct v4l2_subdev sd; struct media_pad pad[CSI_NUM_PADS]; /* the video device at IDMAC output pad */ @@ -178,8 +177,8 @@ static int csi_get_upstream_endpoint(struct csi_priv *priv, * CSI-2 receiver if it is in the path, otherwise stay * with video mux. */ - sd = imx_media_find_upstream_subdev(priv->md, src, - IMX_MEDIA_GRP_ID_CSI2); + sd = imx_media_pipeline_subdev(src, IMX_MEDIA_GRP_ID_CSI2, + true); if (!IS_ERR(sd)) src = &sd->entity; } @@ -193,9 +192,9 @@ static int csi_get_upstream_endpoint(struct csi_priv *priv, src = &priv->sd.entity; /* get source pad of entity directly upstream from src */ - pad = imx_media_find_upstream_pad(priv->md, src, 0); - if (IS_ERR(pad)) - return PTR_ERR(pad); + pad = imx_media_pipeline_pad(src, 0, 0, true); + if (!pad) + return -ENODEV; sd = media_entity_to_v4l2_subdev(pad->entity); @@ -608,7 +607,7 @@ static int csi_idmac_start(struct csi_priv *priv) outfmt = &vdev->fmt.fmt.pix; - ret = imx_media_alloc_dma_buf(priv->md, &priv->underrun_buf, + ret = imx_media_alloc_dma_buf(priv->dev, &priv->underrun_buf, outfmt->sizeimage); if (ret) goto out_put_ipu; @@ -662,7 +661,7 @@ out_free_nfb4eof_irq: out_unsetup: csi_idmac_unsetup(priv, VB2_BUF_STATE_QUEUED); out_free_dma_buf: - imx_media_free_dma_buf(priv->md, &priv->underrun_buf); + imx_media_free_dma_buf(priv->dev, &priv->underrun_buf); out_put_ipu: csi_idmac_put_ipu_resources(priv); return ret; @@ -694,7 +693,7 @@ static void csi_idmac_stop(struct csi_priv *priv) csi_idmac_unsetup(priv, VB2_BUF_STATE_ERROR); - imx_media_free_dma_buf(priv->md, &priv->underrun_buf); + imx_media_free_dma_buf(priv->dev, &priv->underrun_buf); /* cancel the EOF timeout timer */ del_timer_sync(&priv->eof_timeout_timer); @@ -1134,8 +1133,7 @@ static int csi_link_validate(struct v4l2_subdev *sd, */ #if 0 mutex_unlock(&priv->lock); - vc_num = imx_media_find_mipi_csi2_channel(priv->md, - &priv->sd.entity); + vc_num = imx_media_find_mipi_csi2_channel(&priv->sd.entity); if (vc_num < 0) return vc_num; mutex_lock(&priv->lock); @@ -1502,13 +1500,10 @@ static int csi_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *sdformat) { struct csi_priv *priv = v4l2_get_subdevdata(sd); - struct imx_media_video_dev *vdev = priv->vdev; struct v4l2_fwnode_endpoint upstream_ep = { .bus_type = 0 }; const struct imx_media_pixfmt *cc; - struct v4l2_pix_format vdev_fmt; struct v4l2_mbus_framefmt *fmt; struct v4l2_rect *crop, *compose; - struct v4l2_rect vdev_compose; int ret; if (sdformat->pad >= CSI_NUM_PADS) @@ -1558,19 +1553,9 @@ static int csi_set_fmt(struct v4l2_subdev *sd, } } - if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) - goto out; - - priv->cc[sdformat->pad] = cc; - - /* propagate IDMAC output pad format to capture device */ - imx_media_mbus_fmt_to_pix_fmt(&vdev_fmt, &vdev_compose, - &priv->format_mbus[CSI_SRC_PAD_IDMAC], - priv->cc[CSI_SRC_PAD_IDMAC]); - mutex_unlock(&priv->lock); - imx_media_capture_device_set_format(vdev, &vdev_fmt, &vdev_compose); + if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) + priv->cc[sdformat->pad] = cc; - return 0; out: mutex_unlock(&priv->lock); return ret; @@ -1762,9 +1747,6 @@ static int csi_registered(struct v4l2_subdev *sd) int i, ret; u32 code; - /* get media device */ - priv->md = dev_get_drvdata(sd->v4l2_dev->dev); - /* get handle to IPU CSI */ csi = ipu_csi_get(priv->ipu, priv->csi_id); if (IS_ERR(csi)) { @@ -1812,17 +1794,12 @@ static int csi_registered(struct v4l2_subdev *sd) if (ret) goto free_fim; - ret = imx_media_capture_device_register(priv->md, priv->vdev); + ret = imx_media_capture_device_register(priv->vdev); if (ret) goto free_fim; - ret = imx_media_add_video_device(priv->md, priv->vdev); - if (ret) - goto unreg; - return 0; -unreg: - imx_media_capture_device_unregister(priv->vdev); + free_fim: if (priv->fim) imx_media_fim_free(priv->fim); @@ -1983,7 +1960,7 @@ static int imx_csi_probe(struct platform_device *pdev) imx_media_grp_id_to_sd_name(priv->sd.name, sizeof(priv->sd.name), priv->sd.grp_id, ipu_get_num(priv->ipu)); - priv->vdev = imx_media_capture_device_init(&priv->sd, + priv->vdev = imx_media_capture_device_init(priv->sd.dev, &priv->sd, CSI_SRC_PAD_IDMAC); if (IS_ERR(priv->vdev)) return PTR_ERR(priv->vdev); diff --git a/drivers/staging/media/imx/imx-media-dev-common.c b/drivers/staging/media/imx/imx-media-dev-common.c index 6cd93419b81d..66b505f7e8df 100644 --- a/drivers/staging/media/imx/imx-media-dev-common.c +++ b/drivers/staging/media/imx/imx-media-dev-common.c @@ -8,9 +8,341 @@ #include <linux/of_graph.h> #include <linux/of_platform.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mc.h> #include "imx-media.h" -static const struct v4l2_async_notifier_operations imx_media_subdev_ops = { +static inline struct imx_media_dev *notifier2dev(struct v4l2_async_notifier *n) +{ + return container_of(n, struct imx_media_dev, notifier); +} + +/* async subdev bound notifier */ +static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_subdev *asd) +{ + v4l2_info(sd->v4l2_dev, "subdev %s bound\n", sd->name); + + return 0; +} + +/* + * Create the media links for all subdevs that registered. + * Called after all async subdevs have bound. + */ +static int imx_media_create_links(struct v4l2_async_notifier *notifier) +{ + struct imx_media_dev *imxmd = notifier2dev(notifier); + struct v4l2_subdev *sd; + + list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) { + switch (sd->grp_id) { + case IMX_MEDIA_GRP_ID_IPU_VDIC: + case IMX_MEDIA_GRP_ID_IPU_IC_PRP: + case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC: + case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF: + /* + * links have already been created for the + * sync-registered subdevs. + */ + break; + case IMX_MEDIA_GRP_ID_IPU_CSI0: + case IMX_MEDIA_GRP_ID_IPU_CSI1: + case IMX_MEDIA_GRP_ID_CSI: + imx_media_create_csi_of_links(imxmd, sd); + break; + default: + /* + * if this subdev has fwnode links, create media + * links for them. + */ + imx_media_create_of_links(imxmd, sd); + break; + } + } + + return 0; +} + +/* + * adds given video device to given imx-media source pad vdev list. + * Continues upstream from the pad entity's sink pads. + */ +static int imx_media_add_vdev_to_pad(struct imx_media_dev *imxmd, + struct imx_media_video_dev *vdev, + struct media_pad *srcpad) +{ + struct media_entity *entity = srcpad->entity; + struct imx_media_pad_vdev *pad_vdev; + struct list_head *pad_vdev_list; + struct media_link *link; + struct v4l2_subdev *sd; + int i, ret; + + /* skip this entity if not a v4l2_subdev */ + if (!is_media_entity_v4l2_subdev(entity)) + return 0; + + sd = media_entity_to_v4l2_subdev(entity); + + pad_vdev_list = to_pad_vdev_list(sd, srcpad->index); + if (!pad_vdev_list) { + v4l2_warn(&imxmd->v4l2_dev, "%s:%u has no vdev list!\n", + entity->name, srcpad->index); + /* + * shouldn't happen, but no reason to fail driver load, + * just skip this entity. + */ + return 0; + } + + /* just return if we've been here before */ + list_for_each_entry(pad_vdev, pad_vdev_list, list) { + if (pad_vdev->vdev == vdev) + return 0; + } + + dev_dbg(imxmd->md.dev, "adding %s to pad %s:%u\n", + vdev->vfd->entity.name, entity->name, srcpad->index); + + pad_vdev = devm_kzalloc(imxmd->md.dev, sizeof(*pad_vdev), GFP_KERNEL); + if (!pad_vdev) + return -ENOMEM; + + /* attach this vdev to this pad */ + pad_vdev->vdev = vdev; + list_add_tail(&pad_vdev->list, pad_vdev_list); + + /* move upstream from this entity's sink pads */ + for (i = 0; i < entity->num_pads; i++) { + struct media_pad *pad = &entity->pads[i]; + + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + continue; + + list_for_each_entry(link, &entity->links, list) { + if (link->sink != pad) + continue; + ret = imx_media_add_vdev_to_pad(imxmd, vdev, + link->source); + if (ret) + return ret; + } + } + + return 0; +} + +/* + * For every subdevice, allocate an array of list_head's, one list_head + * for each pad, to hold the list of video devices reachable from that + * pad. + */ +static int imx_media_alloc_pad_vdev_lists(struct imx_media_dev *imxmd) +{ + struct list_head *vdev_lists; + struct media_entity *entity; + struct v4l2_subdev *sd; + int i; + + list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) { + entity = &sd->entity; + vdev_lists = devm_kcalloc(imxmd->md.dev, + entity->num_pads, sizeof(*vdev_lists), + GFP_KERNEL); + if (!vdev_lists) + return -ENOMEM; + + /* attach to the subdev's host private pointer */ + sd->host_priv = vdev_lists; + + for (i = 0; i < entity->num_pads; i++) + INIT_LIST_HEAD(to_pad_vdev_list(sd, i)); + } + + return 0; +} + +/* form the vdev lists in all imx-media source pads */ +static int imx_media_create_pad_vdev_lists(struct imx_media_dev *imxmd) +{ + struct imx_media_video_dev *vdev; + struct media_link *link; + int ret; + + ret = imx_media_alloc_pad_vdev_lists(imxmd); + if (ret) + return ret; + + list_for_each_entry(vdev, &imxmd->vdev_list, list) { + link = list_first_entry(&vdev->vfd->entity.links, + struct media_link, list); + ret = imx_media_add_vdev_to_pad(imxmd, vdev, link->source); + if (ret) + return ret; + } + + return 0; +} + +/* async subdev complete notifier */ +int imx_media_probe_complete(struct v4l2_async_notifier *notifier) +{ + struct imx_media_dev *imxmd = notifier2dev(notifier); + int ret; + + mutex_lock(&imxmd->mutex); + + ret = imx_media_create_links(notifier); + if (ret) + goto unlock; + + ret = imx_media_create_pad_vdev_lists(imxmd); + if (ret) + goto unlock; + + ret = v4l2_device_register_subdev_nodes(&imxmd->v4l2_dev); +unlock: + mutex_unlock(&imxmd->mutex); + if (ret) + return ret; + + return media_device_register(&imxmd->md); +} +EXPORT_SYMBOL_GPL(imx_media_probe_complete); + +/* + * adds controls to a video device from an entity subdevice. + * Continues upstream from the entity's sink pads. + */ +static int imx_media_inherit_controls(struct imx_media_dev *imxmd, + struct video_device *vfd, + struct media_entity *entity) +{ + int i, ret = 0; + + if (is_media_entity_v4l2_subdev(entity)) { + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + + dev_dbg(imxmd->md.dev, + "adding controls to %s from %s\n", + vfd->entity.name, sd->entity.name); + + ret = v4l2_ctrl_add_handler(vfd->ctrl_handler, + sd->ctrl_handler, + NULL, true); + if (ret) + return ret; + } + + /* move upstream */ + for (i = 0; i < entity->num_pads; i++) { + struct media_pad *pad, *spad = &entity->pads[i]; + + if (!(spad->flags & MEDIA_PAD_FL_SINK)) + continue; + + pad = media_entity_remote_pad(spad); + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + continue; + + ret = imx_media_inherit_controls(imxmd, vfd, pad->entity); + if (ret) + break; + } + + return ret; +} + +static int imx_media_link_notify(struct media_link *link, u32 flags, + unsigned int notification) +{ + struct imx_media_dev *imxmd = container_of(link->graph_obj.mdev, + struct imx_media_dev, md); + struct media_entity *source = link->source->entity; + struct imx_media_pad_vdev *pad_vdev; + struct list_head *pad_vdev_list; + struct video_device *vfd; + struct v4l2_subdev *sd; + int pad_idx, ret; + + ret = v4l2_pipeline_link_notify(link, flags, notification); + if (ret) + return ret; + + /* don't bother if source is not a subdev */ + if (!is_media_entity_v4l2_subdev(source)) + return 0; + + sd = media_entity_to_v4l2_subdev(source); + pad_idx = link->source->index; + + pad_vdev_list = to_pad_vdev_list(sd, pad_idx); + if (!pad_vdev_list) { + /* nothing to do if source sd has no pad vdev list */ + return 0; + } + + /* + * Before disabling a link, reset controls for all video + * devices reachable from this link. + * + * After enabling a link, refresh controls for all video + * devices reachable from this link. + */ + if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH && + !(flags & MEDIA_LNK_FL_ENABLED)) { + list_for_each_entry(pad_vdev, pad_vdev_list, list) { + vfd = pad_vdev->vdev->vfd; + dev_dbg(imxmd->md.dev, + "reset controls for %s\n", + vfd->entity.name); + v4l2_ctrl_handler_free(vfd->ctrl_handler); + v4l2_ctrl_handler_init(vfd->ctrl_handler, 0); + } + } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH && + (link->flags & MEDIA_LNK_FL_ENABLED)) { + list_for_each_entry(pad_vdev, pad_vdev_list, list) { + vfd = pad_vdev->vdev->vfd; + dev_dbg(imxmd->md.dev, + "refresh controls for %s\n", + vfd->entity.name); + ret = imx_media_inherit_controls(imxmd, vfd, + &vfd->entity); + if (ret) + break; + } + } + + return ret; +} + +static void imx_media_notify(struct v4l2_subdev *sd, unsigned int notification, + void *arg) +{ + struct media_entity *entity = &sd->entity; + int i; + + if (notification != V4L2_DEVICE_NOTIFY_EVENT) + return; + + for (i = 0; i < entity->num_pads; i++) { + struct media_pad *pad = &entity->pads[i]; + struct imx_media_pad_vdev *pad_vdev; + struct list_head *pad_vdev_list; + + pad_vdev_list = to_pad_vdev_list(sd, pad->index); + if (!pad_vdev_list) + continue; + list_for_each_entry(pad_vdev, pad_vdev_list, list) + v4l2_event_queue(pad_vdev->vdev->vfd, arg); + } +} + +static const struct v4l2_async_notifier_operations imx_media_notifier_ops = { .bound = imx_media_subdev_bound, .complete = imx_media_probe_complete, }; @@ -19,7 +351,8 @@ static const struct media_device_ops imx_media_md_ops = { .link_notify = imx_media_link_notify, }; -struct imx_media_dev *imx_media_dev_init(struct device *dev) +struct imx_media_dev *imx_media_dev_init(struct device *dev, + const struct media_device_ops *ops) { struct imx_media_dev *imxmd; int ret; @@ -31,7 +364,7 @@ struct imx_media_dev *imx_media_dev_init(struct device *dev) dev_set_drvdata(dev, imxmd); strscpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model)); - imxmd->md.ops = &imx_media_md_ops; + imxmd->md.ops = ops ? ops : &imx_media_md_ops; imxmd->md.dev = dev; mutex_init(&imxmd->mutex); @@ -50,8 +383,6 @@ struct imx_media_dev *imx_media_dev_init(struct device *dev) goto cleanup; } - dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd); - INIT_LIST_HEAD(&imxmd->vdev_list); v4l2_async_notifier_init(&imxmd->notifier); @@ -65,7 +396,8 @@ cleanup: } EXPORT_SYMBOL_GPL(imx_media_dev_init); -int imx_media_dev_notifier_register(struct imx_media_dev *imxmd) +int imx_media_dev_notifier_register(struct imx_media_dev *imxmd, + const struct v4l2_async_notifier_operations *ops) { int ret; @@ -76,7 +408,7 @@ int imx_media_dev_notifier_register(struct imx_media_dev *imxmd) } /* prepare the async subdev notifier and register it */ - imxmd->notifier.ops = &imx_media_subdev_ops; + imxmd->notifier.ops = ops ? ops : &imx_media_notifier_ops; ret = v4l2_async_notifier_register(&imxmd->v4l2_dev, &imxmd->notifier); if (ret) { diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c index 6be95584006d..6ac371f6e971 100644 --- a/drivers/staging/media/imx/imx-media-dev.c +++ b/drivers/staging/media/imx/imx-media-dev.c @@ -2,24 +2,13 @@ /* * V4L2 Media Controller Driver for Freescale i.MX5/6 SOC * - * Copyright (c) 2016 Mentor Graphics Inc. + * Copyright (c) 2016-2019 Mentor Graphics Inc. */ -#include <linux/delay.h> #include <linux/fs.h> #include <linux/module.h> -#include <linux/of_graph.h> -#include <linux/of_platform.h> -#include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/timer.h> -#include <media/v4l2-ctrls.h> +#include <media/v4l2-async.h> #include <media/v4l2-event.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-mc.h> -#include <video/imx-ipu-v3.h> #include <media/imx.h> #include "imx-media.h" @@ -28,433 +17,31 @@ static inline struct imx_media_dev *notifier2dev(struct v4l2_async_notifier *n) return container_of(n, struct imx_media_dev, notifier); } -/* - * Adds a subdev to the root notifier's async subdev list. If fwnode is - * non-NULL, adds the async as a V4L2_ASYNC_MATCH_FWNODE match type, - * otherwise as a V4L2_ASYNC_MATCH_DEVNAME match type using the dev_name - * of the given platform_device. This is called during driver load when - * forming the async subdev list. - */ -int imx_media_add_async_subdev(struct imx_media_dev *imxmd, - struct fwnode_handle *fwnode, - struct platform_device *pdev) -{ - struct device_node *np = to_of_node(fwnode); - struct imx_media_async_subdev *imxasd; - struct v4l2_async_subdev *asd; - const char *devname = NULL; - int ret; - - if (fwnode) { - asd = v4l2_async_notifier_add_fwnode_subdev(&imxmd->notifier, - fwnode, - sizeof(*imxasd)); - } else { - devname = dev_name(&pdev->dev); - asd = v4l2_async_notifier_add_devname_subdev(&imxmd->notifier, - devname, - sizeof(*imxasd)); - } - - if (IS_ERR(asd)) { - ret = PTR_ERR(asd); - if (ret == -EEXIST) { - if (np) - dev_dbg(imxmd->md.dev, "%s: already added %pOFn\n", - __func__, np); - else - dev_dbg(imxmd->md.dev, "%s: already added %s\n", - __func__, devname); - } - return ret; - } - - imxasd = to_imx_media_asd(asd); - - if (devname) - imxasd->pdev = pdev; - - if (np) - dev_dbg(imxmd->md.dev, "%s: added %pOFn, match type FWNODE\n", - __func__, np); - else - dev_dbg(imxmd->md.dev, "%s: added %s, match type DEVNAME\n", - __func__, devname); - - return 0; -} - -/* - * get IPU from this CSI and add it to the list of IPUs - * the media driver will control. - */ -static int imx_media_get_ipu(struct imx_media_dev *imxmd, - struct v4l2_subdev *csi_sd) -{ - struct ipu_soc *ipu; - int ipu_id; - - ipu = dev_get_drvdata(csi_sd->dev->parent); - if (!ipu) { - v4l2_err(&imxmd->v4l2_dev, - "CSI %s has no parent IPU!\n", csi_sd->name); - return -ENODEV; - } - - ipu_id = ipu_get_num(ipu); - if (ipu_id > 1) { - v4l2_err(&imxmd->v4l2_dev, "invalid IPU id %d!\n", ipu_id); - return -ENODEV; - } - - if (!imxmd->ipu[ipu_id]) - imxmd->ipu[ipu_id] = ipu; - - return 0; -} - /* async subdev bound notifier */ -int imx_media_subdev_bound(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *sd, - struct v4l2_async_subdev *asd) +static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_subdev *asd) { struct imx_media_dev *imxmd = notifier2dev(notifier); - int ret = 0; - - mutex_lock(&imxmd->mutex); + int ret; if (sd->grp_id & IMX_MEDIA_GRP_ID_IPU_CSI) { - ret = imx_media_get_ipu(imxmd, sd); + /* register the IPU internal subdevs */ + ret = imx_media_register_ipu_internal_subdevs(imxmd, sd); if (ret) - goto out; + return ret; } v4l2_info(&imxmd->v4l2_dev, "subdev %s bound\n", sd->name); -out: - mutex_unlock(&imxmd->mutex); - return ret; -} - -/* - * Create the media links for all subdevs that registered. - * Called after all async subdevs have bound. - */ -static int imx_media_create_links(struct v4l2_async_notifier *notifier) -{ - struct imx_media_dev *imxmd = notifier2dev(notifier); - struct v4l2_subdev *sd; - int ret; - - list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) { - switch (sd->grp_id) { - case IMX_MEDIA_GRP_ID_IPU_VDIC: - case IMX_MEDIA_GRP_ID_IPU_IC_PRP: - case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC: - case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF: - case IMX_MEDIA_GRP_ID_IPU_CSI0: - case IMX_MEDIA_GRP_ID_IPU_CSI1: - ret = imx_media_create_ipu_internal_links(imxmd, sd); - if (ret) - return ret; - /* - * the CSIs straddle between the external and the IPU - * internal entities, so create the external links - * to the CSI sink pads. - */ - if (sd->grp_id & IMX_MEDIA_GRP_ID_IPU_CSI) - imx_media_create_csi_of_links(imxmd, sd); - break; - case IMX_MEDIA_GRP_ID_CSI: - imx_media_create_csi_of_links(imxmd, sd); - - break; - default: - /* - * if this subdev has fwnode links, create media - * links for them. - */ - imx_media_create_of_links(imxmd, sd); - break; - } - } - - return 0; -} - -/* - * adds given video device to given imx-media source pad vdev list. - * Continues upstream from the pad entity's sink pads. - */ -static int imx_media_add_vdev_to_pad(struct imx_media_dev *imxmd, - struct imx_media_video_dev *vdev, - struct media_pad *srcpad) -{ - struct media_entity *entity = srcpad->entity; - struct imx_media_pad_vdev *pad_vdev; - struct list_head *pad_vdev_list; - struct media_link *link; - struct v4l2_subdev *sd; - int i, ret; - - /* skip this entity if not a v4l2_subdev */ - if (!is_media_entity_v4l2_subdev(entity)) - return 0; - - sd = media_entity_to_v4l2_subdev(entity); - - pad_vdev_list = to_pad_vdev_list(sd, srcpad->index); - if (!pad_vdev_list) { - v4l2_warn(&imxmd->v4l2_dev, "%s:%u has no vdev list!\n", - entity->name, srcpad->index); - /* - * shouldn't happen, but no reason to fail driver load, - * just skip this entity. - */ - return 0; - } - - /* just return if we've been here before */ - list_for_each_entry(pad_vdev, pad_vdev_list, list) { - if (pad_vdev->vdev == vdev) - return 0; - } - - dev_dbg(imxmd->md.dev, "adding %s to pad %s:%u\n", - vdev->vfd->entity.name, entity->name, srcpad->index); - - pad_vdev = devm_kzalloc(imxmd->md.dev, sizeof(*pad_vdev), GFP_KERNEL); - if (!pad_vdev) - return -ENOMEM; - - /* attach this vdev to this pad */ - pad_vdev->vdev = vdev; - list_add_tail(&pad_vdev->list, pad_vdev_list); - - /* move upstream from this entity's sink pads */ - for (i = 0; i < entity->num_pads; i++) { - struct media_pad *pad = &entity->pads[i]; - - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - continue; - - list_for_each_entry(link, &entity->links, list) { - if (link->sink != pad) - continue; - ret = imx_media_add_vdev_to_pad(imxmd, vdev, - link->source); - if (ret) - return ret; - } - } - - return 0; -} - -/* - * For every subdevice, allocate an array of list_head's, one list_head - * for each pad, to hold the list of video devices reachable from that - * pad. - */ -static int imx_media_alloc_pad_vdev_lists(struct imx_media_dev *imxmd) -{ - struct list_head *vdev_lists; - struct media_entity *entity; - struct v4l2_subdev *sd; - int i; - - list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) { - entity = &sd->entity; - vdev_lists = devm_kcalloc(imxmd->md.dev, - entity->num_pads, sizeof(*vdev_lists), - GFP_KERNEL); - if (!vdev_lists) - return -ENOMEM; - - /* attach to the subdev's host private pointer */ - sd->host_priv = vdev_lists; - - for (i = 0; i < entity->num_pads; i++) - INIT_LIST_HEAD(to_pad_vdev_list(sd, i)); - } - - return 0; -} - -/* form the vdev lists in all imx-media source pads */ -static int imx_media_create_pad_vdev_lists(struct imx_media_dev *imxmd) -{ - struct imx_media_video_dev *vdev; - struct media_link *link; - int ret; - - ret = imx_media_alloc_pad_vdev_lists(imxmd); - if (ret) - return ret; - - list_for_each_entry(vdev, &imxmd->vdev_list, list) { - link = list_first_entry(&vdev->vfd->entity.links, - struct media_link, list); - ret = imx_media_add_vdev_to_pad(imxmd, vdev, link->source); - if (ret) - return ret; - } return 0; } /* async subdev complete notifier */ -int imx_media_probe_complete(struct v4l2_async_notifier *notifier) -{ - struct imx_media_dev *imxmd = notifier2dev(notifier); - int ret; - - mutex_lock(&imxmd->mutex); - - ret = imx_media_create_links(notifier); - if (ret) - goto unlock; - - ret = imx_media_create_pad_vdev_lists(imxmd); - if (ret) - goto unlock; - - ret = v4l2_device_register_subdev_nodes(&imxmd->v4l2_dev); -unlock: - mutex_unlock(&imxmd->mutex); - if (ret) - return ret; - - return media_device_register(&imxmd->md); -} - -/* - * adds controls to a video device from an entity subdevice. - * Continues upstream from the entity's sink pads. - */ -static int imx_media_inherit_controls(struct imx_media_dev *imxmd, - struct video_device *vfd, - struct media_entity *entity) -{ - int i, ret = 0; - - if (is_media_entity_v4l2_subdev(entity)) { - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - - dev_dbg(imxmd->md.dev, - "adding controls to %s from %s\n", - vfd->entity.name, sd->entity.name); - - ret = v4l2_ctrl_add_handler(vfd->ctrl_handler, - sd->ctrl_handler, - NULL, true); - if (ret) - return ret; - } - - /* move upstream */ - for (i = 0; i < entity->num_pads; i++) { - struct media_pad *pad, *spad = &entity->pads[i]; - - if (!(spad->flags & MEDIA_PAD_FL_SINK)) - continue; - - pad = media_entity_remote_pad(spad); - if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) - continue; - - ret = imx_media_inherit_controls(imxmd, vfd, pad->entity); - if (ret) - break; - } - - return ret; -} - -int imx_media_link_notify(struct media_link *link, u32 flags, - unsigned int notification) -{ - struct media_entity *source = link->source->entity; - struct imx_media_pad_vdev *pad_vdev; - struct list_head *pad_vdev_list; - struct imx_media_dev *imxmd; - struct video_device *vfd; - struct v4l2_subdev *sd; - int pad_idx, ret; - - ret = v4l2_pipeline_link_notify(link, flags, notification); - if (ret) - return ret; - - /* don't bother if source is not a subdev */ - if (!is_media_entity_v4l2_subdev(source)) - return 0; - - sd = media_entity_to_v4l2_subdev(source); - pad_idx = link->source->index; - - imxmd = dev_get_drvdata(sd->v4l2_dev->dev); - - pad_vdev_list = to_pad_vdev_list(sd, pad_idx); - if (!pad_vdev_list) { - /* shouldn't happen, but no reason to fail link setup */ - return 0; - } - - /* - * Before disabling a link, reset controls for all video - * devices reachable from this link. - * - * After enabling a link, refresh controls for all video - * devices reachable from this link. - */ - if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH && - !(flags & MEDIA_LNK_FL_ENABLED)) { - list_for_each_entry(pad_vdev, pad_vdev_list, list) { - vfd = pad_vdev->vdev->vfd; - dev_dbg(imxmd->md.dev, - "reset controls for %s\n", - vfd->entity.name); - v4l2_ctrl_handler_free(vfd->ctrl_handler); - v4l2_ctrl_handler_init(vfd->ctrl_handler, 0); - } - } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH && - (link->flags & MEDIA_LNK_FL_ENABLED)) { - list_for_each_entry(pad_vdev, pad_vdev_list, list) { - vfd = pad_vdev->vdev->vfd; - dev_dbg(imxmd->md.dev, - "refresh controls for %s\n", - vfd->entity.name); - ret = imx_media_inherit_controls(imxmd, vfd, - &vfd->entity); - if (ret) - break; - } - } - - return ret; -} - -void imx_media_notify(struct v4l2_subdev *sd, unsigned int notification, - void *arg) -{ - struct media_entity *entity = &sd->entity; - int i; - - if (notification != V4L2_DEVICE_NOTIFY_EVENT) - return; - - for (i = 0; i < entity->num_pads; i++) { - struct media_pad *pad = &entity->pads[i]; - struct imx_media_pad_vdev *pad_vdev; - struct list_head *pad_vdev_list; - - pad_vdev_list = to_pad_vdev_list(sd, pad->index); - if (!pad_vdev_list) - continue; - list_for_each_entry(pad_vdev, pad_vdev_list, list) - v4l2_event_queue(pad_vdev->vdev->vfd, arg); - } -} +static const struct v4l2_async_notifier_operations imx_media_notifier_ops = { + .bound = imx_media_subdev_bound, + .complete = imx_media_probe_complete, +}; static int imx_media_probe(struct platform_device *pdev) { @@ -463,7 +50,7 @@ static int imx_media_probe(struct platform_device *pdev) struct imx_media_dev *imxmd; int ret; - imxmd = imx_media_dev_init(dev); + imxmd = imx_media_dev_init(dev, NULL); if (IS_ERR(imxmd)) return PTR_ERR(imxmd); @@ -474,14 +61,12 @@ static int imx_media_probe(struct platform_device *pdev) goto cleanup; } - ret = imx_media_dev_notifier_register(imxmd); + ret = imx_media_dev_notifier_register(imxmd, &imx_media_notifier_ops); if (ret) - goto del_int; + goto cleanup; return 0; -del_int: - imx_media_remove_ipu_internal_subdevs(imxmd); cleanup: v4l2_async_notifier_cleanup(&imxmd->notifier); v4l2_device_unregister(&imxmd->v4l2_dev); @@ -498,7 +83,7 @@ static int imx_media_remove(struct platform_device *pdev) v4l2_info(&imxmd->v4l2_dev, "Removing imx-media\n"); v4l2_async_notifier_unregister(&imxmd->notifier); - imx_media_remove_ipu_internal_subdevs(imxmd); + imx_media_unregister_ipu_internal_subdevs(imxmd); v4l2_async_notifier_cleanup(&imxmd->notifier); media_device_unregister(&imxmd->md); v4l2_device_unregister(&imxmd->v4l2_dev); diff --git a/drivers/staging/media/imx/imx-media-fim.c b/drivers/staging/media/imx/imx-media-fim.c index 2ab64bc30f5c..3a9182933508 100644 --- a/drivers/staging/media/imx/imx-media-fim.c +++ b/drivers/staging/media/imx/imx-media-fim.c @@ -37,8 +37,6 @@ enum { #define FIM_CL_TOLERANCE_MAX_DEF 0 /* no max tolerance (unbounded) */ struct imx_media_fim { - struct imx_media_dev *md; - /* the owning subdev of this fim instance */ struct v4l2_subdev *sd; @@ -416,7 +414,6 @@ void imx_media_fim_eof_monitor(struct imx_media_fim *fim, ktime_t timestamp) spin_unlock_irqrestore(&fim->lock, flags); } -EXPORT_SYMBOL_GPL(imx_media_fim_eof_monitor); /* Called by the subdev in its s_stream callback */ int imx_media_fim_set_stream(struct imx_media_fim *fim, @@ -453,7 +450,6 @@ out: v4l2_ctrl_unlock(fim->ctrl[FIM_CL_ENABLE]); return ret; } -EXPORT_SYMBOL_GPL(imx_media_fim_set_stream); int imx_media_fim_add_controls(struct imx_media_fim *fim) { @@ -461,7 +457,6 @@ int imx_media_fim_add_controls(struct imx_media_fim *fim) return v4l2_ctrl_add_handler(fim->sd->ctrl_handler, &fim->ctrl_handler, NULL, false); } -EXPORT_SYMBOL_GPL(imx_media_fim_add_controls); /* Called by the subdev in its subdev registered callback */ struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd) @@ -473,8 +468,6 @@ struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd) if (!fim) return ERR_PTR(-ENOMEM); - /* get media device */ - fim->md = dev_get_drvdata(sd->v4l2_dev->dev); fim->sd = sd; spin_lock_init(&fim->lock); @@ -485,10 +478,8 @@ struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd) return fim; } -EXPORT_SYMBOL_GPL(imx_media_fim_init); void imx_media_fim_free(struct imx_media_fim *fim) { v4l2_ctrl_handler_free(&fim->ctrl_handler); } -EXPORT_SYMBOL_GPL(imx_media_fim_free); diff --git a/drivers/staging/media/imx/imx-media-internal-sd.c b/drivers/staging/media/imx/imx-media-internal-sd.c index df49ebfbe98a..cb1e4cdd5079 100644 --- a/drivers/staging/media/imx/imx-media-internal-sd.c +++ b/drivers/staging/media/imx/imx-media-internal-sd.c @@ -9,208 +9,138 @@ #include <linux/platform_device.h> #include "imx-media.h" -enum isd_enum { - isd_csi0 = 0, - isd_csi1, - isd_vdic, - isd_ic_prp, - isd_ic_prpenc, - isd_ic_prpvf, - num_isd, -}; - -static const struct internal_subdev_id { - enum isd_enum index; - const char *name; - u32 grp_id; -} isd_id[num_isd] = { - [isd_csi0] = { - .index = isd_csi0, - .grp_id = IMX_MEDIA_GRP_ID_IPU_CSI0, - .name = "imx-ipuv3-csi", - }, - [isd_csi1] = { - .index = isd_csi1, - .grp_id = IMX_MEDIA_GRP_ID_IPU_CSI1, - .name = "imx-ipuv3-csi", - }, - [isd_vdic] = { - .index = isd_vdic, - .grp_id = IMX_MEDIA_GRP_ID_IPU_VDIC, - .name = "imx-ipuv3-vdic", - }, - [isd_ic_prp] = { - .index = isd_ic_prp, - .grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRP, - .name = "imx-ipuv3-ic", - }, - [isd_ic_prpenc] = { - .index = isd_ic_prpenc, - .grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRPENC, - .name = "imx-ipuv3-ic", - }, - [isd_ic_prpvf] = { - .index = isd_ic_prpvf, - .grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRPVF, - .name = "imx-ipuv3-ic", - }, -}; +/* max pads per internal-sd */ +#define MAX_INTERNAL_PADS 8 +/* max links per internal-sd pad */ +#define MAX_INTERNAL_LINKS 8 struct internal_subdev; struct internal_link { - const struct internal_subdev *remote; + int remote; int local_pad; int remote_pad; }; -/* max pads per internal-sd */ -#define MAX_INTERNAL_PADS 8 -/* max links per internal-sd pad */ -#define MAX_INTERNAL_LINKS 8 - struct internal_pad { + int num_links; struct internal_link link[MAX_INTERNAL_LINKS]; }; -static const struct internal_subdev { - const struct internal_subdev_id *id; +struct internal_subdev { + u32 grp_id; struct internal_pad pad[MAX_INTERNAL_PADS]; -} int_subdev[num_isd] = { - [isd_csi0] = { - .id = &isd_id[isd_csi0], + + struct v4l2_subdev * (*sync_register)(struct v4l2_device *v4l2_dev, + struct device *ipu_dev, + struct ipu_soc *ipu, + u32 grp_id); + int (*sync_unregister)(struct v4l2_subdev *sd); +}; + +static const struct internal_subdev int_subdev[NUM_IPU_SUBDEVS] = { + [IPU_CSI0] = { + .grp_id = IMX_MEDIA_GRP_ID_IPU_CSI0, .pad[CSI_SRC_PAD_DIRECT] = { + .num_links = 2, .link = { { .local_pad = CSI_SRC_PAD_DIRECT, - .remote = &int_subdev[isd_ic_prp], + .remote = IPU_IC_PRP, .remote_pad = PRP_SINK_PAD, }, { .local_pad = CSI_SRC_PAD_DIRECT, - .remote = &int_subdev[isd_vdic], + .remote = IPU_VDIC, .remote_pad = VDIC_SINK_PAD_DIRECT, }, }, }, }, - [isd_csi1] = { - .id = &isd_id[isd_csi1], + [IPU_CSI1] = { + .grp_id = IMX_MEDIA_GRP_ID_IPU_CSI1, .pad[CSI_SRC_PAD_DIRECT] = { + .num_links = 2, .link = { { .local_pad = CSI_SRC_PAD_DIRECT, - .remote = &int_subdev[isd_ic_prp], + .remote = IPU_IC_PRP, .remote_pad = PRP_SINK_PAD, }, { .local_pad = CSI_SRC_PAD_DIRECT, - .remote = &int_subdev[isd_vdic], + .remote = IPU_VDIC, .remote_pad = VDIC_SINK_PAD_DIRECT, }, }, }, }, - [isd_vdic] = { - .id = &isd_id[isd_vdic], + [IPU_VDIC] = { + .grp_id = IMX_MEDIA_GRP_ID_IPU_VDIC, + .sync_register = imx_media_vdic_register, + .sync_unregister = imx_media_vdic_unregister, .pad[VDIC_SRC_PAD_DIRECT] = { + .num_links = 1, .link = { { .local_pad = VDIC_SRC_PAD_DIRECT, - .remote = &int_subdev[isd_ic_prp], + .remote = IPU_IC_PRP, .remote_pad = PRP_SINK_PAD, }, }, }, }, - [isd_ic_prp] = { - .id = &isd_id[isd_ic_prp], + [IPU_IC_PRP] = { + .grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRP, + .sync_register = imx_media_ic_register, + .sync_unregister = imx_media_ic_unregister, .pad[PRP_SRC_PAD_PRPENC] = { + .num_links = 1, .link = { { .local_pad = PRP_SRC_PAD_PRPENC, - .remote = &int_subdev[isd_ic_prpenc], - .remote_pad = 0, + .remote = IPU_IC_PRPENC, + .remote_pad = PRPENCVF_SINK_PAD, }, }, }, .pad[PRP_SRC_PAD_PRPVF] = { + .num_links = 1, .link = { { .local_pad = PRP_SRC_PAD_PRPVF, - .remote = &int_subdev[isd_ic_prpvf], - .remote_pad = 0, + .remote = IPU_IC_PRPVF, + .remote_pad = PRPENCVF_SINK_PAD, }, }, }, }, - [isd_ic_prpenc] = { - .id = &isd_id[isd_ic_prpenc], + [IPU_IC_PRPENC] = { + .grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRPENC, + .sync_register = imx_media_ic_register, + .sync_unregister = imx_media_ic_unregister, }, - [isd_ic_prpvf] = { - .id = &isd_id[isd_ic_prpvf], + [IPU_IC_PRPVF] = { + .grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRPVF, + .sync_register = imx_media_ic_register, + .sync_unregister = imx_media_ic_unregister, }, }; -/* form a device name given an internal subdev and ipu id */ -static inline void isd_to_devname(char *devname, int sz, - const struct internal_subdev *isd, - int ipu_id) -{ - int pdev_id = ipu_id * num_isd + isd->id->index; - - snprintf(devname, sz, "%s.%d", isd->id->name, pdev_id); -} - -static const struct internal_subdev *find_intsd_by_grp_id(u32 grp_id) -{ - enum isd_enum i; - - for (i = 0; i < num_isd; i++) { - const struct internal_subdev *isd = &int_subdev[i]; - - if (isd->id->grp_id == grp_id) - return isd; - } - - return NULL; -} - -static struct v4l2_subdev *find_sink(struct imx_media_dev *imxmd, - struct v4l2_subdev *src, - const struct internal_link *link) -{ - char sink_devname[32]; - int ipu_id; - - /* - * retrieve IPU id from subdev name, note: can't get this from - * struct imx_media_ipu_internal_sd_pdata because if src is - * a CSI, it has different struct ipu_client_platformdata which - * does not contain IPU id. - */ - if (sscanf(src->name, "ipu%d", &ipu_id) != 1) - return NULL; - - isd_to_devname(sink_devname, sizeof(sink_devname), - link->remote, ipu_id - 1); - - return imx_media_find_subdev_by_devname(imxmd, sink_devname); -} - -static int create_ipu_internal_link(struct imx_media_dev *imxmd, - struct v4l2_subdev *src, - const struct internal_link *link) +static int create_internal_link(struct imx_media_dev *imxmd, + struct v4l2_subdev *src, + struct v4l2_subdev *sink, + const struct internal_link *link) { - struct v4l2_subdev *sink; int ret; - sink = find_sink(imxmd, src, link); - if (!sink) - return -ENODEV; + /* skip if this link already created */ + if (media_entity_find_link(&src->entity.pads[link->local_pad], + &sink->entity.pads[link->remote_pad])) + return 0; v4l2_info(&imxmd->v4l2_dev, "%s:%d -> %s:%d\n", src->name, link->local_pad, @@ -219,25 +149,21 @@ static int create_ipu_internal_link(struct imx_media_dev *imxmd, ret = media_create_pad_link(&src->entity, link->local_pad, &sink->entity, link->remote_pad, 0); if (ret) - v4l2_err(&imxmd->v4l2_dev, - "create_pad_link failed: %d\n", ret); + v4l2_err(&imxmd->v4l2_dev, "%s failed: %d\n", __func__, ret); return ret; } -int imx_media_create_ipu_internal_links(struct imx_media_dev *imxmd, - struct v4l2_subdev *sd) +static int create_ipu_internal_links(struct imx_media_dev *imxmd, + const struct internal_subdev *intsd, + struct v4l2_subdev *sd, + int ipu_id) { - const struct internal_subdev *intsd; const struct internal_pad *intpad; const struct internal_link *link; struct media_pad *pad; int i, j, ret; - intsd = find_intsd_by_grp_id(sd->grp_id); - if (!intsd) - return -ENODEV; - /* create the source->sink links */ for (i = 0; i < sd->entity.num_pads; i++) { intpad = &intsd->pad[i]; @@ -246,13 +172,13 @@ int imx_media_create_ipu_internal_links(struct imx_media_dev *imxmd, if (!(pad->flags & MEDIA_PAD_FL_SOURCE)) continue; - for (j = 0; ; j++) { - link = &intpad->link[j]; + for (j = 0; j < intpad->num_links; j++) { + struct v4l2_subdev *sink; - if (!link->remote) - break; + link = &intpad->link[j]; + sink = imxmd->sync_sd[ipu_id][link->remote]; - ret = create_ipu_internal_link(imxmd, sd, link); + ret = create_internal_link(imxmd, sd, sink, link); if (ret) return ret; } @@ -261,85 +187,116 @@ int imx_media_create_ipu_internal_links(struct imx_media_dev *imxmd, return 0; } -/* register an internal subdev as a platform device */ -static int add_internal_subdev(struct imx_media_dev *imxmd, - const struct internal_subdev *isd, - int ipu_id) +int imx_media_register_ipu_internal_subdevs(struct imx_media_dev *imxmd, + struct v4l2_subdev *csi) { - struct imx_media_ipu_internal_sd_pdata pdata; - struct platform_device_info pdevinfo = {}; - struct platform_device *pdev; + struct device *ipu_dev = csi->dev->parent; + const struct internal_subdev *intsd; + struct v4l2_subdev *sd; + struct ipu_soc *ipu; + int i, ipu_id, ret; - pdata.grp_id = isd->id->grp_id; + ipu = dev_get_drvdata(ipu_dev); + if (!ipu) { + v4l2_err(&imxmd->v4l2_dev, "invalid IPU device!\n"); + return -ENODEV; + } - /* the id of IPU this subdev will control */ - pdata.ipu_id = ipu_id; + ipu_id = ipu_get_num(ipu); + if (ipu_id > 1) { + v4l2_err(&imxmd->v4l2_dev, "invalid IPU id %d!\n", ipu_id); + return -ENODEV; + } - /* create subdev name */ - imx_media_grp_id_to_sd_name(pdata.sd_name, sizeof(pdata.sd_name), - pdata.grp_id, ipu_id); + mutex_lock(&imxmd->mutex); - pdevinfo.name = isd->id->name; - pdevinfo.id = ipu_id * num_isd + isd->id->index; - pdevinfo.parent = imxmd->md.dev; - pdevinfo.data = &pdata; - pdevinfo.size_data = sizeof(pdata); - pdevinfo.dma_mask = DMA_BIT_MASK(32); + /* register the synchronous subdevs */ + for (i = 0; i < NUM_IPU_SUBDEVS; i++) { + intsd = &int_subdev[i]; - pdev = platform_device_register_full(&pdevinfo); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); + sd = imxmd->sync_sd[ipu_id][i]; - return imx_media_add_async_subdev(imxmd, NULL, pdev); -} + /* + * skip if this sync subdev already registered or its + * not a sync subdev (one of the CSIs) + */ + if (sd || !intsd->sync_register) + continue; -/* adds the internal subdevs in one ipu */ -int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd, - int ipu_id) -{ - enum isd_enum i; - int ret; + mutex_unlock(&imxmd->mutex); + sd = intsd->sync_register(&imxmd->v4l2_dev, ipu_dev, ipu, + intsd->grp_id); + mutex_lock(&imxmd->mutex); + if (IS_ERR(sd)) { + ret = PTR_ERR(sd); + goto err_unwind; + } - for (i = 0; i < num_isd; i++) { - const struct internal_subdev *isd = &int_subdev[i]; + imxmd->sync_sd[ipu_id][i] = sd; + } - /* - * the CSIs are represented in the device-tree, so those - * devices are already added to the async subdev list by - * of_parse_subdev(). - */ - switch (isd->id->grp_id) { - case IMX_MEDIA_GRP_ID_IPU_CSI0: - case IMX_MEDIA_GRP_ID_IPU_CSI1: - ret = 0; - break; - default: - ret = add_internal_subdev(imxmd, isd, ipu_id); - break; + /* + * all the sync subdevs are registered, create the media links + * between them. + */ + for (i = 0; i < NUM_IPU_SUBDEVS; i++) { + intsd = &int_subdev[i]; + + if (intsd->grp_id == csi->grp_id) { + sd = csi; + } else { + sd = imxmd->sync_sd[ipu_id][i]; + if (!sd) + continue; } - if (ret) - goto remove; + ret = create_ipu_internal_links(imxmd, intsd, sd, ipu_id); + if (ret) { + mutex_unlock(&imxmd->mutex); + imx_media_unregister_ipu_internal_subdevs(imxmd); + return ret; + } } + mutex_unlock(&imxmd->mutex); return 0; -remove: - imx_media_remove_ipu_internal_subdevs(imxmd); +err_unwind: + while (--i >= 0) { + intsd = &int_subdev[i]; + sd = imxmd->sync_sd[ipu_id][i]; + if (!sd || !intsd->sync_unregister) + continue; + mutex_unlock(&imxmd->mutex); + intsd->sync_unregister(sd); + mutex_lock(&imxmd->mutex); + } + + mutex_unlock(&imxmd->mutex); return ret; } -void imx_media_remove_ipu_internal_subdevs(struct imx_media_dev *imxmd) +void imx_media_unregister_ipu_internal_subdevs(struct imx_media_dev *imxmd) { - struct imx_media_async_subdev *imxasd; - struct v4l2_async_subdev *asd; + const struct internal_subdev *intsd; + struct v4l2_subdev *sd; + int i, j; - list_for_each_entry(asd, &imxmd->notifier.asd_list, asd_list) { - imxasd = to_imx_media_asd(asd); + mutex_lock(&imxmd->mutex); - if (!imxasd->pdev) - continue; + for (i = 0; i < 2; i++) { + for (j = 0; j < NUM_IPU_SUBDEVS; j++) { + intsd = &int_subdev[j]; + sd = imxmd->sync_sd[i][j]; + + if (!sd || !intsd->sync_unregister) + continue; - platform_device_unregister(imxasd->pdev); + mutex_unlock(&imxmd->mutex); + intsd->sync_unregister(sd); + mutex_lock(&imxmd->mutex); + } } + + mutex_unlock(&imxmd->mutex); } diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c index 990e82aa8e42..2d3efd2a6dde 100644 --- a/drivers/staging/media/imx/imx-media-of.c +++ b/drivers/staging/media/imx/imx-media-of.c @@ -19,6 +19,9 @@ int imx_media_of_add_csi(struct imx_media_dev *imxmd, struct device_node *csi_np) { + struct v4l2_async_subdev *asd; + int ret = 0; + if (!of_device_is_available(csi_np)) { dev_dbg(imxmd->md.dev, "%s: %pOFn not enabled\n", __func__, csi_np); @@ -26,18 +29,25 @@ int imx_media_of_add_csi(struct imx_media_dev *imxmd, } /* add CSI fwnode to async notifier */ - return imx_media_add_async_subdev(imxmd, of_fwnode_handle(csi_np), - NULL); + asd = v4l2_async_notifier_add_fwnode_subdev(&imxmd->notifier, + of_fwnode_handle(csi_np), + sizeof(*asd)); + if (IS_ERR(asd)) { + ret = PTR_ERR(asd); + if (ret == -EEXIST) + dev_dbg(imxmd->md.dev, "%s: already added %pOFn\n", + __func__, csi_np); + } + + return ret; } EXPORT_SYMBOL_GPL(imx_media_of_add_csi); int imx_media_add_of_subdevs(struct imx_media_dev *imxmd, struct device_node *np) { - bool ipu_found[2] = {false, false}; struct device_node *csi_np; int i, ret; - u32 ipu_id; for (i = 0; ; i++) { csi_np = of_parse_phandle(np, "ports", i); @@ -55,34 +65,15 @@ int imx_media_add_of_subdevs(struct imx_media_dev *imxmd, /* other error, can't continue */ goto err_out; } - - ret = of_alias_get_id(csi_np->parent, "ipu"); - if (ret < 0) - goto err_out; - if (ret > 1) { - ret = -EINVAL; - goto err_out; - } - - ipu_id = ret; - - if (!ipu_found[ipu_id]) { - ret = imx_media_add_ipu_internal_subdevs(imxmd, - ipu_id); - if (ret) - goto err_out; - } - - ipu_found[ipu_id] = true; } return 0; err_out: - imx_media_remove_ipu_internal_subdevs(imxmd); of_node_put(csi_np); return ret; } +EXPORT_SYMBOL_GPL(imx_media_add_of_subdevs); /* * Create a single media link to/from sd using a fwnode link. @@ -152,6 +143,7 @@ int imx_media_create_of_links(struct imx_media_dev *imxmd, return 0; } +EXPORT_SYMBOL_GPL(imx_media_create_of_links); /* * Create media links to the given CSI subdevice's sink pads, @@ -195,3 +187,4 @@ int imx_media_create_csi_of_links(struct imx_media_dev *imxmd, return 0; } +EXPORT_SYMBOL_GPL(imx_media_create_csi_of_links); diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c index b41842dba5ec..b5b8a3b7730a 100644 --- a/drivers/staging/media/imx/imx-media-utils.c +++ b/drivers/staging/media/imx/imx-media-utils.c @@ -573,8 +573,7 @@ void imx_media_fill_default_mbus_fields(struct v4l2_mbus_framefmt *tryfmt, EXPORT_SYMBOL_GPL(imx_media_fill_default_mbus_fields); int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix, - struct v4l2_rect *compose, - const struct v4l2_mbus_framefmt *mbus, + struct v4l2_mbus_framefmt *mbus, const struct imx_media_pixfmt *cc) { u32 width; @@ -621,17 +620,6 @@ int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix, pix->sizeimage = cc->planar ? ((stride * pix->height * cc->bpp) >> 3) : stride * pix->height; - /* - * set capture compose rectangle, which is fixed to the - * source subdevice mbus format. - */ - if (compose) { - compose->left = 0; - compose->top = 0; - compose->width = mbus->width; - compose->height = mbus->height; - } - return 0; } EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt); @@ -643,11 +631,13 @@ int imx_media_mbus_fmt_to_ipu_image(struct ipu_image *image, memset(image, 0, sizeof(*image)); - ret = imx_media_mbus_fmt_to_pix_fmt(&image->pix, &image->rect, - mbus, NULL); + ret = imx_media_mbus_fmt_to_pix_fmt(&image->pix, mbus, NULL); if (ret) return ret; + image->rect.width = mbus->width; + image->rect.height = mbus->height; + return 0; } EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_ipu_image); @@ -675,29 +665,28 @@ int imx_media_ipu_image_to_mbus_fmt(struct v4l2_mbus_framefmt *mbus, } EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt); -void imx_media_free_dma_buf(struct imx_media_dev *imxmd, +void imx_media_free_dma_buf(struct device *dev, struct imx_media_dma_buf *buf) { if (buf->virt) - dma_free_coherent(imxmd->md.dev, buf->len, - buf->virt, buf->phys); + dma_free_coherent(dev, buf->len, buf->virt, buf->phys); buf->virt = NULL; buf->phys = 0; } EXPORT_SYMBOL_GPL(imx_media_free_dma_buf); -int imx_media_alloc_dma_buf(struct imx_media_dev *imxmd, +int imx_media_alloc_dma_buf(struct device *dev, struct imx_media_dma_buf *buf, int size) { - imx_media_free_dma_buf(imxmd, buf); + imx_media_free_dma_buf(dev, buf); buf->len = PAGE_ALIGN(size); - buf->virt = dma_alloc_coherent(imxmd->md.dev, buf->len, &buf->phys, + buf->virt = dma_alloc_coherent(dev, buf->len, &buf->phys, GFP_DMA | GFP_KERNEL); if (!buf->virt) { - dev_err(imxmd->md.dev, "failed to alloc dma buffer\n"); + dev_err(dev, "%s: failed\n", __func__); return -ENOMEM; } @@ -764,35 +753,37 @@ imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd, EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_devname); /* - * Adds a video device to the master video device list. This is called by - * an async subdev that owns a video device when it is registered. + * Adds a video device to the master video device list. This is called + * when a video device is registered. */ -int imx_media_add_video_device(struct imx_media_dev *imxmd, - struct imx_media_video_dev *vdev) +void imx_media_add_video_device(struct imx_media_dev *imxmd, + struct imx_media_video_dev *vdev) { mutex_lock(&imxmd->mutex); list_add_tail(&vdev->list, &imxmd->vdev_list); mutex_unlock(&imxmd->mutex); - return 0; } EXPORT_SYMBOL_GPL(imx_media_add_video_device); /* - * Search upstream/downstream for a subdevice in the current pipeline - * with given grp_id, starting from start_entity. Returns the subdev's - * source/sink pad that it was reached from. If grp_id is zero, just - * returns the nearest source/sink pad to start_entity. Must be called - * with mdev->graph_mutex held. + * Search upstream/downstream for a subdevice or video device pad in the + * current pipeline, starting from start_entity. Returns the device's + * source/sink pad that it was reached from. Must be called with + * mdev->graph_mutex held. + * + * If grp_id != 0, finds a subdevice's pad of given grp_id. + * Else If buftype != 0, finds a video device's pad of given buffer type. + * Else, returns the nearest source/sink pad to start_entity. */ -static struct media_pad * -find_pipeline_pad(struct imx_media_dev *imxmd, - struct media_entity *start_entity, - u32 grp_id, bool upstream) +struct media_pad * +imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id, + enum v4l2_buf_type buftype, bool upstream) { struct media_entity *me = start_entity; struct media_pad *pad = NULL; + struct video_device *vfd; struct v4l2_subdev *sd; int i; @@ -804,16 +795,27 @@ find_pipeline_pad(struct imx_media_dev *imxmd, continue; pad = media_entity_remote_pad(spad); - if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + if (!pad) continue; - if (grp_id != 0) { - sd = media_entity_to_v4l2_subdev(pad->entity); - if (sd->grp_id & grp_id) - return pad; + if (grp_id) { + if (is_media_entity_v4l2_subdev(pad->entity)) { + sd = media_entity_to_v4l2_subdev(pad->entity); + if (sd->grp_id & grp_id) + return pad; + } + + return imx_media_pipeline_pad(pad->entity, grp_id, + buftype, upstream); + } else if (buftype) { + if (is_media_entity_v4l2_video_device(pad->entity)) { + vfd = media_entity_to_video_device(pad->entity); + if (buftype == vfd->queue->type) + return pad; + } - return find_pipeline_pad(imxmd, pad->entity, - grp_id, upstream); + return imx_media_pipeline_pad(pad->entity, grp_id, + buftype, upstream); } else { return pad; } @@ -821,28 +823,33 @@ find_pipeline_pad(struct imx_media_dev *imxmd, return NULL; } +EXPORT_SYMBOL_GPL(imx_media_pipeline_pad); /* - * Search upstream for a subdev in the current pipeline with - * given grp_id. Must be called with mdev->graph_mutex held. + * Search upstream/downstream for a subdev or video device in the current + * pipeline. Must be called with mdev->graph_mutex held. */ -static struct v4l2_subdev * -find_upstream_subdev(struct imx_media_dev *imxmd, - struct media_entity *start_entity, - u32 grp_id) +static struct media_entity * +find_pipeline_entity(struct media_entity *start, u32 grp_id, + enum v4l2_buf_type buftype, bool upstream) { + struct media_pad *pad = NULL; + struct video_device *vfd; struct v4l2_subdev *sd; - struct media_pad *pad; - if (is_media_entity_v4l2_subdev(start_entity)) { - sd = media_entity_to_v4l2_subdev(start_entity); + if (grp_id && is_media_entity_v4l2_subdev(start)) { + sd = media_entity_to_v4l2_subdev(start); if (sd->grp_id & grp_id) - return sd; + return &sd->entity; + } else if (buftype && is_media_entity_v4l2_video_device(start)) { + vfd = media_entity_to_video_device(pad->entity); + if (buftype == vfd->queue->type) + return &vfd->entity; } - pad = find_pipeline_pad(imxmd, start_entity, grp_id, true); + pad = imx_media_pipeline_pad(start, grp_id, buftype, upstream); - return pad ? media_entity_to_v4l2_subdev(pad->entity) : NULL; + return pad ? pad->entity : NULL; } /* @@ -850,62 +857,57 @@ find_upstream_subdev(struct imx_media_dev *imxmd, * start entity in the current pipeline. * Must be called with mdev->graph_mutex held. */ -int imx_media_find_mipi_csi2_channel(struct imx_media_dev *imxmd, - struct media_entity *start_entity) +int imx_media_pipeline_csi2_channel(struct media_entity *start_entity) { struct media_pad *pad; int ret = -EPIPE; - pad = find_pipeline_pad(imxmd, start_entity, IMX_MEDIA_GRP_ID_CSI2, - true); - if (pad) { + pad = imx_media_pipeline_pad(start_entity, IMX_MEDIA_GRP_ID_CSI2, + 0, true); + if (pad) ret = pad->index - 1; - dev_dbg(imxmd->md.dev, "found vc%d from %s\n", - ret, start_entity->name); - } return ret; } -EXPORT_SYMBOL_GPL(imx_media_find_mipi_csi2_channel); +EXPORT_SYMBOL_GPL(imx_media_pipeline_csi2_channel); /* - * Find a source pad reached upstream from the given start entity in - * the current pipeline. Must be called with mdev->graph_mutex held. + * Find a subdev reached upstream from the given start entity in + * the current pipeline. + * Must be called with mdev->graph_mutex held. */ -struct media_pad * -imx_media_find_upstream_pad(struct imx_media_dev *imxmd, - struct media_entity *start_entity, - u32 grp_id) +struct v4l2_subdev * +imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id, + bool upstream) { - struct media_pad *pad; + struct media_entity *me; - pad = find_pipeline_pad(imxmd, start_entity, grp_id, true); - if (!pad) + me = find_pipeline_entity(start_entity, grp_id, 0, upstream); + if (!me) return ERR_PTR(-ENODEV); - return pad; + return media_entity_to_v4l2_subdev(me); } -EXPORT_SYMBOL_GPL(imx_media_find_upstream_pad); +EXPORT_SYMBOL_GPL(imx_media_pipeline_subdev); /* * Find a subdev reached upstream from the given start entity in * the current pipeline. * Must be called with mdev->graph_mutex held. */ -struct v4l2_subdev * -imx_media_find_upstream_subdev(struct imx_media_dev *imxmd, - struct media_entity *start_entity, - u32 grp_id) +struct video_device * +imx_media_pipeline_video_device(struct media_entity *start_entity, + enum v4l2_buf_type buftype, bool upstream) { - struct v4l2_subdev *sd; + struct media_entity *me; - sd = find_upstream_subdev(imxmd, start_entity, grp_id); - if (!sd) + me = find_pipeline_entity(start_entity, 0, buftype, upstream); + if (!me) return ERR_PTR(-ENODEV); - return sd; + return media_entity_to_video_device(me); } -EXPORT_SYMBOL_GPL(imx_media_find_upstream_subdev); +EXPORT_SYMBOL_GPL(imx_media_pipeline_video_device); /* * Turn current pipeline streaming on/off starting from entity. diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c index 4487374c9435..4d90eecb04a2 100644 --- a/drivers/staging/media/imx/imx-media-vdic.c +++ b/drivers/staging/media/imx/imx-media-vdic.c @@ -4,13 +4,6 @@ * * Copyright (c) 2017 Mentor Graphics Inc. */ -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/timer.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> @@ -65,12 +58,11 @@ struct vdic_pipeline_ops { #define S_ALIGN 1 /* multiple of 2 */ struct vdic_priv { - struct device *dev; - struct ipu_soc *ipu; - struct imx_media_dev *md; + struct device *ipu_dev; + struct ipu_soc *ipu; + struct v4l2_subdev sd; struct media_pad pad[VDIC_NUM_PADS]; - int ipu_id; /* lock to protect all members below */ struct mutex lock; @@ -145,8 +137,6 @@ static int vdic_get_ipu_resources(struct vdic_priv *priv) struct ipuv3_channel *ch; struct ipu_vdi *vdi; - priv->ipu = priv->md->ipu[priv->ipu_id]; - vdi = ipu_vdi_get(priv->ipu); if (IS_ERR(vdi)) { v4l2_err(&priv->sd, "failed to get VDIC\n"); @@ -511,7 +501,8 @@ static int vdic_s_stream(struct v4l2_subdev *sd, int enable) if (priv->stream_count != !enable) goto update_count; - dev_dbg(priv->dev, "stream %s\n", enable ? "ON" : "OFF"); + dev_dbg(priv->ipu_dev, "%s: stream %s\n", sd->name, + enable ? "ON" : "OFF"); if (enable) ret = vdic_start(priv); @@ -686,8 +677,8 @@ static int vdic_link_setup(struct media_entity *entity, struct v4l2_subdev *remote_sd; int ret = 0; - dev_dbg(priv->dev, "link setup %s -> %s", remote->entity->name, - local->entity->name); + dev_dbg(priv->ipu_dev, "%s: link setup %s -> %s", + sd->name, remote->entity->name, local->entity->name); mutex_lock(&priv->lock); @@ -860,9 +851,6 @@ static int vdic_registered(struct v4l2_subdev *sd) int i, ret; u32 code; - /* get media device */ - priv->md = dev_get_drvdata(sd->v4l2_dev->dev); - for (i = 0; i < VDIC_NUM_PADS; i++) { priv->pad[i].flags = (i == VDIC_SRC_PAD_DIRECT) ? MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK; @@ -934,77 +922,53 @@ static const struct v4l2_subdev_internal_ops vdic_internal_ops = { .unregistered = vdic_unregistered, }; -static int imx_vdic_probe(struct platform_device *pdev) +struct v4l2_subdev *imx_media_vdic_register(struct v4l2_device *v4l2_dev, + struct device *ipu_dev, + struct ipu_soc *ipu, + u32 grp_id) { - struct imx_media_ipu_internal_sd_pdata *pdata; struct vdic_priv *priv; int ret; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(ipu_dev, sizeof(*priv), GFP_KERNEL); if (!priv) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - platform_set_drvdata(pdev, &priv->sd); - priv->dev = &pdev->dev; - - pdata = priv->dev->platform_data; - priv->ipu_id = pdata->ipu_id; + priv->ipu_dev = ipu_dev; + priv->ipu = ipu; v4l2_subdev_init(&priv->sd, &vdic_subdev_ops); v4l2_set_subdevdata(&priv->sd, priv); priv->sd.internal_ops = &vdic_internal_ops; priv->sd.entity.ops = &vdic_entity_ops; priv->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; - priv->sd.dev = &pdev->dev; - priv->sd.owner = THIS_MODULE; + priv->sd.owner = ipu_dev->driver->owner; priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; - /* get our group id */ - priv->sd.grp_id = pdata->grp_id; - strscpy(priv->sd.name, pdata->sd_name, sizeof(priv->sd.name)); + priv->sd.grp_id = grp_id; + imx_media_grp_id_to_sd_name(priv->sd.name, sizeof(priv->sd.name), + priv->sd.grp_id, ipu_get_num(ipu)); mutex_init(&priv->lock); - ret = v4l2_async_register_subdev(&priv->sd); + ret = v4l2_device_register_subdev(v4l2_dev, &priv->sd); if (ret) goto free; - return 0; + return &priv->sd; free: mutex_destroy(&priv->lock); - return ret; + return ERR_PTR(ret); } -static int imx_vdic_remove(struct platform_device *pdev) +int imx_media_vdic_unregister(struct v4l2_subdev *sd) { - struct v4l2_subdev *sd = platform_get_drvdata(pdev); struct vdic_priv *priv = v4l2_get_subdevdata(sd); v4l2_info(sd, "Removing\n"); - v4l2_async_unregister_subdev(sd); + v4l2_device_unregister_subdev(sd); mutex_destroy(&priv->lock); media_entity_cleanup(&sd->entity); return 0; } - -static const struct platform_device_id imx_vdic_ids[] = { - { .name = "imx-ipuv3-vdic" }, - { }, -}; -MODULE_DEVICE_TABLE(platform, imx_vdic_ids); - -static struct platform_driver imx_vdic_driver = { - .probe = imx_vdic_probe, - .remove = imx_vdic_remove, - .id_table = imx_vdic_ids, - .driver = { - .name = "imx-ipuv3-vdic", - }, -}; -module_platform_driver(imx_vdic_driver); - -MODULE_DESCRIPTION("i.MX VDIC subdev driver"); -MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx-ipuv3-vdic"); diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h index 6587aa49e005..8a60bdafe2da 100644 --- a/drivers/staging/media/imx/imx-media.h +++ b/drivers/staging/media/imx/imx-media.h @@ -16,6 +16,19 @@ #include <video/imx-ipu-v3.h> /* + * Enumeration of the IPU internal sub-devices + */ +enum { + IPU_CSI0 = 0, + IPU_CSI1, + IPU_VDIC, + IPU_IC_PRP, + IPU_IC_PRPENC, + IPU_IC_PRPVF, + NUM_IPU_SUBDEVS, +}; + +/* * Pad definitions for the subdevs with multiple source or * sink pads */ @@ -111,25 +124,6 @@ struct imx_media_pad_vdev { struct list_head list; }; -struct imx_media_ipu_internal_sd_pdata { - char sd_name[V4L2_SUBDEV_NAME_SIZE]; - u32 grp_id; - int ipu_id; -}; - -struct imx_media_async_subdev { - /* the base asd - must be first in this struct */ - struct v4l2_async_subdev asd; - /* the platform device of IPU-internal subdevs */ - struct platform_device *pdev; -}; - -static inline struct imx_media_async_subdev * -to_imx_media_asd(struct v4l2_async_subdev *asd) -{ - return container_of(asd, struct imx_media_async_subdev, asd); -} - struct imx_media_dev { struct media_device md; struct v4l2_device v4l2_dev; @@ -142,11 +136,11 @@ struct imx_media_dev { /* master video device list */ struct list_head vdev_list; - /* IPUs this media driver control, valid after subdevs bound */ - struct ipu_soc *ipu[2]; - /* for async subdev registration */ struct v4l2_async_notifier notifier; + + /* the IPU internal subdev's registered synchronously */ + struct v4l2_subdev *sync_sd[2][NUM_IPU_SUBDEVS]; }; enum codespace_sel { @@ -176,8 +170,7 @@ void imx_media_fill_default_mbus_fields(struct v4l2_mbus_framefmt *tryfmt, struct v4l2_mbus_framefmt *fmt, bool ic_route); int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix, - struct v4l2_rect *compose, - const struct v4l2_mbus_framefmt *mbus, + struct v4l2_mbus_framefmt *mbus, const struct imx_media_pixfmt *cc); int imx_media_mbus_fmt_to_ipu_image(struct ipu_image *image, struct v4l2_mbus_framefmt *mbus); @@ -191,18 +184,18 @@ imx_media_find_subdev_by_fwnode(struct imx_media_dev *imxmd, struct v4l2_subdev * imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd, const char *devname); -int imx_media_add_video_device(struct imx_media_dev *imxmd, - struct imx_media_video_dev *vdev); -int imx_media_find_mipi_csi2_channel(struct imx_media_dev *imxmd, - struct media_entity *start_entity); +void imx_media_add_video_device(struct imx_media_dev *imxmd, + struct imx_media_video_dev *vdev); +int imx_media_pipeline_csi2_channel(struct media_entity *start_entity); struct media_pad * -imx_media_find_upstream_pad(struct imx_media_dev *imxmd, - struct media_entity *start_entity, - u32 grp_id); +imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id, + enum v4l2_buf_type buftype, bool upstream); struct v4l2_subdev * -imx_media_find_upstream_subdev(struct imx_media_dev *imxmd, - struct media_entity *start_entity, - u32 grp_id); +imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id, + bool upstream); +struct video_device * +imx_media_pipeline_video_device(struct media_entity *start_entity, + enum v4l2_buf_type buftype, bool upstream); struct imx_media_dma_buf { void *virt; @@ -210,9 +203,9 @@ struct imx_media_dma_buf { unsigned long len; }; -void imx_media_free_dma_buf(struct imx_media_dev *imxmd, +void imx_media_free_dma_buf(struct device *dev, struct imx_media_dma_buf *buf); -int imx_media_alloc_dma_buf(struct imx_media_dev *imxmd, +int imx_media_alloc_dma_buf(struct device *dev, struct imx_media_dma_buf *buf, int size); @@ -220,22 +213,12 @@ int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd, struct media_entity *entity, bool on); -/* imx-media-dev.c */ -int imx_media_add_async_subdev(struct imx_media_dev *imxmd, - struct fwnode_handle *fwnode, - struct platform_device *pdev); - -int imx_media_subdev_bound(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *sd, - struct v4l2_async_subdev *asd); -int imx_media_link_notify(struct media_link *link, u32 flags, - unsigned int notification); -void imx_media_notify(struct v4l2_subdev *sd, unsigned int notification, - void *arg); +/* imx-media-dev-common.c */ int imx_media_probe_complete(struct v4l2_async_notifier *notifier); - -struct imx_media_dev *imx_media_dev_init(struct device *dev); -int imx_media_dev_notifier_register(struct imx_media_dev *imxmd); +struct imx_media_dev *imx_media_dev_init(struct device *dev, + const struct media_device_ops *ops); +int imx_media_dev_notifier_register(struct imx_media_dev *imxmd, + const struct v4l2_async_notifier_operations *ops); /* imx-media-fim.c */ struct imx_media_fim; @@ -248,11 +231,9 @@ struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd); void imx_media_fim_free(struct imx_media_fim *fim); /* imx-media-internal-sd.c */ -int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd, - int ipu_id); -int imx_media_create_ipu_internal_links(struct imx_media_dev *imxmd, - struct v4l2_subdev *sd); -void imx_media_remove_ipu_internal_subdevs(struct imx_media_dev *imxmd); +int imx_media_register_ipu_internal_subdevs(struct imx_media_dev *imxmd, + struct v4l2_subdev *csi); +void imx_media_unregister_ipu_internal_subdevs(struct imx_media_dev *imxmd); /* imx-media-of.c */ int imx_media_add_of_subdevs(struct imx_media_dev *dev, @@ -264,18 +245,29 @@ int imx_media_create_csi_of_links(struct imx_media_dev *imxmd, int imx_media_of_add_csi(struct imx_media_dev *imxmd, struct device_node *csi_np); +/* imx-media-vdic.c */ +struct v4l2_subdev *imx_media_vdic_register(struct v4l2_device *v4l2_dev, + struct device *ipu_dev, + struct ipu_soc *ipu, + u32 grp_id); +int imx_media_vdic_unregister(struct v4l2_subdev *sd); + +/* imx-ic-common.c */ +struct v4l2_subdev *imx_media_ic_register(struct v4l2_device *v4l2_dev, + struct device *ipu_dev, + struct ipu_soc *ipu, + u32 grp_id); +int imx_media_ic_unregister(struct v4l2_subdev *sd); + /* imx-media-capture.c */ struct imx_media_video_dev * -imx_media_capture_device_init(struct v4l2_subdev *src_sd, int pad); +imx_media_capture_device_init(struct device *dev, struct v4l2_subdev *src_sd, + int pad); void imx_media_capture_device_remove(struct imx_media_video_dev *vdev); -int imx_media_capture_device_register(struct imx_media_dev *md, - struct imx_media_video_dev *vdev); +int imx_media_capture_device_register(struct imx_media_video_dev *vdev); void imx_media_capture_device_unregister(struct imx_media_video_dev *vdev); struct imx_media_buffer * imx_media_capture_device_next_buf(struct imx_media_video_dev *vdev); -void imx_media_capture_device_set_format(struct imx_media_video_dev *vdev, - const struct v4l2_pix_format *pix, - const struct v4l2_rect *compose); void imx_media_capture_device_error(struct imx_media_video_dev *vdev); /* subdev group ids */ diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index a708a0340eb1..f775870df7e0 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -152,8 +152,6 @@ #define CSI_CSICR18 0x48 #define CSI_CSICR19 0x4c -static const char * const imx7_csi_clk_id[] = {"axi", "dcic", "mclk"}; - struct imx7_csi { struct device *dev; struct v4l2_subdev sd; @@ -180,9 +178,7 @@ struct imx7_csi { void __iomem *regbase; int irq; - - int num_clks; - struct clk_bulk_data *clks; + struct clk *mclk; /* active vb2 buffers to send to video dev sink */ struct imx_media_buffer *active_vb2_buf[2]; @@ -199,23 +195,15 @@ struct imx7_csi { struct completion last_eof_completion; }; -#define imx7_csi_reg_read(_csi, _offset) \ - __raw_readl((_csi)->regbase + (_offset)) -#define imx7_csi_reg_write(_csi, _val, _offset) \ - __raw_writel(_val, (_csi)->regbase + (_offset)) - -static void imx7_csi_clk_enable(struct imx7_csi *csi) +static u32 imx7_csi_reg_read(struct imx7_csi *csi, unsigned int offset) { - int ret; - - ret = clk_bulk_prepare_enable(csi->num_clks, csi->clks); - if (ret < 0) - dev_err(csi->dev, "failed to enable clocks\n"); + return readl(csi->regbase + offset); } -static void imx7_csi_clk_disable(struct imx7_csi *csi) +static void imx7_csi_reg_write(struct imx7_csi *csi, unsigned int value, + unsigned int offset) { - clk_bulk_disable_unprepare(csi->num_clks, csi->clks); + writel(value, csi->regbase + offset); } static void imx7_csi_hw_reset(struct imx7_csi *csi) @@ -229,9 +217,9 @@ static void imx7_csi_hw_reset(struct imx7_csi *csi) imx7_csi_reg_write(csi, CSICR3_RESET_VAL, CSI_CSICR3); } -static unsigned long imx7_csi_irq_clear(struct imx7_csi *csi) +static u32 imx7_csi_irq_clear(struct imx7_csi *csi) { - unsigned long isr; + u32 isr; isr = imx7_csi_reg_read(csi, CSI_CSISR); imx7_csi_reg_write(csi, isr, CSI_CSISR); @@ -257,7 +245,7 @@ static void imx7_csi_init_interface(struct imx7_csi *csi) static void imx7_csi_hw_enable_irq(struct imx7_csi *csi) { - unsigned long cr1 = imx7_csi_reg_read(csi, CSI_CSICR1); + u32 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1); cr1 |= BIT_SOF_INTEN; cr1 |= BIT_RFF_OR_INT; @@ -273,7 +261,7 @@ static void imx7_csi_hw_enable_irq(struct imx7_csi *csi) static void imx7_csi_hw_disable_irq(struct imx7_csi *csi) { - unsigned long cr1 = imx7_csi_reg_read(csi, CSI_CSICR1); + u32 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1); cr1 &= ~BIT_SOF_INTEN; cr1 &= ~BIT_RFF_OR_INT; @@ -286,7 +274,7 @@ static void imx7_csi_hw_disable_irq(struct imx7_csi *csi) static void imx7_csi_hw_enable(struct imx7_csi *csi) { - unsigned long cr = imx7_csi_reg_read(csi, CSI_CSICR18); + u32 cr = imx7_csi_reg_read(csi, CSI_CSICR18); cr |= BIT_CSI_HW_ENABLE; @@ -295,7 +283,7 @@ static void imx7_csi_hw_enable(struct imx7_csi *csi) static void imx7_csi_hw_disable(struct imx7_csi *csi) { - unsigned long cr = imx7_csi_reg_read(csi, CSI_CSICR18); + u32 cr = imx7_csi_reg_read(csi, CSI_CSICR18); cr &= ~BIT_CSI_HW_ENABLE; @@ -304,7 +292,7 @@ static void imx7_csi_hw_disable(struct imx7_csi *csi) static void imx7_csi_dma_reflash(struct imx7_csi *csi) { - unsigned long cr3 = imx7_csi_reg_read(csi, CSI_CSICR18); + u32 cr3 = imx7_csi_reg_read(csi, CSI_CSICR18); cr3 = imx7_csi_reg_read(csi, CSI_CSICR3); cr3 |= BIT_DMA_REFLASH_RFF; @@ -313,7 +301,7 @@ static void imx7_csi_dma_reflash(struct imx7_csi *csi) static void imx7_csi_rx_fifo_clear(struct imx7_csi *csi) { - unsigned long cr1; + u32 cr1; cr1 = imx7_csi_reg_read(csi, CSI_CSICR1); imx7_csi_reg_write(csi, cr1 & ~BIT_FCC, CSI_CSICR1); @@ -331,7 +319,7 @@ static void imx7_csi_buf_stride_set(struct imx7_csi *csi, u32 stride) static void imx7_csi_deinterlace_enable(struct imx7_csi *csi, bool enable) { - unsigned long cr18 = imx7_csi_reg_read(csi, CSI_CSICR18); + u32 cr18 = imx7_csi_reg_read(csi, CSI_CSICR18); if (enable) cr18 |= BIT_DEINTERLACE_EN; @@ -343,8 +331,8 @@ static void imx7_csi_deinterlace_enable(struct imx7_csi *csi, bool enable) static void imx7_csi_dmareq_rff_enable(struct imx7_csi *csi) { - unsigned long cr3 = imx7_csi_reg_read(csi, CSI_CSICR3); - unsigned long cr2 = imx7_csi_reg_read(csi, CSI_CSICR2); + u32 cr3 = imx7_csi_reg_read(csi, CSI_CSICR3); + u32 cr2 = imx7_csi_reg_read(csi, CSI_CSICR2); /* Burst Type of DMA Transfer from RxFIFO. INCR16 */ cr2 |= 0xC0000000; @@ -360,7 +348,7 @@ static void imx7_csi_dmareq_rff_enable(struct imx7_csi *csi) static void imx7_csi_dmareq_rff_disable(struct imx7_csi *csi) { - unsigned long cr3 = imx7_csi_reg_read(csi, CSI_CSICR3); + u32 cr3 = imx7_csi_reg_read(csi, CSI_CSICR3); cr3 &= ~BIT_DMA_REQ_EN_RFF; cr3 &= ~BIT_HRESP_ERR_EN; @@ -408,17 +396,23 @@ static void imx7_csi_error_recovery(struct imx7_csi *csi) imx7_csi_hw_enable(csi); } -static void imx7_csi_init(struct imx7_csi *csi) +static int imx7_csi_init(struct imx7_csi *csi) { + int ret; + if (csi->is_init) - return; + return 0; - imx7_csi_clk_enable(csi); + ret = clk_prepare_enable(csi->mclk); + if (ret < 0) + return ret; imx7_csi_hw_reset(csi); imx7_csi_init_interface(csi); imx7_csi_dmareq_rff_enable(csi); csi->is_init = true; + + return 0; } static void imx7_csi_deinit(struct imx7_csi *csi) @@ -429,7 +423,7 @@ static void imx7_csi_deinit(struct imx7_csi *csi) imx7_csi_hw_reset(csi); imx7_csi_init_interface(csi); imx7_csi_dmareq_rff_disable(csi); - imx7_csi_clk_disable(csi); + clk_disable_unprepare(csi->mclk); csi->is_init = false; } @@ -448,11 +442,19 @@ static int imx7_csi_get_upstream_endpoint(struct imx7_csi *csi, src = &csi->src_sd->entity; + /* + * if the source is neither a mux or csi2 get the one directly upstream + * from this csi + */ + if (src->function != MEDIA_ENT_F_VID_IF_BRIDGE && + src->function != MEDIA_ENT_F_VID_MUX) + src = &csi->sd.entity; + skip_video_mux: /* get source pad of entity directly upstream from src */ - pad = imx_media_find_upstream_pad(csi->imxmd, src, 0); - if (IS_ERR(pad)) - return PTR_ERR(pad); + pad = imx_media_pipeline_pad(src, 0, 0, true); + if (!pad) + return -ENODEV; sd = media_entity_to_v4l2_subdev(pad->entity); @@ -531,7 +533,7 @@ static int imx7_csi_link_setup(struct media_entity *entity, init: if (csi->sink || csi->src_sd) - imx7_csi_init(csi); + ret = imx7_csi_init(csi); else imx7_csi_deinit(csi); @@ -653,7 +655,7 @@ static void imx7_csi_vb2_buf_done(struct imx7_csi *csi) static irqreturn_t imx7_csi_irq_handler(int irq, void *data) { struct imx7_csi *csi = data; - unsigned long status; + u32 status; spin_lock(&csi->irqlock); @@ -714,7 +716,7 @@ static int imx7_csi_dma_start(struct imx7_csi *csi) struct v4l2_pix_format *out_pix = &vdev->fmt.fmt.pix; int ret; - ret = imx_media_alloc_dma_buf(csi->imxmd, &csi->underrun_buf, + ret = imx_media_alloc_dma_buf(csi->dev, &csi->underrun_buf, out_pix->sizeimage); if (ret < 0) { v4l2_warn(&csi->sd, "consider increasing the CMA area\n"); @@ -754,7 +756,7 @@ static void imx7_csi_dma_stop(struct imx7_csi *csi) imx7_csi_dma_unsetup_vb2_buf(csi, VB2_BUF_STATE_ERROR); - imx_media_free_dma_buf(csi->imxmd, &csi->underrun_buf); + imx_media_free_dma_buf(csi->dev, &csi->underrun_buf); } static int imx7_csi_configure(struct imx7_csi *csi) @@ -811,7 +813,7 @@ static int imx7_csi_configure(struct imx7_csi *csi) return 0; } -static int imx7_csi_enable(struct imx7_csi *csi) +static void imx7_csi_enable(struct imx7_csi *csi) { imx7_csi_sw_reset(csi); @@ -819,10 +821,7 @@ static int imx7_csi_enable(struct imx7_csi *csi) imx7_csi_dmareq_rff_enable(csi); imx7_csi_hw_enable_irq(csi); imx7_csi_hw_enable(csi); - return 0; } - - return 0; } static void imx7_csi_disable(struct imx7_csi *csi) @@ -1021,7 +1020,6 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, break; default: return -EINVAL; - break; } return 0; } @@ -1031,11 +1029,8 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *sdformat) { struct imx7_csi *csi = v4l2_get_subdevdata(sd); - struct imx_media_video_dev *vdev = csi->vdev; const struct imx_media_pixfmt *outcc; struct v4l2_mbus_framefmt *outfmt; - struct v4l2_pix_format vdev_fmt; - struct v4l2_rect vdev_compose; const struct imx_media_pixfmt *cc; struct v4l2_mbus_framefmt *fmt; struct v4l2_subdev_format format; @@ -1080,19 +1075,8 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd, csi->cc[IMX7_CSI_PAD_SRC] = outcc; } - if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) - goto out_unlock; - - csi->cc[sdformat->pad] = cc; - - /* propagate output pad format to capture device */ - imx_media_mbus_fmt_to_pix_fmt(&vdev_fmt, &vdev_compose, - &csi->format_mbus[IMX7_CSI_PAD_SRC], - csi->cc[IMX7_CSI_PAD_SRC]); - mutex_unlock(&csi->lock); - imx_media_capture_device_set_format(vdev, &vdev_fmt, &vdev_compose); - - return 0; + if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) + csi->cc[sdformat->pad] = cc; out_unlock: mutex_unlock(&csi->lock); @@ -1126,17 +1110,7 @@ static int imx7_csi_registered(struct v4l2_subdev *sd) if (ret < 0) return ret; - ret = imx_media_capture_device_register(csi->imxmd, csi->vdev); - if (ret < 0) - return ret; - - ret = imx_media_add_video_device(csi->imxmd, csi->vdev); - if (ret < 0) { - imx_media_capture_device_unregister(csi->vdev); - return ret; - } - - return 0; + return imx_media_capture_device_register(csi->vdev); } static void imx7_csi_unregistered(struct v4l2_subdev *sd) @@ -1200,31 +1174,12 @@ static int imx7_csi_parse_endpoint(struct device *dev, return fwnode_device_is_available(asd->match.fwnode) ? 0 : -EINVAL; } -static int imx7_csi_clocks_get(struct imx7_csi *csi) -{ - struct device *dev = csi->dev; - int i; - - csi->num_clks = ARRAY_SIZE(imx7_csi_clk_id); - csi->clks = devm_kcalloc(dev, csi->num_clks, sizeof(*csi->clks), - GFP_KERNEL); - - if (!csi->clks) - return -ENOMEM; - - for (i = 0; i < csi->num_clks; i++) - csi->clks[i].id = imx7_csi_clk_id[i]; - - return devm_clk_bulk_get(dev, csi->num_clks, csi->clks); -} - static int imx7_csi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; struct imx_media_dev *imxmd; struct imx7_csi *csi; - struct resource *res; int ret; csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL); @@ -1233,24 +1188,22 @@ static int imx7_csi_probe(struct platform_device *pdev) csi->dev = dev; - ret = imx7_csi_clocks_get(csi); - if (ret < 0) { - dev_err(dev, "Failed to get clocks"); - return -ENODEV; + csi->mclk = devm_clk_get(&pdev->dev, "mclk"); + if (IS_ERR(csi->mclk)) { + ret = PTR_ERR(csi->mclk); + dev_err(dev, "Failed to get mclk: %d", ret); + return ret; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); csi->irq = platform_get_irq(pdev, 0); - if (!res || csi->irq < 0) { + if (csi->irq < 0) { dev_err(dev, "Missing platform resources data\n"); - return -ENODEV; + return csi->irq; } - csi->regbase = devm_ioremap_resource(dev, res); - if (IS_ERR(csi->regbase)) { - dev_err(dev, "Failed platform resources map\n"); - return -ENODEV; - } + csi->regbase = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(csi->regbase)) + return PTR_ERR(csi->regbase); spin_lock_init(&csi->irqlock); mutex_init(&csi->lock); @@ -1260,12 +1213,11 @@ static int imx7_csi_probe(struct platform_device *pdev) (void *)csi); if (ret < 0) { dev_err(dev, "Request CSI IRQ failed.\n"); - ret = -ENODEV; goto destroy_mutex; } /* add media device */ - imxmd = imx_media_dev_init(dev); + imxmd = imx_media_dev_init(dev, NULL); if (IS_ERR(imxmd)) { ret = PTR_ERR(imxmd); goto destroy_mutex; @@ -1276,7 +1228,7 @@ static int imx7_csi_probe(struct platform_device *pdev) if (ret < 0 && ret != -ENODEV && ret != -EEXIST) goto cleanup; - ret = imx_media_dev_notifier_register(imxmd); + ret = imx_media_dev_notifier_register(imxmd, NULL); if (ret < 0) goto cleanup; @@ -1292,7 +1244,8 @@ static int imx7_csi_probe(struct platform_device *pdev) csi->sd.grp_id = IMX_MEDIA_GRP_ID_CSI; snprintf(csi->sd.name, sizeof(csi->sd.name), "csi"); - csi->vdev = imx_media_capture_device_init(&csi->sd, IMX7_CSI_PAD_SRC); + csi->vdev = imx_media_capture_device_init(csi->sd.dev, &csi->sd, + IMX7_CSI_PAD_SRC); if (IS_ERR(csi->vdev)) return PTR_ERR(csi->vdev); diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c index 19455f425416..d1cdf011c8f1 100644 --- a/drivers/staging/media/imx/imx7-mipi-csis.c +++ b/drivers/staging/media/imx/imx7-mipi-csis.c @@ -456,13 +456,9 @@ static void mipi_csis_set_params(struct csi_state *state) MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL); } -static void mipi_csis_clk_enable(struct csi_state *state) +static int mipi_csis_clk_enable(struct csi_state *state) { - int ret; - - ret = clk_bulk_prepare_enable(state->num_clks, state->clks); - if (ret < 0) - dev_err(state->dev, "failed to enable clocks\n"); + return clk_bulk_prepare_enable(state->num_clks, state->clks); } static void mipi_csis_clk_disable(struct csi_state *state) @@ -784,6 +780,17 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static int mipi_csis_registered(struct v4l2_subdev *mipi_sd) +{ + struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); + + state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + + return media_entity_pads_init(&state->mipi_sd.entity, CSIS_PADS_NUM, + state->pads); +} + static const struct v4l2_subdev_core_ops mipi_csis_core_ops = { .log_status = mipi_csis_log_status, }; @@ -809,6 +816,10 @@ static const struct v4l2_subdev_ops mipi_csis_subdev_ops = { .pad = &mipi_csis_pad_ops, }; +static const struct v4l2_subdev_internal_ops mipi_csis_internal_ops = { + .registered = mipi_csis_registered, +}; + static int mipi_csis_parse_dt(struct platform_device *pdev, struct csi_state *state) { @@ -869,6 +880,7 @@ static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd, mipi_sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; mipi_sd->entity.ops = &mipi_csis_entity_ops; + mipi_sd->internal_ops = &mipi_csis_internal_ops; mipi_sd->dev = &pdev->dev; @@ -890,7 +902,6 @@ static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd, return ret; } - static int mipi_csis_dump_regs_show(struct seq_file *m, void *private) { struct csi_state *state = m->private; @@ -938,7 +949,7 @@ static int mipi_csis_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct resource *mem_res; struct csi_state *state; - int ret = -ENOMEM; + int ret; state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); if (!state) @@ -973,7 +984,11 @@ static int mipi_csis_probe(struct platform_device *pdev) if (ret < 0) return ret; - mipi_csis_clk_enable(state); + ret = mipi_csis_clk_enable(state); + if (ret < 0) { + dev_err(state->dev, "failed to enable clocks: %d\n", ret); + return ret; + } ret = devm_request_irq(dev, state->irq, mipi_csis_irq_handler, 0, dev_name(dev), state); @@ -990,13 +1005,6 @@ static int mipi_csis_probe(struct platform_device *pdev) if (ret < 0) goto disable_clock; - state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_pads_init(&state->mipi_sd.entity, CSIS_PADS_NUM, - state->pads); - if (ret < 0) - goto unregister_subdev; - memcpy(state->events, mipi_csis_events, sizeof(state->events)); mipi_csis_debugfs_init(state); @@ -1016,7 +1024,6 @@ static int mipi_csis_probe(struct platform_device *pdev) unregister_all: mipi_csis_debugfs_exit(state); media_entity_cleanup(&state->mipi_sd.entity); -unregister_subdev: v4l2_async_unregister_subdev(&state->mipi_sd); disable_clock: mipi_csis_clk_disable(state); diff --git a/drivers/staging/media/ipu3/include/intel-ipu3.h b/drivers/staging/media/ipu3/include/intel-ipu3.h index 1e7184e4311d..c7cd27efac8a 100644 --- a/drivers/staging/media/ipu3/include/intel-ipu3.h +++ b/drivers/staging/media/ipu3/include/intel-ipu3.h @@ -2472,7 +2472,7 @@ struct ipu3_uapi_acc_param { struct ipu3_uapi_yuvp1_yds_config yds2 __attribute__((aligned(32))); struct ipu3_uapi_yuvp2_tcc_static_config tcc __attribute__((aligned(32))); struct ipu3_uapi_anr_config anr; - struct ipu3_uapi_awb_fr_config_s awb_fr; + struct ipu3_uapi_awb_fr_config_s awb_fr __attribute__((aligned(32))); struct ipu3_uapi_ae_config ae; struct ipu3_uapi_af_config_s af; struct ipu3_uapi_awb_config awb; diff --git a/drivers/staging/media/ipu3/ipu3-css-fw.c b/drivers/staging/media/ipu3/ipu3-css-fw.c index 4122d4e42db6..45aff76198e2 100644 --- a/drivers/staging/media/ipu3/ipu3-css-fw.c +++ b/drivers/staging/media/ipu3/ipu3-css-fw.c @@ -200,13 +200,11 @@ int imgu_css_fw_init(struct imgu_css *css) goto bad_fw; for (j = 0; j < bi->info.isp.num_output_formats; j++) - if (bi->info.isp.output_formats[j] < 0 || - bi->info.isp.output_formats[j] >= + if (bi->info.isp.output_formats[j] >= IMGU_ABI_FRAME_FORMAT_NUM) goto bad_fw; for (j = 0; j < bi->info.isp.num_vf_formats; j++) - if (bi->info.isp.vf_formats[j] < 0 || - bi->info.isp.vf_formats[j] >= + if (bi->info.isp.vf_formats[j] >= IMGU_ABI_FRAME_FORMAT_NUM) goto bad_fw; diff --git a/drivers/staging/media/ipu3/ipu3-css.c b/drivers/staging/media/ipu3/ipu3-css.c index 23cf5b2cfe8b..fd1ed84c400c 100644 --- a/drivers/staging/media/ipu3/ipu3-css.c +++ b/drivers/staging/media/ipu3/ipu3-css.c @@ -24,9 +24,8 @@ #define IPU3_CSS_MAX_H 3136 #define IPU3_CSS_MAX_W 4224 -/* filter size from graph settings is fixed as 4 */ -#define FILTER_SIZE 4 -#define MIN_ENVELOPE 8 +/* minimal envelope size(GDC in - out) should be 4 */ +#define MIN_ENVELOPE 4 /* * pre-allocated buffer size for CSS ABI, auxiliary frames @@ -1827,9 +1826,9 @@ int imgu_css_fmt_try(struct imgu_css *css, vf->width = imgu_css_adjust(vf->width, VF_ALIGN_W); vf->height = imgu_css_adjust(vf->height, 1); - s = (bds->width - gdc->width) / 2 - FILTER_SIZE; + s = (bds->width - gdc->width) / 2; env->width = s < MIN_ENVELOPE ? MIN_ENVELOPE : s; - s = (bds->height - gdc->height) / 2 - FILTER_SIZE; + s = (bds->height - gdc->height) / 2; env->height = s < MIN_ENVELOPE ? MIN_ENVELOPE : s; ret = imgu_css_find_binary(css, pipe, q, r); @@ -2251,9 +2250,8 @@ int imgu_css_set_parameters(struct imgu_css *css, unsigned int pipe, css_pipe->aux_frames[a].height, css_pipe->rect[g].width, css_pipe->rect[g].height, - css_pipe->rect[e].width + FILTER_SIZE, - css_pipe->rect[e].height + - FILTER_SIZE); + css_pipe->rect[e].width, + css_pipe->rect[e].height); } } diff --git a/drivers/staging/media/ipu3/ipu3-dmamap.c b/drivers/staging/media/ipu3/ipu3-dmamap.c index d978a00e1e0b..7431322379f6 100644 --- a/drivers/staging/media/ipu3/ipu3-dmamap.c +++ b/drivers/staging/media/ipu3/ipu3-dmamap.c @@ -31,12 +31,11 @@ static void imgu_dmamap_free_buffer(struct page **pages, * Based on the implementation of __iommu_dma_alloc_pages() * defined in drivers/iommu/dma-iommu.c */ -static struct page **imgu_dmamap_alloc_buffer(size_t size, - unsigned long order_mask, - gfp_t gfp) +static struct page **imgu_dmamap_alloc_buffer(size_t size, gfp_t gfp) { struct page **pages; unsigned int i = 0, count = size >> PAGE_SHIFT; + unsigned int order_mask = 1; const gfp_t high_order_gfp = __GFP_NOWARN | __GFP_NORETRY; /* Allocate mem for array of page ptrs */ @@ -45,10 +44,6 @@ static struct page **imgu_dmamap_alloc_buffer(size_t size, if (!pages) return NULL; - order_mask &= (2U << MAX_ORDER) - 1; - if (!order_mask) - return NULL; - gfp |= __GFP_HIGHMEM | __GFP_ZERO; while (count) { @@ -99,7 +94,6 @@ void *imgu_dmamap_alloc(struct imgu_device *imgu, struct imgu_css_map *map, size_t len) { unsigned long shift = iova_shift(&imgu->iova_domain); - unsigned int alloc_sizes = imgu->mmu->pgsize_bitmap; struct device *dev = &imgu->pci_dev->dev; size_t size = PAGE_ALIGN(len); struct page **pages; @@ -114,8 +108,7 @@ void *imgu_dmamap_alloc(struct imgu_device *imgu, struct imgu_css_map *map, if (!iova) return NULL; - pages = imgu_dmamap_alloc_buffer(size, alloc_sizes >> PAGE_SHIFT, - GFP_KERNEL); + pages = imgu_dmamap_alloc_buffer(size, GFP_KERNEL); if (!pages) goto out_free_iova; @@ -257,7 +250,7 @@ int imgu_dmamap_init(struct imgu_device *imgu) if (ret) return ret; - order = __ffs(imgu->mmu->pgsize_bitmap); + order = __ffs(IPU3_PAGE_SIZE); base_pfn = max_t(unsigned long, 1, imgu->mmu->aperture_start >> order); init_iova_domain(&imgu->iova_domain, 1UL << order, base_pfn); diff --git a/drivers/staging/media/ipu3/ipu3-mmu.c b/drivers/staging/media/ipu3/ipu3-mmu.c index cfc2bdfb14b3..3d969b0522ab 100644 --- a/drivers/staging/media/ipu3/ipu3-mmu.c +++ b/drivers/staging/media/ipu3/ipu3-mmu.c @@ -20,9 +20,6 @@ #include "ipu3-mmu.h" -#define IPU3_PAGE_SHIFT 12 -#define IPU3_PAGE_SIZE (1UL << IPU3_PAGE_SHIFT) - #define IPU3_PT_BITS 10 #define IPU3_PT_PTES (1UL << IPU3_PT_BITS) #define IPU3_PT_SIZE (IPU3_PT_PTES << 2) @@ -238,62 +235,31 @@ static int __imgu_mmu_map(struct imgu_mmu *mmu, unsigned long iova, return 0; } -/* - * The following four functions are implemented based on iommu.c - * drivers/iommu/iommu.c/iommu_pgsize(). +/** + * imgu_mmu_map - map a buffer to a physical address + * + * @info: MMU mappable range + * @iova: the virtual address + * @paddr: the physical address + * @size: length of the mappable area + * + * The function has been adapted from iommu_map() in + * drivers/iommu/iommu.c . */ -static size_t imgu_mmu_pgsize(unsigned long pgsize_bitmap, - unsigned long addr_merge, size_t size) -{ - unsigned int pgsize_idx; - size_t pgsize; - - /* Max page size that still fits into 'size' */ - pgsize_idx = __fls(size); - - /* need to consider alignment requirements ? */ - if (likely(addr_merge)) { - /* Max page size allowed by address */ - unsigned int align_pgsize_idx = __ffs(addr_merge); - - pgsize_idx = min(pgsize_idx, align_pgsize_idx); - } - - /* build a mask of acceptable page sizes */ - pgsize = (1UL << (pgsize_idx + 1)) - 1; - - /* throw away page sizes not supported by the hardware */ - pgsize &= pgsize_bitmap; - - /* make sure we're still sane */ - WARN_ON(!pgsize); - - /* pick the biggest page */ - pgsize_idx = __fls(pgsize); - pgsize = 1UL << pgsize_idx; - - return pgsize; -} - -/* drivers/iommu/iommu.c/iommu_map() */ int imgu_mmu_map(struct imgu_mmu_info *info, unsigned long iova, phys_addr_t paddr, size_t size) { struct imgu_mmu *mmu = to_imgu_mmu(info); - unsigned int min_pagesz; int ret = 0; - /* find out the minimum page size supported */ - min_pagesz = 1 << __ffs(mmu->geometry.pgsize_bitmap); - /* * both the virtual address and the physical one, as well as * the size of the mapping, must be aligned (at least) to the * size of the smallest page supported by the hardware */ - if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) { - dev_err(mmu->dev, "unaligned: iova 0x%lx pa %pa size 0x%zx min_pagesz 0x%x\n", - iova, &paddr, size, min_pagesz); + if (!IS_ALIGNED(iova | paddr | size, IPU3_PAGE_SIZE)) { + dev_err(mmu->dev, "unaligned: iova 0x%lx pa %pa size 0x%zx\n", + iova, &paddr, size); return -EINVAL; } @@ -301,19 +267,15 @@ int imgu_mmu_map(struct imgu_mmu_info *info, unsigned long iova, iova, &paddr, size); while (size) { - size_t pgsize = imgu_mmu_pgsize(mmu->geometry.pgsize_bitmap, - iova | paddr, size); - - dev_dbg(mmu->dev, "mapping: iova 0x%lx pa %pa pgsize 0x%zx\n", - iova, &paddr, pgsize); + dev_dbg(mmu->dev, "mapping: iova 0x%lx pa %pa\n", iova, &paddr); ret = __imgu_mmu_map(mmu, iova, paddr); if (ret) break; - iova += pgsize; - paddr += pgsize; - size -= pgsize; + iova += IPU3_PAGE_SIZE; + paddr += IPU3_PAGE_SIZE; + size -= IPU3_PAGE_SIZE; } call_if_imgu_is_powered(mmu, imgu_mmu_tlb_invalidate); @@ -321,28 +283,36 @@ int imgu_mmu_map(struct imgu_mmu_info *info, unsigned long iova, return ret; } -/* drivers/iommu/iommu.c/default_iommu_map_sg() */ +/** + * imgu_mmu_map_sg - Map a scatterlist + * + * @info: MMU mappable range + * @iova: the virtual address + * @sg: the scatterlist to map + * @nents: number of entries in the scatterlist + * + * The function has been adapted from default_iommu_map_sg() in + * drivers/iommu/iommu.c . + */ size_t imgu_mmu_map_sg(struct imgu_mmu_info *info, unsigned long iova, struct scatterlist *sg, unsigned int nents) { struct imgu_mmu *mmu = to_imgu_mmu(info); struct scatterlist *s; size_t s_length, mapped = 0; - unsigned int i, min_pagesz; + unsigned int i; int ret; - min_pagesz = 1 << __ffs(mmu->geometry.pgsize_bitmap); - for_each_sg(sg, s, nents, i) { phys_addr_t phys = page_to_phys(sg_page(s)) + s->offset; s_length = s->length; - if (!IS_ALIGNED(s->offset, min_pagesz)) + if (!IS_ALIGNED(s->offset, IPU3_PAGE_SIZE)) goto out_err; - /* must be min_pagesz aligned to be mapped singlely */ - if (i == nents - 1 && !IS_ALIGNED(s->length, min_pagesz)) + /* must be IPU3_PAGE_SIZE aligned to be mapped singlely */ + if (i == nents - 1 && !IS_ALIGNED(s->length, IPU3_PAGE_SIZE)) s_length = PAGE_ALIGN(s->length); ret = imgu_mmu_map(info, iova + mapped, phys, s_length); @@ -394,25 +364,30 @@ static size_t __imgu_mmu_unmap(struct imgu_mmu *mmu, return unmap; } -/* drivers/iommu/iommu.c/iommu_unmap() */ +/** + * imgu_mmu_unmap - Unmap a buffer + * + * @info: MMU mappable range + * @iova: the virtual address + * @size: the length of the buffer + * + * The function has been adapted from iommu_unmap() in + * drivers/iommu/iommu.c . + */ size_t imgu_mmu_unmap(struct imgu_mmu_info *info, unsigned long iova, size_t size) { struct imgu_mmu *mmu = to_imgu_mmu(info); size_t unmapped_page, unmapped = 0; - unsigned int min_pagesz; - - /* find out the minimum page size supported */ - min_pagesz = 1 << __ffs(mmu->geometry.pgsize_bitmap); /* * The virtual address, as well as the size of the mapping, must be * aligned (at least) to the size of the smallest page supported * by the hardware */ - if (!IS_ALIGNED(iova | size, min_pagesz)) { - dev_err(mmu->dev, "unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n", - iova, size, min_pagesz); + if (!IS_ALIGNED(iova | size, IPU3_PAGE_SIZE)) { + dev_err(mmu->dev, "unaligned: iova 0x%lx size 0x%zx\n", + iova, size); return -EINVAL; } @@ -423,10 +398,7 @@ size_t imgu_mmu_unmap(struct imgu_mmu_info *info, unsigned long iova, * or we hit an area that isn't mapped. */ while (unmapped < size) { - size_t pgsize = imgu_mmu_pgsize(mmu->geometry.pgsize_bitmap, - iova, size - unmapped); - - unmapped_page = __imgu_mmu_unmap(mmu, iova, pgsize); + unmapped_page = __imgu_mmu_unmap(mmu, iova, IPU3_PAGE_SIZE); if (!unmapped_page) break; @@ -444,6 +416,7 @@ size_t imgu_mmu_unmap(struct imgu_mmu_info *info, unsigned long iova, /** * imgu_mmu_init() - initialize IPU3 MMU block + * * @parent: struct device parent * @base: IOMEM base of hardware registers. * @@ -505,7 +478,6 @@ struct imgu_mmu_info *imgu_mmu_init(struct device *parent, void __iomem *base) mmu->geometry.aperture_start = 0; mmu->geometry.aperture_end = DMA_BIT_MASK(IPU3_MMU_ADDRESS_BITS); - mmu->geometry.pgsize_bitmap = IPU3_PAGE_SIZE; return &mmu->geometry; @@ -523,7 +495,8 @@ fail_group: /** * imgu_mmu_exit() - clean up IPU3 MMU block - * @info: IPU3 MMU private data + * + * @info: MMU mappable range */ void imgu_mmu_exit(struct imgu_mmu_info *info) { diff --git a/drivers/staging/media/ipu3/ipu3-mmu.h b/drivers/staging/media/ipu3/ipu3-mmu.h index fa58827eb19c..a5f0bca7e7e0 100644 --- a/drivers/staging/media/ipu3/ipu3-mmu.h +++ b/drivers/staging/media/ipu3/ipu3-mmu.h @@ -5,17 +5,18 @@ #ifndef __IPU3_MMU_H #define __IPU3_MMU_H +#define IPU3_PAGE_SHIFT 12 +#define IPU3_PAGE_SIZE (1UL << IPU3_PAGE_SHIFT) + /** * struct imgu_mmu_info - Describes mmu geometry * * @aperture_start: First address that can be mapped * @aperture_end: Last address that can be mapped - * @pgsize_bitmap: Bitmap of page sizes in use */ struct imgu_mmu_info { dma_addr_t aperture_start; dma_addr_t aperture_end; - unsigned long pgsize_bitmap; }; struct device; diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c index a7bc22040ed8..3c7ad1eed434 100644 --- a/drivers/staging/media/ipu3/ipu3-v4l2.c +++ b/drivers/staging/media/ipu3/ipu3-v4l2.c @@ -955,12 +955,12 @@ static const struct v4l2_file_operations imgu_v4l2_fops = { static const struct v4l2_ioctl_ops imgu_v4l2_ioctl_ops = { .vidioc_querycap = imgu_vidioc_querycap, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap_mplane = imgu_vidioc_g_fmt, .vidioc_s_fmt_vid_cap_mplane = imgu_vidioc_s_fmt, .vidioc_try_fmt_vid_cap_mplane = imgu_vidioc_try_fmt, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, .vidioc_g_fmt_vid_out_mplane = imgu_vidioc_g_fmt, .vidioc_s_fmt_vid_out_mplane = imgu_vidioc_s_fmt, .vidioc_try_fmt_vid_out_mplane = imgu_vidioc_try_fmt, diff --git a/drivers/staging/media/meson/vdec/Kconfig b/drivers/staging/media/meson/vdec/Kconfig new file mode 100644 index 000000000000..9e1450193392 --- /dev/null +++ b/drivers/staging/media/meson/vdec/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0 + +config VIDEO_MESON_VDEC + tristate "Amlogic video decoder driver" + depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA + depends on ARCH_MESON || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + select MESON_CANVAS + help + Support for the video decoder found in gxbb/gxl/gxm chips. diff --git a/drivers/staging/media/meson/vdec/Makefile b/drivers/staging/media/meson/vdec/Makefile new file mode 100644 index 000000000000..6bea129084b7 --- /dev/null +++ b/drivers/staging/media/meson/vdec/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +# Makefile for Amlogic meson video decoder driver + +meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o +meson-vdec-objs += vdec_1.o +meson-vdec-objs += codec_mpeg12.o + +obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o diff --git a/drivers/staging/media/meson/vdec/TODO b/drivers/staging/media/meson/vdec/TODO new file mode 100644 index 000000000000..70ae990cf13b --- /dev/null +++ b/drivers/staging/media/meson/vdec/TODO @@ -0,0 +1,8 @@ +This driver is in staging until the V4L2 documentation about stateful video +decoders is finalized, as well as the corresponding compliance tests. + +It is at the moment not guaranteed to work properly with a userspace +stack that follows the latest version of the specification, especially +with compression standards like MPEG1/2 where the driver does not support +dynamic resolution switching, including the first one used to determine coded +resolution. diff --git a/drivers/staging/media/meson/vdec/codec_mpeg12.c b/drivers/staging/media/meson/vdec/codec_mpeg12.c new file mode 100644 index 000000000000..48869cc3d973 --- /dev/null +++ b/drivers/staging/media/meson/vdec/codec_mpeg12.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Maxime Jourdan <mjourdan@baylibre.com> + */ + +#include <media/v4l2-mem2mem.h> +#include <media/videobuf2-dma-contig.h> + +#include "codec_mpeg12.h" +#include "dos_regs.h" +#include "vdec_helpers.h" + +#define SIZE_WORKSPACE SZ_128K +/* Offset substracted by the firmware from the workspace paddr */ +#define WORKSPACE_OFFSET (5 * SZ_1K) + +/* map firmware registers to known MPEG1/2 functions */ +#define MREG_SEQ_INFO AV_SCRATCH_4 + #define MPEG2_SEQ_DAR_MASK GENMASK(3, 0) + #define MPEG2_DAR_4_3 2 + #define MPEG2_DAR_16_9 3 + #define MPEG2_DAR_221_100 4 +#define MREG_PIC_INFO AV_SCRATCH_5 +#define MREG_PIC_WIDTH AV_SCRATCH_6 +#define MREG_PIC_HEIGHT AV_SCRATCH_7 +#define MREG_BUFFERIN AV_SCRATCH_8 +#define MREG_BUFFEROUT AV_SCRATCH_9 +#define MREG_CMD AV_SCRATCH_A +#define MREG_CO_MV_START AV_SCRATCH_B +#define MREG_ERROR_COUNT AV_SCRATCH_C +#define MREG_FRAME_OFFSET AV_SCRATCH_D +#define MREG_WAIT_BUFFER AV_SCRATCH_E +#define MREG_FATAL_ERROR AV_SCRATCH_F + +#define PICINFO_PROG 0x00008000 +#define PICINFO_TOP_FIRST 0x00002000 + +struct codec_mpeg12 { + /* Buffer for the MPEG1/2 Workspace */ + void *workspace_vaddr; + dma_addr_t workspace_paddr; +}; + +static const u8 eos_sequence[SZ_1K] = { 0x00, 0x00, 0x01, 0xB7 }; + +static const u8 *codec_mpeg12_eos_sequence(u32 *len) +{ + *len = ARRAY_SIZE(eos_sequence); + return eos_sequence; +} + +static int codec_mpeg12_can_recycle(struct amvdec_core *core) +{ + return !amvdec_read_dos(core, MREG_BUFFERIN); +} + +static void codec_mpeg12_recycle(struct amvdec_core *core, u32 buf_idx) +{ + amvdec_write_dos(core, MREG_BUFFERIN, buf_idx + 1); +} + +static int codec_mpeg12_start(struct amvdec_session *sess) +{ + struct amvdec_core *core = sess->core; + struct codec_mpeg12 *mpeg12; + int ret; + + mpeg12 = kzalloc(sizeof(*mpeg12), GFP_KERNEL); + if (!mpeg12) + return -ENOMEM; + + /* Allocate some memory for the MPEG1/2 decoder's state */ + mpeg12->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, + &mpeg12->workspace_paddr, + GFP_KERNEL); + if (!mpeg12->workspace_vaddr) { + dev_err(core->dev, "Failed to request MPEG 1/2 Workspace\n"); + ret = -ENOMEM; + goto free_mpeg12; + } + + ret = amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_0, 0 }, + (u32[]){ 8, 0 }); + if (ret) + goto free_workspace; + + amvdec_write_dos(core, POWER_CTL_VLD, BIT(4)); + amvdec_write_dos(core, MREG_CO_MV_START, + mpeg12->workspace_paddr + WORKSPACE_OFFSET); + + amvdec_write_dos(core, MPEG1_2_REG, 0); + amvdec_write_dos(core, PSCALE_CTRL, 0); + amvdec_write_dos(core, PIC_HEAD_INFO, 0x380); + amvdec_write_dos(core, M4_CONTROL_REG, 0); + amvdec_write_dos(core, MREG_BUFFERIN, 0); + amvdec_write_dos(core, MREG_BUFFEROUT, 0); + amvdec_write_dos(core, MREG_CMD, (sess->width << 16) | sess->height); + amvdec_write_dos(core, MREG_ERROR_COUNT, 0); + amvdec_write_dos(core, MREG_FATAL_ERROR, 0); + amvdec_write_dos(core, MREG_WAIT_BUFFER, 0); + + sess->keyframe_found = 1; + sess->priv = mpeg12; + + return 0; + +free_workspace: + dma_free_coherent(core->dev, SIZE_WORKSPACE, mpeg12->workspace_vaddr, + mpeg12->workspace_paddr); +free_mpeg12: + kfree(mpeg12); + + return ret; +} + +static int codec_mpeg12_stop(struct amvdec_session *sess) +{ + struct codec_mpeg12 *mpeg12 = sess->priv; + struct amvdec_core *core = sess->core; + + if (mpeg12->workspace_vaddr) + dma_free_coherent(core->dev, SIZE_WORKSPACE, + mpeg12->workspace_vaddr, + mpeg12->workspace_paddr); + + return 0; +} + +static void codec_mpeg12_update_dar(struct amvdec_session *sess) +{ + struct amvdec_core *core = sess->core; + u32 seq = amvdec_read_dos(core, MREG_SEQ_INFO); + u32 ar = seq & MPEG2_SEQ_DAR_MASK; + + switch (ar) { + case MPEG2_DAR_4_3: + amvdec_set_par_from_dar(sess, 4, 3); + break; + case MPEG2_DAR_16_9: + amvdec_set_par_from_dar(sess, 16, 9); + break; + case MPEG2_DAR_221_100: + amvdec_set_par_from_dar(sess, 221, 100); + break; + default: + sess->pixelaspect.numerator = 1; + sess->pixelaspect.denominator = 1; + break; + } +} + +static irqreturn_t codec_mpeg12_threaded_isr(struct amvdec_session *sess) +{ + struct amvdec_core *core = sess->core; + u32 reg; + u32 pic_info; + u32 is_progressive; + u32 buffer_index; + u32 field = V4L2_FIELD_NONE; + u32 offset; + + amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); + reg = amvdec_read_dos(core, MREG_FATAL_ERROR); + if (reg == 1) { + dev_err(core->dev, "MPEG1/2 fatal error\n"); + amvdec_abort(sess); + return IRQ_HANDLED; + } + + reg = amvdec_read_dos(core, MREG_BUFFEROUT); + if (!reg) + return IRQ_HANDLED; + + /* Unclear what this means */ + if ((reg & GENMASK(23, 17)) == GENMASK(23, 17)) + goto end; + + pic_info = amvdec_read_dos(core, MREG_PIC_INFO); + is_progressive = pic_info & PICINFO_PROG; + + if (!is_progressive) + field = (pic_info & PICINFO_TOP_FIRST) ? + V4L2_FIELD_INTERLACED_TB : + V4L2_FIELD_INTERLACED_BT; + + codec_mpeg12_update_dar(sess); + buffer_index = ((reg & 0xf) - 1) & 7; + offset = amvdec_read_dos(core, MREG_FRAME_OFFSET); + amvdec_dst_buf_done_idx(sess, buffer_index, offset, field); + +end: + amvdec_write_dos(core, MREG_BUFFEROUT, 0); + return IRQ_HANDLED; +} + +static irqreturn_t codec_mpeg12_isr(struct amvdec_session *sess) +{ + return IRQ_WAKE_THREAD; +} + +struct amvdec_codec_ops codec_mpeg12_ops = { + .start = codec_mpeg12_start, + .stop = codec_mpeg12_stop, + .isr = codec_mpeg12_isr, + .threaded_isr = codec_mpeg12_threaded_isr, + .can_recycle = codec_mpeg12_can_recycle, + .recycle = codec_mpeg12_recycle, + .eos_sequence = codec_mpeg12_eos_sequence, +}; diff --git a/drivers/staging/media/meson/vdec/codec_mpeg12.h b/drivers/staging/media/meson/vdec/codec_mpeg12.h new file mode 100644 index 000000000000..43cab5f39ca0 --- /dev/null +++ b/drivers/staging/media/meson/vdec/codec_mpeg12.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Maxime Jourdan <mjourdan@baylibre.com> + */ + +#ifndef __MESON_VDEC_CODEC_MPEG12_H_ +#define __MESON_VDEC_CODEC_MPEG12_H_ + +#include "vdec.h" + +extern struct amvdec_codec_ops codec_mpeg12_ops; + +#endif diff --git a/drivers/staging/media/meson/vdec/dos_regs.h b/drivers/staging/media/meson/vdec/dos_regs.h new file mode 100644 index 000000000000..abd810542dbb --- /dev/null +++ b/drivers/staging/media/meson/vdec/dos_regs.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Maxime Jourdan <mjourdan@baylibre.com> + */ + +#ifndef __MESON_VDEC_DOS_REGS_H_ +#define __MESON_VDEC_DOS_REGS_H_ + +/* DOS registers */ +#define VDEC_ASSIST_AMR1_INT8 0x00b4 + +#define ASSIST_MBOX1_CLR_REG 0x01d4 +#define ASSIST_MBOX1_MASK 0x01d8 + +#define MPSR 0x0c04 +#define MCPU_INTR_MSK 0x0c10 +#define CPSR 0x0c84 + +#define IMEM_DMA_CTRL 0x0d00 +#define IMEM_DMA_ADR 0x0d04 +#define IMEM_DMA_COUNT 0x0d08 +#define LMEM_DMA_CTRL 0x0d40 + +#define MC_STATUS0 0x2424 +#define MC_CTRL1 0x242c + +#define PSCALE_RST 0x2440 +#define PSCALE_CTRL 0x2444 +#define PSCALE_BMEM_ADDR 0x247c +#define PSCALE_BMEM_DAT 0x2480 + +#define DBLK_CTRL 0x2544 +#define DBLK_STATUS 0x254c + +#define GCLK_EN 0x260c +#define MDEC_PIC_DC_CTRL 0x2638 +#define MDEC_PIC_DC_STATUS 0x263c +#define ANC0_CANVAS_ADDR 0x2640 +#define MDEC_PIC_DC_THRESH 0x26e0 + +/* Firmware interface registers */ +#define AV_SCRATCH_0 0x2700 +#define AV_SCRATCH_1 0x2704 +#define AV_SCRATCH_2 0x2708 +#define AV_SCRATCH_3 0x270c +#define AV_SCRATCH_4 0x2710 +#define AV_SCRATCH_5 0x2714 +#define AV_SCRATCH_6 0x2718 +#define AV_SCRATCH_7 0x271c +#define AV_SCRATCH_8 0x2720 +#define AV_SCRATCH_9 0x2724 +#define AV_SCRATCH_A 0x2728 +#define AV_SCRATCH_B 0x272c +#define AV_SCRATCH_C 0x2730 +#define AV_SCRATCH_D 0x2734 +#define AV_SCRATCH_E 0x2738 +#define AV_SCRATCH_F 0x273c +#define AV_SCRATCH_G 0x2740 +#define AV_SCRATCH_H 0x2744 +#define AV_SCRATCH_I 0x2748 +#define AV_SCRATCH_J 0x274c +#define AV_SCRATCH_K 0x2750 +#define AV_SCRATCH_L 0x2754 + +#define MPEG1_2_REG 0x3004 +#define PIC_HEAD_INFO 0x300c +#define POWER_CTL_VLD 0x3020 +#define M4_CONTROL_REG 0x30a4 + +/* Stream Buffer (stbuf) regs */ +#define VLD_MEM_VIFIFO_START_PTR 0x3100 +#define VLD_MEM_VIFIFO_CURR_PTR 0x3104 +#define VLD_MEM_VIFIFO_END_PTR 0x3108 +#define VLD_MEM_VIFIFO_CONTROL 0x3110 + #define MEM_FIFO_CNT_BIT 16 + #define MEM_FILL_ON_LEVEL BIT(10) + #define MEM_CTRL_EMPTY_EN BIT(2) + #define MEM_CTRL_FILL_EN BIT(1) +#define VLD_MEM_VIFIFO_WP 0x3114 +#define VLD_MEM_VIFIFO_RP 0x3118 +#define VLD_MEM_VIFIFO_LEVEL 0x311c +#define VLD_MEM_VIFIFO_BUF_CNTL 0x3120 + #define MEM_BUFCTRL_MANUAL BIT(1) +#define VLD_MEM_VIFIFO_WRAP_COUNT 0x3144 + +#define DCAC_DMA_CTRL 0x3848 + +#define DOS_SW_RESET0 0xfc00 +#define DOS_GCLK_EN0 0xfc04 +#define DOS_GEN_CTRL0 0xfc08 +#define DOS_MEM_PD_VDEC 0xfcc0 +#define DOS_MEM_PD_HEVC 0xfccc +#define DOS_SW_RESET3 0xfcd0 +#define DOS_GCLK_EN3 0xfcd4 +#define DOS_VDEC_MCRCC_STALL_CTRL 0xfd00 + +#endif diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c new file mode 100644 index 000000000000..3a21a8cec799 --- /dev/null +++ b/drivers/staging/media/meson/vdec/esparser.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Maxime Jourdan <mjourdan@baylibre.com> + * + * The Elementary Stream Parser is a HW bitstream parser. + * It reads bitstream buffers and feeds them to the VIFIFO + */ + +#include <linux/init.h> +#include <linux/ioctl.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/reset.h> +#include <linux/interrupt.h> +#include <media/videobuf2-dma-contig.h> +#include <media/v4l2-mem2mem.h> + +#include "dos_regs.h" +#include "esparser.h" +#include "vdec_helpers.h" + +/* PARSER REGS (CBUS) */ +#define PARSER_CONTROL 0x00 + #define ES_PACK_SIZE_BIT 8 + #define ES_WRITE BIT(5) + #define ES_SEARCH BIT(1) + #define ES_PARSER_START BIT(0) +#define PARSER_FETCH_ADDR 0x4 +#define PARSER_FETCH_CMD 0x8 +#define PARSER_CONFIG 0x14 + #define PS_CFG_MAX_FETCH_CYCLE_BIT 0 + #define PS_CFG_STARTCODE_WID_24_BIT 10 + #define PS_CFG_MAX_ES_WR_CYCLE_BIT 12 + #define PS_CFG_PFIFO_EMPTY_CNT_BIT 16 +#define PFIFO_WR_PTR 0x18 +#define PFIFO_RD_PTR 0x1c +#define PARSER_SEARCH_PATTERN 0x24 + #define ES_START_CODE_PATTERN 0x00000100 +#define PARSER_SEARCH_MASK 0x28 + #define ES_START_CODE_MASK 0xffffff00 + #define FETCH_ENDIAN_BIT 27 +#define PARSER_INT_ENABLE 0x2c + #define PARSER_INT_HOST_EN_BIT 8 +#define PARSER_INT_STATUS 0x30 + #define PARSER_INTSTAT_SC_FOUND 1 +#define PARSER_ES_CONTROL 0x5c +#define PARSER_VIDEO_START_PTR 0x80 +#define PARSER_VIDEO_END_PTR 0x84 +#define PARSER_VIDEO_WP 0x88 +#define PARSER_VIDEO_HOLE 0x90 + +#define SEARCH_PATTERN_LEN 512 + +static DECLARE_WAIT_QUEUE_HEAD(wq); +static int search_done; + +static irqreturn_t esparser_isr(int irq, void *dev) +{ + int int_status; + struct amvdec_core *core = dev; + + int_status = amvdec_read_parser(core, PARSER_INT_STATUS); + amvdec_write_parser(core, PARSER_INT_STATUS, int_status); + + if (int_status & PARSER_INTSTAT_SC_FOUND) { + amvdec_write_parser(core, PFIFO_RD_PTR, 0); + amvdec_write_parser(core, PFIFO_WR_PTR, 0); + search_done = 1; + wake_up_interruptible(&wq); + } + + return IRQ_HANDLED; +} + +/* Pad the packet to at least 4KiB bytes otherwise the VDEC unit won't trigger + * ISRs. + * Also append a start code 000001ff at the end to trigger + * the ESPARSER interrupt. + */ +static u32 esparser_pad_start_code(struct vb2_buffer *vb) +{ + u32 payload_size = vb2_get_plane_payload(vb, 0); + u32 pad_size = 0; + u8 *vaddr = vb2_plane_vaddr(vb, 0) + payload_size; + + if (payload_size < ESPARSER_MIN_PACKET_SIZE) { + pad_size = ESPARSER_MIN_PACKET_SIZE - payload_size; + memset(vaddr, 0, pad_size); + } + + memset(vaddr + pad_size, 0, SEARCH_PATTERN_LEN); + vaddr[pad_size] = 0x00; + vaddr[pad_size + 1] = 0x00; + vaddr[pad_size + 2] = 0x01; + vaddr[pad_size + 3] = 0xff; + + return pad_size; +} + +static int +esparser_write_data(struct amvdec_core *core, dma_addr_t addr, u32 size) +{ + amvdec_write_parser(core, PFIFO_RD_PTR, 0); + amvdec_write_parser(core, PFIFO_WR_PTR, 0); + amvdec_write_parser(core, PARSER_CONTROL, + ES_WRITE | + ES_PARSER_START | + ES_SEARCH | + (size << ES_PACK_SIZE_BIT)); + + amvdec_write_parser(core, PARSER_FETCH_ADDR, addr); + amvdec_write_parser(core, PARSER_FETCH_CMD, + (7 << FETCH_ENDIAN_BIT) | + (size + SEARCH_PATTERN_LEN)); + + search_done = 0; + return wait_event_interruptible_timeout(wq, search_done, (HZ / 5)); +} + +static u32 esparser_vififo_get_free_space(struct amvdec_session *sess) +{ + u32 vififo_usage; + struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops; + struct amvdec_core *core = sess->core; + + vififo_usage = vdec_ops->vififo_level(sess); + vififo_usage += amvdec_read_parser(core, PARSER_VIDEO_HOLE); + vififo_usage += (6 * SZ_1K); // 6 KiB internal fifo + + if (vififo_usage > sess->vififo_size) { + dev_warn(sess->core->dev, + "VIFIFO usage (%u) > VIFIFO size (%u)\n", + vififo_usage, sess->vififo_size); + return 0; + } + + return sess->vififo_size - vififo_usage; +} + +int esparser_queue_eos(struct amvdec_core *core, const u8 *data, u32 len) +{ + struct device *dev = core->dev; + void *eos_vaddr; + dma_addr_t eos_paddr; + int ret; + + eos_vaddr = dma_alloc_coherent(dev, len + SEARCH_PATTERN_LEN, + &eos_paddr, GFP_KERNEL); + if (!eos_vaddr) + return -ENOMEM; + + memcpy(eos_vaddr, data, len); + ret = esparser_write_data(core, eos_paddr, len); + dma_free_coherent(dev, len + SEARCH_PATTERN_LEN, + eos_vaddr, eos_paddr); + + return ret; +} + +static u32 esparser_get_offset(struct amvdec_session *sess) +{ + struct amvdec_core *core = sess->core; + u32 offset = amvdec_read_parser(core, PARSER_VIDEO_WP) - + sess->vififo_paddr; + + if (offset < sess->last_offset) + sess->wrap_count++; + + sess->last_offset = offset; + offset += (sess->wrap_count * sess->vififo_size); + + return offset; +} + +static int +esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) +{ + int ret; + struct vb2_buffer *vb = &vbuf->vb2_buf; + struct amvdec_core *core = sess->core; + struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; + u32 num_dst_bufs = 0; + u32 payload_size = vb2_get_plane_payload(vb, 0); + dma_addr_t phy = vb2_dma_contig_plane_dma_addr(vb, 0); + u32 offset; + u32 pad_size; + + if (codec_ops->num_pending_bufs) + num_dst_bufs = codec_ops->num_pending_bufs(sess); + + num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); + + if (esparser_vififo_get_free_space(sess) < payload_size || + atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs) + return -EAGAIN; + + v4l2_m2m_src_buf_remove_by_buf(sess->m2m_ctx, vbuf); + + offset = esparser_get_offset(sess); + + amvdec_add_ts_reorder(sess, vb->timestamp, offset); + dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X\n", + vb->timestamp, payload_size, offset); + + pad_size = esparser_pad_start_code(vb); + ret = esparser_write_data(core, phy, payload_size + pad_size); + + if (ret <= 0) { + dev_warn(core->dev, "esparser: input parsing error\n"); + amvdec_remove_ts(sess, vb->timestamp); + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + amvdec_write_parser(core, PARSER_FETCH_CMD, 0); + + return 0; + } + + /* We need to wait until we parse the first keyframe. + * All buffers prior to the first keyframe must be dropped. + */ + if (!sess->keyframe_found) + usleep_range(1000, 2000); + + if (sess->keyframe_found) + atomic_inc(&sess->esparser_queued_bufs); + else + amvdec_remove_ts(sess, vb->timestamp); + + vbuf->flags = 0; + vbuf->field = V4L2_FIELD_NONE; + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); + + return 0; +} + +void esparser_queue_all_src(struct work_struct *work) +{ + struct v4l2_m2m_buffer *buf, *n; + struct amvdec_session *sess = + container_of(work, struct amvdec_session, esparser_queue_work); + + mutex_lock(&sess->lock); + v4l2_m2m_for_each_src_buf_safe(sess->m2m_ctx, buf, n) { + if (sess->should_stop) + break; + + if (esparser_queue(sess, &buf->vb) < 0) + break; + } + mutex_unlock(&sess->lock); +} + +int esparser_power_up(struct amvdec_session *sess) +{ + struct amvdec_core *core = sess->core; + struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops; + + reset_control_reset(core->esparser_reset); + amvdec_write_parser(core, PARSER_CONFIG, + (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) | + (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) | + (16 << PS_CFG_MAX_FETCH_CYCLE_BIT)); + + amvdec_write_parser(core, PFIFO_RD_PTR, 0); + amvdec_write_parser(core, PFIFO_WR_PTR, 0); + + amvdec_write_parser(core, PARSER_SEARCH_PATTERN, + ES_START_CODE_PATTERN); + amvdec_write_parser(core, PARSER_SEARCH_MASK, ES_START_CODE_MASK); + + amvdec_write_parser(core, PARSER_CONFIG, + (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) | + (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) | + (16 << PS_CFG_MAX_FETCH_CYCLE_BIT) | + (2 << PS_CFG_STARTCODE_WID_24_BIT)); + + amvdec_write_parser(core, PARSER_CONTROL, + (ES_SEARCH | ES_PARSER_START)); + + amvdec_write_parser(core, PARSER_VIDEO_START_PTR, sess->vififo_paddr); + amvdec_write_parser(core, PARSER_VIDEO_END_PTR, + sess->vififo_paddr + sess->vififo_size - 8); + amvdec_write_parser(core, PARSER_ES_CONTROL, + amvdec_read_parser(core, PARSER_ES_CONTROL) & ~1); + + if (vdec_ops->conf_esparser) + vdec_ops->conf_esparser(sess); + + amvdec_write_parser(core, PARSER_INT_STATUS, 0xffff); + amvdec_write_parser(core, PARSER_INT_ENABLE, + BIT(PARSER_INT_HOST_EN_BIT)); + + return 0; +} + +int esparser_init(struct platform_device *pdev, struct amvdec_core *core) +{ + struct device *dev = &pdev->dev; + int ret; + int irq; + + irq = platform_get_irq_byname(pdev, "esparser"); + if (irq < 0) { + dev_err(dev, "Failed getting ESPARSER IRQ from dtb\n"); + return irq; + } + + ret = devm_request_irq(dev, irq, esparser_isr, IRQF_SHARED, + "esparserirq", core); + if (ret) { + dev_err(dev, "Failed requesting ESPARSER IRQ\n"); + return ret; + } + + core->esparser_reset = + devm_reset_control_get_exclusive(dev, "esparser"); + if (IS_ERR(core->esparser_reset)) { + dev_err(dev, "Failed to get esparser_reset\n"); + return PTR_ERR(core->esparser_reset); + } + + return 0; +} diff --git a/drivers/staging/media/meson/vdec/esparser.h b/drivers/staging/media/meson/vdec/esparser.h new file mode 100644 index 000000000000..ff51fe7fda66 --- /dev/null +++ b/drivers/staging/media/meson/vdec/esparser.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Maxime Jourdan <mjourdan@baylibre.com> + */ + +#ifndef __MESON_VDEC_ESPARSER_H_ +#define __MESON_VDEC_ESPARSER_H_ + +#include <linux/platform_device.h> + +#include "vdec.h" + +int esparser_init(struct platform_device *pdev, struct amvdec_core *core); +int esparser_power_up(struct amvdec_session *sess); + +/** + * esparser_queue_eos() - write End Of Stream sequence to the ESPARSER + * + * @core vdec core struct + */ +int esparser_queue_eos(struct amvdec_core *core, const u8 *data, u32 len); + +/** + * esparser_queue_all_src() - work handler that writes as many src buffers + * as possible to the ESPARSER + */ +void esparser_queue_all_src(struct work_struct *work); + +#define ESPARSER_MIN_PACKET_SIZE SZ_4K + +#endif diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c new file mode 100644 index 000000000000..0a1a04fd5d13 --- /dev/null +++ b/drivers/staging/media/meson/vdec/vdec.c @@ -0,0 +1,1099 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Maxime Jourdan <mjourdan@baylibre.com> + */ + +#include <linux/of_device.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/mfd/syscon.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/kthread.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-mem2mem.h> +#include <media/v4l2-dev.h> +#include <media/videobuf2-dma-contig.h> + +#include "vdec.h" +#include "esparser.h" +#include "vdec_helpers.h" + +struct dummy_buf { + struct vb2_v4l2_buffer vb; + struct list_head list; +}; + +/* 16 MiB for parsed bitstream swap exchange */ +#define SIZE_VIFIFO SZ_16M + +static u32 get_output_size(u32 width, u32 height) +{ + return ALIGN(width * height, SZ_64K); +} + +u32 amvdec_get_output_size(struct amvdec_session *sess) +{ + return get_output_size(sess->width, sess->height); +} +EXPORT_SYMBOL_GPL(amvdec_get_output_size); + +static int vdec_codec_needs_recycle(struct amvdec_session *sess) +{ + struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; + + return codec_ops->can_recycle && codec_ops->recycle; +} + +static int vdec_recycle_thread(void *data) +{ + struct amvdec_session *sess = data; + struct amvdec_core *core = sess->core; + struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; + struct amvdec_buffer *tmp, *n; + + while (!kthread_should_stop()) { + mutex_lock(&sess->bufs_recycle_lock); + list_for_each_entry_safe(tmp, n, &sess->bufs_recycle, list) { + if (!codec_ops->can_recycle(core)) + break; + + codec_ops->recycle(core, tmp->vb->index); + list_del(&tmp->list); + kfree(tmp); + } + mutex_unlock(&sess->bufs_recycle_lock); + + usleep_range(5000, 10000); + } + + return 0; +} + +static int vdec_poweron(struct amvdec_session *sess) +{ + int ret; + struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops; + + ret = clk_prepare_enable(sess->core->dos_parser_clk); + if (ret) + return ret; + + ret = clk_prepare_enable(sess->core->dos_clk); + if (ret) + goto disable_dos_parser; + + ret = vdec_ops->start(sess); + if (ret) + goto disable_dos; + + esparser_power_up(sess); + + return 0; + +disable_dos: + clk_disable_unprepare(sess->core->dos_clk); +disable_dos_parser: + clk_disable_unprepare(sess->core->dos_parser_clk); + + return ret; +} + +static void vdec_wait_inactive(struct amvdec_session *sess) +{ + /* We consider 50ms with no IRQ to be inactive. */ + while (time_is_after_jiffies64(sess->last_irq_jiffies + + msecs_to_jiffies(50))) + msleep(25); +} + +static void vdec_poweroff(struct amvdec_session *sess) +{ + struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops; + struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; + + sess->should_stop = 1; + vdec_wait_inactive(sess); + if (codec_ops->drain) + codec_ops->drain(sess); + + vdec_ops->stop(sess); + clk_disable_unprepare(sess->core->dos_clk); + clk_disable_unprepare(sess->core->dos_parser_clk); +} + +static void +vdec_queue_recycle(struct amvdec_session *sess, struct vb2_buffer *vb) +{ + struct amvdec_buffer *new_buf; + + new_buf = kmalloc(sizeof(*new_buf), GFP_KERNEL); + new_buf->vb = vb; + + mutex_lock(&sess->bufs_recycle_lock); + list_add_tail(&new_buf->list, &sess->bufs_recycle); + mutex_unlock(&sess->bufs_recycle_lock); +} + +static void vdec_m2m_device_run(void *priv) +{ + struct amvdec_session *sess = priv; + + schedule_work(&sess->esparser_queue_work); +} + +static void vdec_m2m_job_abort(void *priv) +{ + struct amvdec_session *sess = priv; + + v4l2_m2m_job_finish(sess->m2m_dev, sess->m2m_ctx); +} + +static const struct v4l2_m2m_ops vdec_m2m_ops = { + .device_run = vdec_m2m_device_run, + .job_abort = vdec_m2m_job_abort, +}; + +static void process_num_buffers(struct vb2_queue *q, + struct amvdec_session *sess, + unsigned int *num_buffers, + bool is_reqbufs) +{ + const struct amvdec_format *fmt_out = sess->fmt_out; + unsigned int buffers_total = q->num_buffers + *num_buffers; + + if (is_reqbufs && buffers_total < fmt_out->min_buffers) + *num_buffers = fmt_out->min_buffers - q->num_buffers; + if (buffers_total > fmt_out->max_buffers) + *num_buffers = fmt_out->max_buffers - q->num_buffers; + + /* We need to program the complete CAPTURE buffer list + * in registers during start_streaming, and the firmwares + * are free to choose any of them to write frames to. As such, + * we need all of them to be queued into the driver + */ + sess->num_dst_bufs = q->num_buffers + *num_buffers; + q->min_buffers_needed = max(fmt_out->min_buffers, sess->num_dst_bufs); +} + +static int vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct amvdec_session *sess = vb2_get_drv_priv(q); + u32 output_size = amvdec_get_output_size(sess); + + if (*num_planes) { + switch (q->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (*num_planes != 1 || sizes[0] < output_size) + return -EINVAL; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + switch (sess->pixfmt_cap) { + case V4L2_PIX_FMT_NV12M: + if (*num_planes != 2 || + sizes[0] < output_size || + sizes[1] < output_size / 2) + return -EINVAL; + break; + case V4L2_PIX_FMT_YUV420M: + if (*num_planes != 3 || + sizes[0] < output_size || + sizes[1] < output_size / 4 || + sizes[2] < output_size / 4) + return -EINVAL; + break; + default: + return -EINVAL; + } + + process_num_buffers(q, sess, num_buffers, false); + break; + } + + return 0; + } + + switch (q->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + sizes[0] = amvdec_get_output_size(sess); + *num_planes = 1; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + switch (sess->pixfmt_cap) { + case V4L2_PIX_FMT_NV12M: + sizes[0] = output_size; + sizes[1] = output_size / 2; + *num_planes = 2; + break; + case V4L2_PIX_FMT_YUV420M: + sizes[0] = output_size; + sizes[1] = output_size / 4; + sizes[2] = output_size / 4; + *num_planes = 3; + break; + default: + return -EINVAL; + } + + process_num_buffers(q, sess, num_buffers, true); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void vdec_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct amvdec_session *sess = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_m2m_ctx *m2m_ctx = sess->m2m_ctx; + + v4l2_m2m_buf_queue(m2m_ctx, vbuf); + + if (!sess->streamon_out || !sess->streamon_cap) + return; + + if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + vdec_codec_needs_recycle(sess)) + vdec_queue_recycle(sess, vb); + + schedule_work(&sess->esparser_queue_work); +} + +static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct amvdec_session *sess = vb2_get_drv_priv(q); + struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; + struct amvdec_core *core = sess->core; + struct vb2_v4l2_buffer *buf; + int ret; + + if (core->cur_sess && core->cur_sess != sess) { + ret = -EBUSY; + goto bufs_done; + } + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + sess->streamon_out = 1; + else + sess->streamon_cap = 1; + + if (!sess->streamon_out || !sess->streamon_cap) + return 0; + + if (sess->status == STATUS_NEEDS_RESUME && + q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + codec_ops->resume(sess); + sess->status = STATUS_RUNNING; + return 0; + } + + sess->vififo_size = SIZE_VIFIFO; + sess->vififo_vaddr = + dma_alloc_coherent(sess->core->dev, sess->vififo_size, + &sess->vififo_paddr, GFP_KERNEL); + if (!sess->vififo_vaddr) { + dev_err(sess->core->dev, "Failed to request VIFIFO buffer\n"); + ret = -ENOMEM; + goto bufs_done; + } + + sess->should_stop = 0; + sess->keyframe_found = 0; + sess->last_offset = 0; + sess->wrap_count = 0; + sess->pixelaspect.numerator = 1; + sess->pixelaspect.denominator = 1; + atomic_set(&sess->esparser_queued_bufs, 0); + v4l2_ctrl_s_ctrl(sess->ctrl_min_buf_capture, 1); + + ret = vdec_poweron(sess); + if (ret) + goto vififo_free; + + sess->sequence_cap = 0; + if (vdec_codec_needs_recycle(sess)) + sess->recycle_thread = kthread_run(vdec_recycle_thread, sess, + "vdec_recycle"); + + sess->status = STATUS_RUNNING; + core->cur_sess = sess; + + return 0; + +vififo_free: + dma_free_coherent(sess->core->dev, sess->vififo_size, + sess->vififo_vaddr, sess->vififo_paddr); +bufs_done: + while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); + while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + sess->streamon_out = 0; + else + sess->streamon_cap = 0; + + return ret; +} + +static void vdec_free_canvas(struct amvdec_session *sess) +{ + int i; + + for (i = 0; i < sess->canvas_num; ++i) + meson_canvas_free(sess->core->canvas, sess->canvas_alloc[i]); + + sess->canvas_num = 0; +} + +static void vdec_reset_timestamps(struct amvdec_session *sess) +{ + struct amvdec_timestamp *tmp, *n; + + list_for_each_entry_safe(tmp, n, &sess->timestamps, list) { + list_del(&tmp->list); + kfree(tmp); + } +} + +static void vdec_reset_bufs_recycle(struct amvdec_session *sess) +{ + struct amvdec_buffer *tmp, *n; + + list_for_each_entry_safe(tmp, n, &sess->bufs_recycle, list) { + list_del(&tmp->list); + kfree(tmp); + } +} + +static void vdec_stop_streaming(struct vb2_queue *q) +{ + struct amvdec_session *sess = vb2_get_drv_priv(q); + struct amvdec_core *core = sess->core; + struct vb2_v4l2_buffer *buf; + + if (sess->status == STATUS_RUNNING || + (sess->status == STATUS_NEEDS_RESUME && + (!sess->streamon_out || !sess->streamon_cap))) { + if (vdec_codec_needs_recycle(sess)) + kthread_stop(sess->recycle_thread); + + vdec_poweroff(sess); + vdec_free_canvas(sess); + dma_free_coherent(sess->core->dev, sess->vififo_size, + sess->vififo_vaddr, sess->vififo_paddr); + vdec_reset_timestamps(sess); + vdec_reset_bufs_recycle(sess); + kfree(sess->priv); + sess->priv = NULL; + core->cur_sess = NULL; + sess->status = STATUS_STOPPED; + } + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); + + sess->streamon_out = 0; + } else { + while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); + + sess->streamon_cap = 0; + } +} + +static int vdec_vb2_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + vbuf->field = V4L2_FIELD_NONE; + return 0; +} + +static const struct vb2_ops vdec_vb2_ops = { + .queue_setup = vdec_queue_setup, + .start_streaming = vdec_start_streaming, + .stop_streaming = vdec_stop_streaming, + .buf_queue = vdec_vb2_buf_queue, + .buf_prepare = vdec_vb2_buf_prepare, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int +vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + strscpy(cap->driver, "meson-vdec", sizeof(cap->driver)); + strscpy(cap->card, "Amlogic Video Decoder", sizeof(cap->card)); + strscpy(cap->bus_info, "platform:meson-vdec", sizeof(cap->bus_info)); + + return 0; +} + +static const struct amvdec_format * +find_format(const struct amvdec_format *fmts, u32 size, u32 pixfmt) +{ + unsigned int i; + + for (i = 0; i < size; i++) { + if (fmts[i].pixfmt == pixfmt) + return &fmts[i]; + } + + return NULL; +} + +static unsigned int +vdec_supports_pixfmt_cap(const struct amvdec_format *fmt_out, u32 pixfmt_cap) +{ + int i; + + for (i = 0; fmt_out->pixfmts_cap[i]; i++) + if (fmt_out->pixfmts_cap[i] == pixfmt_cap) + return 1; + + return 0; +} + +static const struct amvdec_format * +vdec_try_fmt_common(struct amvdec_session *sess, u32 size, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt; + const struct amvdec_format *fmts = sess->core->platform->formats; + const struct amvdec_format *fmt_out; + + memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved)); + memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + fmt_out = find_format(fmts, size, pixmp->pixelformat); + if (!fmt_out) { + pixmp->pixelformat = V4L2_PIX_FMT_MPEG2; + fmt_out = find_format(fmts, size, pixmp->pixelformat); + } + + pfmt[0].sizeimage = + get_output_size(pixmp->width, pixmp->height); + pfmt[0].bytesperline = 0; + pixmp->num_planes = 1; + } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fmt_out = sess->fmt_out; + if (!vdec_supports_pixfmt_cap(fmt_out, pixmp->pixelformat)) + pixmp->pixelformat = fmt_out->pixfmts_cap[0]; + + memset(pfmt[1].reserved, 0, sizeof(pfmt[1].reserved)); + if (pixmp->pixelformat == V4L2_PIX_FMT_NV12M) { + pfmt[0].sizeimage = + get_output_size(pixmp->width, pixmp->height); + pfmt[0].bytesperline = ALIGN(pixmp->width, 64); + + pfmt[1].sizeimage = + get_output_size(pixmp->width, pixmp->height) / 2; + pfmt[1].bytesperline = ALIGN(pixmp->width, 64); + pixmp->num_planes = 2; + } else if (pixmp->pixelformat == V4L2_PIX_FMT_YUV420M) { + pfmt[0].sizeimage = + get_output_size(pixmp->width, pixmp->height); + pfmt[0].bytesperline = ALIGN(pixmp->width, 64); + + pfmt[1].sizeimage = + get_output_size(pixmp->width, pixmp->height) / 4; + pfmt[1].bytesperline = ALIGN(pixmp->width, 64) / 2; + + pfmt[2].sizeimage = + get_output_size(pixmp->width, pixmp->height) / 4; + pfmt[2].bytesperline = ALIGN(pixmp->width, 64) / 2; + pixmp->num_planes = 3; + } + } else { + return NULL; + } + + pixmp->width = clamp(pixmp->width, (u32)256, fmt_out->max_width); + pixmp->height = clamp(pixmp->height, (u32)144, fmt_out->max_height); + + if (pixmp->field == V4L2_FIELD_ANY) + pixmp->field = V4L2_FIELD_NONE; + + return fmt_out; +} + +static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct amvdec_session *sess = + container_of(file->private_data, struct amvdec_session, fh); + + vdec_try_fmt_common(sess, sess->core->platform->num_formats, f); + + return 0; +} + +static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct amvdec_session *sess = + container_of(file->private_data, struct amvdec_session, fh); + struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + pixmp->pixelformat = sess->pixfmt_cap; + else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + pixmp->pixelformat = sess->fmt_out->pixfmt; + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + pixmp->width = sess->width; + pixmp->height = sess->height; + pixmp->colorspace = sess->colorspace; + pixmp->ycbcr_enc = sess->ycbcr_enc; + pixmp->quantization = sess->quantization; + pixmp->xfer_func = sess->xfer_func; + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + pixmp->width = sess->width; + pixmp->height = sess->height; + } + + vdec_try_fmt_common(sess, sess->core->platform->num_formats, f); + + return 0; +} + +static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct amvdec_session *sess = + container_of(file->private_data, struct amvdec_session, fh); + struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + u32 num_formats = sess->core->platform->num_formats; + const struct amvdec_format *fmt_out; + struct v4l2_pix_format_mplane orig_pixmp; + struct v4l2_format format; + u32 pixfmt_out = 0, pixfmt_cap = 0; + + orig_pixmp = *pixmp; + + fmt_out = vdec_try_fmt_common(sess, num_formats, f); + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + pixfmt_out = pixmp->pixelformat; + pixfmt_cap = sess->pixfmt_cap; + } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + pixfmt_cap = pixmp->pixelformat; + pixfmt_out = sess->fmt_out->pixfmt; + } + + memset(&format, 0, sizeof(format)); + + format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + format.fmt.pix_mp.pixelformat = pixfmt_out; + format.fmt.pix_mp.width = orig_pixmp.width; + format.fmt.pix_mp.height = orig_pixmp.height; + vdec_try_fmt_common(sess, num_formats, &format); + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + sess->width = format.fmt.pix_mp.width; + sess->height = format.fmt.pix_mp.height; + sess->colorspace = pixmp->colorspace; + sess->ycbcr_enc = pixmp->ycbcr_enc; + sess->quantization = pixmp->quantization; + sess->xfer_func = pixmp->xfer_func; + } + + memset(&format, 0, sizeof(format)); + + format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + format.fmt.pix_mp.pixelformat = pixfmt_cap; + format.fmt.pix_mp.width = orig_pixmp.width; + format.fmt.pix_mp.height = orig_pixmp.height; + vdec_try_fmt_common(sess, num_formats, &format); + + sess->width = format.fmt.pix_mp.width; + sess->height = format.fmt.pix_mp.height; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + sess->fmt_out = fmt_out; + else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + sess->pixfmt_cap = format.fmt.pix_mp.pixelformat; + + return 0; +} + +static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct amvdec_session *sess = + container_of(file->private_data, struct amvdec_session, fh); + const struct vdec_platform *platform = sess->core->platform; + const struct amvdec_format *fmt_out; + + memset(f->reserved, 0, sizeof(f->reserved)); + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (f->index >= platform->num_formats) + return -EINVAL; + + fmt_out = &platform->formats[f->index]; + f->pixelformat = fmt_out->pixfmt; + f->flags = fmt_out->flags; + } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fmt_out = sess->fmt_out; + if (f->index >= 4 || !fmt_out->pixfmts_cap[f->index]) + return -EINVAL; + + f->pixelformat = fmt_out->pixfmts_cap[f->index]; + } else { + return -EINVAL; + } + + return 0; +} + +static int vdec_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct amvdec_session *sess = + container_of(file->private_data, struct amvdec_session, fh); + const struct amvdec_format *formats = sess->core->platform->formats; + const struct amvdec_format *fmt; + u32 num_formats = sess->core->platform->num_formats; + + fmt = find_format(formats, num_formats, fsize->pixel_format); + if (!fmt || fsize->index) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + + fsize->stepwise.min_width = 256; + fsize->stepwise.max_width = fmt->max_width; + fsize->stepwise.step_width = 1; + fsize->stepwise.min_height = 144; + fsize->stepwise.max_height = fmt->max_height; + fsize->stepwise.step_height = 1; + + return 0; +} + +static int +vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) +{ + struct amvdec_session *sess = + container_of(file->private_data, struct amvdec_session, fh); + struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; + struct device *dev = sess->core->dev; + int ret; + + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, cmd); + if (ret) + return ret; + + if (!(sess->streamon_out & sess->streamon_cap)) + return 0; + + /* Currently not handled since we do not support dynamic resolution + * for MPEG2. We consider both queues streaming to mean that the + * decoding session is started + */ + if (cmd->cmd == V4L2_DEC_CMD_START) + return 0; + + /* Should not happen */ + if (cmd->cmd != V4L2_DEC_CMD_STOP) + return -EINVAL; + + dev_dbg(dev, "Received V4L2_DEC_CMD_STOP\n"); + sess->should_stop = 1; + + vdec_wait_inactive(sess); + + if (codec_ops->drain) { + codec_ops->drain(sess); + } else if (codec_ops->eos_sequence) { + u32 len; + const u8 *data = codec_ops->eos_sequence(&len); + + esparser_queue_eos(sess->core, data, len); + } + + return ret; +} + +static int vdec_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_event_subscribe(fh, sub, 0, NULL); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); + default: + return -EINVAL; + } +} + +static int vdec_g_pixelaspect(struct file *file, void *fh, int type, + struct v4l2_fract *f) +{ + struct amvdec_session *sess = + container_of(file->private_data, struct amvdec_session, fh); + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + *f = sess->pixelaspect; + return 0; +} + +static const struct v4l2_ioctl_ops vdec_ioctl_ops = { + .vidioc_querycap = vdec_querycap, + .vidioc_enum_fmt_vid_cap = vdec_enum_fmt, + .vidioc_enum_fmt_vid_out = vdec_enum_fmt, + .vidioc_s_fmt_vid_cap_mplane = vdec_s_fmt, + .vidioc_s_fmt_vid_out_mplane = vdec_s_fmt, + .vidioc_g_fmt_vid_cap_mplane = vdec_g_fmt, + .vidioc_g_fmt_vid_out_mplane = vdec_g_fmt, + .vidioc_try_fmt_vid_cap_mplane = vdec_try_fmt, + .vidioc_try_fmt_vid_out_mplane = vdec_try_fmt, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_enum_framesizes = vdec_enum_framesizes, + .vidioc_subscribe_event = vdec_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, + .vidioc_decoder_cmd = vdec_decoder_cmd, + .vidioc_g_pixelaspect = vdec_g_pixelaspect, +}; + +static int m2m_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct amvdec_session *sess = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->ops = &vdec_vb2_ops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->drv_priv = sess; + src_vq->buf_struct_size = sizeof(struct dummy_buf); + src_vq->min_buffers_needed = 1; + src_vq->dev = sess->core->dev; + src_vq->lock = &sess->lock; + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->ops = &vdec_vb2_ops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->drv_priv = sess; + dst_vq->buf_struct_size = sizeof(struct dummy_buf); + dst_vq->min_buffers_needed = 1; + dst_vq->dev = sess->core->dev; + dst_vq->lock = &sess->lock; + ret = vb2_queue_init(dst_vq); + if (ret) { + vb2_queue_release(src_vq); + return ret; + } + + return 0; +} + +static int vdec_init_ctrls(struct amvdec_session *sess) +{ + struct v4l2_ctrl_handler *ctrl_handler = &sess->ctrl_handler; + int ret; + + ret = v4l2_ctrl_handler_init(ctrl_handler, 1); + if (ret) + return ret; + + sess->ctrl_min_buf_capture = + v4l2_ctrl_new_std(ctrl_handler, NULL, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, + 1); + + ret = ctrl_handler->error; + if (ret) { + v4l2_ctrl_handler_free(ctrl_handler); + return ret; + } + + return 0; +} + +static int vdec_open(struct file *file) +{ + struct amvdec_core *core = video_drvdata(file); + struct device *dev = core->dev; + const struct amvdec_format *formats = core->platform->formats; + struct amvdec_session *sess; + int ret; + + sess = kzalloc(sizeof(*sess), GFP_KERNEL); + if (!sess) + return -ENOMEM; + + sess->core = core; + + sess->m2m_dev = v4l2_m2m_init(&vdec_m2m_ops); + if (IS_ERR(sess->m2m_dev)) { + dev_err(dev, "Fail to v4l2_m2m_init\n"); + ret = PTR_ERR(sess->m2m_dev); + goto err_free_sess; + } + + sess->m2m_ctx = v4l2_m2m_ctx_init(sess->m2m_dev, sess, m2m_queue_init); + if (IS_ERR(sess->m2m_ctx)) { + dev_err(dev, "Fail to v4l2_m2m_ctx_init\n"); + ret = PTR_ERR(sess->m2m_ctx); + goto err_m2m_release; + } + + ret = vdec_init_ctrls(sess); + if (ret) + goto err_m2m_release; + + sess->pixfmt_cap = formats[0].pixfmts_cap[0]; + sess->fmt_out = &formats[0]; + sess->width = 1280; + sess->height = 720; + sess->pixelaspect.numerator = 1; + sess->pixelaspect.denominator = 1; + + INIT_LIST_HEAD(&sess->timestamps); + INIT_LIST_HEAD(&sess->bufs_recycle); + INIT_WORK(&sess->esparser_queue_work, esparser_queue_all_src); + mutex_init(&sess->lock); + mutex_init(&sess->bufs_recycle_lock); + spin_lock_init(&sess->ts_spinlock); + + v4l2_fh_init(&sess->fh, core->vdev_dec); + sess->fh.ctrl_handler = &sess->ctrl_handler; + v4l2_fh_add(&sess->fh); + sess->fh.m2m_ctx = sess->m2m_ctx; + file->private_data = &sess->fh; + + return 0; + +err_m2m_release: + v4l2_m2m_release(sess->m2m_dev); +err_free_sess: + kfree(sess); + return ret; +} + +static int vdec_close(struct file *file) +{ + struct amvdec_session *sess = + container_of(file->private_data, struct amvdec_session, fh); + + v4l2_m2m_ctx_release(sess->m2m_ctx); + v4l2_m2m_release(sess->m2m_dev); + v4l2_fh_del(&sess->fh); + v4l2_fh_exit(&sess->fh); + + mutex_destroy(&sess->lock); + mutex_destroy(&sess->bufs_recycle_lock); + + kfree(sess); + + return 0; +} + +static const struct v4l2_file_operations vdec_fops = { + .owner = THIS_MODULE, + .open = vdec_open, + .release = vdec_close, + .unlocked_ioctl = video_ioctl2, + .poll = v4l2_m2m_fop_poll, + .mmap = v4l2_m2m_fop_mmap, +}; + +static irqreturn_t vdec_isr(int irq, void *data) +{ + struct amvdec_core *core = data; + struct amvdec_session *sess = core->cur_sess; + + sess->last_irq_jiffies = get_jiffies_64(); + + return sess->fmt_out->codec_ops->isr(sess); +} + +static irqreturn_t vdec_threaded_isr(int irq, void *data) +{ + struct amvdec_core *core = data; + struct amvdec_session *sess = core->cur_sess; + + return sess->fmt_out->codec_ops->threaded_isr(sess); +} + +static const struct of_device_id vdec_dt_match[] = { + { .compatible = "amlogic,gxbb-vdec", + .data = &vdec_platform_gxbb }, + { .compatible = "amlogic,gxm-vdec", + .data = &vdec_platform_gxm }, + { .compatible = "amlogic,gxl-vdec", + .data = &vdec_platform_gxl }, + {} +}; +MODULE_DEVICE_TABLE(of, vdec_dt_match); + +static int vdec_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct video_device *vdev; + struct amvdec_core *core; + struct resource *r; + const struct of_device_id *of_id; + int irq; + int ret; + + core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL); + if (!core) + return -ENOMEM; + + core->dev = dev; + platform_set_drvdata(pdev, core); + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dos"); + core->dos_base = devm_ioremap_resource(dev, r); + if (IS_ERR(core->dos_base)) { + dev_err(dev, "Couldn't remap DOS memory\n"); + return PTR_ERR(core->dos_base); + } + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "esparser"); + core->esparser_base = devm_ioremap_resource(dev, r); + if (IS_ERR(core->esparser_base)) { + dev_err(dev, "Couldn't remap ESPARSER memory\n"); + return PTR_ERR(core->esparser_base); + } + + core->regmap_ao = + syscon_regmap_lookup_by_phandle(dev->of_node, + "amlogic,ao-sysctrl"); + if (IS_ERR(core->regmap_ao)) { + dev_err(dev, "Couldn't regmap AO sysctrl\n"); + return PTR_ERR(core->regmap_ao); + } + + core->canvas = meson_canvas_get(dev); + if (IS_ERR(core->canvas)) + return PTR_ERR(core->canvas); + + core->dos_parser_clk = devm_clk_get(dev, "dos_parser"); + if (IS_ERR(core->dos_parser_clk)) + return -EPROBE_DEFER; + + core->dos_clk = devm_clk_get(dev, "dos"); + if (IS_ERR(core->dos_clk)) + return -EPROBE_DEFER; + + core->vdec_1_clk = devm_clk_get(dev, "vdec_1"); + if (IS_ERR(core->vdec_1_clk)) + return -EPROBE_DEFER; + + core->vdec_hevc_clk = devm_clk_get(dev, "vdec_hevc"); + if (IS_ERR(core->vdec_hevc_clk)) + return -EPROBE_DEFER; + + irq = platform_get_irq_byname(pdev, "vdec"); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(core->dev, irq, vdec_isr, + vdec_threaded_isr, IRQF_ONESHOT, + "vdec", core); + if (ret) + return ret; + + ret = esparser_init(pdev, core); + if (ret) + return ret; + + ret = v4l2_device_register(dev, &core->v4l2_dev); + if (ret) { + dev_err(dev, "Couldn't register v4l2 device\n"); + return -ENOMEM; + } + + vdev = video_device_alloc(); + if (!vdev) { + ret = -ENOMEM; + goto err_vdev_release; + } + + of_id = of_match_node(vdec_dt_match, dev->of_node); + core->platform = of_id->data; + core->vdev_dec = vdev; + core->dev_dec = dev; + mutex_init(&core->lock); + + strscpy(vdev->name, "meson-video-decoder", sizeof(vdev->name)); + vdev->release = video_device_release; + vdev->fops = &vdec_fops; + vdev->ioctl_ops = &vdec_ioctl_ops; + vdev->vfl_dir = VFL_DIR_M2M; + vdev->v4l2_dev = &core->v4l2_dev; + vdev->lock = &core->lock; + vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + + video_set_drvdata(vdev, core); + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret) { + dev_err(dev, "Failed registering video device\n"); + goto err_vdev_release; + } + + return 0; + +err_vdev_release: + video_device_release(vdev); + return ret; +} + +static int vdec_remove(struct platform_device *pdev) +{ + struct amvdec_core *core = platform_get_drvdata(pdev); + + video_unregister_device(core->vdev_dec); + + return 0; +} + +static struct platform_driver meson_vdec_driver = { + .probe = vdec_probe, + .remove = vdec_remove, + .driver = { + .name = "meson-vdec", + .of_match_table = vdec_dt_match, + }, +}; +module_platform_driver(meson_vdec_driver); + +MODULE_DESCRIPTION("Meson video decoder driver for GXBB/GXL/GXM"); +MODULE_AUTHOR("Maxime Jourdan <mjourdan@baylibre.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/meson/vdec/vdec.h b/drivers/staging/media/meson/vdec/vdec.h new file mode 100644 index 000000000000..d811e7976519 --- /dev/null +++ b/drivers/staging/media/meson/vdec/vdec.h @@ -0,0 +1,267 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Maxime Jourdan <mjourdan@baylibre.com> + */ + +#ifndef __MESON_VDEC_CORE_H_ +#define __MESON_VDEC_CORE_H_ + +#include <linux/irqreturn.h> +#include <linux/regmap.h> +#include <linux/list.h> +#include <media/videobuf2-v4l2.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <linux/soc/amlogic/meson-canvas.h> + +#include "vdec_platform.h" + +/* 32 buffers in 3-plane YUV420 */ +#define MAX_CANVAS (32 * 3) + +struct amvdec_buffer { + struct list_head list; + struct vb2_buffer *vb; +}; + +/** + * struct amvdec_timestamp - stores a src timestamp along with a VIFIFO offset + * + * @list: used to make lists out of this struct + * @ts: timestamp + * @offset: offset in the VIFIFO where the associated packet was written + */ +struct amvdec_timestamp { + struct list_head list; + u64 ts; + u32 offset; +}; + +struct amvdec_session; + +/** + * struct amvdec_core - device parameters, singleton + * + * @dos_base: DOS memory base address + * @esparser_base: PARSER memory base address + * @regmap_ao: regmap for the AO bus + * @dev: core device + * @dev_dec: decoder device + * @platform: platform-specific data + * @canvas: canvas provider reference + * @dos_parser_clk: DOS_PARSER clock + * @dos_clk: DOS clock + * @vdec_1_clk: VDEC_1 clock + * @vdec_hevc_clk: VDEC_HEVC clock + * @esparser_reset: RESET for the PARSER + * @vdec_dec: video device for the decoder + * @v4l2_dev: v4l2 device + * @cur_sess: current decoding session + */ +struct amvdec_core { + void __iomem *dos_base; + void __iomem *esparser_base; + struct regmap *regmap_ao; + + struct device *dev; + struct device *dev_dec; + const struct vdec_platform *platform; + + struct meson_canvas *canvas; + + struct clk *dos_parser_clk; + struct clk *dos_clk; + struct clk *vdec_1_clk; + struct clk *vdec_hevc_clk; + + struct reset_control *esparser_reset; + + struct video_device *vdev_dec; + struct v4l2_device v4l2_dev; + + struct amvdec_session *cur_sess; + struct mutex lock; /* video device lock */ +}; + +/** + * struct amvdec_ops - vdec operations + * + * @start: mandatory call when the vdec needs to initialize + * @stop: mandatory call when the vdec needs to stop + * @conf_esparser: mandatory call to let the vdec configure the ESPARSER + * @vififo_level: mandatory call to get the current amount of data + * in the VIFIFO + * @use_offsets: mandatory call. Returns 1 if the VDEC supports vififo offsets + */ +struct amvdec_ops { + int (*start)(struct amvdec_session *sess); + int (*stop)(struct amvdec_session *sess); + void (*conf_esparser)(struct amvdec_session *sess); + u32 (*vififo_level)(struct amvdec_session *sess); +}; + +/** + * struct amvdec_codec_ops - codec operations + * + * @start: mandatory call when the codec needs to initialize + * @stop: mandatory call when the codec needs to stop + * @load_extended_firmware: optional call to load additional firmware bits + * @num_pending_bufs: optional call to get the number of dst buffers on hold + * @can_recycle: optional call to know if the codec is ready to recycle + * a dst buffer + * @recycle: optional call to tell the codec to recycle a dst buffer. Must go + * in pair with @can_recycle + * @drain: optional call if the codec has a custom way of draining + * @eos_sequence: optional call to get an end sequence to send to esparser + * for flush. Mutually exclusive with @drain. + * @isr: mandatory call when the ISR triggers + * @threaded_isr: mandatory call for the threaded ISR + */ +struct amvdec_codec_ops { + int (*start)(struct amvdec_session *sess); + int (*stop)(struct amvdec_session *sess); + int (*load_extended_firmware)(struct amvdec_session *sess, + const u8 *data, u32 len); + u32 (*num_pending_bufs)(struct amvdec_session *sess); + int (*can_recycle)(struct amvdec_core *core); + void (*recycle)(struct amvdec_core *core, u32 buf_idx); + void (*drain)(struct amvdec_session *sess); + void (*resume)(struct amvdec_session *sess); + const u8 * (*eos_sequence)(u32 *len); + irqreturn_t (*isr)(struct amvdec_session *sess); + irqreturn_t (*threaded_isr)(struct amvdec_session *sess); +}; + +/** + * struct amvdec_format - describes one of the OUTPUT (src) format supported + * + * @pixfmt: V4L2 pixel format + * @min_buffers: minimum amount of CAPTURE (dst) buffers + * @max_buffers: maximum amount of CAPTURE (dst) buffers + * @max_width: maximum picture width supported + * @max_height: maximum picture height supported + * @flags: enum flags associated with this pixfmt + * @vdec_ops: the VDEC operations that support this format + * @codec_ops: the codec operations that support this format + * @firmware_path: Path to the firmware that supports this format + * @pixfmts_cap: list of CAPTURE pixel formats available with pixfmt + */ +struct amvdec_format { + u32 pixfmt; + u32 min_buffers; + u32 max_buffers; + u32 max_width; + u32 max_height; + u32 flags; + + struct amvdec_ops *vdec_ops; + struct amvdec_codec_ops *codec_ops; + + char *firmware_path; + u32 pixfmts_cap[4]; +}; + +enum amvdec_status { + STATUS_STOPPED, + STATUS_RUNNING, + STATUS_NEEDS_RESUME, +}; + +/** + * struct amvdec_session - decoding session parameters + * + * @core: reference to the vdec core struct + * @fh: v4l2 file handle + * @m2m_dev: v4l2 m2m device + * @m2m_ctx: v4l2 m2m context + * @ctrl_handler: V4L2 control handler + * @ctrl_min_buf_capture: V4L2 control V4L2_CID_MIN_BUFFERS_FOR_CAPTURE + * @fmt_out: vdec pixel format for the OUTPUT queue + * @pixfmt_cap: V4L2 pixel format for the CAPTURE queue + * @width: current picture width + * @height: current picture height + * @colorspace: current colorspace + * @ycbcr_enc: current ycbcr_enc + * @quantization: current quantization + * @xfer_func: current transfer function + * @pixelaspect: Pixel Aspect Ratio reported by the decoder + * @esparser_queued_bufs: number of buffers currently queued into ESPARSER + * @esparser_queue_work: work struct for the ESPARSER to process src buffers + * @streamon_cap: stream on flag for capture queue + * @streamon_out: stream on flag for output queue + * @sequence_cap: capture sequence counter + * @should_stop: flag set if userspace signaled EOS via command + * or empty buffer + * @keyframe_found: flag set once a keyframe has been parsed + * @canvas_alloc: array of all the canvas IDs allocated + * @canvas_num: number of canvas IDs allocated + * @vififo_vaddr: virtual address for the VIFIFO + * @vififo_paddr: physical address for the VIFIFO + * @vififo_size: size of the VIFIFO dma alloc + * @bufs_recycle: list of buffers that need to be recycled + * @bufs_recycle_lock: lock for the bufs_recycle list + * @recycle_thread: task struct for the recycling thread + * @timestamps: chronological list of src timestamps + * @ts_spinlock: spinlock for the timestamps list + * @last_irq_jiffies: tracks last time the vdec triggered an IRQ + * @status: current decoding status + * @priv: codec private data + */ +struct amvdec_session { + struct amvdec_core *core; + + struct v4l2_fh fh; + struct v4l2_m2m_dev *m2m_dev; + struct v4l2_m2m_ctx *m2m_ctx; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *ctrl_min_buf_capture; + struct mutex lock; /* cap & out queues lock */ + + const struct amvdec_format *fmt_out; + u32 pixfmt_cap; + + u32 width; + u32 height; + u32 colorspace; + u8 ycbcr_enc; + u8 quantization; + u8 xfer_func; + + struct v4l2_fract pixelaspect; + + atomic_t esparser_queued_bufs; + struct work_struct esparser_queue_work; + + unsigned int streamon_cap, streamon_out; + unsigned int sequence_cap; + unsigned int should_stop; + unsigned int keyframe_found; + unsigned int num_dst_bufs; + + u8 canvas_alloc[MAX_CANVAS]; + u32 canvas_num; + + void *vififo_vaddr; + dma_addr_t vififo_paddr; + u32 vififo_size; + + struct list_head bufs_recycle; + struct mutex bufs_recycle_lock; /* bufs_recycle list lock */ + struct task_struct *recycle_thread; + + struct list_head timestamps; + spinlock_t ts_spinlock; /* timestamp list lock */ + + u64 last_irq_jiffies; + u32 last_offset; + u32 wrap_count; + u32 fw_idx_to_vb2_idx[32]; + + enum amvdec_status status; + void *priv; +}; + +u32 amvdec_get_output_size(struct amvdec_session *sess); + +#endif diff --git a/drivers/staging/media/meson/vdec/vdec_1.c b/drivers/staging/media/meson/vdec/vdec_1.c new file mode 100644 index 000000000000..3a15c6fc0567 --- /dev/null +++ b/drivers/staging/media/meson/vdec/vdec_1.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Maxime Jourdan <mjourdan@baylibre.com> + * + * VDEC_1 is a video decoding block that allows decoding of + * MPEG 1/2/4, H.263, H.264, MJPEG, VC1 + */ + +#include <linux/firmware.h> +#include <linux/clk.h> + +#include "vdec_1.h" +#include "vdec_helpers.h" +#include "dos_regs.h" + +/* AO Registers */ +#define AO_RTI_GEN_PWR_SLEEP0 0xe8 +#define AO_RTI_GEN_PWR_ISO0 0xec + #define GEN_PWR_VDEC_1 (BIT(3) | BIT(2)) + +#define MC_SIZE (4096 * 4) + +static int +vdec_1_load_firmware(struct amvdec_session *sess, const char *fwname) +{ + const struct firmware *fw; + struct amvdec_core *core = sess->core; + struct device *dev = core->dev_dec; + struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; + static void *mc_addr; + static dma_addr_t mc_addr_map; + int ret; + u32 i = 1000; + + ret = request_firmware(&fw, fwname, dev); + if (ret < 0) + return -EINVAL; + + if (fw->size < MC_SIZE) { + dev_err(dev, "Firmware size %zu is too small. Expected %u.\n", + fw->size, MC_SIZE); + ret = -EINVAL; + goto release_firmware; + } + + mc_addr = dma_alloc_coherent(core->dev, MC_SIZE, + &mc_addr_map, GFP_KERNEL); + if (!mc_addr) { + ret = -ENOMEM; + goto release_firmware; + } + + memcpy(mc_addr, fw->data, MC_SIZE); + + amvdec_write_dos(core, MPSR, 0); + amvdec_write_dos(core, CPSR, 0); + + amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(31)); + + amvdec_write_dos(core, IMEM_DMA_ADR, mc_addr_map); + amvdec_write_dos(core, IMEM_DMA_COUNT, MC_SIZE / 4); + amvdec_write_dos(core, IMEM_DMA_CTRL, (0x8000 | (7 << 16))); + + while (--i && amvdec_read_dos(core, IMEM_DMA_CTRL) & 0x8000); + + if (i == 0) { + dev_err(dev, "Firmware load fail (DMA hang?)\n"); + ret = -EINVAL; + goto free_mc; + } + + if (codec_ops->load_extended_firmware) + ret = codec_ops->load_extended_firmware(sess, + fw->data + MC_SIZE, + fw->size - MC_SIZE); + +free_mc: + dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map); +release_firmware: + release_firmware(fw); + return ret; +} + +static int vdec_1_stbuf_power_up(struct amvdec_session *sess) +{ + struct amvdec_core *core = sess->core; + + amvdec_write_dos(core, VLD_MEM_VIFIFO_CONTROL, 0); + amvdec_write_dos(core, VLD_MEM_VIFIFO_WRAP_COUNT, 0); + amvdec_write_dos(core, POWER_CTL_VLD, BIT(4)); + + amvdec_write_dos(core, VLD_MEM_VIFIFO_START_PTR, sess->vififo_paddr); + amvdec_write_dos(core, VLD_MEM_VIFIFO_CURR_PTR, sess->vififo_paddr); + amvdec_write_dos(core, VLD_MEM_VIFIFO_END_PTR, + sess->vififo_paddr + sess->vififo_size - 8); + + amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, 1); + amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, 1); + + amvdec_write_dos(core, VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_MANUAL); + amvdec_write_dos(core, VLD_MEM_VIFIFO_WP, sess->vififo_paddr); + + amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); + amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); + + amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, + (0x11 << MEM_FIFO_CNT_BIT) | MEM_FILL_ON_LEVEL | + MEM_CTRL_FILL_EN | MEM_CTRL_EMPTY_EN); + + return 0; +} + +static void vdec_1_conf_esparser(struct amvdec_session *sess) +{ + struct amvdec_core *core = sess->core; + + /* VDEC_1 specific ESPARSER stuff */ + amvdec_write_dos(core, DOS_GEN_CTRL0, 0); + amvdec_write_dos(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); + amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); +} + +static u32 vdec_1_vififo_level(struct amvdec_session *sess) +{ + struct amvdec_core *core = sess->core; + + return amvdec_read_dos(core, VLD_MEM_VIFIFO_LEVEL); +} + +static int vdec_1_stop(struct amvdec_session *sess) +{ + struct amvdec_core *core = sess->core; + struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; + + amvdec_write_dos(core, MPSR, 0); + amvdec_write_dos(core, CPSR, 0); + amvdec_write_dos(core, ASSIST_MBOX1_MASK, 0); + + amvdec_write_dos(core, DOS_SW_RESET0, BIT(12) | BIT(11)); + amvdec_write_dos(core, DOS_SW_RESET0, 0); + amvdec_read_dos(core, DOS_SW_RESET0); + + /* enable vdec1 isolation */ + regmap_write(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc0); + /* power off vdec1 memories */ + amvdec_write_dos(core, DOS_MEM_PD_VDEC, 0xffffffff); + /* power off vdec1 */ + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VDEC_1, GEN_PWR_VDEC_1); + + clk_disable_unprepare(core->vdec_1_clk); + + if (sess->priv) + codec_ops->stop(sess); + + return 0; +} + +static int vdec_1_start(struct amvdec_session *sess) +{ + int ret; + struct amvdec_core *core = sess->core; + struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; + + /* Configure the vdec clk to the maximum available */ + clk_set_rate(core->vdec_1_clk, 666666666); + ret = clk_prepare_enable(core->vdec_1_clk); + if (ret) + return ret; + + /* Enable power for VDEC_1 */ + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VDEC_1, 0); + usleep_range(10, 20); + + /* Reset VDEC1 */ + amvdec_write_dos(core, DOS_SW_RESET0, 0xfffffffc); + amvdec_write_dos(core, DOS_SW_RESET0, 0x00000000); + + amvdec_write_dos(core, DOS_GCLK_EN0, 0x3ff); + + /* enable VDEC Memories */ + amvdec_write_dos(core, DOS_MEM_PD_VDEC, 0); + /* Remove VDEC1 Isolation */ + regmap_write(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0); + /* Reset DOS top registers */ + amvdec_write_dos(core, DOS_VDEC_MCRCC_STALL_CTRL, 0); + + amvdec_write_dos(core, GCLK_EN, 0x3ff); + amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(31)); + + vdec_1_stbuf_power_up(sess); + + ret = vdec_1_load_firmware(sess, sess->fmt_out->firmware_path); + if (ret) + goto stop; + + ret = codec_ops->start(sess); + if (ret) + goto stop; + + /* Enable IRQ */ + amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); + amvdec_write_dos(core, ASSIST_MBOX1_MASK, 1); + + /* Enable 2-plane output */ + if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) + amvdec_write_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(17)); + else + amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(17)); + + /* Enable firmware processor */ + amvdec_write_dos(core, MPSR, 1); + /* Let the firmware settle */ + usleep_range(10, 20); + + return 0; + +stop: + vdec_1_stop(sess); + return ret; +} + +struct amvdec_ops vdec_1_ops = { + .start = vdec_1_start, + .stop = vdec_1_stop, + .conf_esparser = vdec_1_conf_esparser, + .vififo_level = vdec_1_vififo_level, +}; diff --git a/drivers/staging/media/meson/vdec/vdec_1.h b/drivers/staging/media/meson/vdec/vdec_1.h new file mode 100644 index 000000000000..042d930c40d7 --- /dev/null +++ b/drivers/staging/media/meson/vdec/vdec_1.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Maxime Jourdan <mjourdan@baylibre.com> + */ + +#ifndef __MESON_VDEC_VDEC_1_H_ +#define __MESON_VDEC_VDEC_1_H_ + +#include "vdec.h" + +extern struct amvdec_ops vdec_1_ops; + +#endif diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.c b/drivers/staging/media/meson/vdec/vdec_helpers.c new file mode 100644 index 000000000000..f16948bdbf2f --- /dev/null +++ b/drivers/staging/media/meson/vdec/vdec_helpers.c @@ -0,0 +1,449 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Maxime Jourdan <mjourdan@baylibre.com> + */ + +#include <linux/gcd.h> +#include <media/v4l2-mem2mem.h> +#include <media/v4l2-event.h> +#include <media/videobuf2-dma-contig.h> + +#include "vdec_helpers.h" + +#define NUM_CANVAS_NV12 2 +#define NUM_CANVAS_YUV420 3 + +u32 amvdec_read_dos(struct amvdec_core *core, u32 reg) +{ + return readl_relaxed(core->dos_base + reg); +} +EXPORT_SYMBOL_GPL(amvdec_read_dos); + +void amvdec_write_dos(struct amvdec_core *core, u32 reg, u32 val) +{ + writel_relaxed(val, core->dos_base + reg); +} +EXPORT_SYMBOL_GPL(amvdec_write_dos); + +void amvdec_write_dos_bits(struct amvdec_core *core, u32 reg, u32 val) +{ + amvdec_write_dos(core, reg, amvdec_read_dos(core, reg) | val); +} +EXPORT_SYMBOL_GPL(amvdec_write_dos_bits); + +void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val) +{ + amvdec_write_dos(core, reg, amvdec_read_dos(core, reg) & ~val); +} +EXPORT_SYMBOL_GPL(amvdec_clear_dos_bits); + +u32 amvdec_read_parser(struct amvdec_core *core, u32 reg) +{ + return readl_relaxed(core->esparser_base + reg); +} +EXPORT_SYMBOL_GPL(amvdec_read_parser); + +void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val) +{ + writel_relaxed(val, core->esparser_base + reg); +} +EXPORT_SYMBOL_GPL(amvdec_write_parser); + +static int canvas_alloc(struct amvdec_session *sess, u8 *canvas_id) +{ + int ret; + + if (sess->canvas_num >= MAX_CANVAS) { + dev_err(sess->core->dev, "Reached max number of canvas\n"); + return -ENOMEM; + } + + ret = meson_canvas_alloc(sess->core->canvas, canvas_id); + if (ret) + return ret; + + sess->canvas_alloc[sess->canvas_num++] = *canvas_id; + return 0; +} + +static int set_canvas_yuv420m(struct amvdec_session *sess, + struct vb2_buffer *vb, u32 width, + u32 height, u32 reg) +{ + struct amvdec_core *core = sess->core; + u8 canvas_id[NUM_CANVAS_YUV420]; /* Y U V */ + dma_addr_t buf_paddr[NUM_CANVAS_YUV420]; /* Y U V */ + int ret, i; + + for (i = 0; i < NUM_CANVAS_YUV420; ++i) { + ret = canvas_alloc(sess, &canvas_id[i]); + if (ret) + return ret; + + buf_paddr[i] = + vb2_dma_contig_plane_dma_addr(vb, i); + } + + /* Y plane */ + meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0], + width, height, MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, + MESON_CANVAS_ENDIAN_SWAP64); + + /* U plane */ + meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1], + width / 2, height / 2, MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, + MESON_CANVAS_ENDIAN_SWAP64); + + /* V plane */ + meson_canvas_config(core->canvas, canvas_id[2], buf_paddr[2], + width / 2, height / 2, MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, + MESON_CANVAS_ENDIAN_SWAP64); + + amvdec_write_dos(core, reg, + ((canvas_id[2]) << 16) | + ((canvas_id[1]) << 8) | + (canvas_id[0])); + + return 0; +} + +static int set_canvas_nv12m(struct amvdec_session *sess, + struct vb2_buffer *vb, u32 width, + u32 height, u32 reg) +{ + struct amvdec_core *core = sess->core; + u8 canvas_id[NUM_CANVAS_NV12]; /* Y U/V */ + dma_addr_t buf_paddr[NUM_CANVAS_NV12]; /* Y U/V */ + int ret, i; + + for (i = 0; i < NUM_CANVAS_NV12; ++i) { + ret = canvas_alloc(sess, &canvas_id[i]); + if (ret) + return ret; + + buf_paddr[i] = + vb2_dma_contig_plane_dma_addr(vb, i); + } + + /* Y plane */ + meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0], + width, height, MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, + MESON_CANVAS_ENDIAN_SWAP64); + + /* U/V plane */ + meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1], + width, height / 2, MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, + MESON_CANVAS_ENDIAN_SWAP64); + + amvdec_write_dos(core, reg, + ((canvas_id[1]) << 16) | + ((canvas_id[1]) << 8) | + (canvas_id[0])); + + return 0; +} + +int amvdec_set_canvases(struct amvdec_session *sess, + u32 reg_base[], u32 reg_num[]) +{ + struct v4l2_m2m_buffer *buf; + u32 pixfmt = sess->pixfmt_cap; + u32 width = ALIGN(sess->width, 64); + u32 height = ALIGN(sess->height, 64); + u32 reg_cur = reg_base[0]; + u32 reg_num_cur = 0; + u32 reg_base_cur = 0; + int i = 0; + int ret; + + v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { + if (!reg_base[reg_base_cur]) + return -EINVAL; + + reg_cur = reg_base[reg_base_cur] + reg_num_cur * 4; + + switch (pixfmt) { + case V4L2_PIX_FMT_NV12M: + ret = set_canvas_nv12m(sess, &buf->vb.vb2_buf, width, + height, reg_cur); + if (ret) + return ret; + break; + case V4L2_PIX_FMT_YUV420M: + ret = set_canvas_yuv420m(sess, &buf->vb.vb2_buf, width, + height, reg_cur); + if (ret) + return ret; + break; + default: + dev_err(sess->core->dev, "Unsupported pixfmt %08X\n", + pixfmt); + return -EINVAL; + } + + reg_num_cur++; + if (reg_num_cur >= reg_num[reg_base_cur]) { + reg_base_cur++; + reg_num_cur = 0; + } + + sess->fw_idx_to_vb2_idx[i++] = buf->vb.vb2_buf.index; + } + + return 0; +} +EXPORT_SYMBOL_GPL(amvdec_set_canvases); + +void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset) +{ + struct amvdec_timestamp *new_ts, *tmp; + unsigned long flags; + + new_ts = kmalloc(sizeof(*new_ts), GFP_KERNEL); + new_ts->ts = ts; + new_ts->offset = offset; + + spin_lock_irqsave(&sess->ts_spinlock, flags); + + if (list_empty(&sess->timestamps)) + goto add_tail; + + list_for_each_entry(tmp, &sess->timestamps, list) { + if (ts <= tmp->ts) { + list_add_tail(&new_ts->list, &tmp->list); + goto unlock; + } + } + +add_tail: + list_add_tail(&new_ts->list, &sess->timestamps); +unlock: + spin_unlock_irqrestore(&sess->ts_spinlock, flags); +} +EXPORT_SYMBOL_GPL(amvdec_add_ts_reorder); + +void amvdec_remove_ts(struct amvdec_session *sess, u64 ts) +{ + struct amvdec_timestamp *tmp; + unsigned long flags; + + spin_lock_irqsave(&sess->ts_spinlock, flags); + list_for_each_entry(tmp, &sess->timestamps, list) { + if (tmp->ts == ts) { + list_del(&tmp->list); + kfree(tmp); + goto unlock; + } + } + dev_warn(sess->core->dev_dec, + "Couldn't remove buffer with timestamp %llu from list\n", ts); + +unlock: + spin_unlock_irqrestore(&sess->ts_spinlock, flags); +} +EXPORT_SYMBOL_GPL(amvdec_remove_ts); + +static void dst_buf_done(struct amvdec_session *sess, + struct vb2_v4l2_buffer *vbuf, + u32 field, + u64 timestamp) +{ + struct device *dev = sess->core->dev_dec; + u32 output_size = amvdec_get_output_size(sess); + + switch (sess->pixfmt_cap) { + case V4L2_PIX_FMT_NV12M: + vbuf->vb2_buf.planes[0].bytesused = output_size; + vbuf->vb2_buf.planes[1].bytesused = output_size / 2; + break; + case V4L2_PIX_FMT_YUV420M: + vbuf->vb2_buf.planes[0].bytesused = output_size; + vbuf->vb2_buf.planes[1].bytesused = output_size / 4; + vbuf->vb2_buf.planes[2].bytesused = output_size / 4; + break; + } + + vbuf->vb2_buf.timestamp = timestamp; + vbuf->sequence = sess->sequence_cap++; + + if (sess->should_stop && + atomic_read(&sess->esparser_queued_bufs) <= 2) { + const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; + + dev_dbg(dev, "Signaling EOS\n"); + v4l2_event_queue_fh(&sess->fh, &ev); + vbuf->flags |= V4L2_BUF_FLAG_LAST; + } else if (sess->should_stop) + dev_dbg(dev, "should_stop, %u bufs remain\n", + atomic_read(&sess->esparser_queued_bufs)); + + dev_dbg(dev, "Buffer %u done\n", vbuf->vb2_buf.index); + vbuf->field = field; + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); + + /* Buffer done probably means the vififo got freed */ + schedule_work(&sess->esparser_queue_work); +} + +void amvdec_dst_buf_done(struct amvdec_session *sess, + struct vb2_v4l2_buffer *vbuf, u32 field) +{ + struct device *dev = sess->core->dev_dec; + struct amvdec_timestamp *tmp; + struct list_head *timestamps = &sess->timestamps; + u64 timestamp; + unsigned long flags; + + spin_lock_irqsave(&sess->ts_spinlock, flags); + if (list_empty(timestamps)) { + dev_err(dev, "Buffer %u done but list is empty\n", + vbuf->vb2_buf.index); + + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + spin_unlock_irqrestore(&sess->ts_spinlock, flags); + return; + } + + tmp = list_first_entry(timestamps, struct amvdec_timestamp, list); + timestamp = tmp->ts; + list_del(&tmp->list); + kfree(tmp); + spin_unlock_irqrestore(&sess->ts_spinlock, flags); + + dst_buf_done(sess, vbuf, field, timestamp); + atomic_dec(&sess->esparser_queued_bufs); +} +EXPORT_SYMBOL_GPL(amvdec_dst_buf_done); + +void amvdec_dst_buf_done_offset(struct amvdec_session *sess, + struct vb2_v4l2_buffer *vbuf, + u32 offset, u32 field, bool allow_drop) +{ + struct device *dev = sess->core->dev_dec; + struct amvdec_timestamp *match = NULL; + struct amvdec_timestamp *tmp, *n; + u64 timestamp = 0; + unsigned long flags; + + spin_lock_irqsave(&sess->ts_spinlock, flags); + + /* Look for our vififo offset to get the corresponding timestamp. */ + list_for_each_entry_safe(tmp, n, &sess->timestamps, list) { + s64 delta = (s64)offset - tmp->offset; + + /* Offsets reported by codecs usually differ slightly, + * so we need some wiggle room. + * 4KiB being the minimum packet size, there is no risk here. + */ + if (delta > (-1 * (s32)SZ_4K) && delta < SZ_4K) { + match = tmp; + break; + } + + if (!allow_drop) + continue; + + /* Delete any timestamp entry that appears before our target + * (not all src packets/timestamps lead to a frame) + */ + if (delta > 0 || delta < -1 * (s32)sess->vififo_size) { + atomic_dec(&sess->esparser_queued_bufs); + list_del(&tmp->list); + kfree(tmp); + } + } + + if (!match) { + dev_dbg(dev, "Buffer %u done but can't match offset (%08X)\n", + vbuf->vb2_buf.index, offset); + } else { + timestamp = match->ts; + list_del(&match->list); + kfree(match); + } + spin_unlock_irqrestore(&sess->ts_spinlock, flags); + + dst_buf_done(sess, vbuf, field, timestamp); + if (match) + atomic_dec(&sess->esparser_queued_bufs); +} +EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_offset); + +void amvdec_dst_buf_done_idx(struct amvdec_session *sess, + u32 buf_idx, u32 offset, u32 field) +{ + struct vb2_v4l2_buffer *vbuf; + struct device *dev = sess->core->dev_dec; + + vbuf = v4l2_m2m_dst_buf_remove_by_idx(sess->m2m_ctx, + sess->fw_idx_to_vb2_idx[buf_idx]); + + if (!vbuf) { + dev_err(dev, + "Buffer %u done but it doesn't exist in m2m_ctx\n", + buf_idx); + return; + } + + if (offset != -1) + amvdec_dst_buf_done_offset(sess, vbuf, offset, field, true); + else + amvdec_dst_buf_done(sess, vbuf, field); +} +EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_idx); + +void amvdec_set_par_from_dar(struct amvdec_session *sess, + u32 dar_num, u32 dar_den) +{ + u32 div; + + sess->pixelaspect.numerator = sess->height * dar_num; + sess->pixelaspect.denominator = sess->width * dar_den; + div = gcd(sess->pixelaspect.numerator, sess->pixelaspect.denominator); + sess->pixelaspect.numerator /= div; + sess->pixelaspect.denominator /= div; +} +EXPORT_SYMBOL_GPL(amvdec_set_par_from_dar); + +void amvdec_src_change(struct amvdec_session *sess, u32 width, + u32 height, u32 dpb_size) +{ + static const struct v4l2_event ev = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION }; + + v4l2_ctrl_s_ctrl(sess->ctrl_min_buf_capture, dpb_size); + + /* Check if the capture queue is already configured well for our + * usecase. If so, keep decoding with it and do not send the event + */ + if (sess->width == width && + sess->height == height && + dpb_size <= sess->num_dst_bufs) { + sess->fmt_out->codec_ops->resume(sess); + return; + } + + sess->width = width; + sess->height = height; + sess->status = STATUS_NEEDS_RESUME; + + dev_dbg(sess->core->dev, "Res. changed (%ux%u), DPB size %u\n", + width, height, dpb_size); + v4l2_event_queue_fh(&sess->fh, &ev); +} +EXPORT_SYMBOL_GPL(amvdec_src_change); + +void amvdec_abort(struct amvdec_session *sess) +{ + dev_info(sess->core->dev, "Aborting decoding session!\n"); + vb2_queue_error(&sess->m2m_ctx->cap_q_ctx.q); + vb2_queue_error(&sess->m2m_ctx->out_q_ctx.q); +} +EXPORT_SYMBOL_GPL(amvdec_abort); diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.h b/drivers/staging/media/meson/vdec/vdec_helpers.h new file mode 100644 index 000000000000..a455a9ee1cc2 --- /dev/null +++ b/drivers/staging/media/meson/vdec/vdec_helpers.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Maxime Jourdan <mjourdan@baylibre.com> + */ + +#ifndef __MESON_VDEC_HELPERS_H_ +#define __MESON_VDEC_HELPERS_H_ + +#include "vdec.h" + +/** + * amvdec_set_canvases() - Map VB2 buffers to canvases + * + * @sess: current session + * @reg_base: Registry bases of where to write the canvas indexes + * @reg_num: number of contiguous registers after each reg_base (including it) + */ +int amvdec_set_canvases(struct amvdec_session *sess, + u32 reg_base[], u32 reg_num[]); + +/* Helpers to read/write to the various IPs (DOS, PARSER) */ +u32 amvdec_read_dos(struct amvdec_core *core, u32 reg); +void amvdec_write_dos(struct amvdec_core *core, u32 reg, u32 val); +void amvdec_write_dos_bits(struct amvdec_core *core, u32 reg, u32 val); +void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val); +u32 amvdec_read_parser(struct amvdec_core *core, u32 reg); +void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val); + +/** + * amvdec_dst_buf_done_idx() - Signal that a buffer is done decoding + * + * @sess: current session + * @buf_idx: hardware buffer index + * @offset: VIFIFO bitstream offset corresponding to the buffer + * @field: V4L2 interlaced field + */ +void amvdec_dst_buf_done_idx(struct amvdec_session *sess, u32 buf_idx, + u32 offset, u32 field); +void amvdec_dst_buf_done(struct amvdec_session *sess, + struct vb2_v4l2_buffer *vbuf, u32 field); +void amvdec_dst_buf_done_offset(struct amvdec_session *sess, + struct vb2_v4l2_buffer *vbuf, + u32 offset, u32 field, bool allow_drop); + +/** + * amvdec_add_ts_reorder() - Add a timestamp to the list in chronological order + * + * @sess: current session + * @ts: timestamp to add + * @offset: offset in the VIFIFO where the associated packet was written + */ +void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset); +void amvdec_remove_ts(struct amvdec_session *sess, u64 ts); + +/** + * amvdec_set_par_from_dar() - Set Pixel Aspect Ratio from Display Aspect Ratio + * + * @sess: current session + * @dar_num: numerator of the DAR + * @dar_den: denominator of the DAR + */ +void amvdec_set_par_from_dar(struct amvdec_session *sess, + u32 dar_num, u32 dar_den); + +/** + * amvdec_src_change() - Notify new resolution/DPB size to the core + * + * @sess: current session + * @width: picture width detected by the hardware + * @height: picture height detected by the hardware + * @dpb_size: Decoded Picture Buffer size (= amount of buffers for decoding) + */ +void amvdec_src_change(struct amvdec_session *sess, u32 width, + u32 height, u32 dpb_size); + +/** + * amvdec_abort() - Abort the current decoding session + * + * @sess: current session + */ +void amvdec_abort(struct amvdec_session *sess); +#endif diff --git a/drivers/staging/media/meson/vdec/vdec_platform.c b/drivers/staging/media/meson/vdec/vdec_platform.c new file mode 100644 index 000000000000..824dbc7f46f5 --- /dev/null +++ b/drivers/staging/media/meson/vdec/vdec_platform.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Maxime Jourdan <mjourdan@baylibre.com> + */ + +#include "vdec_platform.h" +#include "vdec.h" + +#include "vdec_1.h" +#include "codec_mpeg12.h" + +static const struct amvdec_format vdec_formats_gxbb[] = { + { + .pixfmt = V4L2_PIX_FMT_MPEG1, + .min_buffers = 8, + .max_buffers = 8, + .max_width = 1920, + .max_height = 1080, + .vdec_ops = &vdec_1_ops, + .codec_ops = &codec_mpeg12_ops, + .firmware_path = "meson/vdec/gxl_mpeg12.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, + }, { + .pixfmt = V4L2_PIX_FMT_MPEG2, + .min_buffers = 8, + .max_buffers = 8, + .max_width = 1920, + .max_height = 1080, + .vdec_ops = &vdec_1_ops, + .codec_ops = &codec_mpeg12_ops, + .firmware_path = "meson/vdec/gxl_mpeg12.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, + }, +}; + +static const struct amvdec_format vdec_formats_gxl[] = { + { + .pixfmt = V4L2_PIX_FMT_MPEG1, + .min_buffers = 8, + .max_buffers = 8, + .max_width = 1920, + .max_height = 1080, + .vdec_ops = &vdec_1_ops, + .codec_ops = &codec_mpeg12_ops, + .firmware_path = "meson/vdec/gxl_mpeg12.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, + }, { + .pixfmt = V4L2_PIX_FMT_MPEG2, + .min_buffers = 8, + .max_buffers = 8, + .max_width = 1920, + .max_height = 1080, + .vdec_ops = &vdec_1_ops, + .codec_ops = &codec_mpeg12_ops, + .firmware_path = "meson/vdec/gxl_mpeg12.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, + }, +}; + +static const struct amvdec_format vdec_formats_gxm[] = { + { + .pixfmt = V4L2_PIX_FMT_MPEG1, + .min_buffers = 8, + .max_buffers = 8, + .max_width = 1920, + .max_height = 1080, + .vdec_ops = &vdec_1_ops, + .codec_ops = &codec_mpeg12_ops, + .firmware_path = "meson/vdec/gxl_mpeg12.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, + }, { + .pixfmt = V4L2_PIX_FMT_MPEG2, + .min_buffers = 8, + .max_buffers = 8, + .max_width = 1920, + .max_height = 1080, + .vdec_ops = &vdec_1_ops, + .codec_ops = &codec_mpeg12_ops, + .firmware_path = "meson/vdec/gxl_mpeg12.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, + }, +}; + +const struct vdec_platform vdec_platform_gxbb = { + .formats = vdec_formats_gxbb, + .num_formats = ARRAY_SIZE(vdec_formats_gxbb), + .revision = VDEC_REVISION_GXBB, +}; + +const struct vdec_platform vdec_platform_gxl = { + .formats = vdec_formats_gxl, + .num_formats = ARRAY_SIZE(vdec_formats_gxl), + .revision = VDEC_REVISION_GXL, +}; + +const struct vdec_platform vdec_platform_gxm = { + .formats = vdec_formats_gxm, + .num_formats = ARRAY_SIZE(vdec_formats_gxm), + .revision = VDEC_REVISION_GXM, +}; diff --git a/drivers/staging/media/meson/vdec/vdec_platform.h b/drivers/staging/media/meson/vdec/vdec_platform.h new file mode 100644 index 000000000000..f6025326db1d --- /dev/null +++ b/drivers/staging/media/meson/vdec/vdec_platform.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Maxime Jourdan <mjourdan@baylibre.com> + */ + +#ifndef __MESON_VDEC_PLATFORM_H_ +#define __MESON_VDEC_PLATFORM_H_ + +#include "vdec.h" + +struct amvdec_format; + +enum vdec_revision { + VDEC_REVISION_GXBB, + VDEC_REVISION_GXL, + VDEC_REVISION_GXM, +}; + +struct vdec_platform { + const struct amvdec_format *formats; + const u32 num_formats; + enum vdec_revision revision; +}; + +extern const struct vdec_platform vdec_platform_gxbb; +extern const struct vdec_platform vdec_platform_gxm; +extern const struct vdec_platform vdec_platform_gxl; + +#endif diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index c2c5a9cd8642..c307707480f7 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -533,12 +533,6 @@ iss_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) strscpy(cap->driver, ISS_VIDEO_DRIVER_NAME, sizeof(cap->driver)); strscpy(cap->card, video->video.name, sizeof(cap->card)); strscpy(cap->bus_info, "media", sizeof(cap->bus_info)); - - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - else - cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT; @@ -1272,6 +1266,11 @@ int omap4iss_video_register(struct iss_video *video, struct v4l2_device *vdev) int ret; video->video.v4l2_dev = vdev; + if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + video->video.device_caps = V4L2_CAP_VIDEO_CAPTURE; + else + video->video.device_caps = V4L2_CAP_VIDEO_OUTPUT; + video->video.device_caps |= V4L2_CAP_STREAMING; ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1); if (ret < 0) diff --git a/drivers/staging/media/rockchip/vpu/Kconfig b/drivers/staging/media/rockchip/vpu/Kconfig deleted file mode 100644 index fc54bbf6753d..000000000000 --- a/drivers/staging/media/rockchip/vpu/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config VIDEO_ROCKCHIP_VPU - tristate "Rockchip VPU driver" - depends on ARCH_ROCKCHIP || COMPILE_TEST - depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER - select VIDEOBUF2_DMA_CONTIG - select VIDEOBUF2_VMALLOC - select V4L2_MEM2MEM_DEV - help - Support for the Video Processing Unit present on Rockchip SoC, - which accelerates video and image encoding and decoding. - To compile this driver as a module, choose M here: the module - will be called rockchip-vpu. diff --git a/drivers/staging/media/rockchip/vpu/Makefile b/drivers/staging/media/rockchip/vpu/Makefile deleted file mode 100644 index ae5d143a0bfa..000000000000 --- a/drivers/staging/media/rockchip/vpu/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_VIDEO_ROCKCHIP_VPU) += rockchip-vpu.o - -rockchip-vpu-y += \ - rockchip_vpu_drv.o \ - rockchip_vpu_enc.o \ - rk3288_vpu_hw.o \ - rk3288_vpu_hw_jpeg_enc.o \ - rk3399_vpu_hw.o \ - rk3399_vpu_hw_jpeg_enc.o \ - rockchip_vpu_jpeg.o diff --git a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c b/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c deleted file mode 100644 index a5e9d183fffd..000000000000 --- a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - * Jeffy Chen <jeffy.chen@rock-chips.com> - */ - -#include <linux/clk.h> - -#include "rockchip_vpu.h" -#include "rockchip_vpu_jpeg.h" -#include "rk3288_vpu_regs.h" - -#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000) - -/* - * Supported formats. - */ - -static const struct rockchip_vpu_fmt rk3288_vpu_enc_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_YUV420M, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P, - }, - { - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422, - }, - { - .fourcc = V4L2_PIX_FMT_UYVY, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422, - }, - { - .fourcc = V4L2_PIX_FMT_JPEG, - .codec_mode = RK_VPU_MODE_JPEG_ENC, - .max_depth = 2, - .header_size = JPEG_HEADER_SIZE, - .frmsize = { - .min_width = 96, - .max_width = 8192, - .step_width = JPEG_MB_DIM, - .min_height = 32, - .max_height = 8192, - .step_height = JPEG_MB_DIM, - }, - }, -}; - -static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id) -{ - struct rockchip_vpu_dev *vpu = dev_id; - enum vb2_buffer_state state; - u32 status, bytesused; - - status = vepu_read(vpu, VEPU_REG_INTERRUPT); - bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8; - state = (status & VEPU_REG_INTERRUPT_FRAME_RDY) ? - VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - - vepu_write(vpu, 0, VEPU_REG_INTERRUPT); - vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); - - rockchip_vpu_irq_done(vpu, bytesused, state); - - return IRQ_HANDLED; -} - -static int rk3288_vpu_hw_init(struct rockchip_vpu_dev *vpu) -{ - /* Bump ACLK to max. possible freq. to improve performance. */ - clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ); - return 0; -} - -static void rk3288_vpu_enc_reset(struct rockchip_vpu_ctx *ctx) -{ - struct rockchip_vpu_dev *vpu = ctx->dev; - - vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT); - vepu_write(vpu, 0, VEPU_REG_ENC_CTRL); - vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); -} - -/* - * Supported codec ops. - */ - -static const struct rockchip_vpu_codec_ops rk3288_vpu_codec_ops[] = { - [RK_VPU_MODE_JPEG_ENC] = { - .run = rk3288_vpu_jpeg_enc_run, - .reset = rk3288_vpu_enc_reset, - }, -}; - -/* - * VPU variant. - */ - -const struct rockchip_vpu_variant rk3288_vpu_variant = { - .enc_offset = 0x0, - .enc_fmts = rk3288_vpu_enc_fmts, - .num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts), - .codec_ops = rk3288_vpu_codec_ops, - .codec = RK_VPU_CODEC_JPEG, - .vepu_irq = rk3288_vepu_irq, - .init = rk3288_vpu_hw_init, - .clk_names = {"aclk", "hclk"}, - .num_clocks = 2 -}; diff --git a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c b/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c deleted file mode 100644 index 06daea66fb49..000000000000 --- a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c +++ /dev/null @@ -1,125 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - */ - -#include <asm/unaligned.h> -#include <media/v4l2-mem2mem.h> -#include "rockchip_vpu_jpeg.h" -#include "rockchip_vpu.h" -#include "rockchip_vpu_common.h" -#include "rockchip_vpu_hw.h" -#include "rk3288_vpu_regs.h" - -#define VEPU_JPEG_QUANT_TABLE_COUNT 16 - -static void rk3288_vpu_set_src_img_ctrl(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx) -{ - struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; - u32 reg; - - reg = VEPU_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width) - | VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(0) - | VEPU_REG_IN_IMG_CTRL_OVRFLB_D4(0) - | VEPU_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); - vepu_write_relaxed(vpu, reg, VEPU_REG_IN_IMG_CTRL); -} - -static void rk3288_vpu_jpeg_enc_set_buffers(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx, - struct vb2_buffer *src_buf) -{ - struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; - dma_addr_t src[3]; - - WARN_ON(pix_fmt->num_planes > 3); - - vepu_write_relaxed(vpu, ctx->bounce_dma_addr, - VEPU_REG_ADDR_OUTPUT_STREAM); - vepu_write_relaxed(vpu, ctx->bounce_size, - VEPU_REG_STR_BUF_LIMIT); - - if (pix_fmt->num_planes == 1) { - src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); - /* single plane formats we supported are all interlaced */ - vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); - } else if (pix_fmt->num_planes == 2) { - src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); - src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); - vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); - vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1); - } else { - src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); - src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); - src[2] = vb2_dma_contig_plane_dma_addr(src_buf, 2); - vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); - vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1); - vepu_write_relaxed(vpu, src[2], VEPU_REG_ADDR_IN_PLANE_2); - } -} - -static void -rk3288_vpu_jpeg_enc_set_qtable(struct rockchip_vpu_dev *vpu, - unsigned char *luma_qtable, - unsigned char *chroma_qtable) -{ - u32 reg, i; - - for (i = 0; i < VEPU_JPEG_QUANT_TABLE_COUNT; i++) { - reg = get_unaligned_be32(&luma_qtable[i]); - vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_LUMA_QUAT(i)); - - reg = get_unaligned_be32(&chroma_qtable[i]); - vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_CHROMA_QUAT(i)); - } -} - -void rk3288_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx) -{ - struct rockchip_vpu_dev *vpu = ctx->dev; - struct vb2_v4l2_buffer *src_buf, *dst_buf; - struct rockchip_vpu_jpeg_ctx jpeg_ctx; - u32 reg; - - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - - memset(&jpeg_ctx, 0, sizeof(jpeg_ctx)); - jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); - jpeg_ctx.width = ctx->dst_fmt.width; - jpeg_ctx.height = ctx->dst_fmt.height; - jpeg_ctx.quality = ctx->jpeg_quality; - rockchip_vpu_jpeg_header_assemble(&jpeg_ctx); - - /* Switch to JPEG encoder mode before writing registers */ - vepu_write_relaxed(vpu, VEPU_REG_ENC_CTRL_ENC_MODE_JPEG, - VEPU_REG_ENC_CTRL); - - rk3288_vpu_set_src_img_ctrl(vpu, ctx); - rk3288_vpu_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf); - rk3288_vpu_jpeg_enc_set_qtable(vpu, - rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 0), - rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 1)); - - reg = VEPU_REG_AXI_CTRL_OUTPUT_SWAP16 - | VEPU_REG_AXI_CTRL_INPUT_SWAP16 - | VEPU_REG_AXI_CTRL_BURST_LEN(16) - | VEPU_REG_AXI_CTRL_OUTPUT_SWAP32 - | VEPU_REG_AXI_CTRL_INPUT_SWAP32 - | VEPU_REG_AXI_CTRL_OUTPUT_SWAP8 - | VEPU_REG_AXI_CTRL_INPUT_SWAP8; - /* Make sure that all registers are written at this point. */ - vepu_write(vpu, reg, VEPU_REG_AXI_CTRL); - - reg = VEPU_REG_ENC_CTRL_WIDTH(JPEG_MB_WIDTH(ctx->src_fmt.width)) - | VEPU_REG_ENC_CTRL_HEIGHT(JPEG_MB_HEIGHT(ctx->src_fmt.height)) - | VEPU_REG_ENC_CTRL_ENC_MODE_JPEG - | VEPU_REG_ENC_PIC_INTRA - | VEPU_REG_ENC_CTRL_EN_BIT; - /* Kick the watchdog and start encoding */ - schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); - vepu_write(vpu, reg, VEPU_REG_ENC_CTRL); -} diff --git a/drivers/staging/media/rockchip/vpu/rk3288_vpu_regs.h b/drivers/staging/media/rockchip/vpu/rk3288_vpu_regs.h deleted file mode 100644 index 9d0b9bdf3297..000000000000 --- a/drivers/staging/media/rockchip/vpu/rk3288_vpu_regs.h +++ /dev/null @@ -1,442 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Rockchip VPU codec driver - * - * Copyright 2018 Google LLC. - * Tomasz Figa <tfiga@chromium.org> - */ - -#ifndef RK3288_VPU_REGS_H_ -#define RK3288_VPU_REGS_H_ - -/* Encoder registers. */ -#define VEPU_REG_INTERRUPT 0x004 -#define VEPU_REG_INTERRUPT_FRAME_RDY BIT(2) -#define VEPU_REG_INTERRUPT_DIS_BIT BIT(1) -#define VEPU_REG_INTERRUPT_BIT BIT(0) -#define VEPU_REG_AXI_CTRL 0x008 -#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP16 BIT(15) -#define VEPU_REG_AXI_CTRL_INPUT_SWAP16 BIT(14) -#define VEPU_REG_AXI_CTRL_BURST_LEN(x) ((x) << 8) -#define VEPU_REG_AXI_CTRL_GATE_BIT BIT(4) -#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP32 BIT(3) -#define VEPU_REG_AXI_CTRL_INPUT_SWAP32 BIT(2) -#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP8 BIT(1) -#define VEPU_REG_AXI_CTRL_INPUT_SWAP8 BIT(0) -#define VEPU_REG_ADDR_OUTPUT_STREAM 0x014 -#define VEPU_REG_ADDR_OUTPUT_CTRL 0x018 -#define VEPU_REG_ADDR_REF_LUMA 0x01c -#define VEPU_REG_ADDR_REF_CHROMA 0x020 -#define VEPU_REG_ADDR_REC_LUMA 0x024 -#define VEPU_REG_ADDR_REC_CHROMA 0x028 -#define VEPU_REG_ADDR_IN_PLANE_0 0x02c -#define VEPU_REG_ADDR_IN_PLANE_1 0x030 -#define VEPU_REG_ADDR_IN_PLANE_2 0x034 -#define VEPU_REG_ENC_CTRL 0x038 -#define VEPU_REG_ENC_CTRL_TIMEOUT_EN BIT(31) -#define VEPU_REG_ENC_CTRL_NAL_MODE_BIT BIT(29) -#define VEPU_REG_ENC_CTRL_WIDTH(w) ((w) << 19) -#define VEPU_REG_ENC_CTRL_HEIGHT(h) ((h) << 10) -#define VEPU_REG_ENC_PIC_INTER (0x0 << 3) -#define VEPU_REG_ENC_PIC_INTRA (0x1 << 3) -#define VEPU_REG_ENC_PIC_MVCINTER (0x2 << 3) -#define VEPU_REG_ENC_CTRL_ENC_MODE_H264 (0x3 << 1) -#define VEPU_REG_ENC_CTRL_ENC_MODE_JPEG (0x2 << 1) -#define VEPU_REG_ENC_CTRL_ENC_MODE_VP8 (0x1 << 1) -#define VEPU_REG_ENC_CTRL_EN_BIT BIT(0) -#define VEPU_REG_IN_IMG_CTRL 0x03c -#define VEPU_REG_IN_IMG_CTRL_ROW_LEN(x) ((x) << 12) -#define VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(x) ((x) << 10) -#define VEPU_REG_IN_IMG_CTRL_OVRFLB_D4(x) ((x) << 6) -#define VEPU_REG_IN_IMG_CTRL_FMT(x) ((x) << 2) -#define VEPU_REG_ENC_CTRL0 0x040 -#define VEPU_REG_ENC_CTRL0_INIT_QP(x) ((x) << 26) -#define VEPU_REG_ENC_CTRL0_SLICE_ALPHA(x) ((x) << 22) -#define VEPU_REG_ENC_CTRL0_SLICE_BETA(x) ((x) << 18) -#define VEPU_REG_ENC_CTRL0_CHROMA_QP_OFFSET(x) ((x) << 13) -#define VEPU_REG_ENC_CTRL0_FILTER_DIS(x) ((x) << 5) -#define VEPU_REG_ENC_CTRL0_IDR_PICID(x) ((x) << 1) -#define VEPU_REG_ENC_CTRL0_CONSTR_INTRA_PRED BIT(0) -#define VEPU_REG_ENC_CTRL1 0x044 -#define VEPU_REG_ENC_CTRL1_PPS_ID(x) ((x) << 24) -#define VEPU_REG_ENC_CTRL1_INTRA_PRED_MODE(x) ((x) << 16) -#define VEPU_REG_ENC_CTRL1_FRAME_NUM(x) ((x)) -#define VEPU_REG_ENC_CTRL2 0x048 -#define VEPU_REG_ENC_CTRL2_DEBLOCKING_FILETER_MODE(x) ((x) << 30) -#define VEPU_REG_ENC_CTRL2_H264_SLICE_SIZE(x) ((x) << 23) -#define VEPU_REG_ENC_CTRL2_DISABLE_QUARTER_PIXMV BIT(22) -#define VEPU_REG_ENC_CTRL2_TRANS8X8_MODE_EN BIT(21) -#define VEPU_REG_ENC_CTRL2_CABAC_INIT_IDC(x) ((x) << 19) -#define VEPU_REG_ENC_CTRL2_ENTROPY_CODING_MODE BIT(18) -#define VEPU_REG_ENC_CTRL2_H264_INTER4X4_MODE BIT(17) -#define VEPU_REG_ENC_CTRL2_H264_STREAM_MODE BIT(16) -#define VEPU_REG_ENC_CTRL2_INTRA16X16_MODE(x) ((x)) -#define VEPU_REG_ENC_CTRL3 0x04c -#define VEPU_REG_ENC_CTRL3_MUTIMV_EN BIT(30) -#define VEPU_REG_ENC_CTRL3_MV_PENALTY_1_4P(x) ((x) << 20) -#define VEPU_REG_ENC_CTRL3_MV_PENALTY_4P(x) ((x) << 10) -#define VEPU_REG_ENC_CTRL3_MV_PENALTY_1P(x) ((x)) -#define VEPU_REG_ENC_CTRL4 0x050 -#define VEPU_REG_ENC_CTRL4_MV_PENALTY_16X8_8X16(x) ((x) << 20) -#define VEPU_REG_ENC_CTRL4_MV_PENALTY_8X8(x) ((x) << 10) -#define VEPU_REG_ENC_CTRL4_8X4_4X8(x) ((x)) -#define VEPU_REG_ENC_CTRL5 0x054 -#define VEPU_REG_ENC_CTRL5_MACROBLOCK_PENALTY(x) ((x) << 24) -#define VEPU_REG_ENC_CTRL5_COMPLETE_SLICES(x) ((x) << 16) -#define VEPU_REG_ENC_CTRL5_INTER_MODE(x) ((x)) -#define VEPU_REG_STR_HDR_REM_MSB 0x058 -#define VEPU_REG_STR_HDR_REM_LSB 0x05c -#define VEPU_REG_STR_BUF_LIMIT 0x060 -#define VEPU_REG_MAD_CTRL 0x064 -#define VEPU_REG_MAD_CTRL_QP_ADJUST(x) ((x) << 28) -#define VEPU_REG_MAD_CTRL_MAD_THREDHOLD(x) ((x) << 22) -#define VEPU_REG_MAD_CTRL_QP_SUM_DIV2(x) ((x)) -#define VEPU_REG_ADDR_VP8_PROB_CNT 0x068 -#define VEPU_REG_QP_VAL 0x06c -#define VEPU_REG_QP_VAL_LUM(x) ((x) << 26) -#define VEPU_REG_QP_VAL_MAX(x) ((x) << 20) -#define VEPU_REG_QP_VAL_MIN(x) ((x) << 14) -#define VEPU_REG_QP_VAL_CHECKPOINT_DISTAN(x) ((x)) -#define VEPU_REG_VP8_QP_VAL(i) (0x06c + ((i) * 0x4)) -#define VEPU_REG_CHECKPOINT(i) (0x070 + ((i) * 0x4)) -#define VEPU_REG_CHECKPOINT_CHECK0(x) (((x) & 0xffff)) -#define VEPU_REG_CHECKPOINT_CHECK1(x) (((x) & 0xffff) << 16) -#define VEPU_REG_CHECKPOINT_RESULT(x) ((((x) >> (16 - 16 \ - * (i & 1))) & 0xffff) \ - * 32) -#define VEPU_REG_CHKPT_WORD_ERR(i) (0x084 + ((i) * 0x4)) -#define VEPU_REG_CHKPT_WORD_ERR_CHK0(x) (((x) & 0xffff)) -#define VEPU_REG_CHKPT_WORD_ERR_CHK1(x) (((x) & 0xffff) << 16) -#define VEPU_REG_VP8_BOOL_ENC 0x08c -#define VEPU_REG_CHKPT_DELTA_QP 0x090 -#define VEPU_REG_CHKPT_DELTA_QP_CHK0(x) (((x) & 0x0f) << 0) -#define VEPU_REG_CHKPT_DELTA_QP_CHK1(x) (((x) & 0x0f) << 4) -#define VEPU_REG_CHKPT_DELTA_QP_CHK2(x) (((x) & 0x0f) << 8) -#define VEPU_REG_CHKPT_DELTA_QP_CHK3(x) (((x) & 0x0f) << 12) -#define VEPU_REG_CHKPT_DELTA_QP_CHK4(x) (((x) & 0x0f) << 16) -#define VEPU_REG_CHKPT_DELTA_QP_CHK5(x) (((x) & 0x0f) << 20) -#define VEPU_REG_CHKPT_DELTA_QP_CHK6(x) (((x) & 0x0f) << 24) -#define VEPU_REG_VP8_CTRL0 0x090 -#define VEPU_REG_RLC_CTRL 0x094 -#define VEPU_REG_RLC_CTRL_STR_OFFS_SHIFT 23 -#define VEPU_REG_RLC_CTRL_STR_OFFS_MASK (0x3f << 23) -#define VEPU_REG_RLC_CTRL_RLC_SUM(x) ((x)) -#define VEPU_REG_MB_CTRL 0x098 -#define VEPU_REG_MB_CNT_OUT(x) (((x) & 0xffff)) -#define VEPU_REG_MB_CNT_SET(x) (((x) & 0xffff) << 16) -#define VEPU_REG_ADDR_NEXT_PIC 0x09c -#define VEPU_REG_JPEG_LUMA_QUAT(i) (0x100 + ((i) * 0x4)) -#define VEPU_REG_JPEG_CHROMA_QUAT(i) (0x140 + ((i) * 0x4)) -#define VEPU_REG_STABILIZATION_OUTPUT 0x0A0 -#define VEPU_REG_ADDR_CABAC_TBL 0x0cc -#define VEPU_REG_ADDR_MV_OUT 0x0d0 -#define VEPU_REG_RGB_YUV_COEFF(i) (0x0d4 + ((i) * 0x4)) -#define VEPU_REG_RGB_MASK_MSB 0x0dc -#define VEPU_REG_INTRA_AREA_CTRL 0x0e0 -#define VEPU_REG_CIR_INTRA_CTRL 0x0e4 -#define VEPU_REG_INTRA_SLICE_BITMAP(i) (0x0e8 + ((i) * 0x4)) -#define VEPU_REG_ADDR_VP8_DCT_PART(i) (0x0e8 + ((i) * 0x4)) -#define VEPU_REG_FIRST_ROI_AREA 0x0f0 -#define VEPU_REG_SECOND_ROI_AREA 0x0f4 -#define VEPU_REG_MVC_CTRL 0x0f8 -#define VEPU_REG_MVC_CTRL_MV16X16_FAVOR(x) ((x) << 28) -#define VEPU_REG_VP8_INTRA_PENALTY(i) (0x100 + ((i) * 0x4)) -#define VEPU_REG_ADDR_VP8_SEG_MAP 0x11c -#define VEPU_REG_VP8_SEG_QP(i) (0x120 + ((i) * 0x4)) -#define VEPU_REG_DMV_4P_1P_PENALTY(i) (0x180 + ((i) * 0x4)) -#define VEPU_REG_DMV_4P_1P_PENALTY_BIT(x, i) ((x) << (i) * 8) -#define VEPU_REG_DMV_QPEL_PENALTY(i) (0x200 + ((i) * 0x4)) -#define VEPU_REG_DMV_QPEL_PENALTY_BIT(x, i) ((x) << (i) * 8) -#define VEPU_REG_VP8_CTRL1 0x280 -#define VEPU_REG_VP8_BIT_COST_GOLDEN 0x284 -#define VEPU_REG_VP8_LOOP_FLT_DELTA(i) (0x288 + ((i) * 0x4)) - -/* Decoder registers. */ -#define VDPU_REG_INTERRUPT 0x004 -#define VDPU_REG_INTERRUPT_DEC_PIC_INF BIT(24) -#define VDPU_REG_INTERRUPT_DEC_TIMEOUT BIT(18) -#define VDPU_REG_INTERRUPT_DEC_SLICE_INT BIT(17) -#define VDPU_REG_INTERRUPT_DEC_ERROR_INT BIT(16) -#define VDPU_REG_INTERRUPT_DEC_ASO_INT BIT(15) -#define VDPU_REG_INTERRUPT_DEC_BUFFER_INT BIT(14) -#define VDPU_REG_INTERRUPT_DEC_BUS_INT BIT(13) -#define VDPU_REG_INTERRUPT_DEC_RDY_INT BIT(12) -#define VDPU_REG_INTERRUPT_DEC_IRQ BIT(8) -#define VDPU_REG_INTERRUPT_DEC_IRQ_DIS BIT(4) -#define VDPU_REG_INTERRUPT_DEC_E BIT(0) -#define VDPU_REG_CONFIG 0x008 -#define VDPU_REG_CONFIG_DEC_AXI_RD_ID(x) (((x) & 0xff) << 24) -#define VDPU_REG_CONFIG_DEC_TIMEOUT_E BIT(23) -#define VDPU_REG_CONFIG_DEC_STRSWAP32_E BIT(22) -#define VDPU_REG_CONFIG_DEC_STRENDIAN_E BIT(21) -#define VDPU_REG_CONFIG_DEC_INSWAP32_E BIT(20) -#define VDPU_REG_CONFIG_DEC_OUTSWAP32_E BIT(19) -#define VDPU_REG_CONFIG_DEC_DATA_DISC_E BIT(18) -#define VDPU_REG_CONFIG_TILED_MODE_MSB BIT(17) -#define VDPU_REG_CONFIG_DEC_OUT_TILED_E BIT(17) -#define VDPU_REG_CONFIG_DEC_LATENCY(x) (((x) & 0x3f) << 11) -#define VDPU_REG_CONFIG_DEC_CLK_GATE_E BIT(10) -#define VDPU_REG_CONFIG_DEC_IN_ENDIAN BIT(9) -#define VDPU_REG_CONFIG_DEC_OUT_ENDIAN BIT(8) -#define VDPU_REG_CONFIG_PRIORITY_MODE(x) (((x) & 0x7) << 5) -#define VDPU_REG_CONFIG_TILED_MODE_LSB BIT(7) -#define VDPU_REG_CONFIG_DEC_ADV_PRE_DIS BIT(6) -#define VDPU_REG_CONFIG_DEC_SCMD_DIS BIT(5) -#define VDPU_REG_CONFIG_DEC_MAX_BURST(x) (((x) & 0x1f) << 0) -#define VDPU_REG_DEC_CTRL0 0x00c -#define VDPU_REG_DEC_CTRL0_DEC_MODE(x) (((x) & 0xf) << 28) -#define VDPU_REG_DEC_CTRL0_RLC_MODE_E BIT(27) -#define VDPU_REG_DEC_CTRL0_SKIP_MODE BIT(26) -#define VDPU_REG_DEC_CTRL0_DIVX3_E BIT(25) -#define VDPU_REG_DEC_CTRL0_PJPEG_E BIT(24) -#define VDPU_REG_DEC_CTRL0_PIC_INTERLACE_E BIT(23) -#define VDPU_REG_DEC_CTRL0_PIC_FIELDMODE_E BIT(22) -#define VDPU_REG_DEC_CTRL0_PIC_B_E BIT(21) -#define VDPU_REG_DEC_CTRL0_PIC_INTER_E BIT(20) -#define VDPU_REG_DEC_CTRL0_PIC_TOPFIELD_E BIT(19) -#define VDPU_REG_DEC_CTRL0_FWD_INTERLACE_E BIT(18) -#define VDPU_REG_DEC_CTRL0_SORENSON_E BIT(17) -#define VDPU_REG_DEC_CTRL0_REF_TOPFIELD_E BIT(16) -#define VDPU_REG_DEC_CTRL0_DEC_OUT_DIS BIT(15) -#define VDPU_REG_DEC_CTRL0_FILTERING_DIS BIT(14) -#define VDPU_REG_DEC_CTRL0_WEBP_E BIT(13) -#define VDPU_REG_DEC_CTRL0_MVC_E BIT(13) -#define VDPU_REG_DEC_CTRL0_PIC_FIXED_QUANT BIT(13) -#define VDPU_REG_DEC_CTRL0_WRITE_MVS_E BIT(12) -#define VDPU_REG_DEC_CTRL0_REFTOPFIRST_E BIT(11) -#define VDPU_REG_DEC_CTRL0_SEQ_MBAFF_E BIT(10) -#define VDPU_REG_DEC_CTRL0_PICORD_COUNT_E BIT(9) -#define VDPU_REG_DEC_CTRL0_DEC_AHB_HLOCK_E BIT(8) -#define VDPU_REG_DEC_CTRL0_DEC_AXI_WR_ID(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL1 0x010 -#define VDPU_REG_DEC_CTRL1_PIC_MB_WIDTH(x) (((x) & 0x1ff) << 23) -#define VDPU_REG_DEC_CTRL1_MB_WIDTH_OFF(x) (((x) & 0xf) << 19) -#define VDPU_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(x) (((x) & 0xff) << 11) -#define VDPU_REG_DEC_CTRL1_MB_HEIGHT_OFF(x) (((x) & 0xf) << 7) -#define VDPU_REG_DEC_CTRL1_ALT_SCAN_E BIT(6) -#define VDPU_REG_DEC_CTRL1_TOPFIELDFIRST_E BIT(5) -#define VDPU_REG_DEC_CTRL1_REF_FRAMES(x) (((x) & 0x1f) << 0) -#define VDPU_REG_DEC_CTRL1_PIC_MB_W_EXT(x) (((x) & 0x7) << 3) -#define VDPU_REG_DEC_CTRL1_PIC_MB_H_EXT(x) (((x) & 0x7) << 0) -#define VDPU_REG_DEC_CTRL1_PIC_REFER_FLAG BIT(0) -#define VDPU_REG_DEC_CTRL2 0x014 -#define VDPU_REG_DEC_CTRL2_STRM_START_BIT(x) (((x) & 0x3f) << 26) -#define VDPU_REG_DEC_CTRL2_SYNC_MARKER_E BIT(25) -#define VDPU_REG_DEC_CTRL2_TYPE1_QUANT_E BIT(24) -#define VDPU_REG_DEC_CTRL2_CH_QP_OFFSET(x) (((x) & 0x1f) << 19) -#define VDPU_REG_DEC_CTRL2_CH_QP_OFFSET2(x) (((x) & 0x1f) << 14) -#define VDPU_REG_DEC_CTRL2_FIELDPIC_FLAG_E BIT(0) -#define VDPU_REG_DEC_CTRL2_INTRADC_VLC_THR(x) (((x) & 0x7) << 16) -#define VDPU_REG_DEC_CTRL2_VOP_TIME_INCR(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL2_DQ_PROFILE BIT(24) -#define VDPU_REG_DEC_CTRL2_DQBI_LEVEL BIT(23) -#define VDPU_REG_DEC_CTRL2_RANGE_RED_FRM_E BIT(22) -#define VDPU_REG_DEC_CTRL2_FAST_UVMC_E BIT(20) -#define VDPU_REG_DEC_CTRL2_TRANSDCTAB BIT(17) -#define VDPU_REG_DEC_CTRL2_TRANSACFRM(x) (((x) & 0x3) << 15) -#define VDPU_REG_DEC_CTRL2_TRANSACFRM2(x) (((x) & 0x3) << 13) -#define VDPU_REG_DEC_CTRL2_MB_MODE_TAB(x) (((x) & 0x7) << 10) -#define VDPU_REG_DEC_CTRL2_MVTAB(x) (((x) & 0x7) << 7) -#define VDPU_REG_DEC_CTRL2_CBPTAB(x) (((x) & 0x7) << 4) -#define VDPU_REG_DEC_CTRL2_2MV_BLK_PAT_TAB(x) (((x) & 0x3) << 2) -#define VDPU_REG_DEC_CTRL2_4MV_BLK_PAT_TAB(x) (((x) & 0x3) << 0) -#define VDPU_REG_DEC_CTRL2_QSCALE_TYPE BIT(24) -#define VDPU_REG_DEC_CTRL2_CON_MV_E BIT(4) -#define VDPU_REG_DEC_CTRL2_INTRA_DC_PREC(x) (((x) & 0x3) << 2) -#define VDPU_REG_DEC_CTRL2_INTRA_VLC_TAB BIT(1) -#define VDPU_REG_DEC_CTRL2_FRAME_PRED_DCT BIT(0) -#define VDPU_REG_DEC_CTRL2_JPEG_QTABLES(x) (((x) & 0x3) << 11) -#define VDPU_REG_DEC_CTRL2_JPEG_MODE(x) (((x) & 0x7) << 8) -#define VDPU_REG_DEC_CTRL2_JPEG_FILRIGHT_E BIT(7) -#define VDPU_REG_DEC_CTRL2_JPEG_STREAM_ALL BIT(6) -#define VDPU_REG_DEC_CTRL2_CR_AC_VLCTABLE BIT(5) -#define VDPU_REG_DEC_CTRL2_CB_AC_VLCTABLE BIT(4) -#define VDPU_REG_DEC_CTRL2_CR_DC_VLCTABLE BIT(3) -#define VDPU_REG_DEC_CTRL2_CB_DC_VLCTABLE BIT(2) -#define VDPU_REG_DEC_CTRL2_CR_DC_VLCTABLE3 BIT(1) -#define VDPU_REG_DEC_CTRL2_CB_DC_VLCTABLE3 BIT(0) -#define VDPU_REG_DEC_CTRL2_STRM1_START_BIT(x) (((x) & 0x3f) << 18) -#define VDPU_REG_DEC_CTRL2_HUFFMAN_E BIT(17) -#define VDPU_REG_DEC_CTRL2_MULTISTREAM_E BIT(16) -#define VDPU_REG_DEC_CTRL2_BOOLEAN_VALUE(x) (((x) & 0xff) << 8) -#define VDPU_REG_DEC_CTRL2_BOOLEAN_RANGE(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL2_ALPHA_OFFSET(x) (((x) & 0x1f) << 5) -#define VDPU_REG_DEC_CTRL2_BETA_OFFSET(x) (((x) & 0x1f) << 0) -#define VDPU_REG_DEC_CTRL3 0x018 -#define VDPU_REG_DEC_CTRL3_START_CODE_E BIT(31) -#define VDPU_REG_DEC_CTRL3_INIT_QP(x) (((x) & 0x3f) << 25) -#define VDPU_REG_DEC_CTRL3_CH_8PIX_ILEAV_E BIT(24) -#define VDPU_REG_DEC_CTRL3_STREAM_LEN_EXT(x) (((x) & 0xff) << 24) -#define VDPU_REG_DEC_CTRL3_STREAM_LEN(x) (((x) & 0xffffff) << 0) -#define VDPU_REG_DEC_CTRL4 0x01c -#define VDPU_REG_DEC_CTRL4_CABAC_E BIT(31) -#define VDPU_REG_DEC_CTRL4_BLACKWHITE_E BIT(30) -#define VDPU_REG_DEC_CTRL4_DIR_8X8_INFER_E BIT(29) -#define VDPU_REG_DEC_CTRL4_WEIGHT_PRED_E BIT(28) -#define VDPU_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(x) (((x) & 0x3) << 26) -#define VDPU_REG_DEC_CTRL4_AVS_H264_H_EXT BIT(25) -#define VDPU_REG_DEC_CTRL4_FRAMENUM_LEN(x) (((x) & 0x1f) << 16) -#define VDPU_REG_DEC_CTRL4_FRAMENUM(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL4_BITPLANE0_E BIT(31) -#define VDPU_REG_DEC_CTRL4_BITPLANE1_E BIT(30) -#define VDPU_REG_DEC_CTRL4_BITPLANE2_E BIT(29) -#define VDPU_REG_DEC_CTRL4_ALT_PQUANT(x) (((x) & 0x1f) << 24) -#define VDPU_REG_DEC_CTRL4_DQ_EDGES(x) (((x) & 0xf) << 20) -#define VDPU_REG_DEC_CTRL4_TTMBF BIT(19) -#define VDPU_REG_DEC_CTRL4_PQINDEX(x) (((x) & 0x1f) << 14) -#define VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT BIT(13) -#define VDPU_REG_DEC_CTRL4_BILIN_MC_E BIT(12) -#define VDPU_REG_DEC_CTRL4_UNIQP_E BIT(11) -#define VDPU_REG_DEC_CTRL4_HALFQP_E BIT(10) -#define VDPU_REG_DEC_CTRL4_TTFRM(x) (((x) & 0x3) << 8) -#define VDPU_REG_DEC_CTRL4_2ND_BYTE_EMUL_E BIT(7) -#define VDPU_REG_DEC_CTRL4_DQUANT_E BIT(6) -#define VDPU_REG_DEC_CTRL4_VC1_ADV_E BIT(5) -#define VDPU_REG_DEC_CTRL4_PJPEG_FILDOWN_E BIT(26) -#define VDPU_REG_DEC_CTRL4_PJPEG_WDIV8 BIT(25) -#define VDPU_REG_DEC_CTRL4_PJPEG_HDIV8 BIT(24) -#define VDPU_REG_DEC_CTRL4_PJPEG_AH(x) (((x) & 0xf) << 20) -#define VDPU_REG_DEC_CTRL4_PJPEG_AL(x) (((x) & 0xf) << 16) -#define VDPU_REG_DEC_CTRL4_PJPEG_SS(x) (((x) & 0xff) << 8) -#define VDPU_REG_DEC_CTRL4_PJPEG_SE(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL4_DCT1_START_BIT(x) (((x) & 0x3f) << 26) -#define VDPU_REG_DEC_CTRL4_DCT2_START_BIT(x) (((x) & 0x3f) << 20) -#define VDPU_REG_DEC_CTRL4_CH_MV_RES BIT(13) -#define VDPU_REG_DEC_CTRL4_INIT_DC_MATCH0(x) (((x) & 0x7) << 9) -#define VDPU_REG_DEC_CTRL4_INIT_DC_MATCH1(x) (((x) & 0x7) << 6) -#define VDPU_REG_DEC_CTRL4_VP7_VERSION BIT(5) -#define VDPU_REG_DEC_CTRL5 0x020 -#define VDPU_REG_DEC_CTRL5_CONST_INTRA_E BIT(31) -#define VDPU_REG_DEC_CTRL5_FILT_CTRL_PRES BIT(30) -#define VDPU_REG_DEC_CTRL5_RDPIC_CNT_PRES BIT(29) -#define VDPU_REG_DEC_CTRL5_8X8TRANS_FLAG_E BIT(28) -#define VDPU_REG_DEC_CTRL5_REFPIC_MK_LEN(x) (((x) & 0x7ff) << 17) -#define VDPU_REG_DEC_CTRL5_IDR_PIC_E BIT(16) -#define VDPU_REG_DEC_CTRL5_IDR_PIC_ID(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL5_MV_SCALEFACTOR(x) (((x) & 0xff) << 24) -#define VDPU_REG_DEC_CTRL5_REF_DIST_FWD(x) (((x) & 0x1f) << 19) -#define VDPU_REG_DEC_CTRL5_REF_DIST_BWD(x) (((x) & 0x1f) << 14) -#define VDPU_REG_DEC_CTRL5_LOOP_FILT_LIMIT(x) (((x) & 0xf) << 14) -#define VDPU_REG_DEC_CTRL5_VARIANCE_TEST_E BIT(13) -#define VDPU_REG_DEC_CTRL5_MV_THRESHOLD(x) (((x) & 0x7) << 10) -#define VDPU_REG_DEC_CTRL5_VAR_THRESHOLD(x) (((x) & 0x3ff) << 0) -#define VDPU_REG_DEC_CTRL5_DIVX_IDCT_E BIT(8) -#define VDPU_REG_DEC_CTRL5_DIVX3_SLICE_SIZE(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL5_PJPEG_REST_FREQ(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL5_RV_PROFILE(x) (((x) & 0x3) << 30) -#define VDPU_REG_DEC_CTRL5_RV_OSV_QUANT(x) (((x) & 0x3) << 28) -#define VDPU_REG_DEC_CTRL5_RV_FWD_SCALE(x) (((x) & 0x3fff) << 14) -#define VDPU_REG_DEC_CTRL5_RV_BWD_SCALE(x) (((x) & 0x3fff) << 0) -#define VDPU_REG_DEC_CTRL5_INIT_DC_COMP0(x) (((x) & 0xffff) << 16) -#define VDPU_REG_DEC_CTRL5_INIT_DC_COMP1(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL6 0x024 -#define VDPU_REG_DEC_CTRL6_PPS_ID(x) (((x) & 0xff) << 24) -#define VDPU_REG_DEC_CTRL6_REFIDX1_ACTIVE(x) (((x) & 0x1f) << 19) -#define VDPU_REG_DEC_CTRL6_REFIDX0_ACTIVE(x) (((x) & 0x1f) << 14) -#define VDPU_REG_DEC_CTRL6_POC_LENGTH(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL6_ICOMP0_E BIT(24) -#define VDPU_REG_DEC_CTRL6_ISCALE0(x) (((x) & 0xff) << 16) -#define VDPU_REG_DEC_CTRL6_ISHIFT0(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL6_STREAM1_LEN(x) (((x) & 0xffffff) << 0) -#define VDPU_REG_DEC_CTRL6_PIC_SLICE_AM(x) (((x) & 0x1fff) << 0) -#define VDPU_REG_DEC_CTRL6_COEFFS_PART_AM(x) (((x) & 0xf) << 24) -#define VDPU_REG_FWD_PIC(i) (0x028 + ((i) * 0x4)) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F5(x) (((x) & 0x1f) << 25) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F4(x) (((x) & 0x1f) << 20) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 15) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 10) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 5) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 0) -#define VDPU_REG_FWD_PIC1_ICOMP1_E BIT(24) -#define VDPU_REG_FWD_PIC1_ISCALE1(x) (((x) & 0xff) << 16) -#define VDPU_REG_FWD_PIC1_ISHIFT1(x) (((x) & 0xffff) << 0) -#define VDPU_REG_FWD_PIC1_SEGMENT_BASE(x) ((x) << 0) -#define VDPU_REG_FWD_PIC1_SEGMENT_UPD_E BIT(1) -#define VDPU_REG_FWD_PIC1_SEGMENT_E BIT(0) -#define VDPU_REG_DEC_CTRL7 0x02c -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F15(x) (((x) & 0x1f) << 25) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F14(x) (((x) & 0x1f) << 20) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F13(x) (((x) & 0x1f) << 15) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F12(x) (((x) & 0x1f) << 10) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F11(x) (((x) & 0x1f) << 5) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F10(x) (((x) & 0x1f) << 0) -#define VDPU_REG_DEC_CTRL7_ICOMP2_E BIT(24) -#define VDPU_REG_DEC_CTRL7_ISCALE2(x) (((x) & 0xff) << 16) -#define VDPU_REG_DEC_CTRL7_ISHIFT2(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL7_DCT3_START_BIT(x) (((x) & 0x3f) << 24) -#define VDPU_REG_DEC_CTRL7_DCT4_START_BIT(x) (((x) & 0x3f) << 18) -#define VDPU_REG_DEC_CTRL7_DCT5_START_BIT(x) (((x) & 0x3f) << 12) -#define VDPU_REG_DEC_CTRL7_DCT6_START_BIT(x) (((x) & 0x3f) << 6) -#define VDPU_REG_DEC_CTRL7_DCT7_START_BIT(x) (((x) & 0x3f) << 0) -#define VDPU_REG_ADDR_STR 0x030 -#define VDPU_REG_ADDR_DST 0x034 -#define VDPU_REG_ADDR_REF(i) (0x038 + ((i) * 0x4)) -#define VDPU_REG_ADDR_REF_FIELD_E BIT(1) -#define VDPU_REG_ADDR_REF_TOPC_E BIT(0) -#define VDPU_REG_REF_PIC(i) (0x078 + ((i) * 0x4)) -#define VDPU_REG_REF_PIC_FILT_TYPE_E BIT(31) -#define VDPU_REG_REF_PIC_FILT_SHARPNESS(x) (((x) & 0x7) << 28) -#define VDPU_REG_REF_PIC_MB_ADJ_0(x) (((x) & 0x7f) << 21) -#define VDPU_REG_REF_PIC_MB_ADJ_1(x) (((x) & 0x7f) << 14) -#define VDPU_REG_REF_PIC_MB_ADJ_2(x) (((x) & 0x7f) << 7) -#define VDPU_REG_REF_PIC_MB_ADJ_3(x) (((x) & 0x7f) << 0) -#define VDPU_REG_REF_PIC_REFER1_NBR(x) (((x) & 0xffff) << 16) -#define VDPU_REG_REF_PIC_REFER0_NBR(x) (((x) & 0xffff) << 0) -#define VDPU_REG_REF_PIC_LF_LEVEL_0(x) (((x) & 0x3f) << 18) -#define VDPU_REG_REF_PIC_LF_LEVEL_1(x) (((x) & 0x3f) << 12) -#define VDPU_REG_REF_PIC_LF_LEVEL_2(x) (((x) & 0x3f) << 6) -#define VDPU_REG_REF_PIC_LF_LEVEL_3(x) (((x) & 0x3f) << 0) -#define VDPU_REG_REF_PIC_QUANT_DELTA_0(x) (((x) & 0x1f) << 27) -#define VDPU_REG_REF_PIC_QUANT_DELTA_1(x) (((x) & 0x1f) << 22) -#define VDPU_REG_REF_PIC_QUANT_0(x) (((x) & 0x7ff) << 11) -#define VDPU_REG_REF_PIC_QUANT_1(x) (((x) & 0x7ff) << 0) -#define VDPU_REG_LT_REF 0x098 -#define VDPU_REG_VALID_REF 0x09c -#define VDPU_REG_ADDR_QTABLE 0x0a0 -#define VDPU_REG_ADDR_DIR_MV 0x0a4 -#define VDPU_REG_BD_REF_PIC(i) (0x0a8 + ((i) * 0x4)) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B2(x) (((x) & 0x1f) << 25) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F2(x) (((x) & 0x1f) << 20) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B1(x) (((x) & 0x1f) << 15) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F1(x) (((x) & 0x1f) << 10) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B0(x) (((x) & 0x1f) << 5) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F0(x) (((x) & 0x1f) << 0) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_2_M1(x) (((x) & 0x3) << 10) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_2_4(x) (((x) & 0x3) << 8) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_4_M1(x) (((x) & 0x3) << 6) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_4_4(x) (((x) & 0x3) << 4) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_6_M1(x) (((x) & 0x3) << 2) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_6_4(x) (((x) & 0x3) << 0) -#define VDPU_REG_BD_REF_PIC_QUANT_DELTA_2(x) (((x) & 0x1f) << 27) -#define VDPU_REG_BD_REF_PIC_QUANT_DELTA_3(x) (((x) & 0x1f) << 22) -#define VDPU_REG_BD_REF_PIC_QUANT_2(x) (((x) & 0x7ff) << 11) -#define VDPU_REG_BD_REF_PIC_QUANT_3(x) (((x) & 0x7ff) << 0) -#define VDPU_REG_BD_P_REF_PIC 0x0bc -#define VDPU_REG_BD_P_REF_PIC_QUANT_DELTA_4(x) (((x) & 0x1f) << 27) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 25) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 20) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 15) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 10) -#define VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_B15(x) (((x) & 0x1f) << 5) -#define VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_F15(x) (((x) & 0x1f) << 0) -#define VDPU_REG_ERR_CONC 0x0c0 -#define VDPU_REG_ERR_CONC_STARTMB_X(x) (((x) & 0x1ff) << 23) -#define VDPU_REG_ERR_CONC_STARTMB_Y(x) (((x) & 0xff) << 15) -#define VDPU_REG_PRED_FLT 0x0c4 -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_0(x) (((x) & 0x3ff) << 22) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_1(x) (((x) & 0x3ff) << 12) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_2(x) (((x) & 0x3ff) << 2) -#define VDPU_REG_REF_BUF_CTRL 0x0cc -#define VDPU_REG_REF_BUF_CTRL_REFBU_E BIT(31) -#define VDPU_REG_REF_BUF_CTRL_REFBU_THR(x) (((x) & 0xfff) << 19) -#define VDPU_REG_REF_BUF_CTRL_REFBU_PICID(x) (((x) & 0x1f) << 14) -#define VDPU_REG_REF_BUF_CTRL_REFBU_EVAL_E BIT(13) -#define VDPU_REG_REF_BUF_CTRL_REFBU_FPARMOD_E BIT(12) -#define VDPU_REG_REF_BUF_CTRL_REFBU_Y_OFFSET(x) (((x) & 0x1ff) << 0) -#define VDPU_REG_REF_BUF_CTRL2 0x0dc -#define VDPU_REG_REF_BUF_CTRL2_REFBU2_BUF_E BIT(31) -#define VDPU_REG_REF_BUF_CTRL2_REFBU2_THR(x) (((x) & 0xfff) << 19) -#define VDPU_REG_REF_BUF_CTRL2_REFBU2_PICID(x) (((x) & 0x1f) << 14) -#define VDPU_REG_REF_BUF_CTRL2_APF_THRESHOLD(x) (((x) & 0x3fff) << 0) - -#endif /* RK3288_VPU_REGS_H_ */ diff --git a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c b/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c deleted file mode 100644 index 6fdef61e2127..000000000000 --- a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - * Jeffy Chen <jeffy.chen@rock-chips.com> - */ - -#include <linux/clk.h> - -#include "rockchip_vpu.h" -#include "rockchip_vpu_jpeg.h" -#include "rk3399_vpu_regs.h" - -#define RK3399_ACLK_MAX_FREQ (400 * 1000 * 1000) - -/* - * Supported formats. - */ - -static const struct rockchip_vpu_fmt rk3399_vpu_enc_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_YUV420M, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P, - }, - { - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422, - }, - { - .fourcc = V4L2_PIX_FMT_UYVY, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422, - }, - { - .fourcc = V4L2_PIX_FMT_JPEG, - .codec_mode = RK_VPU_MODE_JPEG_ENC, - .max_depth = 2, - .header_size = JPEG_HEADER_SIZE, - .frmsize = { - .min_width = 96, - .max_width = 8192, - .step_width = JPEG_MB_DIM, - .min_height = 32, - .max_height = 8192, - .step_height = JPEG_MB_DIM, - }, - }, -}; - -static irqreturn_t rk3399_vepu_irq(int irq, void *dev_id) -{ - struct rockchip_vpu_dev *vpu = dev_id; - enum vb2_buffer_state state; - u32 status, bytesused; - - status = vepu_read(vpu, VEPU_REG_INTERRUPT); - bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8; - state = (status & VEPU_REG_INTERRUPT_FRAME_READY) ? - VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - - vepu_write(vpu, 0, VEPU_REG_INTERRUPT); - vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); - - rockchip_vpu_irq_done(vpu, bytesused, state); - - return IRQ_HANDLED; -} - -static int rk3399_vpu_hw_init(struct rockchip_vpu_dev *vpu) -{ - /* Bump ACLK to max. possible freq. to improve performance. */ - clk_set_rate(vpu->clocks[0].clk, RK3399_ACLK_MAX_FREQ); - return 0; -} - -static void rk3399_vpu_enc_reset(struct rockchip_vpu_ctx *ctx) -{ - struct rockchip_vpu_dev *vpu = ctx->dev; - - vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT); - vepu_write(vpu, 0, VEPU_REG_ENCODE_START); - vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); -} - -/* - * Supported codec ops. - */ - -static const struct rockchip_vpu_codec_ops rk3399_vpu_codec_ops[] = { - [RK_VPU_MODE_JPEG_ENC] = { - .run = rk3399_vpu_jpeg_enc_run, - .reset = rk3399_vpu_enc_reset, - }, -}; - -/* - * VPU variant. - */ - -const struct rockchip_vpu_variant rk3399_vpu_variant = { - .enc_offset = 0x0, - .enc_fmts = rk3399_vpu_enc_fmts, - .num_enc_fmts = ARRAY_SIZE(rk3399_vpu_enc_fmts), - .codec = RK_VPU_CODEC_JPEG, - .codec_ops = rk3399_vpu_codec_ops, - .vepu_irq = rk3399_vepu_irq, - .init = rk3399_vpu_hw_init, - .clk_names = {"aclk", "hclk"}, - .num_clocks = 2 -}; diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu.h deleted file mode 100644 index 1ec2be483e27..000000000000 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu.h +++ /dev/null @@ -1,232 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Rockchip VPU codec driver - * - * Copyright 2018 Google LLC. - * Tomasz Figa <tfiga@chromium.org> - * - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - */ - -#ifndef ROCKCHIP_VPU_H_ -#define ROCKCHIP_VPU_H_ - -#include <linux/platform_device.h> -#include <linux/videodev2.h> -#include <linux/wait.h> -#include <linux/clk.h> - -#include <media/v4l2-ctrls.h> -#include <media/v4l2-device.h> -#include <media/v4l2-ioctl.h> -#include <media/videobuf2-core.h> -#include <media/videobuf2-dma-contig.h> - -#include "rockchip_vpu_hw.h" - -#define ROCKCHIP_VPU_MAX_CLOCKS 4 - -#define JPEG_MB_DIM 16 -#define JPEG_MB_WIDTH(w) DIV_ROUND_UP(w, JPEG_MB_DIM) -#define JPEG_MB_HEIGHT(h) DIV_ROUND_UP(h, JPEG_MB_DIM) - -struct rockchip_vpu_ctx; -struct rockchip_vpu_codec_ops; - -#define RK_VPU_CODEC_JPEG BIT(0) - -/** - * struct rockchip_vpu_variant - information about VPU hardware variant - * - * @enc_offset: Offset from VPU base to encoder registers. - * @enc_fmts: Encoder formats. - * @num_enc_fmts: Number of encoder formats. - * @codec: Supported codecs - * @codec_ops: Codec ops. - * @init: Initialize hardware. - * @vepu_irq: encoder interrupt handler - * @clk_names: array of clock names - * @num_clocks: number of clocks in the array - */ -struct rockchip_vpu_variant { - unsigned int enc_offset; - const struct rockchip_vpu_fmt *enc_fmts; - unsigned int num_enc_fmts; - unsigned int codec; - const struct rockchip_vpu_codec_ops *codec_ops; - int (*init)(struct rockchip_vpu_dev *vpu); - irqreturn_t (*vepu_irq)(int irq, void *priv); - const char *clk_names[ROCKCHIP_VPU_MAX_CLOCKS]; - int num_clocks; -}; - -/** - * enum rockchip_vpu_codec_mode - codec operating mode. - * @RK_VPU_MODE_NONE: No operating mode. Used for RAW video formats. - * @RK_VPU_MODE_JPEG_ENC: JPEG encoder. - */ -enum rockchip_vpu_codec_mode { - RK_VPU_MODE_NONE = -1, - RK_VPU_MODE_JPEG_ENC, -}; - -/** - * struct rockchip_vpu_dev - driver data - * @v4l2_dev: V4L2 device to register video devices for. - * @m2m_dev: mem2mem device associated to this device. - * @mdev: media device associated to this device. - * @vfd_enc: Video device for encoder. - * @pdev: Pointer to VPU platform device. - * @dev: Pointer to device for convenient logging using - * dev_ macros. - * @clocks: Array of clock handles. - * @base: Mapped address of VPU registers. - * @enc_base: Mapped address of VPU encoder register for convenience. - * @vpu_mutex: Mutex to synchronize V4L2 calls. - * @irqlock: Spinlock to synchronize access to data structures - * shared with interrupt handlers. - * @variant: Hardware variant-specific parameters. - * @watchdog_work: Delayed work for hardware timeout handling. - */ -struct rockchip_vpu_dev { - struct v4l2_device v4l2_dev; - struct v4l2_m2m_dev *m2m_dev; - struct media_device mdev; - struct video_device *vfd_enc; - struct platform_device *pdev; - struct device *dev; - struct clk_bulk_data clocks[ROCKCHIP_VPU_MAX_CLOCKS]; - void __iomem *base; - void __iomem *enc_base; - - struct mutex vpu_mutex; /* video_device lock */ - spinlock_t irqlock; - const struct rockchip_vpu_variant *variant; - struct delayed_work watchdog_work; -}; - -/** - * struct rockchip_vpu_ctx - Context (instance) private data. - * - * @dev: VPU driver data to which the context belongs. - * @fh: V4L2 file handler. - * - * @sequence_cap: Sequence counter for capture queue - * @sequence_out: Sequence counter for output queue - * - * @vpu_src_fmt: Descriptor of active source format. - * @src_fmt: V4L2 pixel format of active source format. - * @vpu_dst_fmt: Descriptor of active destination format. - * @dst_fmt: V4L2 pixel format of active destination format. - * - * @ctrl_handler: Control handler used to register controls. - * @jpeg_quality: User-specified JPEG compression quality. - * - * @codec_ops: Set of operations related to codec mode. - * - * @bounce_dma_addr: Bounce buffer bus address. - * @bounce_buf: Bounce buffer pointer. - * @bounce_size: Bounce buffer size. - */ -struct rockchip_vpu_ctx { - struct rockchip_vpu_dev *dev; - struct v4l2_fh fh; - - u32 sequence_cap; - u32 sequence_out; - - const struct rockchip_vpu_fmt *vpu_src_fmt; - struct v4l2_pix_format_mplane src_fmt; - const struct rockchip_vpu_fmt *vpu_dst_fmt; - struct v4l2_pix_format_mplane dst_fmt; - - struct v4l2_ctrl_handler ctrl_handler; - int jpeg_quality; - - const struct rockchip_vpu_codec_ops *codec_ops; - - dma_addr_t bounce_dma_addr; - void *bounce_buf; - size_t bounce_size; -}; - -/** - * struct rockchip_vpu_fmt - information about supported video formats. - * @name: Human readable name of the format. - * @fourcc: FourCC code of the format. See V4L2_PIX_FMT_*. - * @codec_mode: Codec mode related to this format. See - * enum rockchip_vpu_codec_mode. - * @header_size: Optional header size. Currently used by JPEG encoder. - * @max_depth: Maximum depth, for bitstream formats - * @enc_fmt: Format identifier for encoder registers. - * @frmsize: Supported range of frame sizes (only for bitstream formats). - */ -struct rockchip_vpu_fmt { - char *name; - u32 fourcc; - enum rockchip_vpu_codec_mode codec_mode; - int header_size; - int max_depth; - enum rockchip_vpu_enc_fmt enc_fmt; - struct v4l2_frmsize_stepwise frmsize; -}; - -/* Logging helpers */ - -/** - * debug - Module parameter to control level of debugging messages. - * - * Level of debugging messages can be controlled by bits of - * module parameter called "debug". Meaning of particular - * bits is as follows: - * - * bit 0 - global information: mode, size, init, release - * bit 1 - each run start/result information - * bit 2 - contents of small controls from userspace - * bit 3 - contents of big controls from userspace - * bit 4 - detail fmt, ctrl, buffer q/dq information - * bit 5 - detail function enter/leave trace information - * bit 6 - register write/read information - */ -extern int rockchip_vpu_debug; - -#define vpu_debug(level, fmt, args...) \ - do { \ - if (rockchip_vpu_debug & BIT(level)) \ - pr_info("%s:%d: " fmt, \ - __func__, __LINE__, ##args); \ - } while (0) - -#define vpu_err(fmt, args...) \ - pr_err("%s:%d: " fmt, __func__, __LINE__, ##args) - -/* Structure access helpers. */ -static inline struct rockchip_vpu_ctx *fh_to_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct rockchip_vpu_ctx, fh); -} - -/* Register accessors. */ -static inline void vepu_write_relaxed(struct rockchip_vpu_dev *vpu, - u32 val, u32 reg) -{ - vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); - writel_relaxed(val, vpu->enc_base + reg); -} - -static inline void vepu_write(struct rockchip_vpu_dev *vpu, u32 val, u32 reg) -{ - vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); - writel(val, vpu->enc_base + reg); -} - -static inline u32 vepu_read(struct rockchip_vpu_dev *vpu, u32 reg) -{ - u32 val = readl(vpu->enc_base + reg); - - vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); - return val; -} - -#endif /* ROCKCHIP_VPU_H_ */ diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_common.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu_common.h deleted file mode 100644 index ca77668d9579..000000000000 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_common.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - * Alpha Lin <Alpha.Lin@rock-chips.com> - * Jeffy Chen <jeffy.chen@rock-chips.com> - * - * Copyright 2018 Google LLC. - * Tomasz Figa <tfiga@chromium.org> - * - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - */ - -#ifndef ROCKCHIP_VPU_COMMON_H_ -#define ROCKCHIP_VPU_COMMON_H_ - -#include "rockchip_vpu.h" - -extern const struct v4l2_ioctl_ops rockchip_vpu_enc_ioctl_ops; -extern const struct vb2_ops rockchip_vpu_enc_queue_ops; - -void rockchip_vpu_enc_reset_src_fmt(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx); -void rockchip_vpu_enc_reset_dst_fmt(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx); - -#endif /* ROCKCHIP_VPU_COMMON_H_ */ diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c b/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c deleted file mode 100644 index 8bbc905b26c8..000000000000 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c +++ /dev/null @@ -1,542 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Collabora, Ltd. - * Copyright 2018 Google LLC. - * Tomasz Figa <tfiga@chromium.org> - * - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - */ - -#include <linux/clk.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/platform_device.h> -#include <linux/pm.h> -#include <linux/pm_runtime.h> -#include <linux/slab.h> -#include <linux/videodev2.h> -#include <linux/workqueue.h> -#include <media/v4l2-event.h> -#include <media/v4l2-mem2mem.h> -#include <media/videobuf2-core.h> -#include <media/videobuf2-vmalloc.h> - -#include "rockchip_vpu_common.h" -#include "rockchip_vpu.h" -#include "rockchip_vpu_hw.h" - -#define DRIVER_NAME "rockchip-vpu" - -int rockchip_vpu_debug; -module_param_named(debug, rockchip_vpu_debug, int, 0644); -MODULE_PARM_DESC(debug, - "Debug level - higher value produces more verbose messages"); - -static void rockchip_vpu_job_finish(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx, - unsigned int bytesused, - enum vb2_buffer_state result) -{ - struct vb2_v4l2_buffer *src, *dst; - size_t avail_size; - - pm_runtime_mark_last_busy(vpu->dev); - pm_runtime_put_autosuspend(vpu->dev); - clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks); - - src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - - if (WARN_ON(!src)) - return; - if (WARN_ON(!dst)) - return; - - src->sequence = ctx->sequence_out++; - dst->sequence = ctx->sequence_cap++; - - dst->field = src->field; - if (src->flags & V4L2_BUF_FLAG_TIMECODE) - dst->timecode = src->timecode; - dst->vb2_buf.timestamp = src->vb2_buf.timestamp; - dst->flags &= ~(V4L2_BUF_FLAG_TSTAMP_SRC_MASK | - V4L2_BUF_FLAG_TIMECODE); - dst->flags |= src->flags & (V4L2_BUF_FLAG_TSTAMP_SRC_MASK | - V4L2_BUF_FLAG_TIMECODE); - - avail_size = vb2_plane_size(&dst->vb2_buf, 0) - - ctx->vpu_dst_fmt->header_size; - if (bytesused <= avail_size) { - if (ctx->bounce_buf) { - memcpy(vb2_plane_vaddr(&dst->vb2_buf, 0) + - ctx->vpu_dst_fmt->header_size, - ctx->bounce_buf, bytesused); - } - dst->vb2_buf.planes[0].bytesused = - ctx->vpu_dst_fmt->header_size + bytesused; - } else { - result = VB2_BUF_STATE_ERROR; - } - - v4l2_m2m_buf_done(src, result); - v4l2_m2m_buf_done(dst, result); - - v4l2_m2m_job_finish(vpu->m2m_dev, ctx->fh.m2m_ctx); -} - -void rockchip_vpu_irq_done(struct rockchip_vpu_dev *vpu, - unsigned int bytesused, - enum vb2_buffer_state result) -{ - struct rockchip_vpu_ctx *ctx = - v4l2_m2m_get_curr_priv(vpu->m2m_dev); - - /* - * If cancel_delayed_work returns false - * the timeout expired. The watchdog is running, - * and will take care of finishing the job. - */ - if (cancel_delayed_work(&vpu->watchdog_work)) - rockchip_vpu_job_finish(vpu, ctx, bytesused, result); -} - -void rockchip_vpu_watchdog(struct work_struct *work) -{ - struct rockchip_vpu_dev *vpu; - struct rockchip_vpu_ctx *ctx; - - vpu = container_of(to_delayed_work(work), - struct rockchip_vpu_dev, watchdog_work); - ctx = v4l2_m2m_get_curr_priv(vpu->m2m_dev); - if (ctx) { - vpu_err("frame processing timed out!\n"); - ctx->codec_ops->reset(ctx); - rockchip_vpu_job_finish(vpu, ctx, 0, VB2_BUF_STATE_ERROR); - } -} - -static void device_run(void *priv) -{ - struct rockchip_vpu_ctx *ctx = priv; - int ret; - - ret = clk_bulk_enable(ctx->dev->variant->num_clocks, ctx->dev->clocks); - if (ret) - goto err_cancel_job; - ret = pm_runtime_get_sync(ctx->dev->dev); - if (ret < 0) - goto err_cancel_job; - - ctx->codec_ops->run(ctx); - return; - -err_cancel_job: - rockchip_vpu_job_finish(ctx->dev, ctx, 0, VB2_BUF_STATE_ERROR); -} - -static struct v4l2_m2m_ops vpu_m2m_ops = { - .device_run = device_run, -}; - -static int -enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) -{ - struct rockchip_vpu_ctx *ctx = priv; - int ret; - - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - src_vq->io_modes = VB2_MMAP | VB2_DMABUF; - src_vq->drv_priv = ctx; - src_vq->ops = &rockchip_vpu_enc_queue_ops; - src_vq->mem_ops = &vb2_dma_contig_memops; - - /* - * Driver does mostly sequential access, so sacrifice TLB efficiency - * for faster allocation. Also, no CPU access on the source queue, - * so no kernel mapping needed. - */ - src_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES | - DMA_ATTR_NO_KERNEL_MAPPING; - src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - src_vq->lock = &ctx->dev->vpu_mutex; - src_vq->dev = ctx->dev->v4l2_dev.dev; - - ret = vb2_queue_init(src_vq); - if (ret) - return ret; - - /* - * The CAPTURE queue doesn't need dma memory, - * as the CPU needs to create the JPEG frames, - * from the hardware-produced JPEG payload. - * - * For the DMA destination buffer, we use - * a bounce buffer. - */ - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; - dst_vq->drv_priv = ctx; - dst_vq->ops = &rockchip_vpu_enc_queue_ops; - dst_vq->mem_ops = &vb2_vmalloc_memops; - dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - dst_vq->lock = &ctx->dev->vpu_mutex; - dst_vq->dev = ctx->dev->v4l2_dev.dev; - - return vb2_queue_init(dst_vq); -} - -static int rockchip_vpu_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct rockchip_vpu_ctx *ctx; - - ctx = container_of(ctrl->handler, - struct rockchip_vpu_ctx, ctrl_handler); - - vpu_debug(1, "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val); - - switch (ctrl->id) { - case V4L2_CID_JPEG_COMPRESSION_QUALITY: - ctx->jpeg_quality = ctrl->val; - break; - default: - return -EINVAL; - } - - return 0; -} - -static const struct v4l2_ctrl_ops rockchip_vpu_ctrl_ops = { - .s_ctrl = rockchip_vpu_s_ctrl, -}; - -static int rockchip_vpu_ctrls_setup(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx) -{ - v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1); - if (vpu->variant->codec & RK_VPU_CODEC_JPEG) { - v4l2_ctrl_new_std(&ctx->ctrl_handler, &rockchip_vpu_ctrl_ops, - V4L2_CID_JPEG_COMPRESSION_QUALITY, - 5, 100, 1, 50); - if (ctx->ctrl_handler.error) { - vpu_err("Adding JPEG control failed %d\n", - ctx->ctrl_handler.error); - v4l2_ctrl_handler_free(&ctx->ctrl_handler); - return ctx->ctrl_handler.error; - } - } - - return v4l2_ctrl_handler_setup(&ctx->ctrl_handler); -} - -/* - * V4L2 file operations. - */ - -static int rockchip_vpu_open(struct file *filp) -{ - struct rockchip_vpu_dev *vpu = video_drvdata(filp); - struct video_device *vdev = video_devdata(filp); - struct rockchip_vpu_ctx *ctx; - int ret; - - /* - * We do not need any extra locking here, because we operate only - * on local data here, except reading few fields from dev, which - * do not change through device's lifetime (which is guaranteed by - * reference on module from open()) and V4L2 internal objects (such - * as vdev and ctx->fh), which have proper locking done in respective - * helper functions used here. - */ - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->dev = vpu; - if (vdev == vpu->vfd_enc) - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx, - &enc_queue_init); - else - ctx->fh.m2m_ctx = ERR_PTR(-ENODEV); - if (IS_ERR(ctx->fh.m2m_ctx)) { - ret = PTR_ERR(ctx->fh.m2m_ctx); - kfree(ctx); - return ret; - } - - v4l2_fh_init(&ctx->fh, vdev); - filp->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); - - if (vdev == vpu->vfd_enc) { - rockchip_vpu_enc_reset_dst_fmt(vpu, ctx); - rockchip_vpu_enc_reset_src_fmt(vpu, ctx); - } - - ret = rockchip_vpu_ctrls_setup(vpu, ctx); - if (ret) { - vpu_err("Failed to set up controls\n"); - goto err_fh_free; - } - ctx->fh.ctrl_handler = &ctx->ctrl_handler; - - return 0; - -err_fh_free: - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - kfree(ctx); - return ret; -} - -static int rockchip_vpu_release(struct file *filp) -{ - struct rockchip_vpu_ctx *ctx = - container_of(filp->private_data, struct rockchip_vpu_ctx, fh); - - /* - * No need for extra locking because this was the last reference - * to this file. - */ - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - v4l2_ctrl_handler_free(&ctx->ctrl_handler); - kfree(ctx); - - return 0; -} - -static const struct v4l2_file_operations rockchip_vpu_fops = { - .owner = THIS_MODULE, - .open = rockchip_vpu_open, - .release = rockchip_vpu_release, - .poll = v4l2_m2m_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = v4l2_m2m_fop_mmap, -}; - -static const struct of_device_id of_rockchip_vpu_match[] = { - { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, - { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, of_rockchip_vpu_match); - -static int rockchip_vpu_video_device_register(struct rockchip_vpu_dev *vpu) -{ - const struct of_device_id *match; - struct video_device *vfd; - int function, ret; - - match = of_match_node(of_rockchip_vpu_match, vpu->dev->of_node); - vfd = video_device_alloc(); - if (!vfd) { - v4l2_err(&vpu->v4l2_dev, "Failed to allocate video device\n"); - return -ENOMEM; - } - - vfd->fops = &rockchip_vpu_fops; - vfd->release = video_device_release; - vfd->lock = &vpu->vpu_mutex; - vfd->v4l2_dev = &vpu->v4l2_dev; - vfd->vfl_dir = VFL_DIR_M2M; - vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; - vfd->ioctl_ops = &rockchip_vpu_enc_ioctl_ops; - snprintf(vfd->name, sizeof(vfd->name), "%s-enc", match->compatible); - vpu->vfd_enc = vfd; - video_set_drvdata(vfd, vpu); - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); - if (ret) { - v4l2_err(&vpu->v4l2_dev, "Failed to register video device\n"); - goto err_free_dev; - } - v4l2_info(&vpu->v4l2_dev, "registered as /dev/video%d\n", vfd->num); - - function = MEDIA_ENT_F_PROC_VIDEO_ENCODER; - ret = v4l2_m2m_register_media_controller(vpu->m2m_dev, vfd, function); - if (ret) { - v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem media controller\n"); - goto err_unreg_video; - } - return 0; - -err_unreg_video: - video_unregister_device(vfd); -err_free_dev: - video_device_release(vfd); - return ret; -} - -static int rockchip_vpu_probe(struct platform_device *pdev) -{ - const struct of_device_id *match; - struct rockchip_vpu_dev *vpu; - struct resource *res; - int i, ret; - - vpu = devm_kzalloc(&pdev->dev, sizeof(*vpu), GFP_KERNEL); - if (!vpu) - return -ENOMEM; - - vpu->dev = &pdev->dev; - vpu->pdev = pdev; - mutex_init(&vpu->vpu_mutex); - spin_lock_init(&vpu->irqlock); - - match = of_match_node(of_rockchip_vpu_match, pdev->dev.of_node); - vpu->variant = match->data; - - INIT_DELAYED_WORK(&vpu->watchdog_work, rockchip_vpu_watchdog); - - for (i = 0; i < vpu->variant->num_clocks; i++) - vpu->clocks[i].id = vpu->variant->clk_names[i]; - ret = devm_clk_bulk_get(&pdev->dev, vpu->variant->num_clocks, - vpu->clocks); - if (ret) - return ret; - - res = platform_get_resource(vpu->pdev, IORESOURCE_MEM, 0); - vpu->base = devm_ioremap_resource(vpu->dev, res); - if (IS_ERR(vpu->base)) - return PTR_ERR(vpu->base); - vpu->enc_base = vpu->base + vpu->variant->enc_offset; - - ret = dma_set_coherent_mask(vpu->dev, DMA_BIT_MASK(32)); - if (ret) { - dev_err(vpu->dev, "Could not set DMA coherent mask.\n"); - return ret; - } - - if (vpu->variant->vepu_irq) { - int irq; - - irq = platform_get_irq_byname(vpu->pdev, "vepu"); - if (irq <= 0) { - dev_err(vpu->dev, "Could not get vepu IRQ.\n"); - return -ENXIO; - } - - ret = devm_request_irq(vpu->dev, irq, vpu->variant->vepu_irq, - 0, dev_name(vpu->dev), vpu); - if (ret) { - dev_err(vpu->dev, "Could not request vepu IRQ.\n"); - return ret; - } - } - - ret = vpu->variant->init(vpu); - if (ret) { - dev_err(&pdev->dev, "Failed to init VPU hardware\n"); - return ret; - } - - pm_runtime_set_autosuspend_delay(vpu->dev, 100); - pm_runtime_use_autosuspend(vpu->dev); - pm_runtime_enable(vpu->dev); - - ret = clk_bulk_prepare(vpu->variant->num_clocks, vpu->clocks); - if (ret) { - dev_err(&pdev->dev, "Failed to prepare clocks\n"); - return ret; - } - - ret = v4l2_device_register(&pdev->dev, &vpu->v4l2_dev); - if (ret) { - dev_err(&pdev->dev, "Failed to register v4l2 device\n"); - goto err_clk_unprepare; - } - platform_set_drvdata(pdev, vpu); - - vpu->m2m_dev = v4l2_m2m_init(&vpu_m2m_ops); - if (IS_ERR(vpu->m2m_dev)) { - v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem device\n"); - ret = PTR_ERR(vpu->m2m_dev); - goto err_v4l2_unreg; - } - - vpu->mdev.dev = vpu->dev; - strscpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model)); - strscpy(vpu->mdev.bus_info, "platform: " DRIVER_NAME, - sizeof(vpu->mdev.model)); - media_device_init(&vpu->mdev); - vpu->v4l2_dev.mdev = &vpu->mdev; - - ret = rockchip_vpu_video_device_register(vpu); - if (ret) { - dev_err(&pdev->dev, "Failed to register encoder\n"); - goto err_m2m_rel; - } - - ret = media_device_register(&vpu->mdev); - if (ret) { - v4l2_err(&vpu->v4l2_dev, "Failed to register mem2mem media device\n"); - goto err_video_dev_unreg; - } - return 0; -err_video_dev_unreg: - if (vpu->vfd_enc) { - v4l2_m2m_unregister_media_controller(vpu->m2m_dev); - video_unregister_device(vpu->vfd_enc); - video_device_release(vpu->vfd_enc); - } -err_m2m_rel: - media_device_cleanup(&vpu->mdev); - v4l2_m2m_release(vpu->m2m_dev); -err_v4l2_unreg: - v4l2_device_unregister(&vpu->v4l2_dev); -err_clk_unprepare: - clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks); - pm_runtime_dont_use_autosuspend(vpu->dev); - pm_runtime_disable(vpu->dev); - return ret; -} - -static int rockchip_vpu_remove(struct platform_device *pdev) -{ - struct rockchip_vpu_dev *vpu = platform_get_drvdata(pdev); - - v4l2_info(&vpu->v4l2_dev, "Removing %s\n", pdev->name); - - media_device_unregister(&vpu->mdev); - if (vpu->vfd_enc) { - v4l2_m2m_unregister_media_controller(vpu->m2m_dev); - video_unregister_device(vpu->vfd_enc); - video_device_release(vpu->vfd_enc); - } - media_device_cleanup(&vpu->mdev); - v4l2_m2m_release(vpu->m2m_dev); - v4l2_device_unregister(&vpu->v4l2_dev); - clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks); - pm_runtime_dont_use_autosuspend(vpu->dev); - pm_runtime_disable(vpu->dev); - return 0; -} - -static const struct dev_pm_ops rockchip_vpu_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) -}; - -static struct platform_driver rockchip_vpu_driver = { - .probe = rockchip_vpu_probe, - .remove = rockchip_vpu_remove, - .driver = { - .name = DRIVER_NAME, - .of_match_table = of_match_ptr(of_rockchip_vpu_match), - .pm = &rockchip_vpu_pm_ops, - }, -}; -module_platform_driver(rockchip_vpu_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Alpha Lin <Alpha.Lin@Rock-Chips.com>"); -MODULE_AUTHOR("Tomasz Figa <tfiga@chromium.org>"); -MODULE_AUTHOR("Ezequiel Garcia <ezequiel@collabora.com>"); -MODULE_DESCRIPTION("Rockchip VPU codec driver"); diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c b/drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c deleted file mode 100644 index dcbfc3cbc9f3..000000000000 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c +++ /dev/null @@ -1,671 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Collabora, Ltd. - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - * Alpha Lin <Alpha.Lin@rock-chips.com> - * Jeffy Chen <jeffy.chen@rock-chips.com> - * - * Copyright 2018 Google LLC. - * Tomasz Figa <tfiga@chromium.org> - * - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. - */ - -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/pm_runtime.h> -#include <linux/videodev2.h> -#include <linux/workqueue.h> -#include <media/v4l2-ctrls.h> -#include <media/v4l2-event.h> -#include <media/v4l2-mem2mem.h> -#include <media/videobuf2-core.h> -#include <media/videobuf2-dma-sg.h> - -#include "rockchip_vpu.h" -#include "rockchip_vpu_hw.h" -#include "rockchip_vpu_common.h" - -/** - * struct v4l2_format_info - information about a V4L2 format - * @format: 4CC format identifier (V4L2_PIX_FMT_*) - * @header_size: Size of header, optional and used by compressed formats - * @num_planes: Number of planes (1 to 3) - * @cpp: Number of bytes per pixel (per plane) - * @hsub: Horizontal chroma subsampling factor - * @vsub: Vertical chroma subsampling factor - * @is_compressed: Is it a compressed format? - * @multiplanar: Is it a multiplanar variant format? (e.g. NV12M) - */ -struct rockchip_vpu_v4l2_format_info { - u32 format; - u32 header_size; - u8 num_planes; - u8 cpp[3]; - u8 hsub; - u8 vsub; - u8 is_compressed; - u8 multiplanar; -}; - -static const struct rockchip_vpu_v4l2_format_info * -rockchip_vpu_v4l2_format_info(u32 format) -{ - static const struct rockchip_vpu_v4l2_format_info formats[] = { - { .format = V4L2_PIX_FMT_YUV420M, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2, .multiplanar = 1 }, - { .format = V4L2_PIX_FMT_NV12M, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .multiplanar = 1 }, - { .format = V4L2_PIX_FMT_YUYV, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, - { .format = V4L2_PIX_FMT_UYVY, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, - }; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(formats); ++i) { - if (formats[i].format == format) - return &formats[i]; - } - - vpu_err("Unsupported V4L 4CC format (%08x)\n", format); - return NULL; -} - -static void -fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, - int pixelformat, int width, int height) -{ - const struct rockchip_vpu_v4l2_format_info *info; - struct v4l2_plane_pix_format *plane; - int i; - - info = rockchip_vpu_v4l2_format_info(pixelformat); - if (!info) - return; - - pixfmt->width = width; - pixfmt->height = height; - pixfmt->pixelformat = pixelformat; - - if (!info->multiplanar) { - pixfmt->num_planes = 1; - plane = &pixfmt->plane_fmt[0]; - plane->bytesperline = info->is_compressed ? - 0 : width * info->cpp[0]; - plane->sizeimage = info->header_size; - for (i = 0; i < info->num_planes; i++) { - unsigned int hsub = (i == 0) ? 1 : info->hsub; - unsigned int vsub = (i == 0) ? 1 : info->vsub; - - plane->sizeimage += info->cpp[i] * - DIV_ROUND_UP(width, hsub) * - DIV_ROUND_UP(height, vsub); - } - } else { - pixfmt->num_planes = info->num_planes; - for (i = 0; i < info->num_planes; i++) { - unsigned int hsub = (i == 0) ? 1 : info->hsub; - unsigned int vsub = (i == 0) ? 1 : info->vsub; - - plane = &pixfmt->plane_fmt[i]; - plane->bytesperline = - info->cpp[i] * DIV_ROUND_UP(width, hsub); - plane->sizeimage = - plane->bytesperline * DIV_ROUND_UP(height, vsub); - } - } -} - -static const struct rockchip_vpu_fmt * -rockchip_vpu_find_format(struct rockchip_vpu_ctx *ctx, u32 fourcc) -{ - struct rockchip_vpu_dev *dev = ctx->dev; - const struct rockchip_vpu_fmt *formats; - unsigned int num_fmts, i; - - formats = dev->variant->enc_fmts; - num_fmts = dev->variant->num_enc_fmts; - for (i = 0; i < num_fmts; i++) - if (formats[i].fourcc == fourcc) - return &formats[i]; - return NULL; -} - -static const struct rockchip_vpu_fmt * -rockchip_vpu_get_default_fmt(struct rockchip_vpu_ctx *ctx, bool bitstream) -{ - struct rockchip_vpu_dev *dev = ctx->dev; - const struct rockchip_vpu_fmt *formats; - unsigned int num_fmts, i; - - formats = dev->variant->enc_fmts; - num_fmts = dev->variant->num_enc_fmts; - for (i = 0; i < num_fmts; i++) { - if (bitstream == (formats[i].codec_mode != RK_VPU_MODE_NONE)) - return &formats[i]; - } - return NULL; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct rockchip_vpu_dev *vpu = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - - strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver)); - strscpy(cap->card, vdev->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s", - vpu->dev->driver->name); - return 0; -} - -static int vidioc_enum_framesizes(struct file *file, void *priv, - struct v4l2_frmsizeenum *fsize) -{ - struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv); - const struct rockchip_vpu_fmt *fmt; - - if (fsize->index != 0) { - vpu_debug(0, "invalid frame size index (expected 0, got %d)\n", - fsize->index); - return -EINVAL; - } - - fmt = rockchip_vpu_find_format(ctx, fsize->pixel_format); - if (!fmt) { - vpu_debug(0, "unsupported bitstream format (%08x)\n", - fsize->pixel_format); - return -EINVAL; - } - - /* This only makes sense for coded formats */ - if (fmt->codec_mode == RK_VPU_MODE_NONE) - return -EINVAL; - - fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fsize->stepwise = fmt->frmsize; - - return 0; -} - -static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct rockchip_vpu_dev *dev = video_drvdata(file); - const struct rockchip_vpu_fmt *fmt; - const struct rockchip_vpu_fmt *formats; - int num_fmts, i, j = 0; - - formats = dev->variant->enc_fmts; - num_fmts = dev->variant->num_enc_fmts; - for (i = 0; i < num_fmts; i++) { - /* Skip uncompressed formats */ - if (formats[i].codec_mode == RK_VPU_MODE_NONE) - continue; - if (j == f->index) { - fmt = &formats[i]; - f->pixelformat = fmt->fourcc; - return 0; - } - ++j; - } - return -EINVAL; -} - -static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct rockchip_vpu_dev *dev = video_drvdata(file); - const struct rockchip_vpu_fmt *formats; - const struct rockchip_vpu_fmt *fmt; - int num_fmts, i, j = 0; - - formats = dev->variant->enc_fmts; - num_fmts = dev->variant->num_enc_fmts; - for (i = 0; i < num_fmts; i++) { - if (formats[i].codec_mode != RK_VPU_MODE_NONE) - continue; - if (j == f->index) { - fmt = &formats[i]; - f->pixelformat = fmt->fourcc; - return 0; - } - ++j; - } - return -EINVAL; -} - -static int vidioc_g_fmt_out_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv); - - vpu_debug(4, "f->type = %d\n", f->type); - - *pix_mp = ctx->src_fmt; - - return 0; -} - -static int vidioc_g_fmt_cap_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv); - - vpu_debug(4, "f->type = %d\n", f->type); - - *pix_mp = ctx->dst_fmt; - - return 0; -} - -static int -vidioc_try_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) -{ - struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv); - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - const struct rockchip_vpu_fmt *fmt; - - vpu_debug(4, "%c%c%c%c\n", - (pix_mp->pixelformat & 0x7f), - (pix_mp->pixelformat >> 8) & 0x7f, - (pix_mp->pixelformat >> 16) & 0x7f, - (pix_mp->pixelformat >> 24) & 0x7f); - - fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat); - if (!fmt) { - fmt = rockchip_vpu_get_default_fmt(ctx, true); - f->fmt.pix.pixelformat = fmt->fourcc; - } - - pix_mp->num_planes = 1; - pix_mp->field = V4L2_FIELD_NONE; - pix_mp->width = clamp(pix_mp->width, - fmt->frmsize.min_width, - fmt->frmsize.max_width); - pix_mp->height = clamp(pix_mp->height, - fmt->frmsize.min_height, - fmt->frmsize.max_height); - /* Round up to macroblocks. */ - pix_mp->width = round_up(pix_mp->width, JPEG_MB_DIM); - pix_mp->height = round_up(pix_mp->height, JPEG_MB_DIM); - - /* - * For compressed formats the application can specify - * sizeimage. If the application passes a zero sizeimage, - * let's default to the maximum frame size. - */ - if (!pix_mp->plane_fmt[0].sizeimage) - pix_mp->plane_fmt[0].sizeimage = fmt->header_size + - pix_mp->width * pix_mp->height * fmt->max_depth; - memset(pix_mp->plane_fmt[0].reserved, 0, - sizeof(pix_mp->plane_fmt[0].reserved)); - return 0; -} - -static int -vidioc_try_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) -{ - struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv); - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - const struct rockchip_vpu_fmt *fmt; - unsigned int width, height; - int i; - - vpu_debug(4, "%c%c%c%c\n", - (pix_mp->pixelformat & 0x7f), - (pix_mp->pixelformat >> 8) & 0x7f, - (pix_mp->pixelformat >> 16) & 0x7f, - (pix_mp->pixelformat >> 24) & 0x7f); - - fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat); - if (!fmt) { - fmt = rockchip_vpu_get_default_fmt(ctx, false); - f->fmt.pix.pixelformat = fmt->fourcc; - } - - pix_mp->field = V4L2_FIELD_NONE; - width = clamp(pix_mp->width, - ctx->vpu_dst_fmt->frmsize.min_width, - ctx->vpu_dst_fmt->frmsize.max_width); - height = clamp(pix_mp->height, - ctx->vpu_dst_fmt->frmsize.min_height, - ctx->vpu_dst_fmt->frmsize.max_height); - /* Round up to macroblocks. */ - width = round_up(width, JPEG_MB_DIM); - height = round_up(height, JPEG_MB_DIM); - - /* Fill remaining fields */ - fill_pixfmt_mp(pix_mp, fmt->fourcc, width, height); - - for (i = 0; i < pix_mp->num_planes; i++) { - memset(pix_mp->plane_fmt[i].reserved, 0, - sizeof(pix_mp->plane_fmt[i].reserved)); - } - return 0; -} - -void rockchip_vpu_enc_reset_dst_fmt(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx) -{ - struct v4l2_pix_format_mplane *fmt = &ctx->dst_fmt; - - ctx->vpu_dst_fmt = rockchip_vpu_get_default_fmt(ctx, true); - - memset(fmt, 0, sizeof(*fmt)); - - fmt->num_planes = 1; - fmt->width = clamp(fmt->width, ctx->vpu_dst_fmt->frmsize.min_width, - ctx->vpu_dst_fmt->frmsize.max_width); - fmt->height = clamp(fmt->height, ctx->vpu_dst_fmt->frmsize.min_height, - ctx->vpu_dst_fmt->frmsize.max_height); - fmt->pixelformat = ctx->vpu_dst_fmt->fourcc; - fmt->field = V4L2_FIELD_NONE; - fmt->colorspace = V4L2_COLORSPACE_JPEG, - fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - fmt->quantization = V4L2_QUANTIZATION_DEFAULT; - fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; - - fmt->plane_fmt[0].sizeimage = ctx->vpu_dst_fmt->header_size + - fmt->width * fmt->height * ctx->vpu_dst_fmt->max_depth; -} - -void rockchip_vpu_enc_reset_src_fmt(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx) -{ - struct v4l2_pix_format_mplane *fmt = &ctx->src_fmt; - unsigned int width, height; - - ctx->vpu_src_fmt = rockchip_vpu_get_default_fmt(ctx, false); - - memset(fmt, 0, sizeof(*fmt)); - - width = clamp(fmt->width, ctx->vpu_dst_fmt->frmsize.min_width, - ctx->vpu_dst_fmt->frmsize.max_width); - height = clamp(fmt->height, ctx->vpu_dst_fmt->frmsize.min_height, - ctx->vpu_dst_fmt->frmsize.max_height); - fmt->field = V4L2_FIELD_NONE; - fmt->colorspace = V4L2_COLORSPACE_JPEG, - fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - fmt->quantization = V4L2_QUANTIZATION_DEFAULT; - fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; - - fill_pixfmt_mp(fmt, ctx->vpu_src_fmt->fourcc, width, height); -} - -static int -vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv); - struct vb2_queue *vq; - int ret; - - /* Change not allowed if queue is streaming. */ - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (vb2_is_streaming(vq)) - return -EBUSY; - - ret = vidioc_try_fmt_out_mplane(file, priv, f); - if (ret) - return ret; - - ctx->vpu_src_fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat); - ctx->src_fmt = *pix_mp; - - /* Propagate to the CAPTURE format */ - ctx->dst_fmt.colorspace = pix_mp->colorspace; - ctx->dst_fmt.ycbcr_enc = pix_mp->ycbcr_enc; - ctx->dst_fmt.xfer_func = pix_mp->xfer_func; - ctx->dst_fmt.quantization = pix_mp->quantization; - ctx->dst_fmt.width = pix_mp->width; - ctx->dst_fmt.height = pix_mp->height; - - vpu_debug(0, "OUTPUT codec mode: %d\n", ctx->vpu_src_fmt->codec_mode); - vpu_debug(0, "fmt - w: %d, h: %d, mb - w: %d, h: %d\n", - pix_mp->width, pix_mp->height, - JPEG_MB_WIDTH(pix_mp->width), - JPEG_MB_HEIGHT(pix_mp->height)); - return 0; -} - -static int -vidioc_s_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv); - struct rockchip_vpu_dev *vpu = ctx->dev; - struct vb2_queue *vq, *peer_vq; - int ret; - - /* Change not allowed if queue is streaming. */ - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (vb2_is_streaming(vq)) - return -EBUSY; - - /* - * Since format change on the CAPTURE queue will reset - * the OUTPUT queue, we can't allow doing so - * when the OUTPUT queue has buffers allocated. - */ - peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (vb2_is_busy(peer_vq) && - (pix_mp->pixelformat != ctx->dst_fmt.pixelformat || - pix_mp->height != ctx->dst_fmt.height || - pix_mp->width != ctx->dst_fmt.width)) - return -EBUSY; - - ret = vidioc_try_fmt_cap_mplane(file, priv, f); - if (ret) - return ret; - - ctx->vpu_dst_fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat); - ctx->dst_fmt = *pix_mp; - - vpu_debug(0, "CAPTURE codec mode: %d\n", ctx->vpu_dst_fmt->codec_mode); - vpu_debug(0, "fmt - w: %d, h: %d, mb - w: %d, h: %d\n", - pix_mp->width, pix_mp->height, - JPEG_MB_WIDTH(pix_mp->width), - JPEG_MB_HEIGHT(pix_mp->height)); - - /* - * Current raw format might have become invalid with newly - * selected codec, so reset it to default just to be safe and - * keep internal driver state sane. User is mandated to set - * the raw format again after we return, so we don't need - * anything smarter. - */ - rockchip_vpu_enc_reset_src_fmt(vpu, ctx); - return 0; -} - -const struct v4l2_ioctl_ops rockchip_vpu_enc_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_framesizes = vidioc_enum_framesizes, - - .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_cap_mplane, - .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_out_mplane, - .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_out_mplane, - .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap_mplane, - .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_out_mplane, - .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_cap_mplane, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, - - .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, - .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, - .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, - .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, - .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, - .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, - .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, - - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - - .vidioc_streamon = v4l2_m2m_ioctl_streamon, - .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, -}; - -static int -rockchip_vpu_queue_setup(struct vb2_queue *vq, - unsigned int *num_buffers, - unsigned int *num_planes, - unsigned int sizes[], - struct device *alloc_devs[]) -{ - struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vq); - struct v4l2_pix_format_mplane *pixfmt; - int i; - - switch (vq->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - pixfmt = &ctx->dst_fmt; - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - pixfmt = &ctx->src_fmt; - break; - default: - vpu_err("invalid queue type: %d\n", vq->type); - return -EINVAL; - } - - if (*num_planes) { - if (*num_planes != pixfmt->num_planes) - return -EINVAL; - for (i = 0; i < pixfmt->num_planes; ++i) - if (sizes[i] < pixfmt->plane_fmt[i].sizeimage) - return -EINVAL; - return 0; - } - - *num_planes = pixfmt->num_planes; - for (i = 0; i < pixfmt->num_planes; ++i) - sizes[i] = pixfmt->plane_fmt[i].sizeimage; - return 0; -} - -static int rockchip_vpu_buf_prepare(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vb2_queue *vq = vb->vb2_queue; - struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vq); - struct v4l2_pix_format_mplane *pixfmt; - unsigned int sz; - int ret = 0; - int i; - - switch (vq->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - pixfmt = &ctx->dst_fmt; - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - pixfmt = &ctx->src_fmt; - - if (vbuf->field == V4L2_FIELD_ANY) - vbuf->field = V4L2_FIELD_NONE; - if (vbuf->field != V4L2_FIELD_NONE) { - vpu_debug(4, "field %d not supported\n", - vbuf->field); - return -EINVAL; - } - break; - default: - vpu_err("invalid queue type: %d\n", vq->type); - return -EINVAL; - } - - for (i = 0; i < pixfmt->num_planes; ++i) { - sz = pixfmt->plane_fmt[i].sizeimage; - vpu_debug(4, "plane %d size: %ld, sizeimage: %u\n", - i, vb2_plane_size(vb, i), sz); - if (vb2_plane_size(vb, i) < sz) { - vpu_err("plane %d is too small\n", i); - ret = -EINVAL; - break; - } - } - - return ret; -} - -static void rockchip_vpu_buf_queue(struct vb2_buffer *vb) -{ - struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); -} - -static int rockchip_vpu_start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(q); - enum rockchip_vpu_codec_mode codec_mode; - - if (V4L2_TYPE_IS_OUTPUT(q->type)) - ctx->sequence_out = 0; - else - ctx->sequence_cap = 0; - - /* Set codec_ops for the chosen destination format */ - codec_mode = ctx->vpu_dst_fmt->codec_mode; - - vpu_debug(4, "Codec mode = %d\n", codec_mode); - ctx->codec_ops = &ctx->dev->variant->codec_ops[codec_mode]; - - /* A bounce buffer is needed for the JPEG payload */ - if (!V4L2_TYPE_IS_OUTPUT(q->type)) { - ctx->bounce_size = ctx->dst_fmt.plane_fmt[0].sizeimage - - ctx->vpu_dst_fmt->header_size; - ctx->bounce_buf = dma_alloc_attrs(ctx->dev->dev, - ctx->bounce_size, - &ctx->bounce_dma_addr, - GFP_KERNEL, - DMA_ATTR_ALLOC_SINGLE_PAGES); - } - return 0; -} - -static void rockchip_vpu_stop_streaming(struct vb2_queue *q) -{ - struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(q); - - if (!V4L2_TYPE_IS_OUTPUT(q->type)) - dma_free_attrs(ctx->dev->dev, - ctx->bounce_size, - ctx->bounce_buf, - ctx->bounce_dma_addr, - DMA_ATTR_ALLOC_SINGLE_PAGES); - - /* - * The mem2mem framework calls v4l2_m2m_cancel_job before - * .stop_streaming, so there isn't any job running and - * it is safe to return all the buffers. - */ - for (;;) { - struct vb2_v4l2_buffer *vbuf; - - if (V4L2_TYPE_IS_OUTPUT(q->type)) - vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - else - vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - if (!vbuf) - break; - v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); - } -} - -const struct vb2_ops rockchip_vpu_enc_queue_ops = { - .queue_setup = rockchip_vpu_queue_setup, - .buf_prepare = rockchip_vpu_buf_prepare, - .buf_queue = rockchip_vpu_buf_queue, - .start_streaming = rockchip_vpu_start_streaming, - .stop_streaming = rockchip_vpu_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_hw.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu_hw.h deleted file mode 100644 index 2b955da1be1a..000000000000 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_hw.h +++ /dev/null @@ -1,58 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Rockchip VPU codec driver - * - * Copyright 2018 Google LLC. - * Tomasz Figa <tfiga@chromium.org> - */ - -#ifndef ROCKCHIP_VPU_HW_H_ -#define ROCKCHIP_VPU_HW_H_ - -#include <linux/interrupt.h> -#include <linux/v4l2-controls.h> -#include <media/videobuf2-core.h> - -struct rockchip_vpu_dev; -struct rockchip_vpu_ctx; -struct rockchip_vpu_buf; -struct rockchip_vpu_variant; - -/** - * struct rockchip_vpu_codec_ops - codec mode specific operations - * - * @run: Start single {en,de)coding job. Called from atomic context - * to indicate that a pair of buffers is ready and the hardware - * should be programmed and started. - * @done: Read back processing results and additional data from hardware. - * @reset: Reset the hardware in case of a timeout. - */ -struct rockchip_vpu_codec_ops { - void (*run)(struct rockchip_vpu_ctx *ctx); - void (*done)(struct rockchip_vpu_ctx *ctx, enum vb2_buffer_state); - void (*reset)(struct rockchip_vpu_ctx *ctx); -}; - -/** - * enum rockchip_vpu_enc_fmt - source format ID for hardware registers. - */ -enum rockchip_vpu_enc_fmt { - RK3288_VPU_ENC_FMT_YUV420P = 0, - RK3288_VPU_ENC_FMT_YUV420SP = 1, - RK3288_VPU_ENC_FMT_YUYV422 = 2, - RK3288_VPU_ENC_FMT_UYVY422 = 3, -}; - -extern const struct rockchip_vpu_variant rk3399_vpu_variant; -extern const struct rockchip_vpu_variant rk3288_vpu_variant; - -void rockchip_vpu_watchdog(struct work_struct *work); -void rockchip_vpu_run(struct rockchip_vpu_ctx *ctx); -void rockchip_vpu_irq_done(struct rockchip_vpu_dev *vpu, - unsigned int bytesused, - enum vb2_buffer_state result); - -void rk3288_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx); -void rk3399_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx); - -#endif /* ROCKCHIP_VPU_HW_H_ */ diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.h deleted file mode 100644 index 72645d8e2ade..000000000000 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ - -#define JPEG_HEADER_SIZE 601 - -struct rockchip_vpu_jpeg_ctx { - int width; - int height; - int quality; - unsigned char *buffer; -}; - -unsigned char * -rockchip_vpu_jpeg_get_qtable(struct rockchip_vpu_jpeg_ctx *ctx, int index); -void rockchip_vpu_jpeg_header_assemble(struct rockchip_vpu_jpeg_ctx *ctx); diff --git a/drivers/staging/media/soc_camera/imx074.c b/drivers/staging/media/soc_camera/imx074.c index d907aa62f898..14240b74cdd0 100644 --- a/drivers/staging/media/soc_camera/imx074.c +++ b/drivers/staging/media/soc_camera/imx074.c @@ -409,7 +409,7 @@ static int imx074_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct imx074 *priv; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); int ret; diff --git a/drivers/staging/media/soc_camera/mt9t031.c b/drivers/staging/media/soc_camera/mt9t031.c index 615ae9df2c57..c14f23221544 100644 --- a/drivers/staging/media/soc_camera/mt9t031.c +++ b/drivers/staging/media/soc_camera/mt9t031.c @@ -751,7 +751,7 @@ static int mt9t031_probe(struct i2c_client *client, { struct mt9t031 *mt9t031; struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; int ret; if (!ssdd) { diff --git a/drivers/staging/media/soc_camera/soc_mt9v022.c b/drivers/staging/media/soc_camera/soc_mt9v022.c index e7e0d3d29499..1739a618846d 100644 --- a/drivers/staging/media/soc_camera/soc_mt9v022.c +++ b/drivers/staging/media/soc_camera/soc_mt9v022.c @@ -883,7 +883,7 @@ static int mt9v022_probe(struct i2c_client *client, { struct mt9v022 *mt9v022; struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; struct mt9v022_platform_data *pdata; int ret; diff --git a/drivers/staging/media/soc_camera/soc_ov5642.c b/drivers/staging/media/soc_camera/soc_ov5642.c index 94696d7baf83..39ae24dca65f 100644 --- a/drivers/staging/media/soc_camera/soc_ov5642.c +++ b/drivers/staging/media/soc_camera/soc_ov5642.c @@ -687,7 +687,8 @@ static int reg_write16(struct i2c_client *client, u16 reg, u16 val16) } #ifdef CONFIG_VIDEO_ADV_DEBUG -static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int ov5642_get_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; @@ -705,7 +706,8 @@ static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register return ret; } -static int ov5642_set_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) +static int ov5642_set_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/staging/media/sunxi/cedrus/Makefile b/drivers/staging/media/sunxi/cedrus/Makefile index 808842f0119e..c85ac6db0302 100644 --- a/drivers/staging/media/sunxi/cedrus/Makefile +++ b/drivers/staging/media/sunxi/cedrus/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi-cedrus.o -sunxi-cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o cedrus_mpeg2.o +sunxi-cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o \ + cedrus_mpeg2.o cedrus_h264.o diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index d0429c0e6b6b..370937edfc14 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -40,6 +40,36 @@ static const struct cedrus_control cedrus_controls[] = { .codec = CEDRUS_CODEC_MPEG2, .required = false, }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + .elem_size = sizeof(struct v4l2_ctrl_h264_decode_params), + .codec = CEDRUS_CODEC_H264, + .required = true, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, + .elem_size = sizeof(struct v4l2_ctrl_h264_slice_params), + .codec = CEDRUS_CODEC_H264, + .required = true, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_SPS, + .elem_size = sizeof(struct v4l2_ctrl_h264_sps), + .codec = CEDRUS_CODEC_H264, + .required = true, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_PPS, + .elem_size = sizeof(struct v4l2_ctrl_h264_pps), + .codec = CEDRUS_CODEC_H264, + .required = true, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + .elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix), + .codec = CEDRUS_CODEC_H264, + .required = true, + }, }; #define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls) @@ -278,6 +308,7 @@ static int cedrus_probe(struct platform_device *pdev) } dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2; + dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264; mutex_init(&dev->dev_mutex); @@ -369,36 +400,41 @@ static int cedrus_remove(struct platform_device *pdev) } static const struct cedrus_variant sun4i_a10_cedrus_variant = { - /* No particular capability. */ + .mod_rate = 320000000, }; static const struct cedrus_variant sun5i_a13_cedrus_variant = { - /* No particular capability. */ + .mod_rate = 320000000, }; static const struct cedrus_variant sun7i_a20_cedrus_variant = { - /* No particular capability. */ + .mod_rate = 320000000, }; static const struct cedrus_variant sun8i_a33_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED, + .mod_rate = 320000000, }; static const struct cedrus_variant sun8i_h3_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED, + .mod_rate = 402000000, }; static const struct cedrus_variant sun50i_a64_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED, + .mod_rate = 402000000, }; static const struct cedrus_variant sun50i_h5_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED, + .mod_rate = 402000000, }; static const struct cedrus_variant sun50i_h6_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED, .quirks = CEDRUS_QUIRK_NO_DMA_OFFSET, + .mod_rate = 600000000, }; static const struct of_device_id cedrus_dt_match[] = { diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index c57c04b41d2e..3f476d0fd981 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -32,7 +32,7 @@ enum cedrus_codec { CEDRUS_CODEC_MPEG2, - + CEDRUS_CODEC_H264, CEDRUS_CODEC_LAST, }; @@ -42,6 +42,12 @@ enum cedrus_irq_status { CEDRUS_IRQ_OK, }; +enum cedrus_h264_pic_type { + CEDRUS_H264_PIC_TYPE_FRAME = 0, + CEDRUS_H264_PIC_TYPE_FIELD, + CEDRUS_H264_PIC_TYPE_MBAFF, +}; + struct cedrus_control { u32 id; u32 elem_size; @@ -49,6 +55,14 @@ struct cedrus_control { unsigned char required:1; }; +struct cedrus_h264_run { + const struct v4l2_ctrl_h264_decode_params *decode_params; + const struct v4l2_ctrl_h264_pps *pps; + const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; + const struct v4l2_ctrl_h264_slice_params *slice_params; + const struct v4l2_ctrl_h264_sps *sps; +}; + struct cedrus_mpeg2_run { const struct v4l2_ctrl_mpeg2_slice_params *slice_params; const struct v4l2_ctrl_mpeg2_quantization *quantization; @@ -59,12 +73,20 @@ struct cedrus_run { struct vb2_v4l2_buffer *dst; union { + struct cedrus_h264_run h264; struct cedrus_mpeg2_run mpeg2; }; }; struct cedrus_buffer { struct v4l2_m2m_buffer m2m_buf; + + union { + struct { + unsigned int position; + enum cedrus_h264_pic_type pic_type; + } h264; + } codec; }; struct cedrus_ctx { @@ -79,6 +101,19 @@ struct cedrus_ctx { struct v4l2_ctrl **ctrls; struct vb2_buffer *dst_bufs[VIDEO_MAX_FRAME]; + + union { + struct { + void *mv_col_buf; + dma_addr_t mv_col_buf_dma; + ssize_t mv_col_buf_field_size; + ssize_t mv_col_buf_size; + void *pic_info_buf; + dma_addr_t pic_info_buf_dma; + void *neighbor_info_buf; + dma_addr_t neighbor_info_buf_dma; + } h264; + } codec; }; struct cedrus_dec_ops { @@ -94,6 +129,7 @@ struct cedrus_dec_ops { struct cedrus_variant { unsigned int capabilities; unsigned int quirks; + unsigned int mod_rate; }; struct cedrus_dev { @@ -121,6 +157,7 @@ struct cedrus_dev { }; extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2; +extern struct cedrus_dec_ops cedrus_dec_ops_h264; static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val) { diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index 4d6d602cdde6..bdad87eb9d79 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -46,6 +46,19 @@ void cedrus_device_run(void *priv) V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); break; + case V4L2_PIX_FMT_H264_SLICE_RAW: + run.h264.decode_params = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS); + run.h264.pps = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_H264_PPS); + run.h264.scaling_matrix = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX); + run.h264.slice_params = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS); + run.h264.sps = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_H264_SPS); + break; + default: break; } diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c new file mode 100644 index 000000000000..a30bb283f69f --- /dev/null +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c @@ -0,0 +1,576 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Cedrus VPU driver + * + * Copyright (c) 2013 Jens Kuske <jenskuske@gmail.com> + * Copyright (c) 2018 Bootlin + */ + +#include <linux/types.h> + +#include <media/videobuf2-dma-contig.h> + +#include "cedrus.h" +#include "cedrus_hw.h" +#include "cedrus_regs.h" + +enum cedrus_h264_sram_off { + CEDRUS_SRAM_H264_PRED_WEIGHT_TABLE = 0x000, + CEDRUS_SRAM_H264_FRAMEBUFFER_LIST = 0x100, + CEDRUS_SRAM_H264_REF_LIST_0 = 0x190, + CEDRUS_SRAM_H264_REF_LIST_1 = 0x199, + CEDRUS_SRAM_H264_SCALING_LIST_8x8_0 = 0x200, + CEDRUS_SRAM_H264_SCALING_LIST_8x8_1 = 0x210, + CEDRUS_SRAM_H264_SCALING_LIST_4x4 = 0x220, +}; + +struct cedrus_h264_sram_ref_pic { + __le32 top_field_order_cnt; + __le32 bottom_field_order_cnt; + __le32 frame_info; + __le32 luma_ptr; + __le32 chroma_ptr; + __le32 mv_col_top_ptr; + __le32 mv_col_bot_ptr; + __le32 reserved; +} __packed; + +#define CEDRUS_H264_FRAME_NUM 18 + +#define CEDRUS_NEIGHBOR_INFO_BUF_SIZE (16 * SZ_1K) +#define CEDRUS_PIC_INFO_BUF_SIZE (128 * SZ_1K) + +static void cedrus_h264_write_sram(struct cedrus_dev *dev, + enum cedrus_h264_sram_off off, + const void *data, size_t len) +{ + const u32 *buffer = data; + size_t count = DIV_ROUND_UP(len, 4); + + cedrus_write(dev, VE_AVC_SRAM_PORT_OFFSET, off << 2); + + while (count--) + cedrus_write(dev, VE_AVC_SRAM_PORT_DATA, *buffer++); +} + +static dma_addr_t cedrus_h264_mv_col_buf_addr(struct cedrus_ctx *ctx, + unsigned int position, + unsigned int field) +{ + dma_addr_t addr = ctx->codec.h264.mv_col_buf_dma; + + /* Adjust for the position */ + addr += position * ctx->codec.h264.mv_col_buf_field_size * 2; + + /* Adjust for the field */ + addr += field * ctx->codec.h264.mv_col_buf_field_size; + + return addr; +} + +static void cedrus_fill_ref_pic(struct cedrus_ctx *ctx, + struct cedrus_buffer *buf, + unsigned int top_field_order_cnt, + unsigned int bottom_field_order_cnt, + struct cedrus_h264_sram_ref_pic *pic) +{ + struct vb2_buffer *vbuf = &buf->m2m_buf.vb.vb2_buf; + unsigned int position = buf->codec.h264.position; + + pic->top_field_order_cnt = cpu_to_le32(top_field_order_cnt); + pic->bottom_field_order_cnt = cpu_to_le32(bottom_field_order_cnt); + pic->frame_info = cpu_to_le32(buf->codec.h264.pic_type << 8); + + pic->luma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 0)); + pic->chroma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 1)); + pic->mv_col_top_ptr = + cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, position, 0)); + pic->mv_col_bot_ptr = + cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, position, 1)); +} + +static void cedrus_write_frame_list(struct cedrus_ctx *ctx, + struct cedrus_run *run) +{ + struct cedrus_h264_sram_ref_pic pic_list[CEDRUS_H264_FRAME_NUM]; + const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params; + const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params; + const struct v4l2_ctrl_h264_sps *sps = run->h264.sps; + struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + struct cedrus_buffer *output_buf; + struct cedrus_dev *dev = ctx->dev; + unsigned long used_dpbs = 0; + unsigned int position; + unsigned int output = 0; + unsigned int i; + + memset(pic_list, 0, sizeof(pic_list)); + + for (i = 0; i < ARRAY_SIZE(decode->dpb); i++) { + const struct v4l2_h264_dpb_entry *dpb = &decode->dpb[i]; + struct cedrus_buffer *cedrus_buf; + int buf_idx; + + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_VALID)) + continue; + + buf_idx = vb2_find_timestamp(cap_q, dpb->reference_ts, 0); + if (buf_idx < 0) + continue; + + cedrus_buf = vb2_to_cedrus_buffer(ctx->dst_bufs[buf_idx]); + position = cedrus_buf->codec.h264.position; + used_dpbs |= BIT(position); + + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + continue; + + cedrus_fill_ref_pic(ctx, cedrus_buf, + dpb->top_field_order_cnt, + dpb->bottom_field_order_cnt, + &pic_list[position]); + + output = max(position, output); + } + + position = find_next_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM, + output); + if (position >= CEDRUS_H264_FRAME_NUM) + position = find_first_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM); + + output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf); + output_buf->codec.h264.position = position; + + if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) + output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FIELD; + else if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) + output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_MBAFF; + else + output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FRAME; + + cedrus_fill_ref_pic(ctx, output_buf, + decode->top_field_order_cnt, + decode->bottom_field_order_cnt, + &pic_list[position]); + + cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_FRAMEBUFFER_LIST, + pic_list, sizeof(pic_list)); + + cedrus_write(dev, VE_H264_OUTPUT_FRAME_IDX, position); +} + +#define CEDRUS_MAX_REF_IDX 32 + +static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, + struct cedrus_run *run, + const u8 *ref_list, u8 num_ref, + enum cedrus_h264_sram_off sram) +{ + const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params; + struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + struct cedrus_dev *dev = ctx->dev; + u8 sram_array[CEDRUS_MAX_REF_IDX]; + unsigned int i; + size_t size; + + memset(sram_array, 0, sizeof(sram_array)); + + for (i = 0; i < num_ref; i++) { + const struct v4l2_h264_dpb_entry *dpb; + const struct cedrus_buffer *cedrus_buf; + const struct vb2_v4l2_buffer *ref_buf; + unsigned int position; + int buf_idx; + u8 dpb_idx; + + dpb_idx = ref_list[i]; + dpb = &decode->dpb[dpb_idx]; + + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + continue; + + buf_idx = vb2_find_timestamp(cap_q, dpb->reference_ts, 0); + if (buf_idx < 0) + continue; + + ref_buf = to_vb2_v4l2_buffer(ctx->dst_bufs[buf_idx]); + cedrus_buf = vb2_v4l2_to_cedrus_buffer(ref_buf); + position = cedrus_buf->codec.h264.position; + + sram_array[i] |= position << 1; + if (ref_buf->field == V4L2_FIELD_BOTTOM) + sram_array[i] |= BIT(0); + } + + size = min_t(size_t, ALIGN(num_ref, 4), sizeof(sram_array)); + cedrus_h264_write_sram(dev, sram, &sram_array, size); +} + +static void cedrus_write_ref_list0(struct cedrus_ctx *ctx, + struct cedrus_run *run) +{ + const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params; + + _cedrus_write_ref_list(ctx, run, + slice->ref_pic_list0, + slice->num_ref_idx_l0_active_minus1 + 1, + CEDRUS_SRAM_H264_REF_LIST_0); +} + +static void cedrus_write_ref_list1(struct cedrus_ctx *ctx, + struct cedrus_run *run) +{ + const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params; + + _cedrus_write_ref_list(ctx, run, + slice->ref_pic_list1, + slice->num_ref_idx_l1_active_minus1 + 1, + CEDRUS_SRAM_H264_REF_LIST_1); +} + +static void cedrus_write_scaling_lists(struct cedrus_ctx *ctx, + struct cedrus_run *run) +{ + const struct v4l2_ctrl_h264_scaling_matrix *scaling = + run->h264.scaling_matrix; + struct cedrus_dev *dev = ctx->dev; + + cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_8x8_0, + scaling->scaling_list_8x8[0], + sizeof(scaling->scaling_list_8x8[0])); + + cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_8x8_1, + scaling->scaling_list_8x8[3], + sizeof(scaling->scaling_list_8x8[3])); + + cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_4x4, + scaling->scaling_list_4x4, + sizeof(scaling->scaling_list_4x4)); +} + +static void cedrus_write_pred_weight_table(struct cedrus_ctx *ctx, + struct cedrus_run *run) +{ + const struct v4l2_ctrl_h264_slice_params *slice = + run->h264.slice_params; + const struct v4l2_h264_pred_weight_table *pred_weight = + &slice->pred_weight_table; + struct cedrus_dev *dev = ctx->dev; + int i, j, k; + + cedrus_write(dev, VE_H264_SHS_WP, + ((pred_weight->chroma_log2_weight_denom & 0x7) << 4) | + ((pred_weight->luma_log2_weight_denom & 0x7) << 0)); + + cedrus_write(dev, VE_AVC_SRAM_PORT_OFFSET, + CEDRUS_SRAM_H264_PRED_WEIGHT_TABLE << 2); + + for (i = 0; i < ARRAY_SIZE(pred_weight->weight_factors); i++) { + const struct v4l2_h264_weight_factors *factors = + &pred_weight->weight_factors[i]; + + for (j = 0; j < ARRAY_SIZE(factors->luma_weight); j++) { + u32 val; + + val = (((u32)factors->luma_offset[j] & 0x1ff) << 16) | + (factors->luma_weight[j] & 0x1ff); + cedrus_write(dev, VE_AVC_SRAM_PORT_DATA, val); + } + + for (j = 0; j < ARRAY_SIZE(factors->chroma_weight); j++) { + for (k = 0; k < ARRAY_SIZE(factors->chroma_weight[0]); k++) { + u32 val; + + val = (((u32)factors->chroma_offset[j][k] & 0x1ff) << 16) | + (factors->chroma_weight[j][k] & 0x1ff); + cedrus_write(dev, VE_AVC_SRAM_PORT_DATA, val); + } + } + } +} + +static void cedrus_set_params(struct cedrus_ctx *ctx, + struct cedrus_run *run) +{ + const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params; + const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params; + const struct v4l2_ctrl_h264_pps *pps = run->h264.pps; + const struct v4l2_ctrl_h264_sps *sps = run->h264.sps; + struct vb2_buffer *src_buf = &run->src->vb2_buf; + struct cedrus_dev *dev = ctx->dev; + dma_addr_t src_buf_addr; + u32 offset = slice->header_bit_size; + u32 len = (slice->size * 8) - offset; + u32 reg; + + cedrus_write(dev, VE_H264_VLD_LEN, len); + cedrus_write(dev, VE_H264_VLD_OFFSET, offset); + + src_buf_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + cedrus_write(dev, VE_H264_VLD_END, + src_buf_addr + vb2_get_plane_payload(src_buf, 0)); + cedrus_write(dev, VE_H264_VLD_ADDR, + VE_H264_VLD_ADDR_VAL(src_buf_addr) | + VE_H264_VLD_ADDR_FIRST | VE_H264_VLD_ADDR_VALID | + VE_H264_VLD_ADDR_LAST); + + /* + * FIXME: Since the bitstream parsing is done in software, and + * in userspace, this shouldn't be needed anymore. But it + * turns out that removing it breaks the decoding process, + * without any clear indication why. + */ + cedrus_write(dev, VE_H264_TRIGGER_TYPE, + VE_H264_TRIGGER_TYPE_INIT_SWDEC); + + if (((pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) && + (slice->slice_type == V4L2_H264_SLICE_TYPE_P || + slice->slice_type == V4L2_H264_SLICE_TYPE_SP)) || + (pps->weighted_bipred_idc == 1 && + slice->slice_type == V4L2_H264_SLICE_TYPE_B)) + cedrus_write_pred_weight_table(ctx, run); + + if ((slice->slice_type == V4L2_H264_SLICE_TYPE_P) || + (slice->slice_type == V4L2_H264_SLICE_TYPE_SP) || + (slice->slice_type == V4L2_H264_SLICE_TYPE_B)) + cedrus_write_ref_list0(ctx, run); + + if (slice->slice_type == V4L2_H264_SLICE_TYPE_B) + cedrus_write_ref_list1(ctx, run); + + // picture parameters + reg = 0; + /* + * FIXME: the kernel headers are allowing the default value to + * be passed, but the libva doesn't give us that. + */ + reg |= (slice->num_ref_idx_l0_active_minus1 & 0x1f) << 10; + reg |= (slice->num_ref_idx_l1_active_minus1 & 0x1f) << 5; + reg |= (pps->weighted_bipred_idc & 0x3) << 2; + if (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) + reg |= VE_H264_PPS_ENTROPY_CODING_MODE; + if (pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) + reg |= VE_H264_PPS_WEIGHTED_PRED; + if (pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) + reg |= VE_H264_PPS_CONSTRAINED_INTRA_PRED; + if (pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE) + reg |= VE_H264_PPS_TRANSFORM_8X8_MODE; + cedrus_write(dev, VE_H264_PPS, reg); + + // sequence parameters + reg = 0; + reg |= (sps->chroma_format_idc & 0x7) << 19; + reg |= (sps->pic_width_in_mbs_minus1 & 0xff) << 8; + reg |= sps->pic_height_in_map_units_minus1 & 0xff; + if (sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) + reg |= VE_H264_SPS_MBS_ONLY; + if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) + reg |= VE_H264_SPS_MB_ADAPTIVE_FRAME_FIELD; + if (sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) + reg |= VE_H264_SPS_DIRECT_8X8_INFERENCE; + cedrus_write(dev, VE_H264_SPS, reg); + + // slice parameters + reg = 0; + reg |= decode->nal_ref_idc ? BIT(12) : 0; + reg |= (slice->slice_type & 0xf) << 8; + reg |= slice->cabac_init_idc & 0x3; + reg |= VE_H264_SHS_FIRST_SLICE_IN_PIC; + if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) + reg |= VE_H264_SHS_FIELD_PIC; + if (slice->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) + reg |= VE_H264_SHS_BOTTOM_FIELD; + if (slice->flags & V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED) + reg |= VE_H264_SHS_DIRECT_SPATIAL_MV_PRED; + cedrus_write(dev, VE_H264_SHS, reg); + + reg = 0; + reg |= VE_H264_SHS2_NUM_REF_IDX_ACTIVE_OVRD; + reg |= (slice->num_ref_idx_l0_active_minus1 & 0x1f) << 24; + reg |= (slice->num_ref_idx_l1_active_minus1 & 0x1f) << 16; + reg |= (slice->disable_deblocking_filter_idc & 0x3) << 8; + reg |= (slice->slice_alpha_c0_offset_div2 & 0xf) << 4; + reg |= slice->slice_beta_offset_div2 & 0xf; + cedrus_write(dev, VE_H264_SHS2, reg); + + reg = 0; + reg |= (pps->second_chroma_qp_index_offset & 0x3f) << 16; + reg |= (pps->chroma_qp_index_offset & 0x3f) << 8; + reg |= (pps->pic_init_qp_minus26 + 26 + slice->slice_qp_delta) & 0x3f; + cedrus_write(dev, VE_H264_SHS_QP, reg); + + // clear status flags + cedrus_write(dev, VE_H264_STATUS, cedrus_read(dev, VE_H264_STATUS)); + + // enable int + cedrus_write(dev, VE_H264_CTRL, + VE_H264_CTRL_SLICE_DECODE_INT | + VE_H264_CTRL_DECODE_ERR_INT | + VE_H264_CTRL_VLD_DATA_REQ_INT); +} + +static enum cedrus_irq_status +cedrus_h264_irq_status(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + u32 reg = cedrus_read(dev, VE_H264_STATUS); + + if (reg & (VE_H264_STATUS_DECODE_ERR_INT | + VE_H264_STATUS_VLD_DATA_REQ_INT)) + return CEDRUS_IRQ_ERROR; + + if (reg & VE_H264_CTRL_SLICE_DECODE_INT) + return CEDRUS_IRQ_OK; + + return CEDRUS_IRQ_NONE; +} + +static void cedrus_h264_irq_clear(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + + cedrus_write(dev, VE_H264_STATUS, + VE_H264_STATUS_INT_MASK); +} + +static void cedrus_h264_irq_disable(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + u32 reg = cedrus_read(dev, VE_H264_CTRL); + + cedrus_write(dev, VE_H264_CTRL, + reg & ~VE_H264_CTRL_INT_MASK); +} + +static void cedrus_h264_setup(struct cedrus_ctx *ctx, + struct cedrus_run *run) +{ + struct cedrus_dev *dev = ctx->dev; + + cedrus_engine_enable(dev, CEDRUS_CODEC_H264); + + cedrus_write(dev, VE_H264_SDROT_CTRL, 0); + cedrus_write(dev, VE_H264_EXTRA_BUFFER1, + ctx->codec.h264.pic_info_buf_dma); + cedrus_write(dev, VE_H264_EXTRA_BUFFER2, + ctx->codec.h264.neighbor_info_buf_dma); + + cedrus_write_scaling_lists(ctx, run); + cedrus_write_frame_list(ctx, run); + + cedrus_set_params(ctx, run); +} + +static int cedrus_h264_start(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + unsigned int field_size; + unsigned int mv_col_size; + int ret; + + /* + * FIXME: It seems that the H6 cedarX code is using a formula + * here based on the size of the frame, while all the older + * code is using a fixed size, so that might need to be + * changed at some point. + */ + ctx->codec.h264.pic_info_buf = + dma_alloc_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE, + &ctx->codec.h264.pic_info_buf_dma, + GFP_KERNEL); + if (!ctx->codec.h264.pic_info_buf) + return -ENOMEM; + + /* + * That buffer is supposed to be 16kiB in size, and be aligned + * on 16kiB as well. However, dma_alloc_coherent provides the + * guarantee that we'll have a CPU and DMA address aligned on + * the smallest page order that is greater to the requested + * size, so we don't have to overallocate. + */ + ctx->codec.h264.neighbor_info_buf = + dma_alloc_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE, + &ctx->codec.h264.neighbor_info_buf_dma, + GFP_KERNEL); + if (!ctx->codec.h264.neighbor_info_buf) { + ret = -ENOMEM; + goto err_pic_buf; + } + + field_size = DIV_ROUND_UP(ctx->src_fmt.width, 16) * + DIV_ROUND_UP(ctx->src_fmt.height, 16) * 16; + + /* + * FIXME: This is actually conditional to + * V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE not being set, we + * might have to rework this if memory efficiency ever is + * something we need to work on. + */ + field_size = field_size * 2; + + /* + * FIXME: This is actually conditional to + * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY not being set, we might + * have to rework this if memory efficiency ever is something + * we need to work on. + */ + field_size = field_size * 2; + ctx->codec.h264.mv_col_buf_field_size = field_size; + + mv_col_size = field_size * 2 * CEDRUS_H264_FRAME_NUM; + ctx->codec.h264.mv_col_buf_size = mv_col_size; + ctx->codec.h264.mv_col_buf = dma_alloc_coherent(dev->dev, + ctx->codec.h264.mv_col_buf_size, + &ctx->codec.h264.mv_col_buf_dma, + GFP_KERNEL); + if (!ctx->codec.h264.mv_col_buf) { + ret = -ENOMEM; + goto err_neighbor_buf; + } + + return 0; + +err_neighbor_buf: + dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE, + ctx->codec.h264.neighbor_info_buf, + ctx->codec.h264.neighbor_info_buf_dma); + +err_pic_buf: + dma_free_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE, + ctx->codec.h264.pic_info_buf, + ctx->codec.h264.pic_info_buf_dma); + return ret; +} + +static void cedrus_h264_stop(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + + dma_free_coherent(dev->dev, ctx->codec.h264.mv_col_buf_size, + ctx->codec.h264.mv_col_buf, + ctx->codec.h264.mv_col_buf_dma); + dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE, + ctx->codec.h264.neighbor_info_buf, + ctx->codec.h264.neighbor_info_buf_dma); + dma_free_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE, + ctx->codec.h264.pic_info_buf, + ctx->codec.h264.pic_info_buf_dma); +} + +static void cedrus_h264_trigger(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + + cedrus_write(dev, VE_H264_TRIGGER_TYPE, + VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE); +} + +struct cedrus_dec_ops cedrus_dec_ops_h264 = { + .irq_clear = cedrus_h264_irq_clear, + .irq_disable = cedrus_h264_irq_disable, + .irq_status = cedrus_h264_irq_status, + .setup = cedrus_h264_setup, + .start = cedrus_h264_start, + .stop = cedrus_h264_stop, + .trigger = cedrus_h264_trigger, +}; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c index fbfff7c1c771..c34aec7c6e40 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c @@ -46,6 +46,10 @@ int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_codec codec) reg |= VE_MODE_DEC_MPEG; break; + case CEDRUS_CODEC_H264: + reg |= VE_MODE_DEC_H264; + break; + default: return -EINVAL; } @@ -236,7 +240,7 @@ int cedrus_hw_probe(struct cedrus_dev *dev) goto err_sram; } - ret = clk_set_rate(dev->mod_clk, CEDRUS_CLOCK_RATE_DEFAULT); + ret = clk_set_rate(dev->mod_clk, variant->mod_rate); if (ret) { dev_err(dev->dev, "Failed to set clock rate\n"); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h index b43c77d54b95..27d0882397aa 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h @@ -16,8 +16,6 @@ #ifndef _CEDRUS_HW_H_ #define _CEDRUS_HW_H_ -#define CEDRUS_CLOCK_RATE_DEFAULT 320000000 - int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_codec codec); void cedrus_engine_disable(struct cedrus_dev *dev); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h index de2d6b6f64bf..3e9931416e45 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h @@ -232,4 +232,95 @@ #define VE_DEC_MPEG_ROT_LUMA (VE_ENGINE_DEC_MPEG + 0xcc) #define VE_DEC_MPEG_ROT_CHROMA (VE_ENGINE_DEC_MPEG + 0xd0) +#define VE_H264_SPS 0x200 +#define VE_H264_SPS_MBS_ONLY BIT(18) +#define VE_H264_SPS_MB_ADAPTIVE_FRAME_FIELD BIT(17) +#define VE_H264_SPS_DIRECT_8X8_INFERENCE BIT(16) + +#define VE_H264_PPS 0x204 +#define VE_H264_PPS_ENTROPY_CODING_MODE BIT(15) +#define VE_H264_PPS_WEIGHTED_PRED BIT(4) +#define VE_H264_PPS_CONSTRAINED_INTRA_PRED BIT(1) +#define VE_H264_PPS_TRANSFORM_8X8_MODE BIT(0) + +#define VE_H264_SHS 0x208 +#define VE_H264_SHS_FIRST_SLICE_IN_PIC BIT(5) +#define VE_H264_SHS_FIELD_PIC BIT(4) +#define VE_H264_SHS_BOTTOM_FIELD BIT(3) +#define VE_H264_SHS_DIRECT_SPATIAL_MV_PRED BIT(2) + +#define VE_H264_SHS2 0x20c +#define VE_H264_SHS2_NUM_REF_IDX_ACTIVE_OVRD BIT(12) + +#define VE_H264_SHS_WP 0x210 + +#define VE_H264_SHS_QP 0x21c +#define VE_H264_SHS_QP_SCALING_MATRIX_DEFAULT BIT(24) + +#define VE_H264_CTRL 0x220 +#define VE_H264_CTRL_VLD_DATA_REQ_INT BIT(2) +#define VE_H264_CTRL_DECODE_ERR_INT BIT(1) +#define VE_H264_CTRL_SLICE_DECODE_INT BIT(0) + +#define VE_H264_CTRL_INT_MASK (VE_H264_CTRL_VLD_DATA_REQ_INT | \ + VE_H264_CTRL_DECODE_ERR_INT | \ + VE_H264_CTRL_SLICE_DECODE_INT) + +#define VE_H264_TRIGGER_TYPE 0x224 +#define VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE (8 << 0) +#define VE_H264_TRIGGER_TYPE_INIT_SWDEC (7 << 0) + +#define VE_H264_STATUS 0x228 +#define VE_H264_STATUS_VLD_DATA_REQ_INT VE_H264_CTRL_VLD_DATA_REQ_INT +#define VE_H264_STATUS_DECODE_ERR_INT VE_H264_CTRL_DECODE_ERR_INT +#define VE_H264_STATUS_SLICE_DECODE_INT VE_H264_CTRL_SLICE_DECODE_INT + +#define VE_H264_STATUS_INT_MASK VE_H264_CTRL_INT_MASK + +#define VE_H264_CUR_MB_NUM 0x22c + +#define VE_H264_VLD_ADDR 0x230 +#define VE_H264_VLD_ADDR_FIRST BIT(30) +#define VE_H264_VLD_ADDR_LAST BIT(29) +#define VE_H264_VLD_ADDR_VALID BIT(28) +#define VE_H264_VLD_ADDR_VAL(x) (((x) & 0x0ffffff0) | ((x) >> 28)) + +#define VE_H264_VLD_OFFSET 0x234 +#define VE_H264_VLD_LEN 0x238 +#define VE_H264_VLD_END 0x23c +#define VE_H264_SDROT_CTRL 0x240 +#define VE_H264_OUTPUT_FRAME_IDX 0x24c +#define VE_H264_EXTRA_BUFFER1 0x250 +#define VE_H264_EXTRA_BUFFER2 0x254 +#define VE_H264_BASIC_BITS 0x2dc +#define VE_AVC_SRAM_PORT_OFFSET 0x2e0 +#define VE_AVC_SRAM_PORT_DATA 0x2e4 + +#define VE_ISP_INPUT_SIZE 0xa00 +#define VE_ISP_INPUT_STRIDE 0xa04 +#define VE_ISP_CTRL 0xa08 +#define VE_ISP_INPUT_LUMA 0xa78 +#define VE_ISP_INPUT_CHROMA 0xa7c + +#define VE_AVC_PARAM 0xb04 +#define VE_AVC_QP 0xb08 +#define VE_AVC_MOTION_EST 0xb10 +#define VE_AVC_CTRL 0xb14 +#define VE_AVC_TRIGGER 0xb18 +#define VE_AVC_STATUS 0xb1c +#define VE_AVC_BASIC_BITS 0xb20 +#define VE_AVC_UNK_BUF 0xb60 +#define VE_AVC_VLE_ADDR 0xb80 +#define VE_AVC_VLE_END 0xb84 +#define VE_AVC_VLE_OFFSET 0xb88 +#define VE_AVC_VLE_MAX 0xb8c +#define VE_AVC_VLE_LENGTH 0xb90 +#define VE_AVC_REF_LUMA 0xba0 +#define VE_AVC_REF_CHROMA 0xba4 +#define VE_AVC_REC_LUMA 0xbb0 +#define VE_AVC_REC_CHROMA 0xbb4 +#define VE_AVC_REF_SLUMA 0xbb8 +#define VE_AVC_REC_SLUMA 0xbbc +#define VE_AVC_MB_INFO 0xbc0 + #endif diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index 9673874ece10..e2b530b1a956 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -38,6 +38,10 @@ static struct cedrus_format cedrus_formats[] = { .directions = CEDRUS_DECODE_SRC, }, { + .pixelformat = V4L2_PIX_FMT_H264_SLICE_RAW, + .directions = CEDRUS_DECODE_SRC, + }, + { .pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12, .directions = CEDRUS_DECODE_DST, }, @@ -100,6 +104,7 @@ static void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) switch (pix_fmt->pixelformat) { case V4L2_PIX_FMT_MPEG2_SLICE: + case V4L2_PIX_FMT_H264_SLICE_RAW: /* Zero bytes per line for encoded source. */ bytesperline = 0; @@ -464,6 +469,10 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count) ctx->current_codec = CEDRUS_CODEC_MPEG2; break; + case V4L2_PIX_FMT_H264_SLICE_RAW: + ctx->current_codec = CEDRUS_CODEC_H264; + break; + default: return -EINVAL; } diff --git a/drivers/staging/media/tegra-vde/Kconfig b/drivers/staging/media/tegra-vde/Kconfig index ff8e846cd15d..2e7f644ae591 100644 --- a/drivers/staging/media/tegra-vde/Kconfig +++ b/drivers/staging/media/tegra-vde/Kconfig @@ -3,6 +3,7 @@ config TEGRA_VDE tristate "NVIDIA Tegra Video Decoder Engine driver" depends on ARCH_TEGRA || COMPILE_TEST select DMA_SHARED_BUFFER + select IOMMU_IOVA if IOMMU_SUPPORT select SRAM help Say Y here to enable support for the NVIDIA Tegra video decoder diff --git a/drivers/staging/media/tegra-vde/Makefile b/drivers/staging/media/tegra-vde/Makefile index 7f9020e634f3..2827f7601de8 100644 --- a/drivers/staging/media/tegra-vde/Makefile +++ b/drivers/staging/media/tegra-vde/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 +tegra-vde-y := vde.o iommu.o dmabuf-cache.o obj-$(CONFIG_TEGRA_VDE) += tegra-vde.o diff --git a/drivers/staging/media/tegra-vde/dmabuf-cache.c b/drivers/staging/media/tegra-vde/dmabuf-cache.c new file mode 100644 index 000000000000..a93b317885bf --- /dev/null +++ b/drivers/staging/media/tegra-vde/dmabuf-cache.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NVIDIA Tegra Video decoder driver + * + * Copyright (C) 2016-2019 GRATE-DRIVER project + */ + +#include <linux/dma-buf.h> +#include <linux/iova.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/workqueue.h> + +#include "vde.h" + +struct tegra_vde_cache_entry { + enum dma_data_direction dma_dir; + struct dma_buf_attachment *a; + struct delayed_work dwork; + struct tegra_vde *vde; + struct list_head list; + struct sg_table *sgt; + struct iova *iova; + unsigned int refcnt; +}; + +static void tegra_vde_release_entry(struct tegra_vde_cache_entry *entry) +{ + struct dma_buf *dmabuf = entry->a->dmabuf; + + WARN_ON_ONCE(entry->refcnt); + + if (entry->vde->domain) + tegra_vde_iommu_unmap(entry->vde, entry->iova); + + dma_buf_unmap_attachment(entry->a, entry->sgt, entry->dma_dir); + dma_buf_detach(dmabuf, entry->a); + dma_buf_put(dmabuf); + + list_del(&entry->list); + kfree(entry); +} + +static void tegra_vde_delayed_unmap(struct work_struct *work) +{ + struct tegra_vde_cache_entry *entry; + struct tegra_vde *vde; + + entry = container_of(work, struct tegra_vde_cache_entry, + dwork.work); + vde = entry->vde; + + mutex_lock(&vde->map_lock); + tegra_vde_release_entry(entry); + mutex_unlock(&vde->map_lock); +} + +int tegra_vde_dmabuf_cache_map(struct tegra_vde *vde, + struct dma_buf *dmabuf, + enum dma_data_direction dma_dir, + struct dma_buf_attachment **ap, + dma_addr_t *addrp) +{ + struct device *dev = vde->miscdev.parent; + struct dma_buf_attachment *attachment; + struct tegra_vde_cache_entry *entry; + struct sg_table *sgt; + struct iova *iova; + int err; + + mutex_lock(&vde->map_lock); + + list_for_each_entry(entry, &vde->map_list, list) { + if (entry->a->dmabuf != dmabuf) + continue; + + if (!cancel_delayed_work(&entry->dwork)) + continue; + + if (entry->dma_dir != dma_dir) + entry->dma_dir = DMA_BIDIRECTIONAL; + + dma_buf_put(dmabuf); + + if (vde->domain) + *addrp = iova_dma_addr(&vde->iova, entry->iova); + else + *addrp = sg_dma_address(entry->sgt->sgl); + + goto ref; + } + + attachment = dma_buf_attach(dmabuf, dev); + if (IS_ERR(attachment)) { + dev_err(dev, "Failed to attach dmabuf\n"); + err = PTR_ERR(attachment); + goto err_unlock; + } + + sgt = dma_buf_map_attachment(attachment, dma_dir); + if (IS_ERR(sgt)) { + dev_err(dev, "Failed to get dmabufs sg_table\n"); + err = PTR_ERR(sgt); + goto err_detach; + } + + if (!vde->domain && sgt->nents > 1) { + dev_err(dev, "Sparse DMA region is unsupported, please enable IOMMU\n"); + err = -EINVAL; + goto err_unmap; + } + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) { + err = -ENOMEM; + goto err_unmap; + } + + if (vde->domain) { + err = tegra_vde_iommu_map(vde, sgt, &iova, dmabuf->size); + if (err) + goto err_free; + + *addrp = iova_dma_addr(&vde->iova, iova); + } else { + *addrp = sg_dma_address(sgt->sgl); + iova = NULL; + } + + INIT_DELAYED_WORK(&entry->dwork, tegra_vde_delayed_unmap); + list_add(&entry->list, &vde->map_list); + + entry->dma_dir = dma_dir; + entry->iova = iova; + entry->vde = vde; + entry->sgt = sgt; + entry->a = attachment; +ref: + entry->refcnt++; + + *ap = entry->a; + + mutex_unlock(&vde->map_lock); + + return 0; + +err_free: + kfree(entry); +err_unmap: + dma_buf_unmap_attachment(attachment, sgt, dma_dir); +err_detach: + dma_buf_detach(dmabuf, attachment); +err_unlock: + mutex_unlock(&vde->map_lock); + + return err; +} + +void tegra_vde_dmabuf_cache_unmap(struct tegra_vde *vde, + struct dma_buf_attachment *a, + bool release) +{ + struct tegra_vde_cache_entry *entry; + + mutex_lock(&vde->map_lock); + + list_for_each_entry(entry, &vde->map_list, list) { + if (entry->a != a) + continue; + + WARN_ON_ONCE(!entry->refcnt); + + if (--entry->refcnt == 0) { + if (release) + tegra_vde_release_entry(entry); + else + schedule_delayed_work(&entry->dwork, 5 * HZ); + } + break; + } + + mutex_unlock(&vde->map_lock); +} + +void tegra_vde_dmabuf_cache_unmap_sync(struct tegra_vde *vde) +{ + struct tegra_vde_cache_entry *entry, *tmp; + + mutex_lock(&vde->map_lock); + + list_for_each_entry_safe(entry, tmp, &vde->map_list, list) { + if (entry->refcnt) + continue; + + if (!cancel_delayed_work(&entry->dwork)) + continue; + + tegra_vde_release_entry(entry); + } + + mutex_unlock(&vde->map_lock); +} + +void tegra_vde_dmabuf_cache_unmap_all(struct tegra_vde *vde) +{ + struct tegra_vde_cache_entry *entry, *tmp; + + mutex_lock(&vde->map_lock); + + while (!list_empty(&vde->map_list)) { + list_for_each_entry_safe(entry, tmp, &vde->map_list, list) { + if (!cancel_delayed_work(&entry->dwork)) + continue; + + tegra_vde_release_entry(entry); + } + + mutex_unlock(&vde->map_lock); + schedule(); + mutex_lock(&vde->map_lock); + } + + mutex_unlock(&vde->map_lock); +} diff --git a/drivers/staging/media/tegra-vde/iommu.c b/drivers/staging/media/tegra-vde/iommu.c new file mode 100644 index 000000000000..6af863d92123 --- /dev/null +++ b/drivers/staging/media/tegra-vde/iommu.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NVIDIA Tegra Video decoder driver + * + * Copyright (C) 2016-2019 GRATE-DRIVER project + */ + +#include <linux/iommu.h> +#include <linux/iova.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) +#include <asm/dma-iommu.h> +#endif + +#include "vde.h" + +int tegra_vde_iommu_map(struct tegra_vde *vde, + struct sg_table *sgt, + struct iova **iovap, + size_t size) +{ + struct iova *iova; + unsigned long shift; + unsigned long end; + dma_addr_t addr; + + end = vde->domain->geometry.aperture_end; + size = iova_align(&vde->iova, size); + shift = iova_shift(&vde->iova); + + iova = alloc_iova(&vde->iova, size >> shift, end >> shift, true); + if (!iova) + return -ENOMEM; + + addr = iova_dma_addr(&vde->iova, iova); + + size = iommu_map_sg(vde->domain, addr, sgt->sgl, sgt->nents, + IOMMU_READ | IOMMU_WRITE); + if (!size) { + __free_iova(&vde->iova, iova); + return -ENXIO; + } + + *iovap = iova; + + return 0; +} + +void tegra_vde_iommu_unmap(struct tegra_vde *vde, struct iova *iova) +{ + unsigned long shift = iova_shift(&vde->iova); + unsigned long size = iova_size(iova) << shift; + dma_addr_t addr = iova_dma_addr(&vde->iova, iova); + + iommu_unmap(vde->domain, addr, size); + __free_iova(&vde->iova, iova); +} + +int tegra_vde_iommu_init(struct tegra_vde *vde) +{ + struct device *dev = vde->miscdev.parent; + struct iova *iova; + unsigned long order; + unsigned long shift; + int err; + + vde->group = iommu_group_get(dev); + if (!vde->group) + return 0; + +#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) + if (dev->archdata.mapping) { + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); + + arm_iommu_detach_device(dev); + arm_iommu_release_mapping(mapping); + } +#endif + vde->domain = iommu_domain_alloc(&platform_bus_type); + if (!vde->domain) { + err = -ENOMEM; + goto put_group; + } + + err = iova_cache_get(); + if (err) + goto free_domain; + + order = __ffs(vde->domain->pgsize_bitmap); + init_iova_domain(&vde->iova, 1UL << order, 0); + + err = iommu_attach_group(vde->domain, vde->group); + if (err) + goto put_iova; + + /* + * We're using some static addresses that are not accessible by VDE + * to trap invalid memory accesses. + */ + shift = iova_shift(&vde->iova); + iova = reserve_iova(&vde->iova, 0x60000000 >> shift, + 0x70000000 >> shift); + if (!iova) { + err = -ENOMEM; + goto detach_group; + } + + vde->iova_resv_static_addresses = iova; + + /* + * BSEV's end-address wraps around due to integer overflow during + * of hardware context preparation if IOVA is allocated at the end + * of address space and VDE can't handle that. Hence simply reserve + * the last page to avoid the problem. + */ + iova = reserve_iova(&vde->iova, 0xffffffff >> shift, + (0xffffffff >> shift) + 1); + if (!iova) { + err = -ENOMEM; + goto unreserve_iova; + } + + vde->iova_resv_last_page = iova; + + return 0; + +unreserve_iova: + __free_iova(&vde->iova, vde->iova_resv_static_addresses); +detach_group: + iommu_detach_group(vde->domain, vde->group); +put_iova: + put_iova_domain(&vde->iova); + iova_cache_put(); +free_domain: + iommu_domain_free(vde->domain); +put_group: + iommu_group_put(vde->group); + + return err; +} + +void tegra_vde_iommu_deinit(struct tegra_vde *vde) +{ + if (vde->domain) { + __free_iova(&vde->iova, vde->iova_resv_last_page); + __free_iova(&vde->iova, vde->iova_resv_static_addresses); + iommu_detach_group(vde->domain, vde->group); + put_iova_domain(&vde->iova); + iova_cache_put(); + iommu_domain_free(vde->domain); + iommu_group_put(vde->group); + + vde->domain = NULL; + } +} diff --git a/drivers/staging/media/tegra-vde/trace.h b/drivers/staging/media/tegra-vde/trace.h index 85e2f7e2d4d0..e5714107db58 100644 --- a/drivers/staging/media/tegra-vde/trace.h +++ b/drivers/staging/media/tegra-vde/trace.h @@ -8,6 +8,8 @@ #include <linux/tracepoint.h> +#include "vde.h" + DECLARE_EVENT_CLASS(register_access, TP_PROTO(struct tegra_vde *vde, void __iomem *base, u32 offset, u32 value), diff --git a/drivers/staging/media/tegra-vde/uapi.h b/drivers/staging/media/tegra-vde/uapi.h index a0dad1ed94ef..ffb4983e5bb6 100644 --- a/drivers/staging/media/tegra-vde/uapi.h +++ b/drivers/staging/media/tegra-vde/uapi.h @@ -6,8 +6,8 @@ #include <linux/types.h> #include <asm/ioctl.h> -#define FLAG_B_FRAME BIT(0) -#define FLAG_REFERENCE BIT(1) +#define FLAG_B_FRAME 0x1 +#define FLAG_REFERENCE 0x2 struct tegra_vde_h264_frame { __s32 y_fd; @@ -21,40 +21,42 @@ struct tegra_vde_h264_frame { __u32 frame_num; __u32 flags; - __u32 reserved; -} __attribute__((packed)); + // Must be zero'ed + __u32 reserved[6]; +}; struct tegra_vde_h264_decoder_ctx { __s32 bitstream_data_fd; __u32 bitstream_data_offset; __u64 dpb_frames_ptr; - __u8 dpb_frames_nb; - __u8 dpb_ref_frames_with_earlier_poc_nb; + __u32 dpb_frames_nb; + __u32 dpb_ref_frames_with_earlier_poc_nb; // SPS - __u8 baseline_profile; - __u8 level_idc; - __u8 log2_max_pic_order_cnt_lsb; - __u8 log2_max_frame_num; - __u8 pic_order_cnt_type; - __u8 direct_8x8_inference_flag; - __u8 pic_width_in_mbs; - __u8 pic_height_in_mbs; + __u32 baseline_profile; + __u32 level_idc; + __u32 log2_max_pic_order_cnt_lsb; + __u32 log2_max_frame_num; + __u32 pic_order_cnt_type; + __u32 direct_8x8_inference_flag; + __u32 pic_width_in_mbs; + __u32 pic_height_in_mbs; // PPS - __u8 pic_init_qp; - __u8 deblocking_filter_control_present_flag; - __u8 constrained_intra_pred_flag; - __u8 chroma_qp_index_offset; - __u8 pic_order_present_flag; + __u32 pic_init_qp; + __u32 deblocking_filter_control_present_flag; + __u32 constrained_intra_pred_flag; + __u32 chroma_qp_index_offset; + __u32 pic_order_present_flag; // Slice header - __u8 num_ref_idx_l0_active_minus1; - __u8 num_ref_idx_l1_active_minus1; + __u32 num_ref_idx_l0_active_minus1; + __u32 num_ref_idx_l1_active_minus1; - __u32 reserved; -} __attribute__((packed)); + // Must be zero'ed + __u32 reserved[11]; +}; #define VDE_IOCTL_BASE ('v' + 0x20) diff --git a/drivers/staging/media/tegra-vde/tegra-vde.c b/drivers/staging/media/tegra-vde/vde.c index a5020dbf6eef..3466daddf663 100644 --- a/drivers/staging/media/tegra-vde/tegra-vde.c +++ b/drivers/staging/media/tegra-vde/vde.c @@ -11,6 +11,7 @@ #include <linux/genalloc.h> #include <linux/interrupt.h> #include <linux/iopoll.h> +#include <linux/list.h> #include <linux/miscdevice.h> #include <linux/module.h> #include <linux/of_device.h> @@ -22,6 +23,10 @@ #include <soc/tegra/pmc.h> #include "uapi.h" +#include "vde.h" + +#define CREATE_TRACE_POINTS +#include "trace.h" #define ICMDQUE_WR 0x00 #define CMDQUE_CONTROL 0x08 @@ -37,10 +42,6 @@ struct video_frame { struct dma_buf_attachment *cb_dmabuf_attachment; struct dma_buf_attachment *cr_dmabuf_attachment; struct dma_buf_attachment *aux_dmabuf_attachment; - struct sg_table *y_sgt; - struct sg_table *cb_sgt; - struct sg_table *cr_sgt; - struct sg_table *aux_sgt; dma_addr_t y_addr; dma_addr_t cb_addr; dma_addr_t cr_addr; @@ -49,63 +50,6 @@ struct video_frame { u32 flags; }; -struct tegra_vde { - void __iomem *sxe; - void __iomem *bsev; - void __iomem *mbe; - void __iomem *ppe; - void __iomem *mce; - void __iomem *tfe; - void __iomem *ppb; - void __iomem *vdma; - void __iomem *frameid; - struct mutex lock; - struct miscdevice miscdev; - struct reset_control *rst; - struct reset_control *rst_mc; - struct gen_pool *iram_pool; - struct completion decode_completion; - struct clk *clk; - dma_addr_t iram_lists_addr; - u32 *iram; -}; - -static __maybe_unused char const * -tegra_vde_reg_base_name(struct tegra_vde *vde, void __iomem *base) -{ - if (vde->sxe == base) - return "SXE"; - - if (vde->bsev == base) - return "BSEV"; - - if (vde->mbe == base) - return "MBE"; - - if (vde->ppe == base) - return "PPE"; - - if (vde->mce == base) - return "MCE"; - - if (vde->tfe == base) - return "TFE"; - - if (vde->ppb == base) - return "PPB"; - - if (vde->vdma == base) - return "VDMA"; - - if (vde->frameid == base) - return "FRAMEID"; - - return "???"; -} - -#define CREATE_TRACE_POINTS -#include "trace.h" - static void tegra_vde_writel(struct tegra_vde *vde, u32 value, void __iomem *base, u32 offset) { @@ -543,31 +487,18 @@ static void tegra_vde_decode_frame(struct tegra_vde *vde, vde->sxe, 0x00); } -static void tegra_vde_detach_and_put_dmabuf(struct dma_buf_attachment *a, - struct sg_table *sgt, - enum dma_data_direction dma_dir) -{ - struct dma_buf *dmabuf = a->dmabuf; - - dma_buf_unmap_attachment(a, sgt, dma_dir); - dma_buf_detach(dmabuf, a); - dma_buf_put(dmabuf); -} - -static int tegra_vde_attach_dmabuf(struct device *dev, +static int tegra_vde_attach_dmabuf(struct tegra_vde *vde, int fd, unsigned long offset, size_t min_size, size_t align_size, struct dma_buf_attachment **a, - dma_addr_t *addr, - struct sg_table **s, + dma_addr_t *addrp, size_t *size, enum dma_data_direction dma_dir) { - struct dma_buf_attachment *attachment; + struct device *dev = vde->miscdev.parent; struct dma_buf *dmabuf; - struct sg_table *sgt; int err; dmabuf = dma_buf_get(fd); @@ -588,46 +519,24 @@ static int tegra_vde_attach_dmabuf(struct device *dev, return -EINVAL; } - attachment = dma_buf_attach(dmabuf, dev); - if (IS_ERR(attachment)) { - dev_err(dev, "Failed to attach dmabuf\n"); - err = PTR_ERR(attachment); + err = tegra_vde_dmabuf_cache_map(vde, dmabuf, dma_dir, a, addrp); + if (err) goto err_put; - } - sgt = dma_buf_map_attachment(attachment, dma_dir); - if (IS_ERR(sgt)) { - dev_err(dev, "Failed to get dmabufs sg_table\n"); - err = PTR_ERR(sgt); - goto err_detach; - } - - if (sgt->nents != 1) { - dev_err(dev, "Sparse DMA region is unsupported\n"); - err = -EINVAL; - goto err_unmap; - } - - *addr = sg_dma_address(sgt->sgl) + offset; - *a = attachment; - *s = sgt; + *addrp = *addrp + offset; if (size) *size = dmabuf->size - offset; return 0; -err_unmap: - dma_buf_unmap_attachment(attachment, sgt, dma_dir); -err_detach: - dma_buf_detach(dmabuf, attachment); err_put: dma_buf_put(dmabuf); return err; } -static int tegra_vde_attach_dmabufs_to_frame(struct device *dev, +static int tegra_vde_attach_dmabufs_to_frame(struct tegra_vde *vde, struct video_frame *frame, struct tegra_vde_h264_frame *src, enum dma_data_direction dma_dir, @@ -636,29 +545,26 @@ static int tegra_vde_attach_dmabufs_to_frame(struct device *dev, { int err; - err = tegra_vde_attach_dmabuf(dev, src->y_fd, + err = tegra_vde_attach_dmabuf(vde, src->y_fd, src->y_offset, lsize, SZ_256, &frame->y_dmabuf_attachment, &frame->y_addr, - &frame->y_sgt, NULL, dma_dir); if (err) return err; - err = tegra_vde_attach_dmabuf(dev, src->cb_fd, + err = tegra_vde_attach_dmabuf(vde, src->cb_fd, src->cb_offset, csize, SZ_256, &frame->cb_dmabuf_attachment, &frame->cb_addr, - &frame->cb_sgt, NULL, dma_dir); if (err) goto err_release_y; - err = tegra_vde_attach_dmabuf(dev, src->cr_fd, + err = tegra_vde_attach_dmabuf(vde, src->cr_fd, src->cr_offset, csize, SZ_256, &frame->cr_dmabuf_attachment, &frame->cr_addr, - &frame->cr_sgt, NULL, dma_dir); if (err) goto err_release_cb; @@ -668,11 +574,10 @@ static int tegra_vde_attach_dmabufs_to_frame(struct device *dev, return 0; } - err = tegra_vde_attach_dmabuf(dev, src->aux_fd, + err = tegra_vde_attach_dmabuf(vde, src->aux_fd, src->aux_offset, csize, SZ_256, &frame->aux_dmabuf_attachment, &frame->aux_addr, - &frame->aux_sgt, NULL, dma_dir); if (err) goto err_release_cr; @@ -680,34 +585,28 @@ static int tegra_vde_attach_dmabufs_to_frame(struct device *dev, return 0; err_release_cr: - tegra_vde_detach_and_put_dmabuf(frame->cr_dmabuf_attachment, - frame->cr_sgt, dma_dir); + tegra_vde_dmabuf_cache_unmap(vde, frame->cr_dmabuf_attachment, true); err_release_cb: - tegra_vde_detach_and_put_dmabuf(frame->cb_dmabuf_attachment, - frame->cb_sgt, dma_dir); + tegra_vde_dmabuf_cache_unmap(vde, frame->cb_dmabuf_attachment, true); err_release_y: - tegra_vde_detach_and_put_dmabuf(frame->y_dmabuf_attachment, - frame->y_sgt, dma_dir); + tegra_vde_dmabuf_cache_unmap(vde, frame->y_dmabuf_attachment, true); return err; } -static void tegra_vde_release_frame_dmabufs(struct video_frame *frame, +static void tegra_vde_release_frame_dmabufs(struct tegra_vde *vde, + struct video_frame *frame, enum dma_data_direction dma_dir, - bool baseline_profile) + bool baseline_profile, + bool release) { if (!baseline_profile) - tegra_vde_detach_and_put_dmabuf(frame->aux_dmabuf_attachment, - frame->aux_sgt, dma_dir); + tegra_vde_dmabuf_cache_unmap(vde, frame->aux_dmabuf_attachment, + release); - tegra_vde_detach_and_put_dmabuf(frame->cr_dmabuf_attachment, - frame->cr_sgt, dma_dir); - - tegra_vde_detach_and_put_dmabuf(frame->cb_dmabuf_attachment, - frame->cb_sgt, dma_dir); - - tegra_vde_detach_and_put_dmabuf(frame->y_dmabuf_attachment, - frame->y_sgt, dma_dir); + tegra_vde_dmabuf_cache_unmap(vde, frame->cr_dmabuf_attachment, release); + tegra_vde_dmabuf_cache_unmap(vde, frame->cb_dmabuf_attachment, release); + tegra_vde_dmabuf_cache_unmap(vde, frame->y_dmabuf_attachment, release); } static int tegra_vde_validate_frame(struct device *dev, @@ -795,11 +694,10 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde, { struct device *dev = vde->miscdev.parent; struct tegra_vde_h264_decoder_ctx ctx; - struct tegra_vde_h264_frame frames[17]; + struct tegra_vde_h264_frame *frames; struct tegra_vde_h264_frame __user *frames_user; struct video_frame *dpb_frames; struct dma_buf_attachment *bitstream_data_dmabuf_attachment; - struct sg_table *bitstream_sgt; enum dma_data_direction dma_dir; dma_addr_t bitstream_data_addr; dma_addr_t bsev_ptr; @@ -819,22 +717,27 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde, if (ret) return ret; - ret = tegra_vde_attach_dmabuf(dev, ctx.bitstream_data_fd, + ret = tegra_vde_attach_dmabuf(vde, ctx.bitstream_data_fd, ctx.bitstream_data_offset, SZ_16K, SZ_16K, &bitstream_data_dmabuf_attachment, &bitstream_data_addr, - &bitstream_sgt, &bitstream_data_size, DMA_TO_DEVICE); if (ret) return ret; + frames = kmalloc_array(ctx.dpb_frames_nb, sizeof(*frames), GFP_KERNEL); + if (!frames) { + ret = -ENOMEM; + goto release_bitstream_dmabuf; + } + dpb_frames = kcalloc(ctx.dpb_frames_nb, sizeof(*dpb_frames), GFP_KERNEL); if (!dpb_frames) { ret = -ENOMEM; - goto release_bitstream_dmabuf; + goto free_frames; } macroblocks_nb = ctx.pic_width_in_mbs * ctx.pic_height_in_mbs; @@ -860,7 +763,7 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde, dma_dir = (i == 0) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - ret = tegra_vde_attach_dmabufs_to_frame(dev, &dpb_frames[i], + ret = tegra_vde_attach_dmabufs_to_frame(vde, &dpb_frames[i], &frames[i], dma_dir, ctx.baseline_profile, lsize, csize); @@ -948,16 +851,19 @@ release_dpb_frames: while (i--) { dma_dir = (i == 0) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - tegra_vde_release_frame_dmabufs(&dpb_frames[i], dma_dir, - ctx.baseline_profile); + tegra_vde_release_frame_dmabufs(vde, &dpb_frames[i], dma_dir, + ctx.baseline_profile, ret != 0); } free_dpb_frames: kfree(dpb_frames); +free_frames: + kfree(frames); + release_bitstream_dmabuf: - tegra_vde_detach_and_put_dmabuf(bitstream_data_dmabuf_attachment, - bitstream_sgt, DMA_TO_DEVICE); + tegra_vde_dmabuf_cache_unmap(vde, bitstream_data_dmabuf_attachment, + ret != 0); return ret; } @@ -979,9 +885,21 @@ static long tegra_vde_unlocked_ioctl(struct file *filp, return -ENOTTY; } +static int tegra_vde_release_file(struct inode *inode, struct file *filp) +{ + struct miscdevice *miscdev = filp->private_data; + struct tegra_vde *vde = container_of(miscdev, struct tegra_vde, + miscdev); + + tegra_vde_dmabuf_cache_unmap_sync(vde); + + return 0; +} + static const struct file_operations tegra_vde_fops = { .owner = THIS_MODULE, .unlocked_ioctl = tegra_vde_unlocked_ioctl, + .release = tegra_vde_release_file, }; static irqreturn_t tegra_vde_isr(int irq, void *data) @@ -1159,6 +1077,8 @@ static int tegra_vde_probe(struct platform_device *pdev) return -ENOMEM; } + INIT_LIST_HEAD(&vde->map_list); + mutex_init(&vde->map_lock); mutex_init(&vde->lock); init_completion(&vde->decode_completion); @@ -1167,10 +1087,16 @@ static int tegra_vde_probe(struct platform_device *pdev) vde->miscdev.fops = &tegra_vde_fops; vde->miscdev.parent = dev; + err = tegra_vde_iommu_init(vde); + if (err) { + dev_err(dev, "Failed to initialize IOMMU: %d\n", err); + goto err_gen_free; + } + err = misc_register(&vde->miscdev); if (err) { dev_err(dev, "Failed to register misc device: %d\n", err); - goto err_gen_free; + goto err_deinit_iommu; } pm_runtime_enable(dev); @@ -1188,6 +1114,9 @@ static int tegra_vde_probe(struct platform_device *pdev) err_misc_unreg: misc_deregister(&vde->miscdev); +err_deinit_iommu: + tegra_vde_iommu_deinit(vde); + err_gen_free: gen_pool_free(vde->iram_pool, (unsigned long)vde->iram, gen_pool_size(vde->iram_pool)); @@ -1212,6 +1141,9 @@ static int tegra_vde_remove(struct platform_device *pdev) misc_deregister(&vde->miscdev); + tegra_vde_dmabuf_cache_unmap_all(vde); + tegra_vde_iommu_deinit(vde); + gen_pool_free(vde->iram_pool, (unsigned long)vde->iram, gen_pool_size(vde->iram_pool)); diff --git a/drivers/staging/media/tegra-vde/vde.h b/drivers/staging/media/tegra-vde/vde.h new file mode 100644 index 000000000000..d369f1466bc7 --- /dev/null +++ b/drivers/staging/media/tegra-vde/vde.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * NVIDIA Tegra Video decoder driver + * + * Copyright (C) 2016-2019 GRATE-DRIVER project + */ + +#ifndef TEGRA_VDE_H +#define TEGRA_VDE_H + +#include <linux/completion.h> +#include <linux/dma-direction.h> +#include <linux/list.h> +#include <linux/miscdevice.h> +#include <linux/mutex.h> +#include <linux/types.h> +#include <linux/iova.h> + +struct clk; +struct dma_buf; +struct gen_pool; +struct iommu_group; +struct iommu_domain; +struct reset_control; +struct dma_buf_attachment; + +struct tegra_vde { + void __iomem *sxe; + void __iomem *bsev; + void __iomem *mbe; + void __iomem *ppe; + void __iomem *mce; + void __iomem *tfe; + void __iomem *ppb; + void __iomem *vdma; + void __iomem *frameid; + struct mutex lock; + struct mutex map_lock; + struct list_head map_list; + struct miscdevice miscdev; + struct reset_control *rst; + struct reset_control *rst_mc; + struct gen_pool *iram_pool; + struct completion decode_completion; + struct clk *clk; + struct iommu_domain *domain; + struct iommu_group *group; + struct iova_domain iova; + struct iova *iova_resv_static_addresses; + struct iova *iova_resv_last_page; + dma_addr_t iram_lists_addr; + u32 *iram; +}; + +int tegra_vde_iommu_init(struct tegra_vde *vde); +void tegra_vde_iommu_deinit(struct tegra_vde *vde); +int tegra_vde_iommu_map(struct tegra_vde *vde, + struct sg_table *sgt, + struct iova **iovap, + size_t size); +void tegra_vde_iommu_unmap(struct tegra_vde *vde, struct iova *iova); + +int tegra_vde_dmabuf_cache_map(struct tegra_vde *vde, + struct dma_buf *dmabuf, + enum dma_data_direction dma_dir, + struct dma_buf_attachment **ap, + dma_addr_t *addrp); +void tegra_vde_dmabuf_cache_unmap(struct tegra_vde *vde, + struct dma_buf_attachment *a, + bool release); +void tegra_vde_dmabuf_cache_unmap_sync(struct tegra_vde *vde); +void tegra_vde_dmabuf_cache_unmap_all(struct tegra_vde *vde); + +static __maybe_unused char const * +tegra_vde_reg_base_name(struct tegra_vde *vde, void __iomem *base) +{ + if (vde->sxe == base) + return "SXE"; + + if (vde->bsev == base) + return "BSEV"; + + if (vde->mbe == base) + return "MBE"; + + if (vde->ppe == base) + return "PPE"; + + if (vde->mce == base) + return "MCE"; + + if (vde->tfe == base) + return "TFE"; + + if (vde->ppb == base) + return "PPB"; + + if (vde->vdma == base) + return "VDMA"; + + if (vde->frameid == base) + return "FRAMEID"; + + return "???"; +} + +#endif /* TEGRA_VDE_H */ diff --git a/drivers/staging/olpc_dcon/TODO b/drivers/staging/olpc_dcon/TODO index 665a0b061719..fe09efbc7f77 100644 --- a/drivers/staging/olpc_dcon/TODO +++ b/drivers/staging/olpc_dcon/TODO @@ -1,4 +1,11 @@ TODO: + - complete rewrite: + 1. The underlying fbdev drivers need to be converted into drm kernel + modesetting drivers. + 2. The dcon low-power display mode can then be integrated using the + drm damage tracking and self-refresh helpers. + This bolted-on self-refresh support that digs around in fbdev + internals, but isn't properly integrated, is not the correct solution. - see if vx855 gpio API can be made similar enough to cs5535 so we can share more code - convert all uses of the old GPIO API from <linux/gpio.h> to the diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index 6b714f740ac3..a254238be181 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -250,11 +250,7 @@ static bool dcon_blank_fb(struct dcon_priv *dcon, bool blank) int err; console_lock(); - if (!lock_fb_info(dcon->fbinfo)) { - console_unlock(); - dev_err(&dcon->client->dev, "unable to lock framebuffer\n"); - return false; - } + lock_fb_info(dcon->fbinfo); dcon->ignore_fb_events = true; err = fb_blank(dcon->fbinfo, diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c index 68f08dc18da9..49d0470f9a7e 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c @@ -864,10 +864,6 @@ static int vidioc_querycap(struct file *file, void *priv, snprintf((char *)cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev->v4l2_dev.name); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | - V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -1446,6 +1442,8 @@ static const struct video_device vdev_template = { .fops = &camera0_fops, .ioctl_ops = &camera0_ioctl_ops, .release = video_device_release_empty, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE, }; /* Returns the number of cameras, and also the max resolution supported diff --git a/drivers/target/iscsi/cxgbit/cxgbit.h b/drivers/target/iscsi/cxgbit/cxgbit.h index 3cca22e19964..c04cd0832dec 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit.h +++ b/drivers/target/iscsi/cxgbit/cxgbit.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __CXGBIT_H__ diff --git a/drivers/target/iscsi/cxgbit/cxgbit_cm.c b/drivers/target/iscsi/cxgbit/cxgbit_cm.c index dab09b610723..22dd4c457d6a 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_cm.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_cm.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/target/iscsi/cxgbit/cxgbit_ddp.c b/drivers/target/iscsi/cxgbit/cxgbit_ddp.c index d57fd3ed3fa5..c859afa4308e 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_ddp.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_ddp.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "cxgbit.h" diff --git a/drivers/target/iscsi/cxgbit/cxgbit_main.c b/drivers/target/iscsi/cxgbit/cxgbit_main.c index 4a7bb0b49d17..343b129c2cfa 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_main.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_main.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define DRV_NAME "cxgbit" diff --git a/drivers/target/iscsi/cxgbit/cxgbit_target.c b/drivers/target/iscsi/cxgbit/cxgbit_target.c index 29b350a0b58f..24309d937d8c 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_target.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_target.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/workqueue.h> diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index b6e4862cc242..51ddca2033e0 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -81,6 +81,12 @@ out: return CHAP_DIGEST_UNKNOWN; } +static void chap_close(struct iscsi_conn *conn) +{ + kfree(conn->auth_protocol); + conn->auth_protocol = NULL; +} + static struct iscsi_chap *chap_server_open( struct iscsi_conn *conn, struct iscsi_node_auth *auth, @@ -118,7 +124,7 @@ static struct iscsi_chap *chap_server_open( case CHAP_DIGEST_UNKNOWN: default: pr_err("Unsupported CHAP_A value\n"); - kfree(conn->auth_protocol); + chap_close(conn); return NULL; } @@ -133,19 +139,13 @@ static struct iscsi_chap *chap_server_open( * Generate Challenge. */ if (chap_gen_challenge(conn, 1, aic_str, aic_len) < 0) { - kfree(conn->auth_protocol); + chap_close(conn); return NULL; } return chap; } -static void chap_close(struct iscsi_conn *conn) -{ - kfree(conn->auth_protocol); - conn->auth_protocol = NULL; -} - static int chap_server_compute_md5( struct iscsi_conn *conn, struct iscsi_node_auth *auth, diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index f4a075303e9a..6949ea8bc387 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -502,7 +502,7 @@ iblock_execute_write_same(struct se_cmd *cmd) /* Always in 512 byte units for Linux/Block */ block_lba += sg->length >> SECTOR_SHIFT; - sectors -= 1; + sectors -= sg->length >> SECTOR_SHIFT; } iblock_submit_bios(&list); diff --git a/drivers/thermal/broadcom/ns-thermal.c b/drivers/thermal/broadcom/ns-thermal.c index 322e741a2463..c9468ba9d449 100644 --- a/drivers/thermal/broadcom/ns-thermal.c +++ b/drivers/thermal/broadcom/ns-thermal.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c b/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c index 7c71ffb733a1..9716bc3abaf9 100644 --- a/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c +++ b/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* acpi_thermal_rel.c driver for exporting ACPI thermal relationship * * Copyright (c) 2014 Intel Corp - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * */ /* diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c index 5f3ed24e26ec..3517883b5cdb 100644 --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * INT3400 thermal driver * * Copyright (C) 2014, Intel Corporation * Authors: Zhang Rui <rui.zhang@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/thermal/intel/int340x_thermal/int3402_thermal.c b/drivers/thermal/intel/int340x_thermal/int3402_thermal.c index 8e90b3151a42..43fa351e2b9e 100644 --- a/drivers/thermal/intel/int340x_thermal/int3402_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3402_thermal.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * INT3402 thermal driver for memory temperature reporting * * Copyright (C) 2014, Intel Corporation * Authors: Aaron Lu <aaron.lu@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/thermal/intel/int340x_thermal/int3406_thermal.c b/drivers/thermal/intel/int340x_thermal/int3406_thermal.c index f69ab026ba24..f5e42fc2acc0 100644 --- a/drivers/thermal/intel/int340x_thermal/int3406_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3406_thermal.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * INT3406 thermal driver for display participant device * * Copyright (C) 2016, Intel Corporation * Authors: Aaron Lu <aaron.lu@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c index 319b77126168..e85d54d1cdf3 100644 --- a/drivers/thermal/intel/x86_pkg_temp_thermal.c +++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c @@ -43,7 +43,7 @@ MODULE_PARM_DESC(notify_delay_ms, */ #define MAX_NUMBER_OF_TRIPS 2 -struct pkg_device { +struct zone_device { int cpu; bool work_scheduled; u32 tj_max; @@ -58,10 +58,10 @@ static struct thermal_zone_params pkg_temp_tz_params = { .no_hwmon = true, }; -/* Keep track of how many package pointers we allocated in init() */ -static int max_packages __read_mostly; -/* Array of package pointers */ -static struct pkg_device **packages; +/* Keep track of how many zone pointers we allocated in init() */ +static int max_id __read_mostly; +/* Array of zone pointers */ +static struct zone_device **zones; /* Serializes interrupt notification, work and hotplug */ static DEFINE_SPINLOCK(pkg_temp_lock); /* Protects zone operation in the work function against hotplug removal */ @@ -108,12 +108,12 @@ err_out: * * - Other callsites: Must hold pkg_temp_lock */ -static struct pkg_device *pkg_temp_thermal_get_dev(unsigned int cpu) +static struct zone_device *pkg_temp_thermal_get_dev(unsigned int cpu) { - int pkgid = topology_logical_package_id(cpu); + int id = topology_logical_die_id(cpu); - if (pkgid >= 0 && pkgid < max_packages) - return packages[pkgid]; + if (id >= 0 && id < max_id) + return zones[id]; return NULL; } @@ -138,12 +138,13 @@ static int get_tj_max(int cpu, u32 *tj_max) static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp) { - struct pkg_device *pkgdev = tzd->devdata; + struct zone_device *zonedev = tzd->devdata; u32 eax, edx; - rdmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_STATUS, &eax, &edx); + rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_STATUS, + &eax, &edx); if (eax & 0x80000000) { - *temp = pkgdev->tj_max - ((eax >> 16) & 0x7f) * 1000; + *temp = zonedev->tj_max - ((eax >> 16) & 0x7f) * 1000; pr_debug("sys_get_curr_temp %d\n", *temp); return 0; } @@ -153,7 +154,7 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp) static int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip, int *temp) { - struct pkg_device *pkgdev = tzd->devdata; + struct zone_device *zonedev = tzd->devdata; unsigned long thres_reg_value; u32 mask, shift, eax, edx; int ret; @@ -169,14 +170,14 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzd, shift = THERM_SHIFT_THRESHOLD0; } - ret = rdmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, + ret = rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &eax, &edx); if (ret < 0) return ret; thres_reg_value = (eax & mask) >> shift; if (thres_reg_value) - *temp = pkgdev->tj_max - thres_reg_value * 1000; + *temp = zonedev->tj_max - thres_reg_value * 1000; else *temp = 0; pr_debug("sys_get_trip_temp %d\n", *temp); @@ -187,14 +188,14 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzd, static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp) { - struct pkg_device *pkgdev = tzd->devdata; + struct zone_device *zonedev = tzd->devdata; u32 l, h, mask, shift, intr; int ret; - if (trip >= MAX_NUMBER_OF_TRIPS || temp >= pkgdev->tj_max) + if (trip >= MAX_NUMBER_OF_TRIPS || temp >= zonedev->tj_max) return -EINVAL; - ret = rdmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, + ret = rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h); if (ret < 0) return ret; @@ -216,11 +217,12 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp) if (!temp) { l &= ~intr; } else { - l |= (pkgdev->tj_max - temp)/1000 << shift; + l |= (zonedev->tj_max - temp)/1000 << shift; l |= intr; } - return wrmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); + return wrmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, + l, h); } static int sys_get_trip_type(struct thermal_zone_device *thermal, int trip, @@ -275,26 +277,26 @@ static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work) { struct thermal_zone_device *tzone = NULL; int cpu = smp_processor_id(); - struct pkg_device *pkgdev; + struct zone_device *zonedev; u64 msr_val, wr_val; mutex_lock(&thermal_zone_mutex); spin_lock_irq(&pkg_temp_lock); ++pkg_work_cnt; - pkgdev = pkg_temp_thermal_get_dev(cpu); - if (!pkgdev) { + zonedev = pkg_temp_thermal_get_dev(cpu); + if (!zonedev) { spin_unlock_irq(&pkg_temp_lock); mutex_unlock(&thermal_zone_mutex); return; } - pkgdev->work_scheduled = false; + zonedev->work_scheduled = false; rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val); wr_val = msr_val & ~(THERM_LOG_THRESHOLD0 | THERM_LOG_THRESHOLD1); if (wr_val != msr_val) { wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS, wr_val); - tzone = pkgdev->tzone; + tzone = zonedev->tzone; } enable_pkg_thres_interrupt(); @@ -320,7 +322,7 @@ static void pkg_thermal_schedule_work(int cpu, struct delayed_work *work) static int pkg_thermal_notify(u64 msr_val) { int cpu = smp_processor_id(); - struct pkg_device *pkgdev; + struct zone_device *zonedev; unsigned long flags; spin_lock_irqsave(&pkg_temp_lock, flags); @@ -329,10 +331,10 @@ static int pkg_thermal_notify(u64 msr_val) disable_pkg_thres_interrupt(); /* Work is per package, so scheduling it once is enough. */ - pkgdev = pkg_temp_thermal_get_dev(cpu); - if (pkgdev && !pkgdev->work_scheduled) { - pkgdev->work_scheduled = true; - pkg_thermal_schedule_work(pkgdev->cpu, &pkgdev->work); + zonedev = pkg_temp_thermal_get_dev(cpu); + if (zonedev && !zonedev->work_scheduled) { + zonedev->work_scheduled = true; + pkg_thermal_schedule_work(zonedev->cpu, &zonedev->work); } spin_unlock_irqrestore(&pkg_temp_lock, flags); @@ -341,12 +343,12 @@ static int pkg_thermal_notify(u64 msr_val) static int pkg_temp_thermal_device_add(unsigned int cpu) { - int pkgid = topology_logical_package_id(cpu); + int id = topology_logical_die_id(cpu); u32 tj_max, eax, ebx, ecx, edx; - struct pkg_device *pkgdev; + struct zone_device *zonedev; int thres_count, err; - if (pkgid >= max_packages) + if (id >= max_id) return -ENOMEM; cpuid(6, &eax, &ebx, &ecx, &edx); @@ -360,51 +362,51 @@ static int pkg_temp_thermal_device_add(unsigned int cpu) if (err) return err; - pkgdev = kzalloc(sizeof(*pkgdev), GFP_KERNEL); - if (!pkgdev) + zonedev = kzalloc(sizeof(*zonedev), GFP_KERNEL); + if (!zonedev) return -ENOMEM; - INIT_DELAYED_WORK(&pkgdev->work, pkg_temp_thermal_threshold_work_fn); - pkgdev->cpu = cpu; - pkgdev->tj_max = tj_max; - pkgdev->tzone = thermal_zone_device_register("x86_pkg_temp", + INIT_DELAYED_WORK(&zonedev->work, pkg_temp_thermal_threshold_work_fn); + zonedev->cpu = cpu; + zonedev->tj_max = tj_max; + zonedev->tzone = thermal_zone_device_register("x86_pkg_temp", thres_count, (thres_count == MAX_NUMBER_OF_TRIPS) ? 0x03 : 0x01, - pkgdev, &tzone_ops, &pkg_temp_tz_params, 0, 0); - if (IS_ERR(pkgdev->tzone)) { - err = PTR_ERR(pkgdev->tzone); - kfree(pkgdev); + zonedev, &tzone_ops, &pkg_temp_tz_params, 0, 0); + if (IS_ERR(zonedev->tzone)) { + err = PTR_ERR(zonedev->tzone); + kfree(zonedev); return err; } /* Store MSR value for package thermal interrupt, to restore at exit */ - rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, pkgdev->msr_pkg_therm_low, - pkgdev->msr_pkg_therm_high); + rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, zonedev->msr_pkg_therm_low, + zonedev->msr_pkg_therm_high); - cpumask_set_cpu(cpu, &pkgdev->cpumask); + cpumask_set_cpu(cpu, &zonedev->cpumask); spin_lock_irq(&pkg_temp_lock); - packages[pkgid] = pkgdev; + zones[id] = zonedev; spin_unlock_irq(&pkg_temp_lock); return 0; } static int pkg_thermal_cpu_offline(unsigned int cpu) { - struct pkg_device *pkgdev = pkg_temp_thermal_get_dev(cpu); + struct zone_device *zonedev = pkg_temp_thermal_get_dev(cpu); bool lastcpu, was_target; int target; - if (!pkgdev) + if (!zonedev) return 0; - target = cpumask_any_but(&pkgdev->cpumask, cpu); - cpumask_clear_cpu(cpu, &pkgdev->cpumask); + target = cpumask_any_but(&zonedev->cpumask, cpu); + cpumask_clear_cpu(cpu, &zonedev->cpumask); lastcpu = target >= nr_cpu_ids; /* * Remove the sysfs files, if this is the last cpu in the package * before doing further cleanups. */ if (lastcpu) { - struct thermal_zone_device *tzone = pkgdev->tzone; + struct thermal_zone_device *tzone = zonedev->tzone; /* * We must protect against a work function calling @@ -413,7 +415,7 @@ static int pkg_thermal_cpu_offline(unsigned int cpu) * won't try to call. */ mutex_lock(&thermal_zone_mutex); - pkgdev->tzone = NULL; + zonedev->tzone = NULL; mutex_unlock(&thermal_zone_mutex); thermal_zone_device_unregister(tzone); @@ -427,8 +429,8 @@ static int pkg_thermal_cpu_offline(unsigned int cpu) * one. When we drop the lock, then the interrupt notify function * will see the new target. */ - was_target = pkgdev->cpu == cpu; - pkgdev->cpu = target; + was_target = zonedev->cpu == cpu; + zonedev->cpu = target; /* * If this is the last CPU in the package remove the package @@ -437,23 +439,23 @@ static int pkg_thermal_cpu_offline(unsigned int cpu) * worker will see the package anymore. */ if (lastcpu) { - packages[topology_logical_package_id(cpu)] = NULL; + zones[topology_logical_die_id(cpu)] = NULL; /* After this point nothing touches the MSR anymore. */ wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, - pkgdev->msr_pkg_therm_low, pkgdev->msr_pkg_therm_high); + zonedev->msr_pkg_therm_low, zonedev->msr_pkg_therm_high); } /* * Check whether there is work scheduled and whether the work is * targeted at the outgoing CPU. */ - if (pkgdev->work_scheduled && was_target) { + if (zonedev->work_scheduled && was_target) { /* * To cancel the work we need to drop the lock, otherwise * we might deadlock if the work needs to be flushed. */ spin_unlock_irq(&pkg_temp_lock); - cancel_delayed_work_sync(&pkgdev->work); + cancel_delayed_work_sync(&zonedev->work); spin_lock_irq(&pkg_temp_lock); /* * If this is not the last cpu in the package and the work @@ -461,21 +463,21 @@ static int pkg_thermal_cpu_offline(unsigned int cpu) * need to reschedule the work, otherwise the interrupt * stays disabled forever. */ - if (!lastcpu && pkgdev->work_scheduled) - pkg_thermal_schedule_work(target, &pkgdev->work); + if (!lastcpu && zonedev->work_scheduled) + pkg_thermal_schedule_work(target, &zonedev->work); } spin_unlock_irq(&pkg_temp_lock); /* Final cleanup if this is the last cpu */ if (lastcpu) - kfree(pkgdev); + kfree(zonedev); return 0; } static int pkg_thermal_cpu_online(unsigned int cpu) { - struct pkg_device *pkgdev = pkg_temp_thermal_get_dev(cpu); + struct zone_device *zonedev = pkg_temp_thermal_get_dev(cpu); struct cpuinfo_x86 *c = &cpu_data(cpu); /* Paranoia check */ @@ -483,8 +485,8 @@ static int pkg_thermal_cpu_online(unsigned int cpu) return -ENODEV; /* If the package exists, nothing to do */ - if (pkgdev) { - cpumask_set_cpu(cpu, &pkgdev->cpumask); + if (zonedev) { + cpumask_set_cpu(cpu, &zonedev->cpumask); return 0; } return pkg_temp_thermal_device_add(cpu); @@ -503,10 +505,10 @@ static int __init pkg_temp_thermal_init(void) if (!x86_match_cpu(pkg_temp_thermal_ids)) return -ENODEV; - max_packages = topology_max_packages(); - packages = kcalloc(max_packages, sizeof(struct pkg_device *), + max_id = topology_max_packages() * topology_max_die_per_package(); + zones = kcalloc(max_id, sizeof(struct zone_device *), GFP_KERNEL); - if (!packages) + if (!zones) return -ENOMEM; ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "thermal/x86_pkg:online", @@ -525,7 +527,7 @@ static int __init pkg_temp_thermal_init(void) return 0; err: - kfree(packages); + kfree(zones); return ret; } module_init(pkg_temp_thermal_init) @@ -537,7 +539,7 @@ static void __exit pkg_temp_thermal_exit(void) cpuhp_remove_state(pkg_thermal_hp_state); debugfs_remove_recursive(debugfs); - kfree(packages); + kfree(zones); } module_exit(pkg_temp_thermal_exit) diff --git a/drivers/thermal/thermal-generic-adc.c b/drivers/thermal/thermal-generic-adc.c index deb244f12de4..dcecf2e8dc8e 100644 --- a/drivers/thermal/thermal-generic-adc.c +++ b/drivers/thermal/thermal-generic-adc.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic ADC thermal driver * * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. * * Author: Laxman Dewangan <ldewangan@nvidia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/iio/consumer.h> #include <linux/kernel.h> diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index f1c10378fa3e..fbdcef56a676 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -56,6 +56,7 @@ * @max_boot_acl: Maximum number of preboot ACL entries (%0 if not supported) * @rpm: Does the controller support runtime PM (RTD3) * @is_supported: Checks if we can support ICM on this controller + * @cio_reset: Trigger CIO reset * @get_mode: Read and return the ICM firmware mode (optional) * @get_route: Find a route string for given switch * @save_devices: Ask ICM to save devices to ACL when suspending (optional) @@ -74,6 +75,7 @@ struct icm { bool safe_mode; bool rpm; bool (*is_supported)(struct tb *tb); + int (*cio_reset)(struct tb *tb); int (*get_mode)(struct tb *tb); int (*get_route)(struct tb *tb, u8 link, u8 depth, u64 *route); void (*save_devices)(struct tb *tb); @@ -166,6 +168,65 @@ static inline u64 get_parent_route(u64 route) return depth ? route & ~(0xffULL << (depth - 1) * TB_ROUTE_SHIFT) : 0; } +static int pci2cio_wait_completion(struct icm *icm, unsigned long timeout_msec) +{ + unsigned long end = jiffies + msecs_to_jiffies(timeout_msec); + u32 cmd; + + do { + pci_read_config_dword(icm->upstream_port, + icm->vnd_cap + PCIE2CIO_CMD, &cmd); + if (!(cmd & PCIE2CIO_CMD_START)) { + if (cmd & PCIE2CIO_CMD_TIMEOUT) + break; + return 0; + } + + msleep(50); + } while (time_before(jiffies, end)); + + return -ETIMEDOUT; +} + +static int pcie2cio_read(struct icm *icm, enum tb_cfg_space cs, + unsigned int port, unsigned int index, u32 *data) +{ + struct pci_dev *pdev = icm->upstream_port; + int ret, vnd_cap = icm->vnd_cap; + u32 cmd; + + cmd = index; + cmd |= (port << PCIE2CIO_CMD_PORT_SHIFT) & PCIE2CIO_CMD_PORT_MASK; + cmd |= (cs << PCIE2CIO_CMD_CS_SHIFT) & PCIE2CIO_CMD_CS_MASK; + cmd |= PCIE2CIO_CMD_START; + pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_CMD, cmd); + + ret = pci2cio_wait_completion(icm, 5000); + if (ret) + return ret; + + pci_read_config_dword(pdev, vnd_cap + PCIE2CIO_RDDATA, data); + return 0; +} + +static int pcie2cio_write(struct icm *icm, enum tb_cfg_space cs, + unsigned int port, unsigned int index, u32 data) +{ + struct pci_dev *pdev = icm->upstream_port; + int vnd_cap = icm->vnd_cap; + u32 cmd; + + pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_WRDATA, data); + + cmd = index; + cmd |= (port << PCIE2CIO_CMD_PORT_SHIFT) & PCIE2CIO_CMD_PORT_MASK; + cmd |= (cs << PCIE2CIO_CMD_CS_SHIFT) & PCIE2CIO_CMD_CS_MASK; + cmd |= PCIE2CIO_CMD_WRITE | PCIE2CIO_CMD_START; + pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_CMD, cmd); + + return pci2cio_wait_completion(icm, 5000); +} + static bool icm_match(const struct tb_cfg_request *req, const struct ctl_pkg *pkg) { @@ -484,6 +545,7 @@ static void add_switch(struct tb_switch *parent_sw, u64 route, sw->authorized = authorized; sw->security_level = security_level; sw->boot = boot; + init_completion(&sw->rpm_complete); vss = parse_intel_vss(ep_name, ep_name_size); if (vss) @@ -523,6 +585,9 @@ static void update_switch(struct tb_switch *parent_sw, struct tb_switch *sw, /* This switch still exists */ sw->is_unplugged = false; + + /* Runtime resume is now complete */ + complete(&sw->rpm_complete); } static void remove_switch(struct tb_switch *sw) @@ -834,6 +899,11 @@ icm_fr_xdomain_disconnected(struct tb *tb, const struct icm_pkg_header *hdr) } } +static int icm_tr_cio_reset(struct tb *tb) +{ + return pcie2cio_write(tb_priv(tb), TB_CFG_SWITCH, 0, 0x777, BIT(1)); +} + static int icm_tr_driver_ready(struct tb *tb, enum tb_security_level *security_level, size_t *nboot_acl, bool *rpm) @@ -1240,6 +1310,11 @@ static bool icm_ar_is_supported(struct tb *tb) return false; } +static int icm_ar_cio_reset(struct tb *tb) +{ + return pcie2cio_write(tb_priv(tb), TB_CFG_SWITCH, 0, 0x50, BIT(9)); +} + static int icm_ar_get_mode(struct tb *tb) { struct tb_nhi *nhi = tb->nhi; @@ -1477,65 +1552,6 @@ __icm_driver_ready(struct tb *tb, enum tb_security_level *security_level, return -ETIMEDOUT; } -static int pci2cio_wait_completion(struct icm *icm, unsigned long timeout_msec) -{ - unsigned long end = jiffies + msecs_to_jiffies(timeout_msec); - u32 cmd; - - do { - pci_read_config_dword(icm->upstream_port, - icm->vnd_cap + PCIE2CIO_CMD, &cmd); - if (!(cmd & PCIE2CIO_CMD_START)) { - if (cmd & PCIE2CIO_CMD_TIMEOUT) - break; - return 0; - } - - msleep(50); - } while (time_before(jiffies, end)); - - return -ETIMEDOUT; -} - -static int pcie2cio_read(struct icm *icm, enum tb_cfg_space cs, - unsigned int port, unsigned int index, u32 *data) -{ - struct pci_dev *pdev = icm->upstream_port; - int ret, vnd_cap = icm->vnd_cap; - u32 cmd; - - cmd = index; - cmd |= (port << PCIE2CIO_CMD_PORT_SHIFT) & PCIE2CIO_CMD_PORT_MASK; - cmd |= (cs << PCIE2CIO_CMD_CS_SHIFT) & PCIE2CIO_CMD_CS_MASK; - cmd |= PCIE2CIO_CMD_START; - pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_CMD, cmd); - - ret = pci2cio_wait_completion(icm, 5000); - if (ret) - return ret; - - pci_read_config_dword(pdev, vnd_cap + PCIE2CIO_RDDATA, data); - return 0; -} - -static int pcie2cio_write(struct icm *icm, enum tb_cfg_space cs, - unsigned int port, unsigned int index, u32 data) -{ - struct pci_dev *pdev = icm->upstream_port; - int vnd_cap = icm->vnd_cap; - u32 cmd; - - pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_WRDATA, data); - - cmd = index; - cmd |= (port << PCIE2CIO_CMD_PORT_SHIFT) & PCIE2CIO_CMD_PORT_MASK; - cmd |= (cs << PCIE2CIO_CMD_CS_SHIFT) & PCIE2CIO_CMD_CS_MASK; - cmd |= PCIE2CIO_CMD_WRITE | PCIE2CIO_CMD_START; - pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_CMD, cmd); - - return pci2cio_wait_completion(icm, 5000); -} - static int icm_firmware_reset(struct tb *tb, struct tb_nhi *nhi) { struct icm *icm = tb_priv(tb); @@ -1556,7 +1572,7 @@ static int icm_firmware_reset(struct tb *tb, struct tb_nhi *nhi) iowrite32(val, nhi->iobase + REG_FW_STS); /* Trigger CIO reset now */ - return pcie2cio_write(icm, TB_CFG_SWITCH, 0, 0x50, BIT(9)); + return icm->cio_reset(tb); } static int icm_firmware_start(struct tb *tb, struct tb_nhi *nhi) @@ -1770,6 +1786,32 @@ static void icm_unplug_children(struct tb_switch *sw) } } +static int complete_rpm(struct device *dev, void *data) +{ + struct tb_switch *sw = tb_to_switch(dev); + + if (sw) + complete(&sw->rpm_complete); + return 0; +} + +static void remove_unplugged_switch(struct tb_switch *sw) +{ + pm_runtime_get_sync(sw->dev.parent); + + /* + * Signal this and switches below for rpm_complete because + * tb_switch_remove() calls pm_runtime_get_sync() that then waits + * for it. + */ + complete_rpm(&sw->dev, NULL); + bus_for_each_dev(&tb_bus_type, &sw->dev, NULL, complete_rpm); + tb_switch_remove(sw); + + pm_runtime_mark_last_busy(sw->dev.parent); + pm_runtime_put_autosuspend(sw->dev.parent); +} + static void icm_free_unplugged_children(struct tb_switch *sw) { unsigned int i; @@ -1782,7 +1824,7 @@ static void icm_free_unplugged_children(struct tb_switch *sw) port->xdomain = NULL; } else if (tb_port_has_remote(port)) { if (port->remote->sw->is_unplugged) { - tb_switch_remove(port->remote->sw); + remove_unplugged_switch(port->remote->sw); port->remote = NULL; } else { icm_free_unplugged_children(port->remote->sw); @@ -1831,6 +1873,24 @@ static int icm_runtime_suspend(struct tb *tb) return 0; } +static int icm_runtime_suspend_switch(struct tb_switch *sw) +{ + if (tb_route(sw)) + reinit_completion(&sw->rpm_complete); + return 0; +} + +static int icm_runtime_resume_switch(struct tb_switch *sw) +{ + if (tb_route(sw)) { + if (!wait_for_completion_timeout(&sw->rpm_complete, + msecs_to_jiffies(500))) { + dev_dbg(&sw->dev, "runtime resuming timed out\n"); + } + } + return 0; +} + static int icm_runtime_resume(struct tb *tb) { /* @@ -1910,6 +1970,8 @@ static const struct tb_cm_ops icm_ar_ops = { .complete = icm_complete, .runtime_suspend = icm_runtime_suspend, .runtime_resume = icm_runtime_resume, + .runtime_suspend_switch = icm_runtime_suspend_switch, + .runtime_resume_switch = icm_runtime_resume_switch, .handle_event = icm_handle_event, .get_boot_acl = icm_ar_get_boot_acl, .set_boot_acl = icm_ar_set_boot_acl, @@ -1930,6 +1992,8 @@ static const struct tb_cm_ops icm_tr_ops = { .complete = icm_complete, .runtime_suspend = icm_runtime_suspend, .runtime_resume = icm_runtime_resume, + .runtime_suspend_switch = icm_runtime_suspend_switch, + .runtime_resume_switch = icm_runtime_resume_switch, .handle_event = icm_handle_event, .get_boot_acl = icm_ar_get_boot_acl, .set_boot_acl = icm_ar_set_boot_acl, @@ -1975,6 +2039,7 @@ struct tb *icm_probe(struct tb_nhi *nhi) case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_NHI: icm->max_boot_acl = ICM_AR_PREBOOT_ACL_ENTRIES; icm->is_supported = icm_ar_is_supported; + icm->cio_reset = icm_ar_cio_reset; icm->get_mode = icm_ar_get_mode; icm->get_route = icm_ar_get_route; icm->save_devices = icm_fr_save_devices; @@ -1990,6 +2055,7 @@ struct tb *icm_probe(struct tb_nhi *nhi) case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_NHI: icm->max_boot_acl = ICM_AR_PREBOOT_ACL_ENTRIES; icm->is_supported = icm_ar_is_supported; + icm->cio_reset = icm_tr_cio_reset; icm->get_mode = icm_ar_get_mode; icm->driver_ready = icm_tr_driver_ready; icm->device_connected = icm_tr_device_connected; diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index c1b016574fb4..10b56c66fec3 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -239,7 +239,16 @@ static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val, int ret; pm_runtime_get_sync(&sw->dev); + + if (!mutex_trylock(&sw->tb->lock)) { + ret = restart_syscall(); + goto out; + } + ret = dma_port_flash_read(sw->dma_port, offset, val, bytes); + mutex_unlock(&sw->tb->lock); + +out: pm_runtime_mark_last_busy(&sw->dev); pm_runtime_put_autosuspend(&sw->dev); @@ -1019,7 +1028,6 @@ static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val) * the new tunnel too early. */ pci_lock_rescan_remove(); - pm_runtime_get_sync(&sw->dev); switch (val) { /* Approve switch */ @@ -1040,8 +1048,6 @@ static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val) break; } - pm_runtime_mark_last_busy(&sw->dev); - pm_runtime_put_autosuspend(&sw->dev); pci_unlock_rescan_remove(); if (!ret) { @@ -1069,7 +1075,10 @@ static ssize_t authorized_store(struct device *dev, if (val > 2) return -EINVAL; + pm_runtime_get_sync(&sw->dev); ret = tb_switch_set_authorized(sw, val); + pm_runtime_mark_last_busy(&sw->dev); + pm_runtime_put_autosuspend(&sw->dev); return ret ? ret : count; } @@ -1195,8 +1204,12 @@ static ssize_t nvm_authenticate_store(struct device *dev, bool val; int ret; - if (!mutex_trylock(&sw->tb->lock)) - return restart_syscall(); + pm_runtime_get_sync(&sw->dev); + + if (!mutex_trylock(&sw->tb->lock)) { + ret = restart_syscall(); + goto exit_rpm; + } /* If NVMem devices are not yet added */ if (!sw->nvm) { @@ -1217,13 +1230,9 @@ static ssize_t nvm_authenticate_store(struct device *dev, goto exit_unlock; } - pm_runtime_get_sync(&sw->dev); ret = nvm_validate_and_write(sw); - if (ret) { - pm_runtime_mark_last_busy(&sw->dev); - pm_runtime_put_autosuspend(&sw->dev); + if (ret) goto exit_unlock; - } sw->nvm->authenticating = true; @@ -1239,12 +1248,13 @@ static ssize_t nvm_authenticate_store(struct device *dev, } else { ret = nvm_authenticate_device(sw); } - pm_runtime_mark_last_busy(&sw->dev); - pm_runtime_put_autosuspend(&sw->dev); } exit_unlock: mutex_unlock(&sw->tb->lock); +exit_rpm: + pm_runtime_mark_last_busy(&sw->dev); + pm_runtime_put_autosuspend(&sw->dev); if (ret) return ret; @@ -1380,11 +1390,22 @@ static void tb_switch_release(struct device *dev) */ static int __maybe_unused tb_switch_runtime_suspend(struct device *dev) { + struct tb_switch *sw = tb_to_switch(dev); + const struct tb_cm_ops *cm_ops = sw->tb->cm_ops; + + if (cm_ops->runtime_suspend_switch) + return cm_ops->runtime_suspend_switch(sw); + return 0; } static int __maybe_unused tb_switch_runtime_resume(struct device *dev) { + struct tb_switch *sw = tb_to_switch(dev); + const struct tb_cm_ops *cm_ops = sw->tb->cm_ops; + + if (cm_ops->runtime_resume_switch) + return cm_ops->runtime_resume_switch(sw); return 0; } diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index b12c8f33d89c..6407d529871d 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -79,6 +79,8 @@ struct tb_switch_nvm { * @connection_key: Connection key used with ICM messaging * @link: Root switch link this switch is connected (ICM only) * @depth: Depth in the chain this switch is connected (ICM only) + * @rpm_complete: Completion used to wait for runtime resume to + * complete (ICM only) * * When the switch is being added or removed to the domain (other * switches) you need to have domain lock held. @@ -112,6 +114,7 @@ struct tb_switch { u8 connection_key; u8 link; u8 depth; + struct completion rpm_complete; }; /** @@ -250,6 +253,8 @@ struct tb_path { * @complete: Connection manager specific complete * @runtime_suspend: Connection manager specific runtime_suspend * @runtime_resume: Connection manager specific runtime_resume + * @runtime_suspend_switch: Runtime suspend a switch + * @runtime_resume_switch: Runtime resume a switch * @handle_event: Handle thunderbolt event * @get_boot_acl: Get boot ACL list * @set_boot_acl: Set boot ACL list @@ -270,6 +275,8 @@ struct tb_cm_ops { void (*complete)(struct tb *tb); int (*runtime_suspend)(struct tb *tb); int (*runtime_resume)(struct tb *tb); + int (*runtime_suspend_switch)(struct tb_switch *sw); + int (*runtime_resume_switch)(struct tb_switch *sw); void (*handle_event)(struct tb *tb, enum tb_cfg_pkg_type, const void *buf, size_t size); int (*get_boot_acl)(struct tb *tb, uuid_t *uuids, size_t nuuids); diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index e38f104db174..fde8d4073e74 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -487,7 +487,7 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) { - lockdep_assert_held_exclusive(&tty->ldisc_sem); + lockdep_assert_held_write(&tty->ldisc_sem); WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags)); clear_bit(TTY_LDISC_OPEN, &tty->flags); if (ld->ops->close) @@ -509,7 +509,7 @@ static int tty_ldisc_failto(struct tty_struct *tty, int ld) struct tty_ldisc *disc = tty_ldisc_get(tty, ld); int r; - lockdep_assert_held_exclusive(&tty->ldisc_sem); + lockdep_assert_held_write(&tty->ldisc_sem); if (IS_ERR(disc)) return PTR_ERR(disc); tty->ldisc = disc; @@ -633,7 +633,7 @@ EXPORT_SYMBOL_GPL(tty_set_ldisc); */ static void tty_ldisc_kill(struct tty_struct *tty) { - lockdep_assert_held_exclusive(&tty->ldisc_sem); + lockdep_assert_held_write(&tty->ldisc_sem); if (!tty->ldisc) return; /* @@ -681,7 +681,7 @@ int tty_ldisc_reinit(struct tty_struct *tty, int disc) struct tty_ldisc *ld; int retval; - lockdep_assert_held_exclusive(&tty->ldisc_sem); + lockdep_assert_held_write(&tty->ldisc_sem); ld = tty_ldisc_get(tty, disc); if (IS_ERR(ld)) { BUG_ON(disc == N_TTY); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 5c0ca1c24b6f..ec92f36ab5c4 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3822,6 +3822,8 @@ int con_is_bound(const struct consw *csw) { int i, bound = 0; + WARN_CONSOLE_UNLOCKED(); + for (i = 0; i < MAX_NR_CONSOLES; i++) { if (con_driver_map[i] == csw) { bound = 1; @@ -3834,6 +3836,20 @@ int con_is_bound(const struct consw *csw) EXPORT_SYMBOL(con_is_bound); /** + * con_is_visible - checks whether the current console is visible + * @vc: virtual console + * + * RETURNS: zero if not visible, nonzero if visible + */ +bool con_is_visible(const struct vc_data *vc) +{ + WARN_CONSOLE_UNLOCKED(); + + return *vc->vc_display_fg == vc; +} +EXPORT_SYMBOL(con_is_visible); + +/** * con_debug_enter - prepare the console for the kernel debugger * @sw: console driver * @@ -4166,6 +4182,8 @@ void do_blank_screen(int entering_gfx) struct vc_data *vc = vc_cons[fg_console].d; int i; + might_sleep(); + WARN_CONSOLE_UNLOCKED(); if (console_blanked) { diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c index 003badaef5f3..f32cef94aa82 100644 --- a/drivers/uio/uio_dmem_genirq.c +++ b/drivers/uio/uio_dmem_genirq.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/uio/uio_dmem_genirq.c * @@ -6,10 +7,6 @@ * Copyright (C) 2012 Damian Hobson-Garcia * * Based on uio_pdrv_genirq.c by Magnus Damm - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/platform_device.h> diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 6c759934bff3..10688d79d180 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/uio/uio_pdrv_genirq.c * @@ -8,10 +9,6 @@ * Based on uio_pdrv.c by Uwe Kleine-Koenig, * Copyright (C) 2008 by Digi International Inc. * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/platform_device.h> diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 829e947cabf5..6a5ee8e6da10 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1622,6 +1622,25 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on) static int ci_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver); static int ci_udc_stop(struct usb_gadget *gadget); + +/* Match ISOC IN from the highest endpoint */ +static struct usb_ep *ci_udc_match_ep(struct usb_gadget *gadget, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *comp_desc) +{ + struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget); + struct usb_ep *ep; + + if (usb_endpoint_xfer_isoc(desc) && usb_endpoint_dir_in(desc)) { + list_for_each_entry_reverse(ep, &ci->gadget.ep_list, ep_list) { + if (ep->caps.dir_in && !ep->claimed) + return ep; + } + } + + return NULL; +} + /** * Device operations part of the API to the USB controller hardware, * which don't involve endpoints (or i/o) @@ -1635,6 +1654,7 @@ static const struct usb_gadget_ops usb_gadget_ops = { .vbus_draw = ci_udc_vbus_draw, .udc_start = ci_udc_start, .udc_stop = ci_udc_stop, + .match_ep = ci_udc_match_ep, }; static int init_eps(struct ci_hdrc *ci) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index fa783531ee88..a02448105527 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -63,7 +63,7 @@ struct usb_dev_state { unsigned int discsignr; struct pid *disc_pid; const struct cred *cred; - void __user *disccontext; + sigval_t disccontext; unsigned long ifclaimed; u32 disabled_bulk_eps; bool privileges_dropped; @@ -90,6 +90,7 @@ struct async { unsigned int ifnum; void __user *userbuffer; void __user *userurb; + sigval_t userurb_sigval; struct urb *urb; struct usb_memory *usbm; unsigned int mem_usage; @@ -582,22 +583,19 @@ static void async_completed(struct urb *urb) { struct async *as = urb->context; struct usb_dev_state *ps = as->ps; - struct kernel_siginfo sinfo; struct pid *pid = NULL; const struct cred *cred = NULL; unsigned long flags; - int signr; + sigval_t addr; + int signr, errno; spin_lock_irqsave(&ps->lock, flags); list_move_tail(&as->asynclist, &ps->async_completed); as->status = urb->status; signr = as->signr; if (signr) { - clear_siginfo(&sinfo); - sinfo.si_signo = as->signr; - sinfo.si_errno = as->status; - sinfo.si_code = SI_ASYNCIO; - sinfo.si_addr = as->userurb; + errno = as->status; + addr = as->userurb_sigval; pid = get_pid(as->pid); cred = get_cred(as->cred); } @@ -615,7 +613,7 @@ static void async_completed(struct urb *urb) spin_unlock_irqrestore(&ps->lock, flags); if (signr) { - kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred); + kill_pid_usb_asyncio(signr, errno, addr, pid, cred); put_pid(pid); put_cred(cred); } @@ -1427,7 +1425,7 @@ find_memory_area(struct usb_dev_state *ps, const struct usbdevfs_urb *uurb) static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb, struct usbdevfs_iso_packet_desc __user *iso_frame_desc, - void __user *arg) + void __user *arg, sigval_t userurb_sigval) { struct usbdevfs_iso_packet_desc *isopkt = NULL; struct usb_host_endpoint *ep; @@ -1727,6 +1725,7 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb isopkt = NULL; as->ps = ps; as->userurb = arg; + as->userurb_sigval = userurb_sigval; if (as->usbm) { unsigned long uurb_start = (unsigned long)uurb->buffer; @@ -1801,13 +1800,17 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb static int proc_submiturb(struct usb_dev_state *ps, void __user *arg) { struct usbdevfs_urb uurb; + sigval_t userurb_sigval; if (copy_from_user(&uurb, arg, sizeof(uurb))) return -EFAULT; + memset(&userurb_sigval, 0, sizeof(userurb_sigval)); + userurb_sigval.sival_ptr = arg; + return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), - arg); + arg, userurb_sigval); } static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg) @@ -1977,7 +1980,7 @@ static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *a if (copy_from_user(&ds, arg, sizeof(ds))) return -EFAULT; ps->discsignr = ds.signr; - ps->disccontext = compat_ptr(ds.context); + ps->disccontext.sival_int = ds.context; return 0; } @@ -2005,13 +2008,17 @@ static int get_urb32(struct usbdevfs_urb *kurb, static int proc_submiturb_compat(struct usb_dev_state *ps, void __user *arg) { struct usbdevfs_urb uurb; + sigval_t userurb_sigval; if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg)) return -EFAULT; + memset(&userurb_sigval, 0, sizeof(userurb_sigval)); + userurb_sigval.sival_int = ptr_to_compat(arg); + return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, - arg); + arg, userurb_sigval); } static int processcompl_compat(struct async *as, void __user * __user *arg) @@ -2092,7 +2099,7 @@ static int proc_disconnectsignal(struct usb_dev_state *ps, void __user *arg) if (copy_from_user(&ds, arg, sizeof(ds))) return -EFAULT; ps->discsignr = ds.signr; - ps->disccontext = ds.context; + ps->disccontext.sival_ptr = ds.context; return 0; } @@ -2614,22 +2621,15 @@ const struct file_operations usbdev_file_operations = { static void usbdev_remove(struct usb_device *udev) { struct usb_dev_state *ps; - struct kernel_siginfo sinfo; while (!list_empty(&udev->filelist)) { ps = list_entry(udev->filelist.next, struct usb_dev_state, list); destroy_all_async(ps); wake_up_all(&ps->wait); list_del_init(&ps->list); - if (ps->discsignr) { - clear_siginfo(&sinfo); - sinfo.si_signo = ps->discsignr; - sinfo.si_errno = EPIPE; - sinfo.si_code = SI_ASYNCIO; - sinfo.si_addr = ps->disccontext; - kill_pid_info_as_cred(ps->discsignr, &sinfo, - ps->disc_pid, ps->cred); - } + if (ps->discsignr) + kill_pid_usb_asyncio(ps->discsignr, EPIPE, ps->disccontext, + ps->disc_pid, ps->cred); } } diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index 6900eea57526..5949262ff669 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -253,6 +253,15 @@ static void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg) val = (hsotg->hw_params.utmi_phy_data_width == GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16; + if (hsotg->phy) { + /* + * If using the generic PHY framework, check if the PHY bus + * width is 8-bit and set the phyif appropriately. + */ + if (phy_get_bus_width(hsotg->phy) == 8) + val = 8; + } + hsotg->params.phy_utmi_width = val; } diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index d10a7f8daec3..e98d7812da2d 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -271,15 +271,6 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) hsotg->plat = dev_get_platdata(hsotg->dev); - if (hsotg->phy) { - /* - * If using the generic PHY framework, check if the PHY bus - * width is 8-bit and set the phyif appropriately. - */ - if (phy_get_bus_width(hsotg->phy) == 8) - hsotg->params.phy_utmi_width = 8; - } - /* Clock */ hsotg->clk = devm_clk_get_optional(hsotg->dev, "otg"); if (IS_ERR(hsotg->clk)) { diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 8c99392df593..fb0a892687c0 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -423,6 +423,7 @@ uvc_register_video(struct uvc_device *uvc) uvc->vdev.release = video_device_release_empty; uvc->vdev.vfl_dir = VFL_DIR_TX; uvc->vdev.lock = &uvc->video.mutex; + uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; strlcpy(uvc->vdev.name, cdev->gadget->name, sizeof(uvc->vdev.name)); video_set_drvdata(&uvc->vdev, uvc); diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index a1183eccee22..495f0ec663ea 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -71,10 +71,6 @@ uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap) strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card)); strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev), sizeof(cap->bus_info)); - - cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index feffceb31e8a..121782e22c01 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1612,8 +1612,13 @@ static void handle_port_status(struct xhci_hcd *xhci, usb_hcd_resume_root_hub(hcd); } - if (hcd->speed >= HCD_USB3 && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) + if (hcd->speed >= HCD_USB3 && + (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) { + slot_id = xhci_find_slot_id_by_port(hcd, xhci, hcd_portnum + 1); + if (slot_id && xhci->devs[slot_id]) + xhci->devs[slot_id]->flags |= VDEV_PORT_ERROR; bus_state->port_remote_wakeup &= ~(1 << hcd_portnum); + } if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) { xhci_dbg(xhci, "port resume event for port %d\n", port_id); @@ -1801,6 +1806,14 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, { struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; struct xhci_command *command; + + /* + * Avoid resetting endpoint if link is inactive. Can cause host hang. + * Device will be reset soon to recover the link so don't do anything + */ + if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) + return; + command = xhci_alloc_command(xhci, false, GFP_ATOMIC); if (!command) return; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 20db378a6012..3f79f35d0b19 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1466,6 +1466,10 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag xhci_dbg(xhci, "urb submitted during PCI suspend\n"); return -ESHUTDOWN; } + if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) { + xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n"); + return -ENODEV; + } if (usb_endpoint_xfer_isoc(&urb->ep->desc)) num_tds = urb->number_of_packets; @@ -3754,6 +3758,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, } /* If necessary, update the number of active TTs on this root port */ xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps); + virt_dev->flags = 0; ret = 0; command_cleanup: @@ -5060,16 +5065,26 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) } else { /* * Some 3.1 hosts return sbrn 0x30, use xhci supported protocol - * minor revision instead of sbrn + * minor revision instead of sbrn. Minor revision is a two digit + * BCD containing minor and sub-minor numbers, only show minor. */ - minor_rev = xhci->usb3_rhub.min_rev; - if (minor_rev) { + minor_rev = xhci->usb3_rhub.min_rev / 0x10; + + switch (minor_rev) { + case 2: + hcd->speed = HCD_USB32; + hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; + hcd->self.root_hub->rx_lanes = 2; + hcd->self.root_hub->tx_lanes = 2; + break; + case 1: hcd->speed = HCD_USB31; hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; + break; } - xhci_info(xhci, "Host supports USB 3.%x %s SuperSpeed\n", + xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n", minor_rev, - minor_rev ? "Enhanced" : ""); + minor_rev ? "Enhanced " : ""); xhci->usb3_rhub.hcd = hcd; /* xHCI private pointer was set in xhci_pci_probe for the second diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 7f8b950d1a73..92e764c54154 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1010,6 +1010,15 @@ struct xhci_virt_device { u8 real_port; struct xhci_interval_bw_table *bw_table; struct xhci_tt_bw_info *tt_info; + /* + * flags for state tracking based on events and issued commands. + * Software can not rely on states from output contexts because of + * latency between events and xHC updating output context values. + * See xhci 1.1 section 4.8.3 for more details + */ + unsigned long flags; +#define VDEV_PORT_ERROR BIT(0) /* Port error, link inactive */ + /* The current max exit latency for the enabled USB3 link states. */ u16 current_mel; /* Used for the debugfs interfaces. */ diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c index f45d8df5cfb8..86defca6623e 100644 --- a/drivers/usb/roles/class.c +++ b/drivers/usb/roles/class.c @@ -101,7 +101,7 @@ static void *usb_role_switch_match(struct device_connection *con, int ep, struct device *dev; if (con->fwnode) { - if (!fwnode_property_present(con->fwnode, con->id)) + if (con->id && !fwnode_property_present(con->fwnode, con->id)) return NULL; dev = class_find_device(role_class, NULL, con->fwnode, diff --git a/drivers/usb/typec/bus.h b/drivers/usb/typec/bus.h index db40e61d8b72..0c9661c96473 100644 --- a/drivers/usb/typec/bus.h +++ b/drivers/usb/typec/bus.h @@ -35,4 +35,19 @@ extern const struct device_type typec_port_dev_type; #define is_typec_altmode(_dev_) (_dev_->type == &typec_altmode_dev_type) #define is_typec_port(_dev_) (_dev_->type == &typec_port_dev_type) +extern struct class typec_mux_class; + +struct typec_switch { + struct device dev; + typec_switch_set_fn_t set; +}; + +struct typec_mux { + struct device dev; + typec_mux_set_fn_t set; +}; + +#define to_typec_switch(_dev_) container_of(_dev_, struct typec_switch, dev) +#define to_typec_mux(_dev_) container_of(_dev_, struct typec_mux, dev) + #endif /* __USB_TYPEC_ALTMODE_H__ */ diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 2eb623841847..a18285a990a8 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -1646,13 +1646,25 @@ static int __init typec_init(void) if (ret) return ret; + ret = class_register(&typec_mux_class); + if (ret) + goto err_unregister_bus; + typec_class = class_create(THIS_MODULE, "typec"); if (IS_ERR(typec_class)) { - bus_unregister(&typec_bus); - return PTR_ERR(typec_class); + ret = PTR_ERR(typec_class); + goto err_unregister_mux_class; } return 0; + +err_unregister_mux_class: + class_unregister(&typec_mux_class); + +err_unregister_bus: + bus_unregister(&typec_bus); + + return ret; } subsys_initcall(typec_init); @@ -1661,6 +1673,7 @@ static void __exit typec_exit(void) class_destroy(typec_class); ida_destroy(&typec_index_ida); bus_unregister(&typec_bus); + class_unregister(&typec_mux_class); } module_exit(typec_exit); diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c index 2ce54f3fc79c..61b7bc58dd81 100644 --- a/drivers/usb/typec/mux.c +++ b/drivers/usb/typec/mux.c @@ -15,35 +15,47 @@ #include <linux/slab.h> #include <linux/usb/typec_mux.h> -static DEFINE_MUTEX(switch_lock); -static DEFINE_MUTEX(mux_lock); -static LIST_HEAD(switch_list); -static LIST_HEAD(mux_list); +#include "bus.h" + +static int name_match(struct device *dev, const void *name) +{ + return !strcmp((const char *)name, dev_name(dev)); +} + +static bool dev_name_ends_with(struct device *dev, const char *suffix) +{ + const char *name = dev_name(dev); + const int name_len = strlen(name); + const int suffix_len = strlen(suffix); + + if (suffix_len > name_len) + return false; + + return strcmp(name + (name_len - suffix_len), suffix) == 0; +} + +static int switch_fwnode_match(struct device *dev, const void *fwnode) +{ + return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-switch"); +} static void *typec_switch_match(struct device_connection *con, int ep, void *data) { - struct typec_switch *sw; - - if (!con->fwnode) { - list_for_each_entry(sw, &switch_list, entry) - if (!strcmp(con->endpoint[ep], dev_name(sw->dev))) - return sw; - return ERR_PTR(-EPROBE_DEFER); - } + struct device *dev; - /* - * With OF graph the mux node must have a boolean device property named - * "orientation-switch". - */ - if (con->id && !fwnode_property_present(con->fwnode, con->id)) - return NULL; + if (con->fwnode) { + if (con->id && !fwnode_property_present(con->fwnode, con->id)) + return NULL; - list_for_each_entry(sw, &switch_list, entry) - if (dev_fwnode(sw->dev) == con->fwnode) - return sw; + dev = class_find_device(&typec_mux_class, NULL, con->fwnode, + switch_fwnode_match); + } else { + dev = class_find_device(&typec_mux_class, NULL, + con->endpoint[ep], name_match); + } - return con->id ? ERR_PTR(-EPROBE_DEFER) : NULL; + return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER); } /** @@ -59,14 +71,10 @@ struct typec_switch *typec_switch_get(struct device *dev) { struct typec_switch *sw; - mutex_lock(&switch_lock); sw = device_connection_find_match(dev, "orientation-switch", NULL, typec_switch_match); - if (!IS_ERR_OR_NULL(sw)) { - WARN_ON(!try_module_get(sw->dev->driver->owner)); - get_device(sw->dev); - } - mutex_unlock(&switch_lock); + if (!IS_ERR_OR_NULL(sw)) + WARN_ON(!try_module_get(sw->dev.parent->driver->owner)); return sw; } @@ -81,28 +89,64 @@ EXPORT_SYMBOL_GPL(typec_switch_get); void typec_switch_put(struct typec_switch *sw) { if (!IS_ERR_OR_NULL(sw)) { - module_put(sw->dev->driver->owner); - put_device(sw->dev); + module_put(sw->dev.parent->driver->owner); + put_device(&sw->dev); } } EXPORT_SYMBOL_GPL(typec_switch_put); +static void typec_switch_release(struct device *dev) +{ + kfree(to_typec_switch(dev)); +} + +static const struct device_type typec_switch_dev_type = { + .name = "orientation_switch", + .release = typec_switch_release, +}; + /** * typec_switch_register - Register USB Type-C orientation switch - * @sw: USB Type-C orientation switch + * @parent: Parent device + * @desc: Orientation switch description * * This function registers a switch that can be used for routing the correct * data pairs depending on the cable plug orientation from the USB Type-C * connector to the USB controllers. USB Type-C plugs can be inserted * right-side-up or upside-down. */ -int typec_switch_register(struct typec_switch *sw) +struct typec_switch * +typec_switch_register(struct device *parent, + const struct typec_switch_desc *desc) { - mutex_lock(&switch_lock); - list_add_tail(&sw->entry, &switch_list); - mutex_unlock(&switch_lock); + struct typec_switch *sw; + int ret; + + if (!desc || !desc->set) + return ERR_PTR(-EINVAL); + + sw = kzalloc(sizeof(*sw), GFP_KERNEL); + if (!sw) + return ERR_PTR(-ENOMEM); - return 0; + sw->set = desc->set; + + device_initialize(&sw->dev); + sw->dev.parent = parent; + sw->dev.fwnode = desc->fwnode; + sw->dev.class = &typec_mux_class; + sw->dev.type = &typec_switch_dev_type; + sw->dev.driver_data = desc->drvdata; + dev_set_name(&sw->dev, "%s-switch", dev_name(parent)); + + ret = device_add(&sw->dev); + if (ret) { + dev_err(parent, "failed to register switch (%d)\n", ret); + put_device(&sw->dev); + return ERR_PTR(ret); + } + + return sw; } EXPORT_SYMBOL_GPL(typec_switch_register); @@ -114,28 +158,44 @@ EXPORT_SYMBOL_GPL(typec_switch_register); */ void typec_switch_unregister(struct typec_switch *sw) { - mutex_lock(&switch_lock); - list_del(&sw->entry); - mutex_unlock(&switch_lock); + if (!IS_ERR_OR_NULL(sw)) + device_unregister(&sw->dev); } EXPORT_SYMBOL_GPL(typec_switch_unregister); +void typec_switch_set_drvdata(struct typec_switch *sw, void *data) +{ + dev_set_drvdata(&sw->dev, data); +} +EXPORT_SYMBOL_GPL(typec_switch_set_drvdata); + +void *typec_switch_get_drvdata(struct typec_switch *sw) +{ + return dev_get_drvdata(&sw->dev); +} +EXPORT_SYMBOL_GPL(typec_switch_get_drvdata); + /* ------------------------------------------------------------------------- */ +static int mux_fwnode_match(struct device *dev, const void *fwnode) +{ + return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-mux"); +} + static void *typec_mux_match(struct device_connection *con, int ep, void *data) { const struct typec_altmode_desc *desc = data; - struct typec_mux *mux; - int nval; + struct device *dev; bool match; + int nval; u16 *val; int i; if (!con->fwnode) { - list_for_each_entry(mux, &mux_list, entry) - if (!strcmp(con->endpoint[ep], dev_name(mux->dev))) - return mux; - return ERR_PTR(-EPROBE_DEFER); + dev = class_find_device(&typec_mux_class, NULL, + con->endpoint[ep], name_match); + + return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER); } /* @@ -180,11 +240,10 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data) return NULL; find_mux: - list_for_each_entry(mux, &mux_list, entry) - if (dev_fwnode(mux->dev) == con->fwnode) - return mux; + dev = class_find_device(&typec_mux_class, NULL, con->fwnode, + mux_fwnode_match); - return ERR_PTR(-EPROBE_DEFER); + return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER); } /** @@ -202,14 +261,10 @@ struct typec_mux *typec_mux_get(struct device *dev, { struct typec_mux *mux; - mutex_lock(&mux_lock); mux = device_connection_find_match(dev, "mode-switch", (void *)desc, typec_mux_match); - if (!IS_ERR_OR_NULL(mux)) { - WARN_ON(!try_module_get(mux->dev->driver->owner)); - get_device(mux->dev); - } - mutex_unlock(&mux_lock); + if (!IS_ERR_OR_NULL(mux)) + WARN_ON(!try_module_get(mux->dev.parent->driver->owner)); return mux; } @@ -224,28 +279,63 @@ EXPORT_SYMBOL_GPL(typec_mux_get); void typec_mux_put(struct typec_mux *mux) { if (!IS_ERR_OR_NULL(mux)) { - module_put(mux->dev->driver->owner); - put_device(mux->dev); + module_put(mux->dev.parent->driver->owner); + put_device(&mux->dev); } } EXPORT_SYMBOL_GPL(typec_mux_put); +static void typec_mux_release(struct device *dev) +{ + kfree(to_typec_mux(dev)); +} + +static const struct device_type typec_mux_dev_type = { + .name = "mode_switch", + .release = typec_mux_release, +}; + /** * typec_mux_register - Register Multiplexer routing USB Type-C pins - * @mux: USB Type-C Connector Multiplexer/DeMultiplexer + * @parent: Parent device + * @desc: Multiplexer description * * USB Type-C connectors can be used for alternate modes of operation besides * USB when Accessory/Alternate Modes are supported. With some of those modes, * the pins on the connector need to be reconfigured. This function registers * multiplexer switches routing the pins on the connector. */ -int typec_mux_register(struct typec_mux *mux) +struct typec_mux * +typec_mux_register(struct device *parent, const struct typec_mux_desc *desc) { - mutex_lock(&mux_lock); - list_add_tail(&mux->entry, &mux_list); - mutex_unlock(&mux_lock); + struct typec_mux *mux; + int ret; + + if (!desc || !desc->set) + return ERR_PTR(-EINVAL); + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + mux->set = desc->set; + + device_initialize(&mux->dev); + mux->dev.parent = parent; + mux->dev.fwnode = desc->fwnode; + mux->dev.class = &typec_mux_class; + mux->dev.type = &typec_mux_dev_type; + mux->dev.driver_data = desc->drvdata; + dev_set_name(&mux->dev, "%s-mux", dev_name(parent)); + + ret = device_add(&mux->dev); + if (ret) { + dev_err(parent, "failed to register mux (%d)\n", ret); + put_device(&mux->dev); + return ERR_PTR(ret); + } - return 0; + return mux; } EXPORT_SYMBOL_GPL(typec_mux_register); @@ -257,8 +347,24 @@ EXPORT_SYMBOL_GPL(typec_mux_register); */ void typec_mux_unregister(struct typec_mux *mux) { - mutex_lock(&mux_lock); - list_del(&mux->entry); - mutex_unlock(&mux_lock); + if (!IS_ERR_OR_NULL(mux)) + device_unregister(&mux->dev); } EXPORT_SYMBOL_GPL(typec_mux_unregister); + +void typec_mux_set_drvdata(struct typec_mux *mux, void *data) +{ + dev_set_drvdata(&mux->dev, data); +} +EXPORT_SYMBOL_GPL(typec_mux_set_drvdata); + +void *typec_mux_get_drvdata(struct typec_mux *mux) +{ + return dev_get_drvdata(&mux->dev); +} +EXPORT_SYMBOL_GPL(typec_mux_get_drvdata); + +struct class typec_mux_class = { + .name = "typec_mux", + .owner = THIS_MODULE, +}; diff --git a/drivers/usb/typec/mux/pi3usb30532.c b/drivers/usb/typec/mux/pi3usb30532.c index 9294e85fd34b..5585b109095b 100644 --- a/drivers/usb/typec/mux/pi3usb30532.c +++ b/drivers/usb/typec/mux/pi3usb30532.c @@ -23,8 +23,8 @@ struct pi3usb30532 { struct i2c_client *client; struct mutex lock; /* protects the cached conf register */ - struct typec_switch sw; - struct typec_mux mux; + struct typec_switch *sw; + struct typec_mux *mux; u8 conf; }; @@ -48,7 +48,7 @@ static int pi3usb30532_set_conf(struct pi3usb30532 *pi, u8 new_conf) static int pi3usb30532_sw_set(struct typec_switch *sw, enum typec_orientation orientation) { - struct pi3usb30532 *pi = container_of(sw, struct pi3usb30532, sw); + struct pi3usb30532 *pi = typec_switch_get_drvdata(sw); u8 new_conf; int ret; @@ -75,7 +75,7 @@ static int pi3usb30532_sw_set(struct typec_switch *sw, static int pi3usb30532_mux_set(struct typec_mux *mux, int state) { - struct pi3usb30532 *pi = container_of(mux, struct pi3usb30532, mux); + struct pi3usb30532 *pi = typec_mux_get_drvdata(mux); u8 new_conf; int ret; @@ -113,6 +113,8 @@ static int pi3usb30532_mux_set(struct typec_mux *mux, int state) static int pi3usb30532_probe(struct i2c_client *client) { struct device *dev = &client->dev; + struct typec_switch_desc sw_desc; + struct typec_mux_desc mux_desc; struct pi3usb30532 *pi; int ret; @@ -121,10 +123,6 @@ static int pi3usb30532_probe(struct i2c_client *client) return -ENOMEM; pi->client = client; - pi->sw.dev = dev; - pi->sw.set = pi3usb30532_sw_set; - pi->mux.dev = dev; - pi->mux.set = pi3usb30532_mux_set; mutex_init(&pi->lock); ret = i2c_smbus_read_byte_data(client, PI3USB30532_CONF); @@ -134,17 +132,27 @@ static int pi3usb30532_probe(struct i2c_client *client) } pi->conf = ret; - ret = typec_switch_register(&pi->sw); - if (ret) { - dev_err(dev, "Error registering typec switch: %d\n", ret); - return ret; + sw_desc.drvdata = pi; + sw_desc.fwnode = dev->fwnode; + sw_desc.set = pi3usb30532_sw_set; + + pi->sw = typec_switch_register(dev, &sw_desc); + if (IS_ERR(pi->sw)) { + dev_err(dev, "Error registering typec switch: %ld\n", + PTR_ERR(pi->sw)); + return PTR_ERR(pi->sw); } - ret = typec_mux_register(&pi->mux); - if (ret) { - typec_switch_unregister(&pi->sw); - dev_err(dev, "Error registering typec mux: %d\n", ret); - return ret; + mux_desc.drvdata = pi; + mux_desc.fwnode = dev->fwnode; + mux_desc.set = pi3usb30532_mux_set; + + pi->mux = typec_mux_register(dev, &mux_desc); + if (IS_ERR(pi->mux)) { + typec_switch_unregister(pi->sw); + dev_err(dev, "Error registering typec mux: %ld\n", + PTR_ERR(pi->mux)); + return PTR_ERR(pi->mux); } i2c_set_clientdata(client, pi); @@ -155,8 +163,8 @@ static int pi3usb30532_remove(struct i2c_client *client) { struct pi3usb30532 *pi = i2c_get_clientdata(client); - typec_mux_unregister(&pi->mux); - typec_switch_unregister(&pi->sw); + typec_mux_unregister(pi->mux); + typec_switch_unregister(pi->sw); return 0; } diff --git a/drivers/uwb/allocator.c b/drivers/uwb/allocator.c index 6e3e713f0ef7..2e1590124d5f 100644 --- a/drivers/uwb/allocator.c +++ b/drivers/uwb/allocator.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * UWB reservation management. * * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> #include <linux/slab.h> diff --git a/drivers/uwb/drp-avail.c b/drivers/uwb/drp-avail.c index 40a540a5a72e..02392ab82a7d 100644 --- a/drivers/uwb/drp-avail.c +++ b/drivers/uwb/drp-avail.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Ultra Wide Band * DRP availability management @@ -6,19 +7,6 @@ * Reinette Chatre <reinette.chatre@intel.com> * Copyright (C) 2008 Cambridge Silicon Radio Ltd. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * * Manage DRP Availability (the MAS available for DRP * reservations). Thus: * diff --git a/drivers/uwb/drp-ie.c b/drivers/uwb/drp-ie.c index ed993e363472..4b545b41161c 100644 --- a/drivers/uwb/drp-ie.c +++ b/drivers/uwb/drp-ie.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * UWB DRP IE management. * * Copyright (C) 2005-2006 Intel Corporation * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> #include <linux/random.h> diff --git a/drivers/uwb/drp.c b/drivers/uwb/drp.c index 625f706b8160..869987bede7b 100644 --- a/drivers/uwb/drp.c +++ b/drivers/uwb/drp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Ultra Wide Band * Dynamic Reservation Protocol handling @@ -5,18 +6,6 @@ * Copyright (C) 2005-2006 Intel Corporation * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kthread.h> #include <linux/freezer.h> diff --git a/drivers/uwb/ie-rcv.c b/drivers/uwb/ie-rcv.c index 5fac5744a699..51a4706e0dd3 100644 --- a/drivers/uwb/ie-rcv.c +++ b/drivers/uwb/ie-rcv.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Ultra Wide Band * IE Received notification handling. * * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/errno.h> diff --git a/drivers/uwb/pal.c b/drivers/uwb/pal.c index 678e93741ae1..765fd426dbd1 100644 --- a/drivers/uwb/pal.c +++ b/drivers/uwb/pal.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * UWB PAL support. * * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> #include <linux/debugfs.h> diff --git a/drivers/uwb/radio.c b/drivers/uwb/radio.c index 2427e944883d..240dd755927e 100644 --- a/drivers/uwb/radio.c +++ b/drivers/uwb/radio.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * UWB radio (channel) management. * * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> #include <linux/uwb.h> diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c index fe25a8cc6fa1..ec924deb0a32 100644 --- a/drivers/uwb/rsv.c +++ b/drivers/uwb/rsv.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * UWB reservation management. * * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> #include <linux/uwb.h> diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c index ae23151442cb..ed8608763134 100644 --- a/drivers/vfio/mdev/mdev_core.c +++ b/drivers/vfio/mdev/mdev_core.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Mediated device Core Driver * * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. * Author: Neo Jia <cjia@nvidia.com> * Kirti Wankhede <kwankhede@nvidia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/vfio/mdev/mdev_driver.c b/drivers/vfio/mdev/mdev_driver.c index 6f0391f6f9b6..0d3223aee20b 100644 --- a/drivers/vfio/mdev/mdev_driver.c +++ b/drivers/vfio/mdev/mdev_driver.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * MDEV driver * * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. * Author: Neo Jia <cjia@nvidia.com> * Kirti Wankhede <kwankhede@nvidia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h index 398767526276..7d922950caaf 100644 --- a/drivers/vfio/mdev/mdev_private.h +++ b/drivers/vfio/mdev/mdev_private.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Mediated device interal definitions * * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. * Author: Neo Jia <cjia@nvidia.com> * Kirti Wankhede <kwankhede@nvidia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef MDEV_PRIVATE_H diff --git a/drivers/vfio/mdev/mdev_sysfs.c b/drivers/vfio/mdev/mdev_sysfs.c index ffa3dcebf201..7570c7602ab4 100644 --- a/drivers/vfio/mdev/mdev_sysfs.c +++ b/drivers/vfio/mdev/mdev_sysfs.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * File attributes for Mediated devices * * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. * Author: Neo Jia <cjia@nvidia.com> * Kirti Wankhede <kwankhede@nvidia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/sysfs.h> diff --git a/drivers/vfio/mdev/vfio_mdev.c b/drivers/vfio/mdev/vfio_mdev.c index d230620fe02d..30964a4e0a28 100644 --- a/drivers/vfio/mdev/vfio_mdev.c +++ b/drivers/vfio/mdev/vfio_mdev.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * VFIO based driver for Mediated device * * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. * Author: Neo Jia <cjia@nvidia.com> * Kirti Wankhede <kwankhede@nvidia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index cab71da46f4a..703948c9fbe1 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Red Hat, Inc. All rights reserved. * Author: Alex Williamson <alex.williamson@redhat.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Derived from original vfio: * Copyright 2010 Cisco Systems, Inc. All rights reserved. * Author: Tom Lyon, pugs@cisco.com diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index 52963a904790..f0891bd8444c 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * VFIO PCI config space virtualization * * Copyright (C) 2012 Red Hat, Inc. All rights reserved. * Author: Alex Williamson <alex.williamson@redhat.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Derived from original vfio: * Copyright 2010 Cisco Systems, Inc. All rights reserved. * Author: Tom Lyon, pugs@cisco.com diff --git a/drivers/vfio/pci/vfio_pci_igd.c b/drivers/vfio/pci/vfio_pci_igd.c index 6394b168ef29..53d97f459252 100644 --- a/drivers/vfio/pci/vfio_pci_igd.c +++ b/drivers/vfio/pci/vfio_pci_igd.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * VFIO PCI Intel Graphics support * * Copyright (C) 2016 Red Hat, Inc. All rights reserved. * Author: Alex Williamson <alex.williamson@redhat.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Register a device specific region through which to provide read-only * access to the Intel IGD opregion. The register defining the opregion * address is also virtualized to prevent user modification. diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 1c46045b0e7f..3fa3f728fb39 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * VFIO PCI interrupt handling * * Copyright (C) 2012 Red Hat, Inc. All rights reserved. * Author: Alex Williamson <alex.williamson@redhat.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Derived from original vfio: * Copyright 2010 Cisco Systems, Inc. All rights reserved. * Author: Tom Lyon, pugs@cisco.com diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h index 1812cf22fc4f..ee6ee91718a4 100644 --- a/drivers/vfio/pci/vfio_pci_private.h +++ b/drivers/vfio/pci/vfio_pci_private.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Red Hat, Inc. All rights reserved. * Author: Alex Williamson <alex.williamson@redhat.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Derived from original vfio: * Copyright 2010 Cisco Systems, Inc. All rights reserved. * Author: Tom Lyon, pugs@cisco.com diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c index a6029d0a5524..0120d8324a40 100644 --- a/drivers/vfio/pci/vfio_pci_rdwr.c +++ b/drivers/vfio/pci/vfio_pci_rdwr.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * VFIO PCI I/O Port & MMIO access * * Copyright (C) 2012 Red Hat, Inc. All rights reserved. * Author: Alex Williamson <alex.williamson@redhat.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Derived from original vfio: * Copyright 2010 Cisco Systems, Inc. All rights reserved. * Author: Tom Lyon, pugs@cisco.com diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 82fcf07fa9ea..388597930b64 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * VFIO core * * Copyright (C) 2012 Red Hat, Inc. All rights reserved. * Author: Alex Williamson <alex.williamson@redhat.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Derived from original vfio: * Copyright 2010 Cisco Systems, Inc. All rights reserved. * Author: Tom Lyon, pugs@cisco.com diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index 40ddc0c5f677..7048c9198c21 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * VFIO: IOMMU DMA mapping support for TCE on POWER * * Copyright (C) 2013 IBM Corp. All rights reserved. * Author: Alexey Kardashevskiy <aik@ozlabs.ru> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Derived from original vfio_iommu_type1.c: * Copyright (C) 2012 Red Hat, Inc. All rights reserved. * Author: Alex Williamson <alex.williamson@redhat.com> diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 3ddc375e7063..add34adfadc7 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * VFIO: IOMMU DMA mapping support for Type1 IOMMU * * Copyright (C) 2012 Red Hat, Inc. All rights reserved. * Author: Alex Williamson <alex.williamson@redhat.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Derived from original vfio: * Copyright 2010 Cisco Systems, Inc. All rights reserved. * Author: Tom Lyon, pugs@cisco.com diff --git a/drivers/vfio/vfio_spapr_eeh.c b/drivers/vfio/vfio_spapr_eeh.c index 1a742fe8f6db..67f55ac1d459 100644 --- a/drivers/vfio/vfio_spapr_eeh.c +++ b/drivers/vfio/vfio_spapr_eeh.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * EEH functionality support for VFIO devices. The feature is only * available on sPAPR compatible platforms. * * Copyright Gavin Shan, IBM Corporation 2014. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/vfio/virqfd.c b/drivers/vfio/virqfd.c index 2a1be859ee71..997cb5d0a657 100644 --- a/drivers/vfio/virqfd.c +++ b/drivers/vfio/virqfd.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * VFIO generic eventfd code for IRQFD support. * Derived from drivers/vfio/pci/vfio_pci_intrs.c * * Copyright (C) 2012 Red Hat, Inc. All rights reserved. * Author: Alex Williamson <alex.williamson@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/vfio.h> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 2d9df786a9d3..d57ebdd616d9 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -1,8 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) 2009 Red Hat, Inc. * Author: Michael S. Tsirkin <mst@redhat.com> * - * This work is licensed under the terms of the GNU GPL, version 2. - * * virtio-net server in host kernel. */ diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c index 40589850eb33..9e90e969af55 100644 --- a/drivers/vhost/test.c +++ b/drivers/vhost/test.c @@ -1,8 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) 2009 Red Hat, Inc. * Author: Michael S. Tsirkin <mst@redhat.com> * - * This work is licensed under the terms of the GNU GPL, version 2. - * * test virtio server in host kernel. */ diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 3f3eac4bcc58..e995c12d8e24 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) 2009 Red Hat, Inc. * Copyright (C) 2006 Rusty Russell IBM Corporation * @@ -6,8 +7,6 @@ * Inspiration, some code, and most witty comments come from * Documentation/virtual/lguest/lguest.c, by Rusty Russell * - * This work is licensed under the terms of the GNU GPL, version 2. - * * Generic code for virtio server in host kernel. */ diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 814bed72d793..6a50e1d0529c 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vhost transport for vsock * * Copyright (C) 2013-2015 Red Hat, Inc. * Author: Asias He <asias@redhat.com> * Stefan Hajnoczi <stefanha@redhat.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. */ #include <linux/miscdevice.h> #include <linux/atomic.h> diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index 51e0c4be08df..20d96a5ac384 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Backlight driver for Marvell Semiconductor 88PM8606 * * Copyright (C) 2009 Marvell International Ltd. * Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> diff --git a/drivers/video/backlight/apple_bl.c b/drivers/video/backlight/apple_bl.c index 6a34ab936726..c0d9339cff87 100644 --- a/drivers/video/backlight/apple_bl.c +++ b/drivers/video/backlight/apple_bl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Backlight Driver for Intel-based Apples * @@ -7,10 +8,6 @@ * Copyright (C) 2006 Felipe Alfaro Solana <felipe_alfaro @linuxmail.org> * Copyright (C) 2007 Julien BLACHE <jb@jblache.org> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This driver triggers SMIs which cause the firmware to change the * backlight brightness. This is icky in many ways, but it's impractical to * get at the firmware code in order to figure out what it's actually doing. diff --git a/drivers/video/backlight/arcxcnn_bl.c b/drivers/video/backlight/arcxcnn_bl.c index dec790de72ff..7b1c0a0e6cad 100644 --- a/drivers/video/backlight/arcxcnn_bl.c +++ b/drivers/video/backlight/arcxcnn_bl.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Backlight driver for ArcticSand ARC_X_C_0N_0N Devices * * Copyright 2016 ArcticSand, Inc. * Author : Brian Dodge <bdodge@arcticsand.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/backlight.h> diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 1ef8b6fd62ac..5dc07106a59e 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -47,7 +47,7 @@ static int fb_notifier_callback(struct notifier_block *self, int fb_blank = 0; /* If we aren't interested in this event, skip it immediately ... */ - if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK) + if (event != FB_EVENT_BLANK) return 0; bd = container_of(self, struct backlight_device, fb_notif); diff --git a/drivers/video/backlight/bd6107.c b/drivers/video/backlight/bd6107.c index fdb2f7e2c6b5..d344fb03cb86 100644 --- a/drivers/video/backlight/bd6107.c +++ b/drivers/video/backlight/bd6107.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ROHM Semiconductor BD6107 LED Driver * * Copyright (C) 2013 Ideas on board SPRL * * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/backlight.h> diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index f5574060f9c8..68f7592c5060 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LCD/Backlight Driver for Sharp Zaurus Handhelds (various models) * @@ -8,11 +9,6 @@ * Copyright (c) 2008 Marvell International Ltd. * Converted to SPI device based LCD/Backlight device driver * by Eric Miao <eric.miao@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c index f793738f06fb..62540e4bdedb 100644 --- a/drivers/video/backlight/da903x_bl.c +++ b/drivers/video/backlight/da903x_bl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Backlight driver for Dialog Semiconductor DA9030/DA9034 * @@ -6,10 +7,6 @@ * * Copyright (C) 2006-2008 Marvell International Ltd. * Eric Miao <eric.miao@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c index 0067931821c6..4149e0b2f83c 100644 --- a/drivers/video/backlight/ep93xx_bl.c +++ b/drivers/video/backlight/ep93xx_bl.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for the Cirrus EP93xx lcd backlight * * Copyright (c) 2010 H Hartley Sweeten <hsweeten@visionengravers.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This driver controls the pulse width modulated brightness control output, * BRIGHT, on the Cirrus EP9307, EP9312, and EP9315 processors. */ diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c index 4dea91acea13..8fe63dbc8590 100644 --- a/drivers/video/backlight/generic_bl.c +++ b/drivers/video/backlight/generic_bl.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic Backlight Driver * * Copyright (c) 2004-2008 Richard Purdie - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c index e470da95d806..b9300f3e1ee6 100644 --- a/drivers/video/backlight/gpio_backlight.c +++ b/drivers/video/backlight/gpio_backlight.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * gpio_backlight.c - Simple GPIO-controlled backlight - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/backlight.h> diff --git a/drivers/video/backlight/ili9320.c b/drivers/video/backlight/ili9320.c index 2cf39e6d519d..168ac79523d7 100644 --- a/drivers/video/backlight/ili9320.c +++ b/drivers/video/backlight/ili9320.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/video/backlight/ili9320.c * * ILI9320 LCD controller driver core. @@ -5,10 +6,6 @@ * Copyright 2007 Simtec Electronics * http://armlinux.simtec.co.uk/ * Ben Dooks <ben@simtec.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/video/backlight/ili9320.h b/drivers/video/backlight/ili9320.h index 42329e7aa9a8..fc59e389d59a 100644 --- a/drivers/video/backlight/ili9320.h +++ b/drivers/video/backlight/ili9320.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* drivers/video/backlight/ili9320.h * * ILI9320 LCD controller driver core. @@ -6,10 +7,6 @@ * Ben Dooks <ben@simtec.co.uk> * * http://armlinux.simtec.co.uk/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /* Holder for register and value pairs. */ diff --git a/drivers/video/backlight/ipaq_micro_bl.c b/drivers/video/backlight/ipaq_micro_bl.c index 347dc11d4ceb..1123f67c12b3 100644 --- a/drivers/video/backlight/ipaq_micro_bl.c +++ b/drivers/video/backlight/ipaq_micro_bl.c @@ -1,7 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. * * iPAQ microcontroller backlight support * Author : Linus Walleij <linus.walleij@linaro.org> diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c index 96312c3afc07..1dfe13c18925 100644 --- a/drivers/video/backlight/kb3886_bl.c +++ b/drivers/video/backlight/kb3886_bl.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Backlight Driver for the KB3886 Backlight * * Copyright (c) 2007-2008 Claudio Nieder * * Based on corgi_bl.c by Richard Purdie and kb3886 driver by Robert Woerle - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index e6054e2492c5..8554b4aa980c 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * l4f00242t03.c -- support for Epson L4F00242T03 LCD * @@ -5,10 +6,6 @@ * * Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com> * Inspired by Marek Vasut work in l4f00242t03.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 151b18776add..d6b653aa4ee9 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -30,18 +30,6 @@ static int fb_notifier_callback(struct notifier_block *self, struct lcd_device *ld; struct fb_event *evdata = data; - /* If we aren't interested in this event, skip it immediately ... */ - switch (event) { - case FB_EVENT_BLANK: - case FB_EVENT_MODE_CHANGE: - case FB_EVENT_MODE_CHANGE_ALL: - case FB_EARLY_EVENT_BLANK: - case FB_R_EARLY_EVENT_BLANK: - break; - default: - return 0; - } - ld = container_of(self, struct lcd_device, fb_notif); if (!ld->ops) return 0; diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c index 75d996490cf0..b04b35d007a2 100644 --- a/drivers/video/backlight/lm3630a_bl.c +++ b/drivers/video/backlight/lm3630a_bl.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Simple driver for Texas Instruments LM3630A Backlight driver chip * Copyright (C) 2012 Texas Instruments -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* */ #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c index 086611c7bc03..48c04155a5f9 100644 --- a/drivers/video/backlight/lm3639_bl.c +++ b/drivers/video/backlight/lm3639_bl.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Simple driver for Texas Instruments LM3639 Backlight + Flash LED driver chip * Copyright (C) 2012 Texas Instruments -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* */ #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c index 4237aaa7f269..35bc012b22cc 100644 --- a/drivers/video/backlight/lms283gf05.c +++ b/drivers/video/backlight/lms283gf05.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * lms283gf05.c -- support for Samsung LMS283GF05 LCD * * Copyright (c) 2009 Marek Vasut <marek.vasut@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index 73612485ed07..f68920131a4a 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LP855x Backlight Driver * * Copyright (C) 2011 Texas Instruments - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/video/backlight/lp8788_bl.c b/drivers/video/backlight/lp8788_bl.c index cf869ec90cce..ba42f3fe0c73 100644 --- a/drivers/video/backlight/lp8788_bl.c +++ b/drivers/video/backlight/lp8788_bl.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LP8788 MFD - backlight driver * * Copyright 2012 Texas Instruments * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/backlight.h> diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c index 885612cc1008..5cbf621e48bd 100644 --- a/drivers/video/backlight/ltv350qv.c +++ b/drivers/video/backlight/ltv350qv.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Power control for Samsung LTV350QV Quarter VGA LCD Panel * * Copyright (C) 2006, 2007 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> #include <linux/err.h> diff --git a/drivers/video/backlight/ltv350qv.h b/drivers/video/backlight/ltv350qv.h index 189112e3fc7a..c70890776a94 100644 --- a/drivers/video/backlight/ltv350qv.h +++ b/drivers/video/backlight/ltv350qv.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Register definitions for Samsung LTV350QV Quarter VGA LCD Panel * * Copyright (C) 2006, 2007 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __LTV350QV_H #define __LTV350QV_H diff --git a/drivers/video/backlight/lv5207lp.c b/drivers/video/backlight/lv5207lp.c index 8ab7297b118a..c6ad73a784e2 100644 --- a/drivers/video/backlight/lv5207lp.c +++ b/drivers/video/backlight/lv5207lp.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Sanyo LV5207LP LED Driver * * Copyright (C) 2013 Ideas on board SPRL * * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/backlight.h> diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index f3aa6088f1d9..97cc260ff9d1 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Backlight driver for Maxim MAX8925 * * Copyright (C) 2009 Marvell International Ltd. * Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> diff --git a/drivers/video/backlight/ot200_bl.c b/drivers/video/backlight/ot200_bl.c index 3acdb9f646ed..23ee7106c72a 100644 --- a/drivers/video/backlight/ot200_bl.c +++ b/drivers/video/backlight/ot200_bl.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Bachmann electronic GmbH * Christian Gmeiner <christian.gmeiner@gmail.com> * * Backlight driver for ot200 visualisation device from * Bachmann electronic GmbH. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/video/backlight/pandora_bl.c b/drivers/video/backlight/pandora_bl.c index 9618766e3866..f946470ce9f6 100644 --- a/drivers/video/backlight/pandora_bl.c +++ b/drivers/video/backlight/pandora_bl.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Backlight driver for Pandora handheld. * Pandora uses TWL4030 PWM0 -> TPS61161 combo for control backlight. * Based on pwm_bl.c * * Copyright 2009,2012 Gražvydas Ignotas <notasas@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index 872a3bf21faf..b2bfbf070200 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/video/backlight/platform_lcd.c * * Copyright 2008 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * * Generic platform-device LCD power control interface. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index fb45f866b923..20d379ac8440 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/backlight/pwm_bl.c * * simple PWM based backlight control, board code has to setup * 1) pin configuration so PWM waveforms can output * 2) platform_data being correctly configured - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c index d414c7a3acf5..2355f00f5773 100644 --- a/drivers/video/backlight/sky81452-backlight.c +++ b/drivers/video/backlight/sky81452-backlight.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * sky81452-backlight.c SKY81452 backlight driver * * Copyright 2014 Skyworks Solutions Inc. * Author : Gyungoh Yoo <jack.yoo@skyworksinc.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/backlight.h> diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c index 97067597e6bf..1275e815bd86 100644 --- a/drivers/video/backlight/tosa_bl.c +++ b/drivers/video/backlight/tosa_bl.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LCD / Backlight control code for Sharp SL-6000x (tosa) * * Copyright (c) 2005 Dirk Opfer * Copyright (c) 2007,2008 Dmitry Baryshkov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c index 4dc5ee8debeb..65cb7578776f 100644 --- a/drivers/video/backlight/tosa_lcd.c +++ b/drivers/video/backlight/tosa_lcd.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LCD / Backlight control code for Sharp SL-6000x (tosa) * * Copyright (c) 2005 Dirk Opfer * Copyright (c) 2007,2008 Dmitry Baryshkov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/video/backlight/vgg2432a4.c b/drivers/video/backlight/vgg2432a4.c index 242a9948f57f..9bf277ca4ae9 100644 --- a/drivers/video/backlight/vgg2432a4.c +++ b/drivers/video/backlight/vgg2432a4.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/video/backlight/vgg2432a4.c * * VGG2432A4 (ILI9320) LCD controller driver. @@ -5,10 +6,6 @@ * Copyright 2007 Simtec Electronics * http://armlinux.simtec.co.uk/ * Ben Dooks <ben@simtec.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c index 6eab0d6c262a..e55977d54c15 100644 --- a/drivers/video/backlight/wm831x_bl.c +++ b/drivers/video/backlight/wm831x_bl.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Backlight driver for Wolfson Microelectronics WM831x PMICs * * Copyright 2009 Wolfson Microelectonics plc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index ff886e99104b..2a0d0bda7faa 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -34,6 +34,8 @@ static bool dummycon_putc_called; void dummycon_register_output_notifier(struct notifier_block *nb) { + WARN_CONSOLE_UNLOCKED(); + raw_notifier_chain_register(&dummycon_output_nh, nb); if (dummycon_putc_called) @@ -42,11 +44,15 @@ void dummycon_register_output_notifier(struct notifier_block *nb) void dummycon_unregister_output_notifier(struct notifier_block *nb) { + WARN_CONSOLE_UNLOCKED(); + raw_notifier_chain_unregister(&dummycon_output_nh, nb); } static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { + WARN_CONSOLE_UNLOCKED(); + dummycon_putc_called = true; raw_notifier_call_chain(&dummycon_output_nh, 0, NULL); } diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 1b2f5f31fb6f..b174af914e7a 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -332,7 +332,8 @@ config FB_SA1100 config FB_IMX tristate "Freescale i.MX1/21/25/27 LCD support" - depends on FB && ARCH_MXC + depends on FB && HAVE_CLK && HAS_IOMEM + depends on ARCH_MXC || COMPILE_TEST select LCD_CLASS_DEVICE select FB_CFB_FILLRECT select FB_CFB_COPYAREA @@ -670,7 +671,8 @@ config FB_HGA config FB_GBE bool "SGI Graphics Backend frame buffer support" - depends on (FB = y) && SGI_IP32 + depends on (FB = y) && HAS_IOMEM + depends on SGI_IP32 || COMPILE_TEST select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -808,7 +810,8 @@ config FB_XVR1000 config FB_PVR2 tristate "NEC PowerVR 2 display support" - depends on FB && SH_DREAMCAST + depends on FB && HAS_IOMEM + depends on SH_DREAMCAST || COMPILE_TEST select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -856,7 +859,8 @@ config FB_S1D13XXX config FB_ATMEL tristate "AT91 LCD Controller support" - depends on FB && OF && HAVE_FB_ATMEL + depends on FB && OF && HAVE_CLK && HAS_IOMEM + depends on HAVE_FB_ATMEL || COMPILE_TEST select FB_BACKLIGHT select FB_CFB_FILLRECT select FB_CFB_COPYAREA @@ -1729,7 +1733,8 @@ config FB_68328 config FB_PXA168 tristate "PXA168/910 LCD framebuffer support" - depends on FB && (CPU_PXA168 || CPU_PXA910) + depends on FB && HAVE_CLK && HAS_IOMEM + depends on CPU_PXA168 || CPU_PXA910 || COMPILE_TEST select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1873,7 +1878,8 @@ config FB_TMIO_ACCELL config FB_S3C tristate "Samsung S3C framebuffer support" - depends on FB && (CPU_S3C2416 || ARCH_S3C64XX) + depends on FB && HAVE_CLK && HAS_IOMEM + depends on (CPU_S3C2416 || ARCH_S3C64XX) || COMPILE_TEST select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -2055,7 +2061,8 @@ config FB_SH7760 config FB_DA8XX tristate "DA8xx/OMAP-L1xx/AM335x Framebuffer support" - depends on FB && (ARCH_DAVINCI_DA8XX || SOC_AM33XX) + depends on FB && HAVE_CLK && HAS_IOMEM + depends on ARCH_DAVINCI_DA8XX || SOC_AM33XX || COMPILE_TEST select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -2172,7 +2179,7 @@ config FB_EP93XX config FB_PRE_INIT_FB bool "Don't reinitialize, use bootloader's GDC/Display configuration" - depends on FB && (FB_MB862XX_LIME || FB_MXS) + depends on FB && FB_MB862XX_LIME ---help--- Select this option if display contents should be inherited as set by the bootloader. @@ -2213,17 +2220,6 @@ config FB_JZ4740 help Framebuffer support for the JZ4740 SoC. -config FB_MXS - tristate "MXS LCD framebuffer support" - depends on FB && (ARCH_MXS || ARCH_MXC) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MODE_HELPERS - select VIDEOMODE_HELPERS - help - Framebuffer support for the MXS SoC. - config FB_PUV3_UNIGFX tristate "PKUnity v3 Unigfx framebuffer support" depends on FB && UNICORE32 && ARCH_PUV3 diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index 655f2537cac1..7dc4861a93e6 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -131,7 +131,6 @@ obj-$(CONFIG_FB_VGA16) += vga16fb.o obj-$(CONFIG_FB_OF) += offb.o obj-$(CONFIG_FB_MX3) += mx3fb.o obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o -obj-$(CONFIG_FB_MXS) += mxsfb.o obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o obj-$(CONFIG_FB_SIMPLE) += simplefb.o diff --git a/drivers/video/fbdev/acornfb.c b/drivers/video/fbdev/acornfb.c index 0c325b4da61d..92f23e3bc27a 100644 --- a/drivers/video/fbdev/acornfb.c +++ b/drivers/video/fbdev/acornfb.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/acornfb.c * * Copyright (C) 1998-2001 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Frame buffer code for Acorn platforms * * NOTE: Most of the modes with X!=640 will disappear shortly. diff --git a/drivers/video/fbdev/acornfb.h b/drivers/video/fbdev/acornfb.h index 175c8ff3367c..f8df4ecb4fd7 100644 --- a/drivers/video/fbdev/acornfb.h +++ b/drivers/video/fbdev/acornfb.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/video/acornfb.h * * Copyright (C) 1998,1999 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Frame buffer code for Acorn platforms */ #if defined(HAS_VIDC20) diff --git a/drivers/video/fbdev/amifb.c b/drivers/video/fbdev/amifb.c index 758457026694..91ddc9602014 100644 --- a/drivers/video/fbdev/amifb.c +++ b/drivers/video/fbdev/amifb.c @@ -3554,10 +3554,8 @@ static int __init amifb_probe(struct platform_device *pdev) custom.dmacon = DMAF_ALL | DMAF_MASTER; info = framebuffer_alloc(sizeof(struct amifb_par), &pdev->dev); - if (!info) { - dev_err(&pdev->dev, "framebuffer_alloc failed\n"); + if (!info) return -ENOMEM; - } strcpy(info->fix.id, "Amiga "); info->fix.visual = FB_VISUAL_PSEUDOCOLOR; diff --git a/drivers/video/fbdev/arkfb.c b/drivers/video/fbdev/arkfb.c index 13ba371e70aa..f940e8b66b85 100644 --- a/drivers/video/fbdev/arkfb.c +++ b/drivers/video/fbdev/arkfb.c @@ -954,10 +954,8 @@ static int ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) /* Allocate and fill driver data structure */ info = framebuffer_alloc(sizeof(struct arkfb_info), &(dev->dev)); - if (! info) { - dev_err(&(dev->dev), "cannot allocate memory\n"); + if (!info) return -ENOMEM; - } par = info->par; mutex_init(&par->open_lock); diff --git a/drivers/video/fbdev/atafb.c b/drivers/video/fbdev/atafb.c index b986af2a8042..fc9dfb0a95af 100644 --- a/drivers/video/fbdev/atafb.c +++ b/drivers/video/fbdev/atafb.c @@ -77,29 +77,8 @@ #define SWITCH_SND7 0x80 #define SWITCH_NONE 0x00 - #define up(x, r) (((x) + (r) - 1) & ~((r)-1)) - /* - * Interface to the world - */ - -static int atafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); -static int atafb_set_par(struct fb_info *info); -static int atafb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, - unsigned int blue, unsigned int transp, - struct fb_info *info); -static int atafb_blank(int blank, struct fb_info *info); -static int atafb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info); -static void atafb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect); -static void atafb_copyarea(struct fb_info *info, - const struct fb_copyarea *region); -static void atafb_imageblit(struct fb_info *info, const struct fb_image *image); -static int atafb_ioctl(struct fb_info *info, unsigned int cmd, - unsigned long arg); - static int default_par; /* default resolution (0=none) */ diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index e67dfd94bf1d..5ff8e0320d95 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -673,7 +673,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info) lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0); /* Disable all interrupts */ - lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); + lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0U); /* Enable FIFO & DMA errors */ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI); @@ -950,7 +950,7 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo) struct fb_videomode fb_vm; struct gpio_desc *gpiod; struct videomode vm; - int ret = -ENOENT; + int ret; int i; sinfo->config = (struct atmel_lcdfb_config*) @@ -1053,10 +1053,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) ret = -ENOMEM; info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev); - if (!info) { - dev_err(dev, "cannot allocate memory\n"); + if (!info) goto out; - } sinfo = info->par; sinfo->pdev = pdev; @@ -1291,7 +1289,7 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg) * We don't want to handle interrupts while the clock is * stopped. It may take forever. */ - lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); + lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0U); sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_CTR); lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0); diff --git a/drivers/video/fbdev/aty/aty128fb.c b/drivers/video/fbdev/aty/aty128fb.c index 794434891291..8504e19437ff 100644 --- a/drivers/video/fbdev/aty/aty128fb.c +++ b/drivers/video/fbdev/aty/aty128fb.c @@ -2103,10 +2103,9 @@ static int aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* We have the resources. Now virtualize them */ info = framebuffer_alloc(sizeof(struct aty128fb_par), &pdev->dev); - if (info == NULL) { - printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n"); + if (!info) goto err_free_mmio; - } + par = info->par; info->pseudo_palette = par->pseudo_palette; @@ -2350,70 +2349,6 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg) return -EINVAL; } -#if 0 - /* - * Accelerated functions - */ - -static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty, - u_int width, u_int height, - struct fb_info_aty128 *par) -{ - u32 save_dp_datatype, save_dp_cntl, dstval; - - if (!width || !height) - return; - - dstval = depth_to_dst(par->current_par.crtc.depth); - if (dstval == DST_24BPP) { - srcx *= 3; - dstx *= 3; - width *= 3; - } else if (dstval == -EINVAL) { - printk("aty128fb: invalid depth or RGBA\n"); - return; - } - - wait_for_fifo(2, par); - save_dp_datatype = aty_ld_le32(DP_DATATYPE); - save_dp_cntl = aty_ld_le32(DP_CNTL); - - wait_for_fifo(6, par); - aty_st_le32(SRC_Y_X, (srcy << 16) | srcx); - aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT); - aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM); - aty_st_le32(DP_DATATYPE, save_dp_datatype | dstval | SRC_DSTCOLOR); - - aty_st_le32(DST_Y_X, (dsty << 16) | dstx); - aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width); - - par->blitter_may_be_busy = 1; - - wait_for_fifo(2, par); - aty_st_le32(DP_DATATYPE, save_dp_datatype); - aty_st_le32(DP_CNTL, save_dp_cntl); -} - - - /* - * Text mode accelerated functions - */ - -static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, - int dx, int height, int width) -{ - sx *= fontwidth(p); - sy *= fontheight(p); - dx *= fontwidth(p); - dy *= fontheight(p); - width *= fontwidth(p); - height *= fontheight(p); - - aty128_rectcopy(sx, sy, dx, dy, width, height, - (struct fb_info_aty128 *)p->fb_info); -} -#endif /* 0 */ - static void aty128_set_suspend(struct aty128fb_par *par, int suspend) { u32 pmgt; diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index b6fe103df145..72bcfbe42e49 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -3550,10 +3550,9 @@ static int atyfb_pci_probe(struct pci_dev *pdev, /* Allocate framebuffer */ info = framebuffer_alloc(sizeof(struct atyfb_par), &pdev->dev); - if (!info) { - PRINTKE("atyfb_pci_probe() can't alloc fb_info\n"); + if (!info) return -ENOMEM; - } + par = info->par; par->bus_type = PCI; info->fix = atyfb_fix; @@ -3643,10 +3642,9 @@ static int __init atyfb_atari_probe(void) } info = framebuffer_alloc(sizeof(struct atyfb_par), NULL); - if (!info) { - PRINTKE("atyfb_atari_probe() can't alloc fb_info\n"); + if (!info) return -ENOMEM; - } + par = info->par; info->fix = atyfb_fix; @@ -3916,8 +3914,7 @@ static int atyfb_reboot_notify(struct notifier_block *nb, if (!reboot_info) goto out; - if (!lock_fb_info(reboot_info)) - goto out; + lock_fb_info(reboot_info); par = reboot_info->par; diff --git a/drivers/video/fbdev/aty/radeon_backlight.c b/drivers/video/fbdev/aty/radeon_backlight.c index 301d6d6aeead..d2c1263ad260 100644 --- a/drivers/video/fbdev/aty/radeon_backlight.c +++ b/drivers/video/fbdev/aty/radeon_backlight.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Backlight code for ATI Radeon based graphic cards * * Copyright (c) 2000 Ani Joshi <ajoshi@kernel.crashing.org> * Copyright (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org> * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "radeonfb.h" diff --git a/drivers/video/fbdev/aty/radeon_base.c b/drivers/video/fbdev/aty/radeon_base.c index e8594bbaea60..6f891d82eebe 100644 --- a/drivers/video/fbdev/aty/radeon_base.c +++ b/drivers/video/fbdev/aty/radeon_base.c @@ -2294,8 +2294,6 @@ static int radeonfb_pci_register(struct pci_dev *pdev, info = framebuffer_alloc(sizeof(struct radeonfb_info), &pdev->dev); if (!info) { - printk (KERN_ERR "radeonfb (%s): could not allocate memory\n", - pci_name(pdev)); ret = -ENOMEM; goto err_disable; } diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c index 3872ccef4cb2..26caffb02b7e 100644 --- a/drivers/video/fbdev/au1200fb.c +++ b/drivers/video/fbdev/au1200fb.c @@ -147,6 +147,7 @@ struct au1200_lcd_iodata_t { struct au1200fb_device { struct fb_info *fb_info; /* FB driver info record */ struct au1200fb_platdata *pd; + struct device *dev; int plane; unsigned char* fb_mem; /* FrameBuffer memory map */ @@ -1232,10 +1233,8 @@ static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct au1200fb_device *fbdev = info->par; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */ - - return vm_iomap_memory(vma, fbdev->fb_phys, fbdev->fb_len); + return dma_mmap_attrs(fbdev->dev, vma, fbdev->fb_mem, fbdev->fb_phys, + fbdev->fb_len, DMA_ATTR_NON_CONSISTENT); } static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata) @@ -1647,7 +1646,6 @@ static int au1200fb_drv_probe(struct platform_device *dev) struct au1200fb_device *fbdev; struct au1200fb_platdata *pd; struct fb_info *fbi = NULL; - unsigned long page; int bpp, plane, ret, irq; print_info("" DRIVER_DESC ""); @@ -1685,6 +1683,7 @@ static int au1200fb_drv_probe(struct platform_device *dev) fbdev = fbi->par; fbdev->fb_info = fbi; fbdev->pd = pd; + fbdev->dev = &dev->dev; fbdev->plane = plane; @@ -1702,16 +1701,6 @@ static int au1200fb_drv_probe(struct platform_device *dev) goto failed; } - /* - * Set page reserved so that mmap will work. This is necessary - * since we'll be remapping normal memory. - */ - for (page = (unsigned long)fbdev->fb_phys; - page < PAGE_ALIGN((unsigned long)fbdev->fb_phys + - fbdev->fb_len); - page += PAGE_SIZE) { - SetPageReserved(pfn_to_page(page >> PAGE_SHIFT)); /* LCD DMA is NOT coherent on Au1200 */ - } print_dbg("Framebuffer memory map at %p", fbdev->fb_mem); print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024); diff --git a/drivers/video/fbdev/chipsfb.c b/drivers/video/fbdev/chipsfb.c index ca549e1532e6..f4dc320dcafe 100644 --- a/drivers/video/fbdev/chipsfb.c +++ b/drivers/video/fbdev/chipsfb.c @@ -366,7 +366,6 @@ static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) p = framebuffer_alloc(0, &dp->dev); if (p == NULL) { - dev_err(&dp->dev, "Cannot allocate framebuffer structure\n"); rc = -ENOMEM; goto err_disable; } diff --git a/drivers/video/fbdev/cirrusfb.c b/drivers/video/fbdev/cirrusfb.c index b3be06dd2908..e4ce5667b125 100644 --- a/drivers/video/fbdev/cirrusfb.c +++ b/drivers/video/fbdev/cirrusfb.c @@ -2093,7 +2093,6 @@ static int cirrusfb_pci_register(struct pci_dev *pdev, info = framebuffer_alloc(sizeof(struct cirrusfb_info), &pdev->dev); if (!info) { - printk(KERN_ERR "cirrusfb: could not allocate memory\n"); ret = -ENOMEM; goto err_out; } @@ -2206,10 +2205,8 @@ static int cirrusfb_zorro_register(struct zorro_dev *z, struct cirrusfb_info *cinfo; info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev); - if (!info) { - printk(KERN_ERR "cirrusfb: could not allocate memory\n"); + if (!info) return -ENOMEM; - } zcl = (const struct zorrocl *)ent->driver_data; btype = zcl->type; diff --git a/drivers/video/fbdev/controlfb.c b/drivers/video/fbdev/controlfb.c index 7af8db28bb80..9a680ef3ffc3 100644 --- a/drivers/video/fbdev/controlfb.c +++ b/drivers/video/fbdev/controlfb.c @@ -182,7 +182,7 @@ int init_module(void) int ret = -ENXIO; dp = of_find_node_by_name(NULL, "control"); - if (dp != 0 && !control_of_init(dp)) + if (dp && !control_of_init(dp)) ret = 0; of_node_put(dp); @@ -580,7 +580,7 @@ static int __init control_init(void) control_setup(option); dp = of_find_node_by_name(NULL, "control"); - if (dp != 0 && !control_of_init(dp)) + if (dp && !control_of_init(dp)) ret = 0; of_node_put(dp); @@ -683,8 +683,8 @@ static int __init control_of_init(struct device_node *dp) return -ENXIO; } p = kzalloc(sizeof(*p), GFP_KERNEL); - if (p == 0) - return -ENXIO; + if (!p) + return -ENOMEM; control_fb = p; /* save it for cleanups */ /* Map in frame buffer and registers */ diff --git a/drivers/video/fbdev/core/fbcmap.c b/drivers/video/fbdev/core/fbcmap.c index 2811c4afde01..e5ae33c1a8e8 100644 --- a/drivers/video/fbdev/core/fbcmap.c +++ b/drivers/video/fbdev/core/fbcmap.c @@ -285,11 +285,7 @@ int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info) goto out; } umap.start = cmap->start; - if (!lock_fb_info(info)) { - rc = -ENODEV; - goto out; - } - + lock_fb_info(info); rc = fb_set_cmap(&umap, info); unlock_fb_info(info); out: diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index a9c69ae30878..c9235a2f42f8 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -76,6 +76,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/crc32.h> /* For counting font checksums */ +#include <linux/uaccess.h> #include <asm/fb.h> #include <asm/irq.h> @@ -87,13 +88,32 @@ # define DPRINTK(fmt, args...) #endif +/* + * FIXME: Locking + * + * - fbcon state itself is protected by the console_lock, and the code does a + * pretty good job at making sure that lock is held everywhere it's needed. + * + * - access to the registered_fb array is entirely unprotected. This should use + * proper object lifetime handling, i.e. get/put_fb_info. This also means + * switching from indices to proper pointers for fb_info everywhere. + * + * - fbcon doesn't bother with fb_lock/unlock at all. This is buggy, since it + * means concurrent access to the same fbdev from both fbcon and userspace + * will blow up. To fix this all fbcon calls from fbmem.c need to be moved out + * of fb_lock/unlock protected sections, since otherwise we'll recurse and + * deadlock eventually. Aside: Due to these deadlock issues the fbdev code in + * fbmem.c cannot use locking asserts, and there's lots of callers which get + * the rules wrong, e.g. fbsysfs.c entirely missed fb_lock/unlock calls too. + */ + enum { FBCON_LOGO_CANSHOW = -1, /* the logo can be shown */ FBCON_LOGO_DRAW = -2, /* draw the logo to a console */ FBCON_LOGO_DONTSHOW = -3 /* do not show the logo */ }; -static struct display fb_display[MAX_NR_CONSOLES]; +static struct fbcon_display fb_display[MAX_NR_CONSOLES]; static signed char con2fb_map[MAX_NR_CONSOLES]; static signed char con2fb_map_boot[MAX_NR_CONSOLES]; @@ -112,7 +132,6 @@ static int softback_lines; static int first_fb_vc; static int last_fb_vc = MAX_NR_CONSOLES - 1; static int fbcon_is_default = 1; -static int fbcon_has_exited; static int primary_device = -1; static int fbcon_has_console_bind; @@ -185,11 +204,11 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count); static __inline__ void ywrap_down(struct vc_data *vc, int count); static __inline__ void ypan_up(struct vc_data *vc, int count); static __inline__ void ypan_down(struct vc_data *vc, int count); -static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, +static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx, int dy, int dx, int height, int width, u_int y_break); static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, int unit); -static void fbcon_redraw_move(struct vc_data *vc, struct display *p, +static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, int line, int count, int dy); static void fbcon_modechanged(struct fb_info *info); static void fbcon_set_all_vcs(struct fb_info *info); @@ -220,7 +239,7 @@ static void fbcon_rotate(struct fb_info *info, u32 rotate) fb_info = registered_fb[con2fb_map[ops->currcon]]; if (info == fb_info) { - struct display *p = &fb_display[ops->currcon]; + struct fbcon_display *p = &fb_display[ops->currcon]; if (rotate < 4) p->con_rotate = rotate; @@ -235,7 +254,7 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate) { struct fbcon_ops *ops = info->fbcon_par; struct vc_data *vc; - struct display *p; + struct fbcon_display *p; int i; if (!ops || ops->currcon < 0 || rotate > 3) @@ -900,7 +919,7 @@ static int set_con2fb_map(int unit, int newidx, int user) * Low Level Operations */ /* NOTE: fbcon cannot be __init: it may be called from do_take_over_console later */ -static int var_to_display(struct display *disp, +static int var_to_display(struct fbcon_display *disp, struct fb_var_screeninfo *var, struct fb_info *info) { @@ -925,7 +944,7 @@ static int var_to_display(struct display *disp, } static void display_to_var(struct fb_var_screeninfo *var, - struct display *disp) + struct fbcon_display *disp) { fb_videomode_to_var(var, disp->mode); var->xres_virtual = disp->xres_virtual; @@ -946,7 +965,7 @@ static void display_to_var(struct fb_var_screeninfo *var, static const char *fbcon_startup(void) { const char *display_desc = "frame buffer device"; - struct display *p = &fb_display[fg_console]; + struct fbcon_display *p = &fb_display[fg_console]; struct vc_data *vc = vc_cons[fg_console].d; const struct font_desc *font = NULL; struct module *owner; @@ -1050,23 +1069,26 @@ static const char *fbcon_startup(void) info->var.bits_per_pixel); fbcon_add_cursor_timer(info); - fbcon_has_exited = 0; return display_desc; } static void fbcon_init(struct vc_data *vc, int init) { - struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fb_info *info; struct fbcon_ops *ops; struct vc_data **default_mode = vc->vc_display_fg; struct vc_data *svc = *default_mode; - struct display *t, *p = &fb_display[vc->vc_num]; + struct fbcon_display *t, *p = &fb_display[vc->vc_num]; int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256; int cap, ret; - if (info_idx == -1 || info == NULL) + if (WARN_ON(info_idx == -1)) return; + if (con2fb_map[vc->vc_num] == -1) + con2fb_map[vc->vc_num] = info_idx; + + info = registered_fb[con2fb_map[vc->vc_num]]; cap = info->flags; if (logo_shown < 0 && console_loglevel <= CONSOLE_LOGLEVEL_QUIET) @@ -1203,7 +1225,7 @@ static void fbcon_init(struct vc_data *vc, int init) ops->p = &fb_display[fg_console]; } -static void fbcon_free_font(struct display *p, bool freefont) +static void fbcon_free_font(struct fbcon_display *p, bool freefont) { if (freefont && p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); @@ -1215,7 +1237,7 @@ static void set_vc_hi_font(struct vc_data *vc, bool set); static void fbcon_deinit(struct vc_data *vc) { - struct display *p = &fb_display[vc->vc_num]; + struct fbcon_display *p = &fb_display[vc->vc_num]; struct fb_info *info; struct fbcon_ops *ops; int idx; @@ -1288,7 +1310,7 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; - struct display *p = &fb_display[vc->vc_num]; + struct fbcon_display *p = &fb_display[vc->vc_num]; u_int y_break; if (fbcon_is_inactive(vc, info)) @@ -1324,7 +1346,7 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, int count, int ypos, int xpos) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; - struct display *p = &fb_display[vc->vc_num]; + struct fbcon_display *p = &fb_display[vc->vc_num]; struct fbcon_ops *ops = info->fbcon_par; if (!fbcon_is_inactive(vc, info)) @@ -1388,7 +1410,7 @@ static int scrollback_current = 0; static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, int unit) { - struct display *p, *t; + struct fbcon_display *p, *t; struct vc_data **default_mode, *vc; struct vc_data *svc; struct fbcon_ops *ops = info->fbcon_par; @@ -1457,7 +1479,7 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; - struct display *p = &fb_display[vc->vc_num]; + struct fbcon_display *p = &fb_display[vc->vc_num]; p->yscroll += count; if (p->yscroll >= p->vrows) /* Deal with wrap */ @@ -1476,7 +1498,7 @@ static __inline__ void ywrap_down(struct vc_data *vc, int count) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; - struct display *p = &fb_display[vc->vc_num]; + struct fbcon_display *p = &fb_display[vc->vc_num]; p->yscroll -= count; if (p->yscroll < 0) /* Deal with wrap */ @@ -1494,7 +1516,7 @@ static __inline__ void ywrap_down(struct vc_data *vc, int count) static __inline__ void ypan_up(struct vc_data *vc, int count) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; - struct display *p = &fb_display[vc->vc_num]; + struct fbcon_display *p = &fb_display[vc->vc_num]; struct fbcon_ops *ops = info->fbcon_par; p->yscroll += count; @@ -1519,7 +1541,7 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; - struct display *p = &fb_display[vc->vc_num]; + struct fbcon_display *p = &fb_display[vc->vc_num]; p->yscroll += count; @@ -1542,7 +1564,7 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) static __inline__ void ypan_down(struct vc_data *vc, int count) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; - struct display *p = &fb_display[vc->vc_num]; + struct fbcon_display *p = &fb_display[vc->vc_num]; struct fbcon_ops *ops = info->fbcon_par; p->yscroll -= count; @@ -1567,7 +1589,7 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; - struct display *p = &fb_display[vc->vc_num]; + struct fbcon_display *p = &fb_display[vc->vc_num]; p->yscroll -= count; @@ -1587,7 +1609,7 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) scrollback_current = 0; } -static void fbcon_redraw_softback(struct vc_data *vc, struct display *p, +static void fbcon_redraw_softback(struct vc_data *vc, struct fbcon_display *p, long delta) { int count = vc->vc_rows; @@ -1680,7 +1702,7 @@ static void fbcon_redraw_softback(struct vc_data *vc, struct display *p, } } -static void fbcon_redraw_move(struct vc_data *vc, struct display *p, +static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, int line, int count, int dy) { unsigned short *s = (unsigned short *) @@ -1715,7 +1737,7 @@ static void fbcon_redraw_move(struct vc_data *vc, struct display *p, } static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, - struct display *p, int line, int count, int ycount) + struct fbcon_display *p, int line, int count, int ycount) { int offset = ycount * vc->vc_cols; unsigned short *d = (unsigned short *) @@ -1764,7 +1786,7 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, } } -static void fbcon_redraw(struct vc_data *vc, struct display *p, +static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p, int line, int count, int offset) { unsigned short *d = (unsigned short *) @@ -1848,7 +1870,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, enum con_scroll dir, unsigned int count) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; - struct display *p = &fb_display[vc->vc_num]; + struct fbcon_display *p = &fb_display[vc->vc_num]; int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; if (fbcon_is_inactive(vc, info)) @@ -2052,7 +2074,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, int height, int width) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; - struct display *p = &fb_display[vc->vc_num]; + struct fbcon_display *p = &fb_display[vc->vc_num]; if (fbcon_is_inactive(vc, info)) return; @@ -2071,7 +2093,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, p->vrows - p->yscroll); } -static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, +static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx, int dy, int dx, int height, int width, u_int y_break) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; @@ -2113,7 +2135,7 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int s height, width); } -static void updatescrollmode(struct display *p, +static void updatescrollmode(struct fbcon_display *p, struct fb_info *info, struct vc_data *vc) { @@ -2165,7 +2187,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; - struct display *p = &fb_display[vc->vc_num]; + struct fbcon_display *p = &fb_display[vc->vc_num]; struct fb_var_screeninfo var = info->var; int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh; @@ -2210,7 +2232,7 @@ static int fbcon_switch(struct vc_data *vc) { struct fb_info *info, *old_info = NULL; struct fbcon_ops *ops; - struct display *p = &fb_display[vc->vc_num]; + struct fbcon_display *p = &fb_display[vc->vc_num]; struct fb_var_screeninfo var; int i, ret, prev_console, charcnt = 256; @@ -2348,8 +2370,6 @@ static int fbcon_switch(struct vc_data *vc) static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, int blank) { - struct fb_event event; - if (blank) { unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; @@ -2360,14 +2380,6 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols); vc->vc_video_erase_char = oldc; } - - - if (!lock_fb_info(info)) - return; - event.info = info; - event.data = ␣ - fb_notifier_call_chain(FB_EVENT_CONBLANK, &event); - unlock_fb_info(info); } static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) @@ -2394,9 +2406,8 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); ops->cursor_flash = (!blank); - if (!(info->flags & FBINFO_MISC_USEREVENT)) - if (fb_blank(info, blank)) - fbcon_generic_blank(vc, info, blank); + if (fb_blank(info, blank)) + fbcon_generic_blank(vc, info, blank); } if (!blank) @@ -2553,7 +2564,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; - struct display *p = &fb_display[vc->vc_num]; + struct fbcon_display *p = &fb_display[vc->vc_num]; int resize; int cnt; char *old_data = NULL; @@ -2601,7 +2612,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, static int fbcon_copy_font(struct vc_data *vc, int con) { - struct display *od = &fb_display[con]; + struct fbcon_display *od = &fb_display[con]; struct console_font *f = &vc->vc_font; if (od->fontdata == f->data) @@ -2826,7 +2837,7 @@ static void fbcon_scrolldelta(struct vc_data *vc, int lines) { struct fb_info *info = registered_fb[con2fb_map[fg_console]]; struct fbcon_ops *ops = info->fbcon_par; - struct display *disp = &fb_display[fg_console]; + struct fbcon_display *disp = &fb_display[fg_console]; int offset, limit, scrollback_old; if (softback_top) { @@ -2918,7 +2929,7 @@ static int fbcon_set_origin(struct vc_data *vc) return 0; } -static void fbcon_suspended(struct fb_info *info) +void fbcon_suspended(struct fb_info *info) { struct vc_data *vc = NULL; struct fbcon_ops *ops = info->fbcon_par; @@ -2931,7 +2942,7 @@ static void fbcon_suspended(struct fb_info *info) fbcon_cursor(vc, CM_ERASE); } -static void fbcon_resumed(struct fb_info *info) +void fbcon_resumed(struct fb_info *info) { struct vc_data *vc; struct fbcon_ops *ops = info->fbcon_par; @@ -2947,7 +2958,7 @@ static void fbcon_modechanged(struct fb_info *info) { struct fbcon_ops *ops = info->fbcon_par; struct vc_data *vc; - struct display *p; + struct fbcon_display *p; int rows, cols; if (!ops || ops->currcon < 0) @@ -2987,7 +2998,7 @@ static void fbcon_set_all_vcs(struct fb_info *info) { struct fbcon_ops *ops = info->fbcon_par; struct vc_data *vc; - struct display *p; + struct fbcon_display *p; int i, rows, cols, fg = -1; if (!ops || ops->currcon < 0) @@ -3018,11 +3029,21 @@ static void fbcon_set_all_vcs(struct fb_info *info) fbcon_modechanged(info); } -static int fbcon_mode_deleted(struct fb_info *info, - struct fb_videomode *mode) + +void fbcon_update_vcs(struct fb_info *info, bool all) +{ + if (all) + fbcon_set_all_vcs(info); + else + fbcon_modechanged(info); +} +EXPORT_SYMBOL(fbcon_update_vcs); + +int fbcon_mode_deleted(struct fb_info *info, + struct fb_videomode *mode) { struct fb_info *fb_info; - struct display *p; + struct fbcon_display *p; int i, j, found = 0; /* before deletion, ensure that mode is not in use */ @@ -3045,7 +3066,7 @@ static int fbcon_mode_deleted(struct fb_info *info, } #ifdef CONFIG_VT_HW_CONSOLE_BINDING -static int fbcon_unbind(void) +static void fbcon_unbind(void) { int ret; @@ -3054,25 +3075,21 @@ static int fbcon_unbind(void) if (!ret) fbcon_has_console_bind = 0; - - return ret; } #else -static inline int fbcon_unbind(void) -{ - return -EINVAL; -} +static inline void fbcon_unbind(void) {} #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ /* called with console_lock held */ -static int fbcon_fb_unbind(int idx) +void fbcon_fb_unbind(struct fb_info *info) { int i, new_idx = -1, ret = 0; + int idx = info->node; WARN_CONSOLE_UNLOCKED(); if (!fbcon_has_console_bind) - return 0; + return; for (i = first_fb_vc; i <= last_fb_vc; i++) { if (con2fb_map[i] != idx && @@ -3105,26 +3122,24 @@ static int fbcon_fb_unbind(int idx) idx, 0); if (ret) { con2fb_map[i] = idx; - return ret; + return; } } } } - ret = fbcon_unbind(); + fbcon_unbind(); } - - return ret; } /* called with console_lock held */ -static int fbcon_fb_unregistered(struct fb_info *info) +void fbcon_fb_unregistered(struct fb_info *info) { int i, idx; WARN_CONSOLE_UNLOCKED(); if (deferred_takeover) - return 0; + return; idx = info->node; for (i = first_fb_vc; i <= last_fb_vc; i++) { @@ -3153,21 +3168,18 @@ static int fbcon_fb_unregistered(struct fb_info *info) if (!num_registered_fb) do_unregister_con_driver(&fb_con); - - return 0; } -/* called with console_lock held */ -static void fbcon_remap_all(int idx) +void fbcon_remap_all(struct fb_info *info) { - int i; - - WARN_CONSOLE_UNLOCKED(); + int i, idx = info->node; + console_lock(); if (deferred_takeover) { for (i = first_fb_vc; i <= last_fb_vc; i++) con2fb_map_boot[i] = idx; fbcon_map_override(); + console_unlock(); return; } @@ -3180,6 +3192,7 @@ static void fbcon_remap_all(int idx) first_fb_vc + 1, last_fb_vc + 1); info_idx = idx; } + console_unlock(); } #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY @@ -3213,7 +3226,7 @@ static inline void fbcon_select_primary(struct fb_info *info) #endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */ /* called with console_lock held */ -static int fbcon_fb_registered(struct fb_info *info) +int fbcon_fb_registered(struct fb_info *info) { int ret = 0, i, idx; @@ -3247,7 +3260,7 @@ static int fbcon_fb_registered(struct fb_info *info) return ret; } -static void fbcon_fb_blanked(struct fb_info *info, int blank) +void fbcon_fb_blanked(struct fb_info *info, int blank) { struct fbcon_ops *ops = info->fbcon_par; struct vc_data *vc; @@ -3269,7 +3282,7 @@ static void fbcon_fb_blanked(struct fb_info *info, int blank) ops->blank_state = blank; } -static void fbcon_new_modelist(struct fb_info *info) +void fbcon_new_modelist(struct fb_info *info) { int i; struct vc_data *vc; @@ -3290,11 +3303,11 @@ static void fbcon_new_modelist(struct fb_info *info) } } -static void fbcon_get_requirement(struct fb_info *info, - struct fb_blit_caps *caps) +void fbcon_get_requirement(struct fb_info *info, + struct fb_blit_caps *caps) { struct vc_data *vc; - struct display *p; + struct fbcon_display *p; if (caps->flags) { int i, charcnt; @@ -3326,80 +3339,47 @@ static void fbcon_get_requirement(struct fb_info *info, } } -static int fbcon_event_notify(struct notifier_block *self, - unsigned long action, void *data) +int fbcon_set_con2fb_map_ioctl(void __user *argp) { - struct fb_event *event = data; - struct fb_info *info = event->info; - struct fb_videomode *mode; - struct fb_con2fbmap *con2fb; - struct fb_blit_caps *caps; - int idx, ret = 0; - - /* - * ignore all events except driver registration and deregistration - * if fbcon is not active - */ - if (fbcon_has_exited && !(action == FB_EVENT_FB_REGISTERED || - action == FB_EVENT_FB_UNREGISTERED)) - goto done; + struct fb_con2fbmap con2fb; + int ret; - switch(action) { - case FB_EVENT_SUSPEND: - fbcon_suspended(info); - break; - case FB_EVENT_RESUME: - fbcon_resumed(info); - break; - case FB_EVENT_MODE_CHANGE: - fbcon_modechanged(info); - break; - case FB_EVENT_MODE_CHANGE_ALL: - fbcon_set_all_vcs(info); - break; - case FB_EVENT_MODE_DELETE: - mode = event->data; - ret = fbcon_mode_deleted(info, mode); - break; - case FB_EVENT_FB_UNBIND: - idx = info->node; - ret = fbcon_fb_unbind(idx); - break; - case FB_EVENT_FB_REGISTERED: - ret = fbcon_fb_registered(info); - break; - case FB_EVENT_FB_UNREGISTERED: - ret = fbcon_fb_unregistered(info); - break; - case FB_EVENT_SET_CONSOLE_MAP: - /* called with console lock held */ - con2fb = event->data; - ret = set_con2fb_map(con2fb->console - 1, - con2fb->framebuffer, 1); - break; - case FB_EVENT_GET_CONSOLE_MAP: - con2fb = event->data; - con2fb->framebuffer = con2fb_map[con2fb->console - 1]; - break; - case FB_EVENT_BLANK: - fbcon_fb_blanked(info, *(int *)event->data); - break; - case FB_EVENT_NEW_MODELIST: - fbcon_new_modelist(info); - break; - case FB_EVENT_GET_REQ: - caps = event->data; - fbcon_get_requirement(info, caps); - break; - case FB_EVENT_REMAP_ALL_CONSOLE: - idx = info->node; - fbcon_remap_all(idx); - break; + if (copy_from_user(&con2fb, argp, sizeof(con2fb))) + return -EFAULT; + if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) + return -EINVAL; + if (con2fb.framebuffer >= FB_MAX) + return -EINVAL; + if (!registered_fb[con2fb.framebuffer]) + request_module("fb%d", con2fb.framebuffer); + if (!registered_fb[con2fb.framebuffer]) { + return -EINVAL; } -done: + + console_lock(); + ret = set_con2fb_map(con2fb.console - 1, + con2fb.framebuffer, 1); + console_unlock(); + return ret; } +int fbcon_get_con2fb_map_ioctl(void __user *argp) +{ + struct fb_con2fbmap con2fb; + + if (copy_from_user(&con2fb, argp, sizeof(con2fb))) + return -EFAULT; + if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) + return -EINVAL; + + console_lock(); + con2fb.framebuffer = con2fb_map[con2fb.console - 1]; + console_unlock(); + + return copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; +} + /* * The console `switch' structure for the frame buffer based console */ @@ -3431,10 +3411,6 @@ static const struct consw fb_con = { .con_debug_leave = fbcon_debug_leave, }; -static struct notifier_block fbcon_event_notifier = { - .notifier_call = fbcon_event_notify, -}; - static ssize_t store_rotate(struct device *device, struct device_attribute *attr, const char *buf, size_t count) @@ -3443,9 +3419,6 @@ static ssize_t store_rotate(struct device *device, int rotate, idx; char **last = NULL; - if (fbcon_has_exited) - return count; - console_lock(); idx = con2fb_map[fg_console]; @@ -3468,9 +3441,6 @@ static ssize_t store_rotate_all(struct device *device, int rotate, idx; char **last = NULL; - if (fbcon_has_exited) - return count; - console_lock(); idx = con2fb_map[fg_console]; @@ -3491,9 +3461,6 @@ static ssize_t show_rotate(struct device *device, struct fb_info *info; int rotate = 0, idx; - if (fbcon_has_exited) - return 0; - console_lock(); idx = con2fb_map[fg_console]; @@ -3514,9 +3481,6 @@ static ssize_t show_cursor_blink(struct device *device, struct fbcon_ops *ops; int idx, blink = -1; - if (fbcon_has_exited) - return 0; - console_lock(); idx = con2fb_map[fg_console]; @@ -3543,9 +3507,6 @@ static ssize_t store_cursor_blink(struct device *device, int blink, idx; char **last = NULL; - if (fbcon_has_exited) - return count; - console_lock(); idx = con2fb_map[fg_console]; @@ -3668,9 +3629,6 @@ static void fbcon_exit(void) struct fb_info *info; int i, j, mapped; - if (fbcon_has_exited) - return; - #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER if (deferred_takeover) { dummycon_unregister_output_notifier(&fbcon_output_nb); @@ -3695,7 +3653,7 @@ static void fbcon_exit(void) for (j = first_fb_vc; j <= last_fb_vc; j++) { if (con2fb_map[j] == i) { mapped = 1; - break; + con2fb_map[j] = -1; } } @@ -3718,8 +3676,6 @@ static void fbcon_exit(void) info->queue.func = NULL; } } - - fbcon_has_exited = 1; } void __init fb_console_init(void) @@ -3727,7 +3683,6 @@ void __init fb_console_init(void) int i; console_lock(); - fb_register_client(&fbcon_event_notifier); fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), NULL, "fbcon"); @@ -3763,7 +3718,6 @@ static void __exit fbcon_deinit_device(void) void __exit fb_console_exit(void) { console_lock(); - fb_unregister_client(&fbcon_event_notifier); fbcon_deinit_device(); device_destroy(fb_class, MKDEV(0, 0)); fbcon_exit(); diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h index 21912a3ba32f..20dea853765f 100644 --- a/drivers/video/fbdev/core/fbcon.h +++ b/drivers/video/fbdev/core/fbcon.h @@ -25,7 +25,7 @@ * low-level frame buffer device */ -struct display { +struct fbcon_display { /* Filled in by the low-level console driver */ const u_char *fontdata; int userfont; /* != 0 if fontdata kmalloc()ed */ @@ -68,7 +68,7 @@ struct fbcon_ops { struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */ struct timer_list cursor_timer; /* Cursor timer */ struct fb_cursor cursor_state; - struct display *p; + struct fbcon_display *p; struct fb_info *info; int currcon; /* Current VC. */ int cur_blink_jiffies; @@ -225,7 +225,7 @@ extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); #define FBCON_ATTRIBUTE_REVERSE 2 #define FBCON_ATTRIBUTE_BOLD 4 -static inline int real_y(struct display *p, int ypos) +static inline int real_y(struct fbcon_display *p, int ypos) { int rows = p->vrows; diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index d1949c92be98..64dd732021d8 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -80,17 +80,6 @@ static void put_fb_info(struct fb_info *fb_info) fb_info->fbops->fb_destroy(fb_info); } -int lock_fb_info(struct fb_info *info) -{ - mutex_lock(&info->lock); - if (!info->fbops) { - mutex_unlock(&info->lock); - return 0; - } - return 1; -} -EXPORT_SYMBOL(lock_fb_info); - /* * Helpers */ @@ -943,16 +932,13 @@ EXPORT_SYMBOL(fb_pan_display); static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, u32 activate) { - struct fb_event event; struct fb_blit_caps caps, fbcaps; int err = 0; memset(&caps, 0, sizeof(caps)); memset(&fbcaps, 0, sizeof(fbcaps)); caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0; - event.info = info; - event.data = ∩︀ - fb_notifier_call_chain(FB_EVENT_GET_REQ, &event); + fbcon_get_requirement(info, &caps); info->fbops->fb_get_caps(info, &fbcaps, var); if (((fbcaps.x ^ caps.x) & caps.x) || @@ -968,6 +954,10 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) { int flags = info->flags; int ret = 0; + u32 activate; + struct fb_var_screeninfo old_var; + struct fb_videomode mode; + struct fb_event event; if (var->activate & FB_ACTIVATE_INV_MODE) { struct fb_videomode mode1, mode2; @@ -977,100 +967,90 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) /* make sure we don't delete the videomode of current var */ ret = fb_mode_is_equal(&mode1, &mode2); - if (!ret) { - struct fb_event event; - - event.info = info; - event.data = &mode1; - ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event); - } + if (!ret) + fbcon_mode_deleted(info, &mode1); if (!ret) - fb_delete_videomode(&mode1, &info->modelist); + fb_delete_videomode(&mode1, &info->modelist); - ret = (ret) ? -EINVAL : 0; - goto done; + return ret ? -EINVAL : 0; } - if ((var->activate & FB_ACTIVATE_FORCE) || - memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { - u32 activate = var->activate; + if (!(var->activate & FB_ACTIVATE_FORCE) && + !memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) + return 0; - /* When using FOURCC mode, make sure the red, green, blue and - * transp fields are set to 0. - */ - if ((info->fix.capabilities & FB_CAP_FOURCC) && - var->grayscale > 1) { - if (var->red.offset || var->green.offset || - var->blue.offset || var->transp.offset || - var->red.length || var->green.length || - var->blue.length || var->transp.length || - var->red.msb_right || var->green.msb_right || - var->blue.msb_right || var->transp.msb_right) - return -EINVAL; - } + activate = var->activate; - if (!info->fbops->fb_check_var) { - *var = info->var; - goto done; - } + /* When using FOURCC mode, make sure the red, green, blue and + * transp fields are set to 0. + */ + if ((info->fix.capabilities & FB_CAP_FOURCC) && + var->grayscale > 1) { + if (var->red.offset || var->green.offset || + var->blue.offset || var->transp.offset || + var->red.length || var->green.length || + var->blue.length || var->transp.length || + var->red.msb_right || var->green.msb_right || + var->blue.msb_right || var->transp.msb_right) + return -EINVAL; + } - ret = info->fbops->fb_check_var(var, info); + if (!info->fbops->fb_check_var) { + *var = info->var; + return 0; + } - if (ret) - goto done; + ret = info->fbops->fb_check_var(var, info); - if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { - struct fb_var_screeninfo old_var; - struct fb_videomode mode; + if (ret) + return ret; - if (info->fbops->fb_get_caps) { - ret = fb_check_caps(info, var, activate); + if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) + return 0; - if (ret) - goto done; - } + if (info->fbops->fb_get_caps) { + ret = fb_check_caps(info, var, activate); - old_var = info->var; - info->var = *var; + if (ret) + return ret; + } - if (info->fbops->fb_set_par) { - ret = info->fbops->fb_set_par(info); + old_var = info->var; + info->var = *var; - if (ret) { - info->var = old_var; - printk(KERN_WARNING "detected " - "fb_set_par error, " - "error code: %d\n", ret); - goto done; - } - } + if (info->fbops->fb_set_par) { + ret = info->fbops->fb_set_par(info); - fb_pan_display(info, &info->var); - fb_set_cmap(&info->cmap, info); - fb_var_to_videomode(&mode, &info->var); + if (ret) { + info->var = old_var; + printk(KERN_WARNING "detected " + "fb_set_par error, " + "error code: %d\n", ret); + return ret; + } + } - if (info->modelist.prev && info->modelist.next && - !list_empty(&info->modelist)) - ret = fb_add_videomode(&mode, &info->modelist); + fb_pan_display(info, &info->var); + fb_set_cmap(&info->cmap, info); + fb_var_to_videomode(&mode, &info->var); - if (!ret && (flags & FBINFO_MISC_USEREVENT)) { - struct fb_event event; - int evnt = (activate & FB_ACTIVATE_ALL) ? - FB_EVENT_MODE_CHANGE_ALL : - FB_EVENT_MODE_CHANGE; + if (info->modelist.prev && info->modelist.next && + !list_empty(&info->modelist)) + ret = fb_add_videomode(&mode, &info->modelist); - info->flags &= ~FBINFO_MISC_USEREVENT; - event.info = info; - event.data = &mode; - fb_notifier_call_chain(evnt, &event); - } - } - } + if (ret) + return ret; - done: - return ret; + event.info = info; + event.data = &mode; + fb_notifier_call_chain(FB_EVENT_MODE_CHANGE, &event); + + if (flags & FBINFO_MISC_USEREVENT) + fbcon_update_vcs(info, activate & FB_ACTIVATE_ALL); + + return 0; } EXPORT_SYMBOL(fb_set_var); @@ -1112,17 +1092,14 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, struct fb_ops *fb; struct fb_var_screeninfo var; struct fb_fix_screeninfo fix; - struct fb_con2fbmap con2fb; struct fb_cmap cmap_from; struct fb_cmap_user cmap; - struct fb_event event; void __user *argp = (void __user *)arg; long ret = 0; switch (cmd) { case FBIOGET_VSCREENINFO: - if (!lock_fb_info(info)) - return -ENODEV; + lock_fb_info(info); var = info->var; unlock_fb_info(info); @@ -1132,10 +1109,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, if (copy_from_user(&var, argp, sizeof(var))) return -EFAULT; console_lock(); - if (!lock_fb_info(info)) { - console_unlock(); - return -ENODEV; - } + lock_fb_info(info); info->flags |= FBINFO_MISC_USEREVENT; ret = fb_set_var(info, &var); info->flags &= ~FBINFO_MISC_USEREVENT; @@ -1145,8 +1119,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, ret = -EFAULT; break; case FBIOGET_FSCREENINFO: - if (!lock_fb_info(info)) - return -ENODEV; + lock_fb_info(info); fix = info->fix; if (info->flags & FBINFO_HIDE_SMEM_START) fix.smem_start = 0; @@ -1162,8 +1135,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, case FBIOGETCMAP: if (copy_from_user(&cmap, argp, sizeof(cmap))) return -EFAULT; - if (!lock_fb_info(info)) - return -ENODEV; + lock_fb_info(info); cmap_from = info->cmap; unlock_fb_info(info); ret = fb_cmap_to_user(&cmap_from, &cmap); @@ -1172,10 +1144,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, if (copy_from_user(&var, argp, sizeof(var))) return -EFAULT; console_lock(); - if (!lock_fb_info(info)) { - console_unlock(); - return -ENODEV; - } + lock_fb_info(info); ret = fb_pan_display(info, &var); unlock_fb_info(info); console_unlock(); @@ -1186,58 +1155,22 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, ret = -EINVAL; break; case FBIOGET_CON2FBMAP: - if (copy_from_user(&con2fb, argp, sizeof(con2fb))) - return -EFAULT; - if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) - return -EINVAL; - con2fb.framebuffer = -1; - event.data = &con2fb; - if (!lock_fb_info(info)) - return -ENODEV; - event.info = info; - fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event); - unlock_fb_info(info); - ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; + ret = fbcon_get_con2fb_map_ioctl(argp); break; case FBIOPUT_CON2FBMAP: - if (copy_from_user(&con2fb, argp, sizeof(con2fb))) - return -EFAULT; - if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) - return -EINVAL; - if (con2fb.framebuffer >= FB_MAX) - return -EINVAL; - if (!registered_fb[con2fb.framebuffer]) - request_module("fb%d", con2fb.framebuffer); - if (!registered_fb[con2fb.framebuffer]) { - ret = -EINVAL; - break; - } - event.data = &con2fb; - console_lock(); - if (!lock_fb_info(info)) { - console_unlock(); - return -ENODEV; - } - event.info = info; - ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event); - unlock_fb_info(info); - console_unlock(); + ret = fbcon_set_con2fb_map_ioctl(argp); break; case FBIOBLANK: console_lock(); - if (!lock_fb_info(info)) { - console_unlock(); - return -ENODEV; - } - info->flags |= FBINFO_MISC_USEREVENT; + lock_fb_info(info); ret = fb_blank(info, arg); - info->flags &= ~FBINFO_MISC_USEREVENT; + /* might again call into fb_blank */ + fbcon_fb_blanked(info, arg); unlock_fb_info(info); console_unlock(); break; default: - if (!lock_fb_info(info)) - return -ENODEV; + lock_fb_info(info); fb = info->fbops; if (fb->fb_ioctl) ret = fb->fb_ioctl(info, cmd, arg); @@ -1357,8 +1290,7 @@ static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd, { struct fb_fix_screeninfo fix; - if (!lock_fb_info(info)) - return -ENODEV; + lock_fb_info(info); fix = info->fix; if (info->flags & FBINFO_HIDE_SMEM_START) fix.smem_start = 0; @@ -1418,8 +1350,6 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) if (!info) return -ENODEV; fb = info->fbops; - if (!fb) - return -ENODEV; mutex_lock(&info->mm_lock); if (fb->fb_mmap) { int res; @@ -1483,7 +1413,7 @@ __releases(&info->lock) if (IS_ERR(info)) return PTR_ERR(info); - mutex_lock(&info->lock); + lock_fb_info(info); if (!try_module_get(info->fbops->owner)) { res = -ENODEV; goto out; @@ -1499,7 +1429,7 @@ __releases(&info->lock) fb_deferred_io_open(info, inode, file); #endif out: - mutex_unlock(&info->lock); + unlock_fb_info(info); if (res) put_fb_info(info); return res; @@ -1512,11 +1442,11 @@ __releases(&info->lock) { struct fb_info * const info = file->private_data; - mutex_lock(&info->lock); + lock_fb_info(info); if (info->fbops->fb_release) info->fbops->fb_release(info,1); module_put(info->fbops->owner); - mutex_unlock(&info->lock); + unlock_fb_info(info); put_fb_info(info); return 0; } @@ -1621,13 +1551,13 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena, return false; } -static int do_unregister_framebuffer(struct fb_info *fb_info); +static void do_unregister_framebuffer(struct fb_info *fb_info); #define VGA_FB_PHYS 0xA0000 -static int do_remove_conflicting_framebuffers(struct apertures_struct *a, - const char *name, bool primary) +static void do_remove_conflicting_framebuffers(struct apertures_struct *a, + const char *name, bool primary) { - int i, ret; + int i; /* check all firmware fbs and kick off if the base addr overlaps */ for_each_registered_fb(i) { @@ -1643,13 +1573,9 @@ static int do_remove_conflicting_framebuffers(struct apertures_struct *a, printk(KERN_INFO "fb%d: switching to %s from %s\n", i, name, registered_fb[i]->fix.id); - ret = do_unregister_framebuffer(registered_fb[i]); - if (ret) - return ret; + do_unregister_framebuffer(registered_fb[i]); } } - - return 0; } static bool lockless_register_fb; @@ -1660,17 +1586,14 @@ MODULE_PARM_DESC(lockless_register_fb, static int do_register_framebuffer(struct fb_info *fb_info) { int i, ret; - struct fb_event event; struct fb_videomode mode; if (fb_check_foreignness(fb_info)) return -ENOSYS; - ret = do_remove_conflicting_framebuffers(fb_info->apertures, - fb_info->fix.id, - fb_is_primary_device(fb_info)); - if (ret) - return ret; + do_remove_conflicting_framebuffers(fb_info->apertures, + fb_info->fix.id, + fb_is_primary_device(fb_info)); if (num_registered_fb == FB_MAX) return -ENXIO; @@ -1723,20 +1646,22 @@ static int do_register_framebuffer(struct fb_info *fb_info) fb_add_videomode(&mode, &fb_info->modelist); registered_fb[i] = fb_info; - event.info = fb_info; +#ifdef CONFIG_GUMSTIX_AM200EPD + { + struct fb_event event; + event.info = fb_info; + fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); + } +#endif + if (!lockless_register_fb) console_lock(); else atomic_inc(&ignore_console_lock_warning); - if (!lock_fb_info(fb_info)) { - ret = -ENODEV; - goto unlock_console; - } - ret = 0; - - fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); + lock_fb_info(fb_info); + ret = fbcon_fb_registered(fb_info); unlock_fb_info(fb_info); -unlock_console: + if (!lockless_register_fb) console_unlock(); else @@ -1744,44 +1669,44 @@ unlock_console: return ret; } -static int unbind_console(struct fb_info *fb_info) +static void unbind_console(struct fb_info *fb_info) { - struct fb_event event; - int ret; int i = fb_info->node; - if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) - return -EINVAL; + if (WARN_ON(i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)) + return; console_lock(); - if (!lock_fb_info(fb_info)) { - console_unlock(); - return -ENODEV; - } - - event.info = fb_info; - ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); + lock_fb_info(fb_info); + fbcon_fb_unbind(fb_info); unlock_fb_info(fb_info); console_unlock(); - - return ret; } -static int __unlink_framebuffer(struct fb_info *fb_info); - -static int do_unregister_framebuffer(struct fb_info *fb_info) +void unlink_framebuffer(struct fb_info *fb_info) { - struct fb_event event; - int ret; + int i; + + i = fb_info->node; + if (WARN_ON(i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)) + return; - ret = unbind_console(fb_info); + if (!fb_info->dev) + return; - if (ret) - return -EINVAL; + device_destroy(fb_class, MKDEV(FB_MAJOR, i)); pm_vt_switch_unregister(fb_info->dev); - __unlink_framebuffer(fb_info); + unbind_console(fb_info); + + fb_info->dev = NULL; +} +EXPORT_SYMBOL(unlink_framebuffer); + +static void do_unregister_framebuffer(struct fb_info *fb_info) +{ + unlink_framebuffer(fb_info); if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) kfree(fb_info->pixmap.addr); @@ -1789,46 +1714,21 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) registered_fb[fb_info->node] = NULL; num_registered_fb--; fb_cleanup_device(fb_info); - event.info = fb_info; +#ifdef CONFIG_GUMSTIX_AM200EPD + { + struct fb_event event; + event.info = fb_info; + fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); + } +#endif console_lock(); - fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); + fbcon_fb_unregistered(fb_info); console_unlock(); /* this may free fb info */ put_fb_info(fb_info); - return 0; } -static int __unlink_framebuffer(struct fb_info *fb_info) -{ - int i; - - i = fb_info->node; - if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) - return -EINVAL; - - if (fb_info->dev) { - device_destroy(fb_class, MKDEV(FB_MAJOR, i)); - fb_info->dev = NULL; - } - - return 0; -} - -int unlink_framebuffer(struct fb_info *fb_info) -{ - int ret; - - ret = __unlink_framebuffer(fb_info); - if (ret) - return ret; - - unbind_console(fb_info); - - return 0; -} -EXPORT_SYMBOL(unlink_framebuffer); - /** * remove_conflicting_framebuffers - remove firmware-configured framebuffers * @a: memory range, users of which are to be removed @@ -1842,7 +1742,6 @@ EXPORT_SYMBOL(unlink_framebuffer); int remove_conflicting_framebuffers(struct apertures_struct *a, const char *name, bool primary) { - int ret; bool do_free = false; if (!a) { @@ -1856,13 +1755,13 @@ int remove_conflicting_framebuffers(struct apertures_struct *a, } mutex_lock(®istration_lock); - ret = do_remove_conflicting_framebuffers(a, name, primary); + do_remove_conflicting_framebuffers(a, name, primary); mutex_unlock(®istration_lock); if (do_free) kfree(a); - return ret; + return 0; } EXPORT_SYMBOL(remove_conflicting_framebuffers); @@ -1959,16 +1858,12 @@ EXPORT_SYMBOL(register_framebuffer); * that the driver implements fb_open() and fb_release() to * check that no processes are using the device. */ -int +void unregister_framebuffer(struct fb_info *fb_info) { - int ret; - mutex_lock(®istration_lock); - ret = do_unregister_framebuffer(fb_info); + do_unregister_framebuffer(fb_info); mutex_unlock(®istration_lock); - - return ret; } EXPORT_SYMBOL(unregister_framebuffer); @@ -1983,15 +1878,14 @@ EXPORT_SYMBOL(unregister_framebuffer); */ void fb_set_suspend(struct fb_info *info, int state) { - struct fb_event event; + WARN_CONSOLE_UNLOCKED(); - event.info = info; if (state) { - fb_notifier_call_chain(FB_EVENT_SUSPEND, &event); + fbcon_suspended(info); info->state = FBINFO_STATE_SUSPENDED; } else { info->state = FBINFO_STATE_RUNNING; - fb_notifier_call_chain(FB_EVENT_RESUME, &event); + fbcon_resumed(info); } } EXPORT_SYMBOL(fb_set_suspend); @@ -2059,7 +1953,6 @@ subsys_initcall(fbmem_init); int fb_new_modelist(struct fb_info *info) { - struct fb_event event; struct fb_var_screeninfo var = info->var; struct list_head *pos, *n; struct fb_modelist *modelist; @@ -2079,14 +1972,12 @@ int fb_new_modelist(struct fb_info *info) } } - err = 1; + if (list_empty(&info->modelist)) + return 1; - if (!list_empty(&info->modelist)) { - event.info = info; - err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event); - } + fbcon_new_modelist(info); - return err; + return 0; } MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/core/fbsysfs.c b/drivers/video/fbdev/core/fbsysfs.c index 954ed99e80da..d54c88f88991 100644 --- a/drivers/video/fbdev/core/fbsysfs.c +++ b/drivers/video/fbdev/core/fbsysfs.c @@ -14,6 +14,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/fb.h> +#include <linux/fbcon.h> #include <linux/console.h> #include <linux/module.h> @@ -175,10 +176,7 @@ static ssize_t store_modes(struct device *device, return -EINVAL; console_lock(); - if (!lock_fb_info(fb_info)) { - console_unlock(); - return -ENODEV; - } + lock_fb_info(fb_info); list_splice(&fb_info->modelist, &old_list); fb_videomode_to_modelist((const struct fb_videomode *)buf, i, @@ -304,12 +302,13 @@ static ssize_t store_blank(struct device *device, { struct fb_info *fb_info = dev_get_drvdata(device); char *last = NULL; - int err; + int err, arg; + arg = simple_strtoul(buf, &last, 0); console_lock(); - fb_info->flags |= FBINFO_MISC_USEREVENT; - err = fb_blank(fb_info, simple_strtoul(buf, &last, 0)); - fb_info->flags &= ~FBINFO_MISC_USEREVENT; + err = fb_blank(fb_info, arg); + /* might again call into fb_blank */ + fbcon_fb_blanked(fb_info, arg); console_unlock(); if (err < 0) return err; @@ -405,10 +404,7 @@ static ssize_t store_fbstate(struct device *device, state = simple_strtoul(buf, &last, 0); console_lock(); - if (!lock_fb_info(fb_info)) { - console_unlock(); - return -ENODEV; - } + lock_fb_info(fb_info); fb_set_suspend(fb_info, (int)state); diff --git a/drivers/video/fbdev/cyber2000fb.c b/drivers/video/fbdev/cyber2000fb.c index 9a5751cb4e16..3a2d9ff0aa42 100644 --- a/drivers/video/fbdev/cyber2000fb.c +++ b/drivers/video/fbdev/cyber2000fb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/cyber2000fb.c * @@ -9,10 +10,6 @@ * 32 bit support, text color and panning fixes for modes != 8 bit * Copyright (C) 2002 Denis Oliver Kropp <dok@directfb.org> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Integraphics CyberPro 2000, 2010 and 5000 frame buffer device * * Based on cyberfb.c. @@ -61,7 +58,6 @@ struct cfb_info { struct fb_info fb; struct display_switch *dispsw; - struct display *display; unsigned char __iomem *region; unsigned char __iomem *regs; u_int id; @@ -1642,10 +1638,6 @@ static void cyberpro_common_resume(struct cfb_info *cfb) } /* - * PCI specific support. - */ -#ifdef CONFIG_PCI -/* * We need to wake up the CyberPro, and make sure its in linear memory * mode. Unfortunately, this is specific to the platform and card that * we are running on. @@ -1861,7 +1853,6 @@ static struct pci_driver cyberpro_driver = { .resume = cyberpro_pci_resume, .id_table = cyberpro_pci_table }; -#endif /* * I don't think we can use the "module_init" stuff here because diff --git a/drivers/video/fbdev/cyber2000fb.h b/drivers/video/fbdev/cyber2000fb.h index bad69102e774..04641aa13acc 100644 --- a/drivers/video/fbdev/cyber2000fb.h +++ b/drivers/video/fbdev/cyber2000fb.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/video/cyber2000fb.h * * Copyright (C) 1998-2000 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Integraphics Cyber2000 frame buffer device */ diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c index 9ea817ac1d81..b1cf248f3291 100644 --- a/drivers/video/fbdev/da8xx-fb.c +++ b/drivers/video/fbdev/da8xx-fb.c @@ -1387,7 +1387,6 @@ static int fb_probe(struct platform_device *device) da8xx_fb_info = framebuffer_alloc(sizeof(struct da8xx_fb_par), &device->dev); if (!da8xx_fb_info) { - dev_dbg(&device->dev, "Memory allocation failed for fb_info\n"); ret = -ENOMEM; goto err_pm_runtime_disable; } diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index 9f39f0c360e0..04a22663b4fb 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -169,6 +169,11 @@ static void efifb_show_boot_graphics(struct fb_info *info) return; } + if (bgrt_tab.status & 0x06) { + pr_info("efifb: BGRT rotation bits set, not showing boot graphics\n"); + return; + } + /* Avoid flashing the logo if we're going to print std probe messages */ if (console_loglevel > CONSOLE_LOGLEVEL_QUIET) return; @@ -448,7 +453,6 @@ static int efifb_probe(struct platform_device *dev) info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); if (!info) { - pr_err("efifb: cannot allocate framebuffer\n"); err = -ENOMEM; goto err_release_mem; } diff --git a/drivers/video/fbdev/ep93xx-fb.c b/drivers/video/fbdev/ep93xx-fb.c index 75f0db25d19f..d04a047094fc 100644 --- a/drivers/video/fbdev/ep93xx-fb.c +++ b/drivers/video/fbdev/ep93xx-fb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/ep93xx-fb.c * @@ -10,11 +11,6 @@ * * Based on the Cirrus Logic ep93xxfb driver, and various other ep93xxfb * drivers. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/platform_device.h> diff --git a/drivers/video/fbdev/fb-puv3.c b/drivers/video/fbdev/fb-puv3.c index 1bddcc20b2c0..fa62c4dff7d1 100644 --- a/drivers/video/fbdev/fb-puv3.c +++ b/drivers/video/fbdev/fb-puv3.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Frame Buffer Driver for PKUnity-v3 Unigfx * Code specific to PKUnity SoC and UniCore ISA * * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> * Copyright (C) 2001-2010 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/video/fbdev/gbefb.c b/drivers/video/fbdev/gbefb.c index 3fcb33232ba3..b9f6a82a0495 100644 --- a/drivers/video/fbdev/gbefb.c +++ b/drivers/video/fbdev/gbefb.c @@ -39,9 +39,7 @@ struct gbefb_par { int valid; }; -#ifdef CONFIG_SGI_IP32 #define GBE_BASE 0x16000000 /* SGI O2 */ -#endif /* macro for fastest write-though access to the framebuffer */ #ifdef CONFIG_MIPS @@ -51,10 +49,6 @@ struct gbefb_par { #define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_CACHABLE_NO_WA) #endif #endif -#ifdef CONFIG_X86 -#define pgprot_fb(_prot) (((_prot) & ~_PAGE_CACHE_MASK) | \ - cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS)) -#endif /* * RAM we reserve for the frame buffer. This defines the maximum screen @@ -279,7 +273,7 @@ static void gbe_turn_off(void) val = 0; SET_GBE_FIELD(VT_XY, FREEZE, val, 1); gbe->vt_xy = val; - udelay(10000); + mdelay(10); for (i = 0; i < 10000; i++) { val = gbe->vt_xy; if (GET_GBE_FIELD(VT_XY, FREEZE, val) != 1) @@ -294,7 +288,7 @@ static void gbe_turn_off(void) val = gbe->dotclock; SET_GBE_FIELD(DOTCLK, RUN, val, 0); gbe->dotclock = val; - udelay(10000); + mdelay(10); for (i = 0; i < 10000; i++) { val = gbe->dotclock; if (GET_GBE_FIELD(DOTCLK, RUN, val)) @@ -331,7 +325,7 @@ static void gbe_turn_on(void) val = gbe->dotclock; SET_GBE_FIELD(DOTCLK, RUN, val, 1); gbe->dotclock = val; - udelay(10000); + mdelay(10); for (i = 0; i < 10000; i++) { val = gbe->dotclock; if (GET_GBE_FIELD(DOTCLK, RUN, val) != 1) @@ -346,7 +340,7 @@ static void gbe_turn_on(void) val = 0; SET_GBE_FIELD(VT_XY, FREEZE, val, 0); gbe->vt_xy = val; - udelay(10000); + mdelay(10); for (i = 0; i < 10000; i++) { val = gbe->vt_xy; if (GET_GBE_FIELD(VT_XY, FREEZE, val)) @@ -547,7 +541,7 @@ static void gbe_set_timing_info(struct gbe_timing_info *timing) SET_GBE_FIELD(DOTCLK, P, val, timing->pll_p); SET_GBE_FIELD(DOTCLK, RUN, val, 0); /* do not start yet */ gbe->dotclock = val; - udelay(10000); + mdelay(10); /* setup pixel counter */ val = 0; @@ -1018,9 +1012,10 @@ static int gbefb_mmap(struct fb_info *info, /* remap using the fastest write-through mode on architecture */ /* try not polluting the cache when possible */ +#ifdef CONFIG_MIPS pgprot_val(vma->vm_page_prot) = pgprot_fb(pgprot_val(vma->vm_page_prot)); - +#endif /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */ /* look for the starting tile */ diff --git a/drivers/video/fbdev/grvga.c b/drivers/video/fbdev/grvga.c index df5d546e57e9..d22e8b0c906d 100644 --- a/drivers/video/fbdev/grvga.c +++ b/drivers/video/fbdev/grvga.c @@ -336,10 +336,8 @@ static int grvga_probe(struct platform_device *dev) char *options = NULL, *mode_opt = NULL; info = framebuffer_alloc(sizeof(struct grvga_par), &dev->dev); - if (!info) { - dev_err(&dev->dev, "framebuffer_alloc failed\n"); + if (!info) return -ENOMEM; - } /* Expecting: "grvga: modestring, [addr:<framebuffer physical address>], [size:<framebuffer size>] * diff --git a/drivers/video/fbdev/gxt4500.c b/drivers/video/fbdev/gxt4500.c index 37527a10b954..c7502fd8f447 100644 --- a/drivers/video/fbdev/gxt4500.c +++ b/drivers/video/fbdev/gxt4500.c @@ -643,10 +643,9 @@ static int gxt4500_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } info = framebuffer_alloc(sizeof(struct gxt4500_par), &pdev->dev); - if (!info) { - dev_err(&pdev->dev, "gxt4500: cannot alloc FB info record\n"); + if (!info) goto err_free_fb; - } + par = info->par; cardtype = ent->driver_data; par->refclk_ps = cardinfo[cardtype].refclk_ps; diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index 00f5bdcc6c6f..2dcb7c58b31e 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -762,10 +762,8 @@ static int hvfb_probe(struct hv_device *hdev, int ret; info = framebuffer_alloc(sizeof(struct hvfb_par), &hdev->device); - if (!info) { - pr_err("No memory for framebuffer info\n"); + if (!info) return -ENOMEM; - } par = info->par; par->info = info; diff --git a/drivers/video/fbdev/i740fb.c b/drivers/video/fbdev/i740fb.c index 24d3280a5b5f..347cf8babc3e 100644 --- a/drivers/video/fbdev/i740fb.c +++ b/drivers/video/fbdev/i740fb.c @@ -1006,10 +1006,8 @@ static int i740fb_probe(struct pci_dev *dev, const struct pci_device_id *ent) u8 *edid; info = framebuffer_alloc(sizeof(struct i740fb_par), &(dev->dev)); - if (!info) { - dev_err(&(dev->dev), "cannot allocate framebuffer\n"); + if (!info) return -ENOMEM; - } par = info->par; mutex_init(&par->open_lock); diff --git a/drivers/video/fbdev/imsttfb.c b/drivers/video/fbdev/imsttfb.c index 35bba3c2036d..58b01c7d9056 100644 --- a/drivers/video/fbdev/imsttfb.c +++ b/drivers/video/fbdev/imsttfb.c @@ -1477,11 +1477,8 @@ static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) printk(KERN_ERR "imsttfb: no OF node for pci device\n"); info = framebuffer_alloc(sizeof(struct imstt_par), &pdev->dev); - - if (!info) { - printk(KERN_ERR "imsttfb: Can't allocate memory\n"); + if (!info) return -ENOMEM; - } par = info->par; diff --git a/drivers/video/fbdev/imxfb.c b/drivers/video/fbdev/imxfb.c index c4eb8661f751..b3286d1fa543 100644 --- a/drivers/video/fbdev/imxfb.c +++ b/drivers/video/fbdev/imxfb.c @@ -974,10 +974,9 @@ static int imxfb_probe(struct platform_device *pdev) } fbi->map_size = PAGE_ALIGN(info->fix.smem_len); - info->screen_base = dma_alloc_wc(&pdev->dev, fbi->map_size, - &fbi->map_dma, GFP_KERNEL); - - if (!info->screen_base) { + info->screen_buffer = dma_alloc_wc(&pdev->dev, fbi->map_size, + &fbi->map_dma, GFP_KERNEL); + if (!info->screen_buffer) { dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret); ret = -ENOMEM; goto failed_map; @@ -1046,7 +1045,7 @@ failed_cmap: if (pdata && pdata->exit) pdata->exit(fbi->pdev); failed_platform_init: - dma_free_wc(&pdev->dev, fbi->map_size, info->screen_base, + dma_free_wc(&pdev->dev, fbi->map_size, info->screen_buffer, fbi->map_dma); failed_map: iounmap(fbi->regs); @@ -1077,7 +1076,7 @@ static int imxfb_remove(struct platform_device *pdev) pdata = dev_get_platdata(&pdev->dev); if (pdata && pdata->exit) pdata->exit(fbi->pdev); - dma_free_wc(&pdev->dev, fbi->map_size, info->screen_base, + dma_free_wc(&pdev->dev, fbi->map_size, info->screen_buffer, fbi->map_dma); iounmap(fbi->regs); release_mem_region(res->start, resource_size(res)); diff --git a/drivers/video/fbdev/intelfb/intelfbdrv.c b/drivers/video/fbdev/intelfb/intelfbdrv.c index d7463a2a5d83..a76c61512c60 100644 --- a/drivers/video/fbdev/intelfb/intelfbdrv.c +++ b/drivers/video/fbdev/intelfb/intelfbdrv.c @@ -491,10 +491,9 @@ static int intelfb_pci_register(struct pci_dev *pdev, } info = framebuffer_alloc(sizeof(struct intelfb_info), &pdev->dev); - if (!info) { - ERR_MSG("Could not allocate memory for intelfb_info.\n"); - return -ENODEV; - } + if (!info) + return -ENOMEM; + if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) { ERR_MSG("Could not allocate cmap for intelfb_info.\n"); goto err_out_cmap; diff --git a/drivers/video/fbdev/jz4740_fb.c b/drivers/video/fbdev/jz4740_fb.c index 145095655cc2..0b6fa25f6924 100644 --- a/drivers/video/fbdev/jz4740_fb.c +++ b/drivers/video/fbdev/jz4740_fb.c @@ -457,7 +457,6 @@ static int jzfb_alloc_devmem(struct jzfb *jzfb) { int max_videosize = 0; struct fb_videomode *mode = jzfb->pdata->modes; - void *page; int i; for (i = 0; i < jzfb->pdata->num_modes; ++mode, ++i) { @@ -482,12 +481,6 @@ static int jzfb_alloc_devmem(struct jzfb *jzfb) if (!jzfb->vidmem) goto err_free_framedesc; - for (page = jzfb->vidmem; - page < jzfb->vidmem + PAGE_ALIGN(jzfb->vidmem_size); - page += PAGE_SIZE) { - SetPageReserved(virt_to_page(page)); - } - jzfb->framedesc->next = jzfb->framedesc_phys; jzfb->framedesc->addr = jzfb->vidmem_phys; jzfb->framedesc->id = 0xdeafbead; @@ -535,10 +528,8 @@ static int jzfb_probe(struct platform_device *pdev) } fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev); - if (!fb) { - dev_err(&pdev->dev, "Failed to allocate framebuffer device\n"); + if (!fb) return -ENOMEM; - } fb->fbops = &jzfb_ops; fb->flags = FBINFO_DEFAULT; diff --git a/drivers/video/fbdev/mb862xx/mb862xx-i2c.c b/drivers/video/fbdev/mb862xx/mb862xx-i2c.c index ba96c44f2761..ffdb1597d303 100644 --- a/drivers/video/fbdev/mb862xx/mb862xx-i2c.c +++ b/drivers/video/fbdev/mb862xx/mb862xx-i2c.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Coral-P(A)/Lime I2C adapter driver * * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/fb.h> diff --git a/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c b/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c index 8dd296d257dd..f58ff900e82a 100644 --- a/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c +++ b/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/mb862xx/mb862xxfb_accel.c * @@ -6,11 +7,6 @@ * (C) 2007 Alexander Shishkin <virtuoso@slind.org> * (C) 2009 Valentin Sitdikov <v.sitdikov@gmail.com> * (C) 2009 Siemens AG - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/fb.h> #include <linux/delay.h> diff --git a/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c b/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c index cd372527c9e4..962c0171d271 100644 --- a/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c +++ b/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/mb862xx/mb862xxfb.c * @@ -5,11 +6,6 @@ * * (C) 2008 Anatolij Gustschin <agust@denx.de> * DENX Software Engineering - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #undef DEBUG @@ -684,10 +680,8 @@ static int of_platform_mb862xx_probe(struct platform_device *ofdev) } info = framebuffer_alloc(sizeof(struct mb862xxfb_par), dev); - if (info == NULL) { - dev_err(dev, "cannot allocate framebuffer\n"); + if (!info) return -ENOMEM; - } par = info->par; par->info = info; @@ -1009,7 +1003,6 @@ static int mb862xx_pci_probe(struct pci_dev *pdev, info = framebuffer_alloc(sizeof(struct mb862xxfb_par), dev); if (!info) { - dev_err(dev, "framebuffer alloc failed\n"); ret = -ENOMEM; goto dis_dev; } diff --git a/drivers/video/fbdev/mbx/mbxfb.c b/drivers/video/fbdev/mbx/mbxfb.c index 6ded480a69b4..50935252b50b 100644 --- a/drivers/video/fbdev/mbx/mbxfb.c +++ b/drivers/video/fbdev/mbx/mbxfb.c @@ -899,10 +899,8 @@ static int mbxfb_probe(struct platform_device *dev) } fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev); - if (fbi == NULL) { - dev_err(&dev->dev, "framebuffer_alloc failed\n"); + if (!fbi) return -ENOMEM; - } mfbi = fbi->par; fbi->pseudo_palette = mfbi->pseudo_palette; diff --git a/drivers/video/fbdev/mmp/hw/mmp_ctrl.c b/drivers/video/fbdev/mmp/hw/mmp_ctrl.c index 87d943f15a12..17174cd7a5bb 100644 --- a/drivers/video/fbdev/mmp/hw/mmp_ctrl.c +++ b/drivers/video/fbdev/mmp/hw/mmp_ctrl.c @@ -433,7 +433,7 @@ static int mmphw_probe(struct platform_device *pdev) { struct mmp_mach_plat_info *mi; struct resource *res; - int ret, i, size, irq; + int ret, i, irq; struct mmphw_path_plat *path_plat; struct mmphw_ctrl *ctrl = NULL; @@ -461,9 +461,9 @@ static int mmphw_probe(struct platform_device *pdev) } /* allocate */ - size = sizeof(struct mmphw_ctrl) + sizeof(struct mmphw_path_plat) * - mi->path_num; - ctrl = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + ctrl = devm_kzalloc(&pdev->dev, + struct_size(ctrl, path_plats, mi->path_num), + GFP_KERNEL); if (!ctrl) { ret = -ENOMEM; goto failed; diff --git a/drivers/video/fbdev/mx3fb.c b/drivers/video/fbdev/mx3fb.c index 1c3c7ab26a95..bafd5f5fac5a 100644 --- a/drivers/video/fbdev/mx3fb.c +++ b/drivers/video/fbdev/mx3fb.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2008 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de> * * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/video/fbdev/mxsfb.c b/drivers/video/fbdev/mxsfb.c deleted file mode 100644 index d8bebe35b410..000000000000 --- a/drivers/video/fbdev/mxsfb.c +++ /dev/null @@ -1,1028 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2010 Juergen Beisert, Pengutronix - * - * This code is based on: - * Author: Vitaly Wool <vital@embeddedalley.com> - * - * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. - */ - -#define DRIVER_NAME "mxsfb" - -/** - * @file - * @brief LCDIF driver for i.MX23 and i.MX28 - * - * The LCDIF support four modes of operation - * - MPU interface (to drive smart displays) -> not supported yet - * - VSYNC interface (like MPU interface plus Vsync) -> not supported yet - * - Dotclock interface (to drive LC displays with RGB data and sync signals) - * - DVI (to drive ITU-R BT656) -> not supported yet - * - * This driver depends on a correct setup of the pins used for this purpose - * (platform specific). - * - * For the developer: Don't forget to set the data bus width to the display - * in the imx_fb_videomode structure. You will else end up with ugly colours. - * If you fight against jitter you can vary the clock delay. This is a feature - * of the i.MX28 and you can vary it between 2 ns ... 8 ns in 2 ns steps. Give - * the required value in the imx_fb_videomode structure. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/of_device.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/dma-mapping.h> -#include <linux/io.h> -#include <linux/fb.h> -#include <linux/regulator/consumer.h> -#include <video/of_display_timing.h> -#include <video/of_videomode.h> -#include <video/videomode.h> - -#define REG_SET 4 -#define REG_CLR 8 - -#define LCDC_CTRL 0x00 -#define LCDC_CTRL1 0x10 -#define LCDC_V4_CTRL2 0x20 -#define LCDC_V3_TRANSFER_COUNT 0x20 -#define LCDC_V4_TRANSFER_COUNT 0x30 -#define LCDC_V4_CUR_BUF 0x40 -#define LCDC_V4_NEXT_BUF 0x50 -#define LCDC_V3_CUR_BUF 0x30 -#define LCDC_V3_NEXT_BUF 0x40 -#define LCDC_TIMING 0x60 -#define LCDC_VDCTRL0 0x70 -#define LCDC_VDCTRL1 0x80 -#define LCDC_VDCTRL2 0x90 -#define LCDC_VDCTRL3 0xa0 -#define LCDC_VDCTRL4 0xb0 -#define LCDC_DVICTRL0 0xc0 -#define LCDC_DVICTRL1 0xd0 -#define LCDC_DVICTRL2 0xe0 -#define LCDC_DVICTRL3 0xf0 -#define LCDC_DVICTRL4 0x100 -#define LCDC_V4_DATA 0x180 -#define LCDC_V3_DATA 0x1b0 -#define LCDC_V4_DEBUG0 0x1d0 -#define LCDC_V3_DEBUG0 0x1f0 - -#define CTRL_SFTRST (1 << 31) -#define CTRL_CLKGATE (1 << 30) -#define CTRL_BYPASS_COUNT (1 << 19) -#define CTRL_VSYNC_MODE (1 << 18) -#define CTRL_DOTCLK_MODE (1 << 17) -#define CTRL_DATA_SELECT (1 << 16) -#define CTRL_SET_BUS_WIDTH(x) (((x) & 0x3) << 10) -#define CTRL_GET_BUS_WIDTH(x) (((x) >> 10) & 0x3) -#define CTRL_SET_WORD_LENGTH(x) (((x) & 0x3) << 8) -#define CTRL_GET_WORD_LENGTH(x) (((x) >> 8) & 0x3) -#define CTRL_MASTER (1 << 5) -#define CTRL_DF16 (1 << 3) -#define CTRL_DF18 (1 << 2) -#define CTRL_DF24 (1 << 1) -#define CTRL_RUN (1 << 0) - -#define CTRL1_FIFO_CLEAR (1 << 21) -#define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16) -#define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf) - -#define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16) -#define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff) -#define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff) -#define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff) - - -#define VDCTRL0_ENABLE_PRESENT (1 << 28) -#define VDCTRL0_VSYNC_ACT_HIGH (1 << 27) -#define VDCTRL0_HSYNC_ACT_HIGH (1 << 26) -#define VDCTRL0_DOTCLK_ACT_FALLING (1 << 25) -#define VDCTRL0_ENABLE_ACT_HIGH (1 << 24) -#define VDCTRL0_VSYNC_PERIOD_UNIT (1 << 21) -#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT (1 << 20) -#define VDCTRL0_HALF_LINE (1 << 19) -#define VDCTRL0_HALF_LINE_MODE (1 << 18) -#define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff) -#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff) - -#define VDCTRL2_SET_HSYNC_PERIOD(x) ((x) & 0x3ffff) -#define VDCTRL2_GET_HSYNC_PERIOD(x) ((x) & 0x3ffff) - -#define VDCTRL3_MUX_SYNC_SIGNALS (1 << 29) -#define VDCTRL3_VSYNC_ONLY (1 << 28) -#define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16) -#define GET_HOR_WAIT_CNT(x) (((x) >> 16) & 0xfff) -#define SET_VERT_WAIT_CNT(x) ((x) & 0xffff) -#define GET_VERT_WAIT_CNT(x) ((x) & 0xffff) - -#define VDCTRL4_SET_DOTCLK_DLY(x) (((x) & 0x7) << 29) /* v4 only */ -#define VDCTRL4_GET_DOTCLK_DLY(x) (((x) >> 29) & 0x7) /* v4 only */ -#define VDCTRL4_SYNC_SIGNALS_ON (1 << 18) -#define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff) - -#define DEBUG0_HSYNC (1 < 26) -#define DEBUG0_VSYNC (1 < 25) - -#define MIN_XRES 120 -#define MIN_YRES 120 - -#define RED 0 -#define GREEN 1 -#define BLUE 2 -#define TRANSP 3 - -#define STMLCDIF_8BIT 1 /** pixel data bus to the display is of 8 bit width */ -#define STMLCDIF_16BIT 0 /** pixel data bus to the display is of 16 bit width */ -#define STMLCDIF_18BIT 2 /** pixel data bus to the display is of 18 bit width */ -#define STMLCDIF_24BIT 3 /** pixel data bus to the display is of 24 bit width */ - -#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT (1 << 6) -#define MXSFB_SYNC_DOTCLK_FALLING_ACT (1 << 7) /* negative edge sampling */ - -enum mxsfb_devtype { - MXSFB_V3, - MXSFB_V4, -}; - -/* CPU dependent register offsets */ -struct mxsfb_devdata { - unsigned transfer_count; - unsigned cur_buf; - unsigned next_buf; - unsigned debug0; - unsigned hs_wdth_mask; - unsigned hs_wdth_shift; - unsigned ipversion; -}; - -struct mxsfb_info { - struct platform_device *pdev; - struct clk *clk; - struct clk *clk_axi; - struct clk *clk_disp_axi; - void __iomem *base; /* registers */ - unsigned allocated_size; - int enabled; - unsigned ld_intf_width; - unsigned dotclk_delay; - const struct mxsfb_devdata *devdata; - u32 sync; - struct regulator *reg_lcd; - int pre_init; -}; - -#define mxsfb_is_v3(host) (host->devdata->ipversion == 3) -#define mxsfb_is_v4(host) (host->devdata->ipversion == 4) - -static const struct mxsfb_devdata mxsfb_devdata[] = { - [MXSFB_V3] = { - .transfer_count = LCDC_V3_TRANSFER_COUNT, - .cur_buf = LCDC_V3_CUR_BUF, - .next_buf = LCDC_V3_NEXT_BUF, - .debug0 = LCDC_V3_DEBUG0, - .hs_wdth_mask = 0xff, - .hs_wdth_shift = 24, - .ipversion = 3, - }, - [MXSFB_V4] = { - .transfer_count = LCDC_V4_TRANSFER_COUNT, - .cur_buf = LCDC_V4_CUR_BUF, - .next_buf = LCDC_V4_NEXT_BUF, - .debug0 = LCDC_V4_DEBUG0, - .hs_wdth_mask = 0x3fff, - .hs_wdth_shift = 18, - .ipversion = 4, - }, -}; - -/* mask and shift depends on architecture */ -static inline u32 set_hsync_pulse_width(struct mxsfb_info *host, unsigned val) -{ - return (val & host->devdata->hs_wdth_mask) << - host->devdata->hs_wdth_shift; -} - -static inline u32 get_hsync_pulse_width(struct mxsfb_info *host, unsigned val) -{ - return (val >> host->devdata->hs_wdth_shift) & - host->devdata->hs_wdth_mask; -} - -static const struct fb_bitfield def_rgb565[] = { - [RED] = { - .offset = 11, - .length = 5, - }, - [GREEN] = { - .offset = 5, - .length = 6, - }, - [BLUE] = { - .offset = 0, - .length = 5, - }, - [TRANSP] = { /* no support for transparency */ - .length = 0, - } -}; - -static const struct fb_bitfield def_rgb888[] = { - [RED] = { - .offset = 16, - .length = 8, - }, - [GREEN] = { - .offset = 8, - .length = 8, - }, - [BLUE] = { - .offset = 0, - .length = 8, - }, - [TRANSP] = { /* no support for transparency */ - .length = 0, - } -}; - -static inline unsigned chan_to_field(unsigned chan, struct fb_bitfield *bf) -{ - chan &= 0xffff; - chan >>= 16 - bf->length; - return chan << bf->offset; -} - -static int mxsfb_check_var(struct fb_var_screeninfo *var, - struct fb_info *fb_info) -{ - struct mxsfb_info *host = fb_info->par; - const struct fb_bitfield *rgb = NULL; - - if (var->xres < MIN_XRES) - var->xres = MIN_XRES; - if (var->yres < MIN_YRES) - var->yres = MIN_YRES; - - var->xres_virtual = var->xres; - - var->yres_virtual = var->yres; - - switch (var->bits_per_pixel) { - case 16: - /* always expect RGB 565 */ - rgb = def_rgb565; - break; - case 32: - switch (host->ld_intf_width) { - case STMLCDIF_8BIT: - pr_debug("Unsupported LCD bus width mapping\n"); - break; - case STMLCDIF_16BIT: - case STMLCDIF_18BIT: - case STMLCDIF_24BIT: - /* real 24 bit */ - rgb = def_rgb888; - break; - } - break; - default: - pr_err("Unsupported colour depth: %u\n", var->bits_per_pixel); - return -EINVAL; - } - - /* - * Copy the RGB parameters for this display - * from the machine specific parameters. - */ - var->red = rgb[RED]; - var->green = rgb[GREEN]; - var->blue = rgb[BLUE]; - var->transp = rgb[TRANSP]; - - return 0; -} - -static inline void mxsfb_enable_axi_clk(struct mxsfb_info *host) -{ - if (host->clk_axi) - clk_prepare_enable(host->clk_axi); -} - -static inline void mxsfb_disable_axi_clk(struct mxsfb_info *host) -{ - if (host->clk_axi) - clk_disable_unprepare(host->clk_axi); -} - -static void mxsfb_enable_controller(struct fb_info *fb_info) -{ - struct mxsfb_info *host = fb_info->par; - u32 reg; - int ret; - - dev_dbg(&host->pdev->dev, "%s\n", __func__); - - if (host->reg_lcd) { - ret = regulator_enable(host->reg_lcd); - if (ret) { - dev_err(&host->pdev->dev, - "lcd regulator enable failed: %d\n", ret); - return; - } - } - - if (host->clk_disp_axi) - clk_prepare_enable(host->clk_disp_axi); - clk_prepare_enable(host->clk); - clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U); - - mxsfb_enable_axi_clk(host); - - /* if it was disabled, re-enable the mode again */ - writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET); - - /* enable the SYNC signals first, then the DMA engine */ - reg = readl(host->base + LCDC_VDCTRL4); - reg |= VDCTRL4_SYNC_SIGNALS_ON; - writel(reg, host->base + LCDC_VDCTRL4); - - writel(CTRL_RUN, host->base + LCDC_CTRL + REG_SET); - - host->enabled = 1; -} - -static void mxsfb_disable_controller(struct fb_info *fb_info) -{ - struct mxsfb_info *host = fb_info->par; - unsigned loop; - u32 reg; - int ret; - - dev_dbg(&host->pdev->dev, "%s\n", __func__); - - /* - * Even if we disable the controller here, it will still continue - * until its FIFOs are running out of data - */ - writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_CLR); - - loop = 1000; - while (loop) { - reg = readl(host->base + LCDC_CTRL); - if (!(reg & CTRL_RUN)) - break; - loop--; - } - - reg = readl(host->base + LCDC_VDCTRL4); - writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4); - - mxsfb_disable_axi_clk(host); - - clk_disable_unprepare(host->clk); - if (host->clk_disp_axi) - clk_disable_unprepare(host->clk_disp_axi); - - host->enabled = 0; - - if (host->reg_lcd) { - ret = regulator_disable(host->reg_lcd); - if (ret) - dev_err(&host->pdev->dev, - "lcd regulator disable failed: %d\n", ret); - } -} - -static int mxsfb_set_par(struct fb_info *fb_info) -{ - struct mxsfb_info *host = fb_info->par; - u32 ctrl, vdctrl0, vdctrl4; - int line_size, fb_size; - int reenable = 0; - - line_size = fb_info->var.xres * (fb_info->var.bits_per_pixel >> 3); - fb_size = fb_info->var.yres_virtual * line_size; - - if (fb_size > fb_info->fix.smem_len) - return -ENOMEM; - - fb_info->fix.line_length = line_size; - - if (host->pre_init) { - mxsfb_enable_controller(fb_info); - host->pre_init = 0; - return 0; - } - - /* - * It seems, you can't re-program the controller if it is still running. - * This may lead into shifted pictures (FIFO issue?). - * So, first stop the controller and drain its FIFOs - */ - if (host->enabled) { - reenable = 1; - mxsfb_disable_controller(fb_info); - } - - mxsfb_enable_axi_clk(host); - - /* clear the FIFOs */ - writel(CTRL1_FIFO_CLEAR, host->base + LCDC_CTRL1 + REG_SET); - - ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER | - CTRL_SET_BUS_WIDTH(host->ld_intf_width); - - switch (fb_info->var.bits_per_pixel) { - case 16: - dev_dbg(&host->pdev->dev, "Setting up RGB565 mode\n"); - ctrl |= CTRL_SET_WORD_LENGTH(0); - writel(CTRL1_SET_BYTE_PACKAGING(0xf), host->base + LCDC_CTRL1); - break; - case 32: - dev_dbg(&host->pdev->dev, "Setting up RGB888/666 mode\n"); - ctrl |= CTRL_SET_WORD_LENGTH(3); - switch (host->ld_intf_width) { - case STMLCDIF_8BIT: - mxsfb_disable_axi_clk(host); - dev_err(&host->pdev->dev, - "Unsupported LCD bus width mapping\n"); - return -EINVAL; - case STMLCDIF_16BIT: - case STMLCDIF_18BIT: - case STMLCDIF_24BIT: - /* real 24 bit */ - break; - } - /* do not use packed pixels = one pixel per word instead */ - writel(CTRL1_SET_BYTE_PACKAGING(0x7), host->base + LCDC_CTRL1); - break; - default: - mxsfb_disable_axi_clk(host); - dev_err(&host->pdev->dev, "Unhandled color depth of %u\n", - fb_info->var.bits_per_pixel); - return -EINVAL; - } - - writel(ctrl, host->base + LCDC_CTRL); - - writel(TRANSFER_COUNT_SET_VCOUNT(fb_info->var.yres) | - TRANSFER_COUNT_SET_HCOUNT(fb_info->var.xres), - host->base + host->devdata->transfer_count); - - vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* always in DOTCLOCK mode */ - VDCTRL0_VSYNC_PERIOD_UNIT | - VDCTRL0_VSYNC_PULSE_WIDTH_UNIT | - VDCTRL0_SET_VSYNC_PULSE_WIDTH(fb_info->var.vsync_len); - if (fb_info->var.sync & FB_SYNC_HOR_HIGH_ACT) - vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH; - if (fb_info->var.sync & FB_SYNC_VERT_HIGH_ACT) - vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH; - if (host->sync & MXSFB_SYNC_DATA_ENABLE_HIGH_ACT) - vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH; - if (host->sync & MXSFB_SYNC_DOTCLK_FALLING_ACT) - vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING; - - writel(vdctrl0, host->base + LCDC_VDCTRL0); - - /* frame length in lines */ - writel(fb_info->var.upper_margin + fb_info->var.vsync_len + - fb_info->var.lower_margin + fb_info->var.yres, - host->base + LCDC_VDCTRL1); - - /* line length in units of clocks or pixels */ - writel(set_hsync_pulse_width(host, fb_info->var.hsync_len) | - VDCTRL2_SET_HSYNC_PERIOD(fb_info->var.left_margin + - fb_info->var.hsync_len + fb_info->var.right_margin + - fb_info->var.xres), - host->base + LCDC_VDCTRL2); - - writel(SET_HOR_WAIT_CNT(fb_info->var.left_margin + - fb_info->var.hsync_len) | - SET_VERT_WAIT_CNT(fb_info->var.upper_margin + - fb_info->var.vsync_len), - host->base + LCDC_VDCTRL3); - - vdctrl4 = SET_DOTCLK_H_VALID_DATA_CNT(fb_info->var.xres); - if (mxsfb_is_v4(host)) - vdctrl4 |= VDCTRL4_SET_DOTCLK_DLY(host->dotclk_delay); - writel(vdctrl4, host->base + LCDC_VDCTRL4); - - writel(fb_info->fix.smem_start + - fb_info->fix.line_length * fb_info->var.yoffset, - host->base + host->devdata->next_buf); - - mxsfb_disable_axi_clk(host); - - if (reenable) - mxsfb_enable_controller(fb_info); - - return 0; -} - -static int mxsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *fb_info) -{ - unsigned int val; - int ret = -EINVAL; - - /* - * If greyscale is true, then we convert the RGB value - * to greyscale no matter what visual we are using. - */ - if (fb_info->var.grayscale) - red = green = blue = (19595 * red + 38470 * green + - 7471 * blue) >> 16; - - switch (fb_info->fix.visual) { - case FB_VISUAL_TRUECOLOR: - /* - * 12 or 16-bit True Colour. We encode the RGB value - * according to the RGB bitfield information. - */ - if (regno < 16) { - u32 *pal = fb_info->pseudo_palette; - - val = chan_to_field(red, &fb_info->var.red); - val |= chan_to_field(green, &fb_info->var.green); - val |= chan_to_field(blue, &fb_info->var.blue); - - pal[regno] = val; - ret = 0; - } - break; - - case FB_VISUAL_STATIC_PSEUDOCOLOR: - case FB_VISUAL_PSEUDOCOLOR: - break; - } - - return ret; -} - -static int mxsfb_blank(int blank, struct fb_info *fb_info) -{ - struct mxsfb_info *host = fb_info->par; - - switch (blank) { - case FB_BLANK_POWERDOWN: - case FB_BLANK_VSYNC_SUSPEND: - case FB_BLANK_HSYNC_SUSPEND: - case FB_BLANK_NORMAL: - if (host->enabled) - mxsfb_disable_controller(fb_info); - break; - - case FB_BLANK_UNBLANK: - if (!host->enabled) - mxsfb_enable_controller(fb_info); - break; - } - return 0; -} - -static int mxsfb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *fb_info) -{ - struct mxsfb_info *host = fb_info->par; - unsigned offset; - - if (var->xoffset != 0) - return -EINVAL; - - offset = fb_info->fix.line_length * var->yoffset; - - mxsfb_enable_axi_clk(host); - - /* update on next VSYNC */ - writel(fb_info->fix.smem_start + offset, - host->base + host->devdata->next_buf); - - mxsfb_disable_axi_clk(host); - - return 0; -} - -static struct fb_ops mxsfb_ops = { - .owner = THIS_MODULE, - .fb_check_var = mxsfb_check_var, - .fb_set_par = mxsfb_set_par, - .fb_setcolreg = mxsfb_setcolreg, - .fb_blank = mxsfb_blank, - .fb_pan_display = mxsfb_pan_display, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, -}; - -static int mxsfb_restore_mode(struct fb_info *fb_info, - struct fb_videomode *vmode) -{ - struct mxsfb_info *host = fb_info->par; - unsigned period; - unsigned long pa, fbsize; - int bits_per_pixel, ofs, ret = 0; - u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl; - - mxsfb_enable_axi_clk(host); - - /* Only restore the mode when the controller is running */ - ctrl = readl(host->base + LCDC_CTRL); - if (!(ctrl & CTRL_RUN)) { - ret = -EINVAL; - goto err; - } - - vdctrl0 = readl(host->base + LCDC_VDCTRL0); - vdctrl2 = readl(host->base + LCDC_VDCTRL2); - vdctrl3 = readl(host->base + LCDC_VDCTRL3); - vdctrl4 = readl(host->base + LCDC_VDCTRL4); - - transfer_count = readl(host->base + host->devdata->transfer_count); - - vmode->xres = TRANSFER_COUNT_GET_HCOUNT(transfer_count); - vmode->yres = TRANSFER_COUNT_GET_VCOUNT(transfer_count); - - switch (CTRL_GET_WORD_LENGTH(ctrl)) { - case 0: - bits_per_pixel = 16; - break; - case 3: - bits_per_pixel = 32; - break; - case 1: - default: - ret = -EINVAL; - goto err; - } - - fb_info->var.bits_per_pixel = bits_per_pixel; - - vmode->pixclock = KHZ2PICOS(clk_get_rate(host->clk) / 1000U); - vmode->hsync_len = get_hsync_pulse_width(host, vdctrl2); - vmode->left_margin = GET_HOR_WAIT_CNT(vdctrl3) - vmode->hsync_len; - vmode->right_margin = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2) - - vmode->hsync_len - vmode->left_margin - vmode->xres; - vmode->vsync_len = VDCTRL0_GET_VSYNC_PULSE_WIDTH(vdctrl0); - period = readl(host->base + LCDC_VDCTRL1); - vmode->upper_margin = GET_VERT_WAIT_CNT(vdctrl3) - vmode->vsync_len; - vmode->lower_margin = period - vmode->vsync_len - - vmode->upper_margin - vmode->yres; - - vmode->vmode = FB_VMODE_NONINTERLACED; - - vmode->sync = 0; - if (vdctrl0 & VDCTRL0_HSYNC_ACT_HIGH) - vmode->sync |= FB_SYNC_HOR_HIGH_ACT; - if (vdctrl0 & VDCTRL0_VSYNC_ACT_HIGH) - vmode->sync |= FB_SYNC_VERT_HIGH_ACT; - - pr_debug("Reconstructed video mode:\n"); - pr_debug("%dx%d, hsync: %u left: %u, right: %u, vsync: %u, upper: %u, lower: %u\n", - vmode->xres, vmode->yres, vmode->hsync_len, vmode->left_margin, - vmode->right_margin, vmode->vsync_len, vmode->upper_margin, - vmode->lower_margin); - pr_debug("pixclk: %ldkHz\n", PICOS2KHZ(vmode->pixclock)); - - host->ld_intf_width = CTRL_GET_BUS_WIDTH(ctrl); - host->dotclk_delay = VDCTRL4_GET_DOTCLK_DLY(vdctrl4); - - fb_info->fix.line_length = vmode->xres * (bits_per_pixel >> 3); - - pa = readl(host->base + host->devdata->cur_buf); - fbsize = fb_info->fix.line_length * vmode->yres; - if (pa < fb_info->fix.smem_start) { - ret = -EINVAL; - goto err; - } - if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len) { - ret = -EINVAL; - goto err; - } - ofs = pa - fb_info->fix.smem_start; - if (ofs) { - memmove(fb_info->screen_base, fb_info->screen_base + ofs, fbsize); - writel(fb_info->fix.smem_start, host->base + host->devdata->next_buf); - } - - fb_info->fix.ypanstep = 1; - - clk_prepare_enable(host->clk); - host->enabled = 1; - -err: - if (ret) - mxsfb_disable_axi_clk(host); - - return ret; -} - -static int mxsfb_init_fbinfo_dt(struct fb_info *fb_info, - struct fb_videomode *vmode) -{ - struct mxsfb_info *host = fb_info->par; - struct fb_var_screeninfo *var = &fb_info->var; - struct device *dev = &host->pdev->dev; - struct device_node *np = host->pdev->dev.of_node; - struct device_node *display_np; - struct videomode vm; - u32 width; - int ret; - - display_np = of_parse_phandle(np, "display", 0); - if (!display_np) { - dev_err(dev, "failed to find display phandle\n"); - return -ENOENT; - } - - ret = of_property_read_u32(display_np, "bus-width", &width); - if (ret < 0) { - dev_err(dev, "failed to get property bus-width\n"); - goto put_display_node; - } - - switch (width) { - case 8: - host->ld_intf_width = STMLCDIF_8BIT; - break; - case 16: - host->ld_intf_width = STMLCDIF_16BIT; - break; - case 18: - host->ld_intf_width = STMLCDIF_18BIT; - break; - case 24: - host->ld_intf_width = STMLCDIF_24BIT; - break; - default: - dev_err(dev, "invalid bus-width value\n"); - ret = -EINVAL; - goto put_display_node; - } - - ret = of_property_read_u32(display_np, "bits-per-pixel", - &var->bits_per_pixel); - if (ret < 0) { - dev_err(dev, "failed to get property bits-per-pixel\n"); - goto put_display_node; - } - - ret = of_get_videomode(display_np, &vm, OF_USE_NATIVE_MODE); - if (ret) { - dev_err(dev, "failed to get videomode from DT\n"); - goto put_display_node; - } - - ret = fb_videomode_from_videomode(&vm, vmode); - if (ret < 0) - goto put_display_node; - - if (vm.flags & DISPLAY_FLAGS_DE_HIGH) - host->sync |= MXSFB_SYNC_DATA_ENABLE_HIGH_ACT; - - /* - * The PIXDATA flags of the display_flags enum are controller - * centric, e.g. NEGEDGE means drive data on negative edge. - * However, the drivers flag is display centric: Sample the - * data on negative (falling) edge. Therefore, check for the - * POSEDGE flag: - * drive on positive edge => sample on negative edge - */ - if (vm.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE) - host->sync |= MXSFB_SYNC_DOTCLK_FALLING_ACT; - -put_display_node: - of_node_put(display_np); - return ret; -} - -static int mxsfb_init_fbinfo(struct fb_info *fb_info, - struct fb_videomode *vmode) -{ - int ret; - struct mxsfb_info *host = fb_info->par; - struct device *dev = &host->pdev->dev; - struct fb_var_screeninfo *var = &fb_info->var; - dma_addr_t fb_phys; - void *fb_virt; - unsigned fb_size; - - fb_info->fbops = &mxsfb_ops; - fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST; - strlcpy(fb_info->fix.id, "mxs", sizeof(fb_info->fix.id)); - fb_info->fix.type = FB_TYPE_PACKED_PIXELS; - fb_info->fix.ypanstep = 1; - fb_info->fix.visual = FB_VISUAL_TRUECOLOR, - fb_info->fix.accel = FB_ACCEL_NONE; - - ret = mxsfb_init_fbinfo_dt(fb_info, vmode); - if (ret) - return ret; - - var->nonstd = 0; - var->activate = FB_ACTIVATE_NOW; - var->accel_flags = 0; - var->vmode = FB_VMODE_NONINTERLACED; - - /* Memory allocation for framebuffer */ - fb_size = SZ_2M; - fb_virt = dma_alloc_wc(dev, PAGE_ALIGN(fb_size), &fb_phys, GFP_KERNEL); - if (!fb_virt) - return -ENOMEM; - - fb_info->fix.smem_start = fb_phys; - fb_info->screen_base = fb_virt; - fb_info->screen_size = fb_info->fix.smem_len = fb_size; - - if (mxsfb_restore_mode(fb_info, vmode)) - memset(fb_virt, 0, fb_size); - - return 0; -} - -static void mxsfb_free_videomem(struct fb_info *fb_info) -{ - struct mxsfb_info *host = fb_info->par; - struct device *dev = &host->pdev->dev; - - dma_free_wc(dev, fb_info->screen_size, fb_info->screen_base, - fb_info->fix.smem_start); -} - -static const struct platform_device_id mxsfb_devtype[] = { - { - .name = "imx23-fb", - .driver_data = MXSFB_V3, - }, { - .name = "imx28-fb", - .driver_data = MXSFB_V4, - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(platform, mxsfb_devtype); - -static const struct of_device_id mxsfb_dt_ids[] = { - { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devtype[0], }, - { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devtype[1], }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, mxsfb_dt_ids); - -static int mxsfb_probe(struct platform_device *pdev) -{ - const struct of_device_id *of_id = - of_match_device(mxsfb_dt_ids, &pdev->dev); - struct resource *res; - struct mxsfb_info *host; - struct fb_info *fb_info; - struct fb_videomode *mode; - int ret; - - if (of_id) - pdev->id_entry = of_id->data; - - fb_info = framebuffer_alloc(sizeof(struct mxsfb_info), &pdev->dev); - if (!fb_info) { - dev_err(&pdev->dev, "Failed to allocate fbdev\n"); - return -ENOMEM; - } - - mode = devm_kzalloc(&pdev->dev, sizeof(struct fb_videomode), - GFP_KERNEL); - if (mode == NULL) - return -ENOMEM; - - host = fb_info->par; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - host->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(host->base)) { - ret = PTR_ERR(host->base); - goto fb_release; - } - - host->pdev = pdev; - platform_set_drvdata(pdev, host); - - host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data]; - - host->clk = devm_clk_get(&host->pdev->dev, NULL); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - goto fb_release; - } - - host->clk_axi = devm_clk_get(&host->pdev->dev, "axi"); - if (IS_ERR(host->clk_axi)) - host->clk_axi = NULL; - - host->clk_disp_axi = devm_clk_get(&host->pdev->dev, "disp_axi"); - if (IS_ERR(host->clk_disp_axi)) - host->clk_disp_axi = NULL; - - host->reg_lcd = devm_regulator_get(&pdev->dev, "lcd"); - if (IS_ERR(host->reg_lcd)) - host->reg_lcd = NULL; - -#if defined(CONFIG_FB_PRE_INIT_FB) - host->pre_init = 1; -#endif - - fb_info->pseudo_palette = devm_kcalloc(&pdev->dev, 16, sizeof(u32), - GFP_KERNEL); - if (!fb_info->pseudo_palette) { - ret = -ENOMEM; - goto fb_release; - } - - ret = mxsfb_init_fbinfo(fb_info, mode); - if (ret != 0) - goto fb_release; - - fb_videomode_to_var(&fb_info->var, mode); - - /* init the color fields */ - mxsfb_check_var(&fb_info->var, fb_info); - - platform_set_drvdata(pdev, fb_info); - - ret = register_framebuffer(fb_info); - if (ret != 0) { - dev_err(&pdev->dev,"Failed to register framebuffer\n"); - goto fb_destroy; - } - - if (!host->enabled) { - mxsfb_enable_axi_clk(host); - writel(0, host->base + LCDC_CTRL); - mxsfb_disable_axi_clk(host); - mxsfb_set_par(fb_info); - mxsfb_enable_controller(fb_info); - } - - host->pre_init = 0; - dev_info(&pdev->dev, "initialized\n"); - - return 0; - -fb_destroy: - if (host->enabled) - clk_disable_unprepare(host->clk); -fb_release: - framebuffer_release(fb_info); - - return ret; -} - -static int mxsfb_remove(struct platform_device *pdev) -{ - struct fb_info *fb_info = platform_get_drvdata(pdev); - struct mxsfb_info *host = fb_info->par; - - if (host->enabled) - mxsfb_disable_controller(fb_info); - - unregister_framebuffer(fb_info); - mxsfb_free_videomem(fb_info); - - framebuffer_release(fb_info); - - return 0; -} - -static void mxsfb_shutdown(struct platform_device *pdev) -{ - struct fb_info *fb_info = platform_get_drvdata(pdev); - struct mxsfb_info *host = fb_info->par; - - mxsfb_enable_axi_clk(host); - - /* - * Force stop the LCD controller as keeping it running during reboot - * might interfere with the BootROM's boot mode pads sampling. - */ - writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR); - - mxsfb_disable_axi_clk(host); -} - -static struct platform_driver mxsfb_driver = { - .probe = mxsfb_probe, - .remove = mxsfb_remove, - .shutdown = mxsfb_shutdown, - .id_table = mxsfb_devtype, - .driver = { - .name = DRIVER_NAME, - .of_match_table = mxsfb_dt_ids, - }, -}; - -module_platform_driver(mxsfb_driver); - -MODULE_DESCRIPTION("Freescale mxs framebuffer driver"); -MODULE_AUTHOR("Sascha Hauer, Pengutronix"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/neofb.c b/drivers/video/fbdev/neofb.c index 5d3a444083f7..b770946a0920 100644 --- a/drivers/video/fbdev/neofb.c +++ b/drivers/video/fbdev/neofb.c @@ -2122,14 +2122,7 @@ static void neofb_remove(struct pci_dev *dev) DBG("neofb_remove"); if (info) { - /* - * If unregister_framebuffer fails, then - * we will be leaving hooks that could cause - * oopsen laying around. - */ - if (unregister_framebuffer(info)) - printk(KERN_WARNING - "neofb: danger danger! Oopsen imminent!\n"); + unregister_framebuffer(info); neo_unmap_video(info); fb_destroy_modedb(info->monspecs.modedb); diff --git a/drivers/video/fbdev/nvidia/nv_backlight.c b/drivers/video/fbdev/nvidia/nv_backlight.c index 5c151b2ea683..e705a7872301 100644 --- a/drivers/video/fbdev/nvidia/nv_backlight.c +++ b/drivers/video/fbdev/nvidia/nv_backlight.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Backlight code for nVidia based graphic cards * * Copyright 2004 Antonino Daplas <adaplas@pol.net> * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/backlight.h> diff --git a/drivers/video/fbdev/omap/omapfb_main.c b/drivers/video/fbdev/omap/omapfb_main.c index 406f972d2e42..90eca64e3144 100644 --- a/drivers/video/fbdev/omap/omapfb_main.c +++ b/drivers/video/fbdev/omap/omapfb_main.c @@ -1502,8 +1502,6 @@ static int planes_init(struct omapfb_device *fbdev) fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct), fbdev->dev); if (fbi == NULL) { - dev_err(fbdev->dev, - "unable to allocate memory for plane info\n"); planes_cleanup(fbdev); return -ENOMEM; } diff --git a/drivers/video/fbdev/omap2/omapfb/displays/connector-analog-tv.c b/drivers/video/fbdev/omap2/omapfb/displays/connector-analog-tv.c index 9d78411a3bf7..63bd13ba429e 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/connector-analog-tv.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/connector-analog-tv.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Analog TV Connector driver * * Copyright (C) 2013 Texas Instruments * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/slab.h> diff --git a/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c b/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c index 06e1db34541e..b4a1aefff766 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic DVI Connector driver * * Copyright (C) 2013 Texas Instruments * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/i2c.h> diff --git a/drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c b/drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c index 58d5803ede67..49551afbdbe0 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI Connector driver * * Copyright (C) 2013 Texas Instruments * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/slab.h> diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c index a9a67167cc3d..ba7ed4039f8a 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OPA362 analog video amplifier with output/power control * @@ -8,10 +9,6 @@ * * Copyright (C) 2013 Texas Instruments * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/gpio.h> diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c index 8c0953d069b7..09a59bd93d61 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TFP410 DPI-to-DVI encoder driver * * Copyright (C) 2013 Texas Instruments * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/gpio.h> diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c index 47f0459e3551..67f0c9250e9e 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TPD12S015 HDMI ESD protection & level shifter chip driver * * Copyright (C) 2013 Texas Instruments * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/completion.h> diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dpi.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dpi.c index ace3d818afe5..37c9f5bfaefe 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dpi.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dpi.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic MIPI DPI Panel Driver * * Copyright (C) 2013 Texas Instruments * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/gpio.h> diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c index 87497a00241f..4b0793abdd84 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic DSI Command Mode panel driver * * Copyright (C) 2013 Texas Instruments * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ /* #define DEBUG */ diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c index 6cd759c01037..0f93a260e432 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LG.Philips LB035Q02 LCD Panel driver * * Copyright (C) 2013 Texas Instruments * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * Based on a driver by: Steve Sakoman <steve@sakoman.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sharp-ls037v7dw01.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sharp-ls037v7dw01.c index a8be18a87fa0..a3912fc8031f 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sharp-ls037v7dw01.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * LCD panel driver for Sharp LS037V7DW01 * * Copyright (C) 2013 Texas Instruments * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/delay.h> diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c index f2c2fef3db74..1293515e4b16 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Sony ACX565AKM LCD Panel driver * @@ -6,18 +7,6 @@ * Original Driver Author: Imre Deak <imre.deak@nokia.com> * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com> * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c index f6da8755b859..595ebd8bd5dc 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Toppoly TD028TTEC1 panel support * @@ -10,18 +11,6 @@ * * Ported and adapted from Neo 1973 U-Boot by: * H. Nikolaus Schaller <hns@goldelico.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> diff --git a/drivers/video/fbdev/omap2/omapfb/dss/Kconfig b/drivers/video/fbdev/omap2/omapfb/dss/Kconfig index a34820e8ab97..36b97fee2d57 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/Kconfig +++ b/drivers/video/fbdev/omap2/omapfb/dss/Kconfig @@ -39,18 +39,6 @@ config FB_OMAP2_DSS_DPI help DPI Interface. This is the Parallel Display Interface. -config FB_OMAP2_DSS_RFBI - bool "RFBI support" - depends on BROKEN - help - MIPI DBI support (RFBI, Remote Framebuffer Interface, in Texas - Instrument's terminology). - - DBI is a bus between the host processor and a peripheral, - such as a display or a framebuffer chip. - - See http://www.mipi.org/ for DBI specifications. - config FB_OMAP2_DSS_VENC bool "VENC support" default y diff --git a/drivers/video/fbdev/omap2/omapfb/dss/Makefile b/drivers/video/fbdev/omap2/omapfb/dss/Makefile index 7318d5260e8d..eb3689ae8d87 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/Makefile +++ b/drivers/video/fbdev/omap2/omapfb/dss/Makefile @@ -8,7 +8,6 @@ omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \ dispc-compat.o display-sysfs.o omapdss-$(CONFIG_FB_OMAP2_DSS_DPI) += dpi.o -omapdss-$(CONFIG_FB_OMAP2_DSS_RFBI) += rfbi.o omapdss-$(CONFIG_FB_OMAP2_DSS_VENC) += venc.o omapdss-$(CONFIG_FB_OMAP2_DSS_SDI) += sdi.o omapdss-$(CONFIG_FB_OMAP2_DSS_DSI) += dsi.o diff --git a/drivers/video/fbdev/omap2/omapfb/dss/apply.c b/drivers/video/fbdev/omap2/omapfb/dss/apply.c index 2481f4871f66..c71021091828 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/apply.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/apply.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Texas Instruments * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "APPLY" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/core.c b/drivers/video/fbdev/omap2/omapfb/dss/core.c index b5956a1a30d4..37858be8be83 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/core.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/dss/core.c * @@ -6,18 +7,6 @@ * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "CORE" @@ -218,9 +207,6 @@ static int (*dss_output_drv_reg_funcs[])(void) __initdata = { #ifdef CONFIG_FB_OMAP2_DSS_SDI sdi_init_platform_driver, #endif -#ifdef CONFIG_FB_OMAP2_DSS_RFBI - rfbi_init_platform_driver, -#endif #ifdef CONFIG_FB_OMAP2_DSS_VENC venc_init_platform_driver, #endif @@ -242,9 +228,6 @@ static void (*dss_output_drv_unreg_funcs[])(void) = { #ifdef CONFIG_FB_OMAP2_DSS_VENC venc_uninit_platform_driver, #endif -#ifdef CONFIG_FB_OMAP2_DSS_RFBI - rfbi_uninit_platform_driver, -#endif #ifdef CONFIG_FB_OMAP2_DSS_SDI sdi_uninit_platform_driver, #endif diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c b/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c index a864608c5df1..3417618310ff 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Texas Instruments * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "APPLY" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.h b/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.h index 14a69b3d4fb0..f51fe1a4a305 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.h +++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Texas Instruments * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAP2_DSS_DISPC_COMPAT_H diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc.c b/drivers/video/fbdev/omap2/omapfb/dss/dispc.c index a06d9c25765c..376ee5bc3ddc 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dispc.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/dss/dispc.c * @@ -6,18 +7,6 @@ * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DISPC" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc.h b/drivers/video/fbdev/omap2/omapfb/dss/dispc.h index e014d0419c58..65bba5420db7 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dispc.h +++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/video/omap2/dss/dispc.h * * Copyright (C) 2011 Texas Instruments * Author: Archit Taneja <archit@ti.com> - * - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAP2_DISPC_REG_H diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c b/drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c index 59c9a5c47ca9..2c85ec9733b1 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/dss/dispc_coefs.c * * Copyright (C) 2011 Texas Instruments * Author: Chandrabhanu Mahapatra <cmahapatra@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> diff --git a/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c index b3fdbfd0b82d..6dbe265b312d 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DISPLAY" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/display.c b/drivers/video/fbdev/omap2/omapfb/dss/display.c index dd5468695c43..f91db94c9905 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/display.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/display.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/dss/display.c * @@ -6,18 +7,6 @@ * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DISPLAY" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dpi.c b/drivers/video/fbdev/omap2/omapfb/dss/dpi.c index da09806b940c..e2e7fe6f89ee 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dpi.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dpi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/dss/dpi.c * @@ -6,18 +7,6 @@ * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DPI" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dsi.c b/drivers/video/fbdev/omap2/omapfb/dss/dsi.c index 8e1d60d48dbb..d620376216e1 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dsi.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dsi.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/dss/dsi.c * * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DSI" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss.c b/drivers/video/fbdev/omap2/omapfb/dss/dss.c index f0cac9e0eb94..7252d22dd117 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dss.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dss.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/dss/dss.c * @@ -6,18 +7,6 @@ * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "DSS" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss.h b/drivers/video/fbdev/omap2/omapfb/dss/dss.h index b1a354494144..a2269008590f 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dss.h +++ b/drivers/video/fbdev/omap2/omapfb/dss/dss.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/video/omap2/dss/dss.h * @@ -6,18 +7,6 @@ * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAP2_DSS_H @@ -472,10 +461,6 @@ void hdmi4_uninit_platform_driver(void); int hdmi5_init_platform_driver(void) __init; void hdmi5_uninit_platform_driver(void); -/* RFBI */ -int rfbi_init_platform_driver(void) __init; -void rfbi_uninit_platform_driver(void); - #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr) diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss_features.c b/drivers/video/fbdev/omap2/omapfb/dss/dss_features.c index e8d428bc47e3..62c2d48d9e09 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dss_features.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dss_features.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/dss/dss_features.c * * Copyright (C) 2010 Texas Instruments * Author: Archit Taneja <archit@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss_features.h b/drivers/video/fbdev/omap2/omapfb/dss/dss_features.h index 3d67d39f192f..6d66d6270c9d 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dss_features.h +++ b/drivers/video/fbdev/omap2/omapfb/dss/dss_features.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/video/omap2/dss/dss_features.h * * Copyright (C) 2010 Texas Instruments * Author: Archit Taneja <archit@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __OMAP2_DSS_FEATURES_H diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi.h b/drivers/video/fbdev/omap2/omapfb/dss/hdmi.h index f6de87e078b0..b9d4480ecfad 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi.h +++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * HDMI driver definition for TI OMAP4 Processor. * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _HDMI_H diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c index 28de56e21c74..7060ae56c062 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI interface DSS driver for TI's OMAP4 family of SoCs. * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ * Authors: Yong Zhi * Mythri pk <mythripk@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "HDMI" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c index d146793dd044..6b79b52d5fad 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ti_hdmi_4xxx_ip.c * @@ -5,18 +6,6 @@ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ * Authors: Yong Zhi * Mythri pk <mythripk@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "HDMICORE" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h index a069f96ec6f6..f066d1f69132 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h +++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * HDMI header definition for OMAP4 HDMI core IP * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _HDMI4_CORE_H_ diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c index 2e2fcc3d6d4f..ac49531e4732 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI driver for OMAP5 * @@ -8,18 +9,6 @@ * Mythri pk * Archit Taneja <archit@ti.com> * Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "HDMI" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c index bbfe7e2d4332..2f6ff14a48d9 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP5 HDMI CORE IP driver library * @@ -8,18 +9,6 @@ * Mythri pk * Archit Taneja <archit@ti.com> * Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h index f2f1022c5516..f10b8a283011 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h +++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * HDMI driver definition for TI OMAP5 processors. * * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _HDMI5_CORE_H_ diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c index 11dbc05d5720..9c645adba9e2 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI PHY * * Copyright (C) 2013 Texas Instruments Incorporated - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c index bc591fc12aef..4991be031b0b 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI PLL * * Copyright (C) 2013 Texas Instruments Incorporated - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #define DSS_SUBSYS_NAME "HDMIPLL" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c index 4af6ba220744..41ad52b9d013 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HDMI wrapper * * Copyright (C) 2013 Texas Instruments Incorporated - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #define DSS_SUBSYS_NAME "HDMIWP" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c index 44b96af4ef4e..b52cc1af0959 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "MANAGER" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/manager.c b/drivers/video/fbdev/omap2/omapfb/dss/manager.c index d21c641e1f3c..2c2da35345d0 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/manager.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/manager.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/dss/manager.c * @@ -6,18 +7,6 @@ * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "MANAGER" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c b/drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c index 5da7ed6d653e..0ae0cab252d3 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Texas Instruments * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ /* diff --git a/drivers/video/fbdev/omap2/omapfb/dss/output.c b/drivers/video/fbdev/omap2/omapfb/dss/output.c index bed9a978269d..4e2992a0ce50 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/output.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/output.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Texas Instruments Ltd * Author: Archit Taneja <archit@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> diff --git a/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c index f1f6c0aea752..36acf366213a 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "OVERLAY" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/overlay.c b/drivers/video/fbdev/omap2/omapfb/dss/overlay.c index be17a4785a5e..8c8e627da13d 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/overlay.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/overlay.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/dss/overlay.c * @@ -6,18 +7,6 @@ * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "OVERLAY" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/pll.c b/drivers/video/fbdev/omap2/omapfb/dss/pll.c index 0564c5606cd0..725194d52445 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/pll.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/pll.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Texas Instruments Incorporated - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "PLL" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/rfbi.c b/drivers/video/fbdev/omap2/omapfb/dss/rfbi.c deleted file mode 100644 index 562b0c4ae0c6..000000000000 --- a/drivers/video/fbdev/omap2/omapfb/dss/rfbi.c +++ /dev/null @@ -1,1078 +0,0 @@ -/* - * linux/drivers/video/omap2/dss/rfbi.c - * - * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> - * - * Some code and ideas taken from drivers/video/omap/ driver - * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#define DSS_SUBSYS_NAME "RFBI" - -#include <linux/kernel.h> -#include <linux/dma-mapping.h> -#include <linux/export.h> -#include <linux/vmalloc.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/delay.h> -#include <linux/kfifo.h> -#include <linux/ktime.h> -#include <linux/hrtimer.h> -#include <linux/seq_file.h> -#include <linux/semaphore.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/component.h> - -#include <video/omapfb_dss.h> -#include "dss.h" - -struct rfbi_reg { u16 idx; }; - -#define RFBI_REG(idx) ((const struct rfbi_reg) { idx }) - -#define RFBI_REVISION RFBI_REG(0x0000) -#define RFBI_SYSCONFIG RFBI_REG(0x0010) -#define RFBI_SYSSTATUS RFBI_REG(0x0014) -#define RFBI_CONTROL RFBI_REG(0x0040) -#define RFBI_PIXEL_CNT RFBI_REG(0x0044) -#define RFBI_LINE_NUMBER RFBI_REG(0x0048) -#define RFBI_CMD RFBI_REG(0x004c) -#define RFBI_PARAM RFBI_REG(0x0050) -#define RFBI_DATA RFBI_REG(0x0054) -#define RFBI_READ RFBI_REG(0x0058) -#define RFBI_STATUS RFBI_REG(0x005c) - -#define RFBI_CONFIG(n) RFBI_REG(0x0060 + (n)*0x18) -#define RFBI_ONOFF_TIME(n) RFBI_REG(0x0064 + (n)*0x18) -#define RFBI_CYCLE_TIME(n) RFBI_REG(0x0068 + (n)*0x18) -#define RFBI_DATA_CYCLE1(n) RFBI_REG(0x006c + (n)*0x18) -#define RFBI_DATA_CYCLE2(n) RFBI_REG(0x0070 + (n)*0x18) -#define RFBI_DATA_CYCLE3(n) RFBI_REG(0x0074 + (n)*0x18) - -#define RFBI_VSYNC_WIDTH RFBI_REG(0x0090) -#define RFBI_HSYNC_WIDTH RFBI_REG(0x0094) - -#define REG_FLD_MOD(idx, val, start, end) \ - rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end)) - -enum omap_rfbi_cycleformat { - OMAP_DSS_RFBI_CYCLEFORMAT_1_1 = 0, - OMAP_DSS_RFBI_CYCLEFORMAT_2_1 = 1, - OMAP_DSS_RFBI_CYCLEFORMAT_3_1 = 2, - OMAP_DSS_RFBI_CYCLEFORMAT_3_2 = 3, -}; - -enum omap_rfbi_datatype { - OMAP_DSS_RFBI_DATATYPE_12 = 0, - OMAP_DSS_RFBI_DATATYPE_16 = 1, - OMAP_DSS_RFBI_DATATYPE_18 = 2, - OMAP_DSS_RFBI_DATATYPE_24 = 3, -}; - -enum omap_rfbi_parallelmode { - OMAP_DSS_RFBI_PARALLELMODE_8 = 0, - OMAP_DSS_RFBI_PARALLELMODE_9 = 1, - OMAP_DSS_RFBI_PARALLELMODE_12 = 2, - OMAP_DSS_RFBI_PARALLELMODE_16 = 3, -}; - -static int rfbi_convert_timings(struct rfbi_timings *t); -static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div); - -static struct { - struct platform_device *pdev; - void __iomem *base; - - unsigned long l4_khz; - - enum omap_rfbi_datatype datatype; - enum omap_rfbi_parallelmode parallelmode; - - enum omap_rfbi_te_mode te_mode; - int te_enabled; - - void (*framedone_callback)(void *data); - void *framedone_callback_data; - - struct omap_dss_device *dssdev[2]; - - struct semaphore bus_lock; - - struct omap_video_timings timings; - int pixel_size; - int data_lines; - struct rfbi_timings intf_timings; - - struct omap_dss_device output; -} rfbi; - -static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) -{ - __raw_writel(val, rfbi.base + idx.idx); -} - -static inline u32 rfbi_read_reg(const struct rfbi_reg idx) -{ - return __raw_readl(rfbi.base + idx.idx); -} - -static int rfbi_runtime_get(void) -{ - int r; - - DSSDBG("rfbi_runtime_get\n"); - - r = pm_runtime_get_sync(&rfbi.pdev->dev); - WARN_ON(r < 0); - return r < 0 ? r : 0; -} - -static void rfbi_runtime_put(void) -{ - int r; - - DSSDBG("rfbi_runtime_put\n"); - - r = pm_runtime_put_sync(&rfbi.pdev->dev); - WARN_ON(r < 0 && r != -ENOSYS); -} - -static void rfbi_bus_lock(void) -{ - down(&rfbi.bus_lock); -} - -static void rfbi_bus_unlock(void) -{ - up(&rfbi.bus_lock); -} - -static void rfbi_write_command(const void *buf, u32 len) -{ - switch (rfbi.parallelmode) { - case OMAP_DSS_RFBI_PARALLELMODE_8: - { - const u8 *b = buf; - for (; len; len--) - rfbi_write_reg(RFBI_CMD, *b++); - break; - } - - case OMAP_DSS_RFBI_PARALLELMODE_16: - { - const u16 *w = buf; - BUG_ON(len & 1); - for (; len; len -= 2) - rfbi_write_reg(RFBI_CMD, *w++); - break; - } - - case OMAP_DSS_RFBI_PARALLELMODE_9: - case OMAP_DSS_RFBI_PARALLELMODE_12: - default: - BUG(); - } -} - -static void rfbi_read_data(void *buf, u32 len) -{ - switch (rfbi.parallelmode) { - case OMAP_DSS_RFBI_PARALLELMODE_8: - { - u8 *b = buf; - for (; len; len--) { - rfbi_write_reg(RFBI_READ, 0); - *b++ = rfbi_read_reg(RFBI_READ); - } - break; - } - - case OMAP_DSS_RFBI_PARALLELMODE_16: - { - u16 *w = buf; - BUG_ON(len & ~1); - for (; len; len -= 2) { - rfbi_write_reg(RFBI_READ, 0); - *w++ = rfbi_read_reg(RFBI_READ); - } - break; - } - - case OMAP_DSS_RFBI_PARALLELMODE_9: - case OMAP_DSS_RFBI_PARALLELMODE_12: - default: - BUG(); - } -} - -static void rfbi_write_data(const void *buf, u32 len) -{ - switch (rfbi.parallelmode) { - case OMAP_DSS_RFBI_PARALLELMODE_8: - { - const u8 *b = buf; - for (; len; len--) - rfbi_write_reg(RFBI_PARAM, *b++); - break; - } - - case OMAP_DSS_RFBI_PARALLELMODE_16: - { - const u16 *w = buf; - BUG_ON(len & 1); - for (; len; len -= 2) - rfbi_write_reg(RFBI_PARAM, *w++); - break; - } - - case OMAP_DSS_RFBI_PARALLELMODE_9: - case OMAP_DSS_RFBI_PARALLELMODE_12: - default: - BUG(); - - } -} - -static void rfbi_write_pixels(const void __iomem *buf, int scr_width, - u16 x, u16 y, - u16 w, u16 h) -{ - int start_offset = scr_width * y + x; - int horiz_offset = scr_width - w; - int i; - - if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 && - rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) { - const u16 __iomem *pd = buf; - pd += start_offset; - - for (; h; --h) { - for (i = 0; i < w; ++i) { - const u8 __iomem *b = (const u8 __iomem *)pd; - rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1)); - rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0)); - ++pd; - } - pd += horiz_offset; - } - } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_24 && - rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) { - const u32 __iomem *pd = buf; - pd += start_offset; - - for (; h; --h) { - for (i = 0; i < w; ++i) { - const u8 __iomem *b = (const u8 __iomem *)pd; - rfbi_write_reg(RFBI_PARAM, __raw_readb(b+2)); - rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1)); - rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0)); - ++pd; - } - pd += horiz_offset; - } - } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 && - rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_16) { - const u16 __iomem *pd = buf; - pd += start_offset; - - for (; h; --h) { - for (i = 0; i < w; ++i) { - rfbi_write_reg(RFBI_PARAM, __raw_readw(pd)); - ++pd; - } - pd += horiz_offset; - } - } else { - BUG(); - } -} - -static int rfbi_transfer_area(struct omap_dss_device *dssdev, - void (*callback)(void *data), void *data) -{ - u32 l; - int r; - struct omap_overlay_manager *mgr = rfbi.output.manager; - u16 width = rfbi.timings.x_res; - u16 height = rfbi.timings.y_res; - - /*BUG_ON(callback == 0);*/ - BUG_ON(rfbi.framedone_callback != NULL); - - DSSDBG("rfbi_transfer_area %dx%d\n", width, height); - - dss_mgr_set_timings(mgr, &rfbi.timings); - - r = dss_mgr_enable(mgr); - if (r) - return r; - - rfbi.framedone_callback = callback; - rfbi.framedone_callback_data = data; - - rfbi_write_reg(RFBI_PIXEL_CNT, width * height); - - l = rfbi_read_reg(RFBI_CONTROL); - l = FLD_MOD(l, 1, 0, 0); /* enable */ - if (!rfbi.te_enabled) - l = FLD_MOD(l, 1, 4, 4); /* ITE */ - - rfbi_write_reg(RFBI_CONTROL, l); - - return 0; -} - -static void framedone_callback(void *data) -{ - void (*callback)(void *data); - - DSSDBG("FRAMEDONE\n"); - - REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0); - - callback = rfbi.framedone_callback; - rfbi.framedone_callback = NULL; - - if (callback != NULL) - callback(rfbi.framedone_callback_data); -} - -#if 1 /* VERBOSE */ -static void rfbi_print_timings(void) -{ - u32 l; - u32 time; - - l = rfbi_read_reg(RFBI_CONFIG(0)); - time = 1000000000 / rfbi.l4_khz; - if (l & (1 << 4)) - time *= 2; - - DSSDBG("Tick time %u ps\n", time); - l = rfbi_read_reg(RFBI_ONOFF_TIME(0)); - DSSDBG("CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, " - "REONTIME %d, REOFFTIME %d\n", - l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f, - (l >> 20) & 0x0f, (l >> 24) & 0x3f); - - l = rfbi_read_reg(RFBI_CYCLE_TIME(0)); - DSSDBG("WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, " - "ACCESSTIME %d\n", - (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f, - (l >> 22) & 0x3f); -} -#else -static void rfbi_print_timings(void) {} -#endif - - - - -static u32 extif_clk_period; - -static inline unsigned long round_to_extif_ticks(unsigned long ps, int div) -{ - int bus_tick = extif_clk_period * div; - return (ps + bus_tick - 1) / bus_tick * bus_tick; -} - -static int calc_reg_timing(struct rfbi_timings *t, int div) -{ - t->clk_div = div; - - t->cs_on_time = round_to_extif_ticks(t->cs_on_time, div); - - t->we_on_time = round_to_extif_ticks(t->we_on_time, div); - t->we_off_time = round_to_extif_ticks(t->we_off_time, div); - t->we_cycle_time = round_to_extif_ticks(t->we_cycle_time, div); - - t->re_on_time = round_to_extif_ticks(t->re_on_time, div); - t->re_off_time = round_to_extif_ticks(t->re_off_time, div); - t->re_cycle_time = round_to_extif_ticks(t->re_cycle_time, div); - - t->access_time = round_to_extif_ticks(t->access_time, div); - t->cs_off_time = round_to_extif_ticks(t->cs_off_time, div); - t->cs_pulse_width = round_to_extif_ticks(t->cs_pulse_width, div); - - DSSDBG("[reg]cson %d csoff %d reon %d reoff %d\n", - t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); - DSSDBG("[reg]weon %d weoff %d recyc %d wecyc %d\n", - t->we_on_time, t->we_off_time, t->re_cycle_time, - t->we_cycle_time); - DSSDBG("[reg]rdaccess %d cspulse %d\n", - t->access_time, t->cs_pulse_width); - - return rfbi_convert_timings(t); -} - -static int calc_extif_timings(struct rfbi_timings *t) -{ - u32 max_clk_div; - int div; - - rfbi_get_clk_info(&extif_clk_period, &max_clk_div); - for (div = 1; div <= max_clk_div; div++) { - if (calc_reg_timing(t, div) == 0) - break; - } - - if (div <= max_clk_div) - return 0; - - DSSERR("can't setup timings\n"); - return -1; -} - - -static void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t) -{ - int r; - - if (!t->converted) { - r = calc_extif_timings(t); - if (r < 0) - DSSERR("Failed to calc timings\n"); - } - - BUG_ON(!t->converted); - - rfbi_write_reg(RFBI_ONOFF_TIME(rfbi_module), t->tim[0]); - rfbi_write_reg(RFBI_CYCLE_TIME(rfbi_module), t->tim[1]); - - /* TIMEGRANULARITY */ - REG_FLD_MOD(RFBI_CONFIG(rfbi_module), - (t->tim[2] ? 1 : 0), 4, 4); - - rfbi_print_timings(); -} - -static int ps_to_rfbi_ticks(int time, int div) -{ - unsigned long tick_ps; - int ret; - - /* Calculate in picosecs to yield more exact results */ - tick_ps = 1000000000 / (rfbi.l4_khz) * div; - - ret = (time + tick_ps - 1) / tick_ps; - - return ret; -} - -static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div) -{ - *clk_period = 1000000000 / rfbi.l4_khz; - *max_clk_div = 2; -} - -static int rfbi_convert_timings(struct rfbi_timings *t) -{ - u32 l; - int reon, reoff, weon, weoff, cson, csoff, cs_pulse; - int actim, recyc, wecyc; - int div = t->clk_div; - - if (div <= 0 || div > 2) - return -1; - - /* Make sure that after conversion it still holds that: - * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff, - * csoff > cson, csoff >= max(weoff, reoff), actim > reon - */ - weon = ps_to_rfbi_ticks(t->we_on_time, div); - weoff = ps_to_rfbi_ticks(t->we_off_time, div); - if (weoff <= weon) - weoff = weon + 1; - if (weon > 0x0f) - return -1; - if (weoff > 0x3f) - return -1; - - reon = ps_to_rfbi_ticks(t->re_on_time, div); - reoff = ps_to_rfbi_ticks(t->re_off_time, div); - if (reoff <= reon) - reoff = reon + 1; - if (reon > 0x0f) - return -1; - if (reoff > 0x3f) - return -1; - - cson = ps_to_rfbi_ticks(t->cs_on_time, div); - csoff = ps_to_rfbi_ticks(t->cs_off_time, div); - if (csoff <= cson) - csoff = cson + 1; - if (csoff < max(weoff, reoff)) - csoff = max(weoff, reoff); - if (cson > 0x0f) - return -1; - if (csoff > 0x3f) - return -1; - - l = cson; - l |= csoff << 4; - l |= weon << 10; - l |= weoff << 14; - l |= reon << 20; - l |= reoff << 24; - - t->tim[0] = l; - - actim = ps_to_rfbi_ticks(t->access_time, div); - if (actim <= reon) - actim = reon + 1; - if (actim > 0x3f) - return -1; - - wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div); - if (wecyc < weoff) - wecyc = weoff; - if (wecyc > 0x3f) - return -1; - - recyc = ps_to_rfbi_ticks(t->re_cycle_time, div); - if (recyc < reoff) - recyc = reoff; - if (recyc > 0x3f) - return -1; - - cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div); - if (cs_pulse > 0x3f) - return -1; - - l = wecyc; - l |= recyc << 6; - l |= cs_pulse << 12; - l |= actim << 22; - - t->tim[1] = l; - - t->tim[2] = div - 1; - - t->converted = 1; - - return 0; -} - -/* xxx FIX module selection missing */ -static int rfbi_setup_te(enum omap_rfbi_te_mode mode, - unsigned hs_pulse_time, unsigned vs_pulse_time, - int hs_pol_inv, int vs_pol_inv, int extif_div) -{ - int hs, vs; - int min; - u32 l; - - hs = ps_to_rfbi_ticks(hs_pulse_time, 1); - vs = ps_to_rfbi_ticks(vs_pulse_time, 1); - if (hs < 2) - return -EDOM; - if (mode == OMAP_DSS_RFBI_TE_MODE_2) - min = 2; - else /* OMAP_DSS_RFBI_TE_MODE_1 */ - min = 4; - if (vs < min) - return -EDOM; - if (vs == hs) - return -EINVAL; - rfbi.te_mode = mode; - DSSDBG("setup_te: mode %d hs %d vs %d hs_inv %d vs_inv %d\n", - mode, hs, vs, hs_pol_inv, vs_pol_inv); - - rfbi_write_reg(RFBI_HSYNC_WIDTH, hs); - rfbi_write_reg(RFBI_VSYNC_WIDTH, vs); - - l = rfbi_read_reg(RFBI_CONFIG(0)); - if (hs_pol_inv) - l &= ~(1 << 21); - else - l |= 1 << 21; - if (vs_pol_inv) - l &= ~(1 << 20); - else - l |= 1 << 20; - - return 0; -} - -/* xxx FIX module selection missing */ -static int rfbi_enable_te(bool enable, unsigned line) -{ - u32 l; - - DSSDBG("te %d line %d mode %d\n", enable, line, rfbi.te_mode); - if (line > (1 << 11) - 1) - return -EINVAL; - - l = rfbi_read_reg(RFBI_CONFIG(0)); - l &= ~(0x3 << 2); - if (enable) { - rfbi.te_enabled = 1; - l |= rfbi.te_mode << 2; - } else - rfbi.te_enabled = 0; - rfbi_write_reg(RFBI_CONFIG(0), l); - rfbi_write_reg(RFBI_LINE_NUMBER, line); - - return 0; -} - -static int rfbi_configure_bus(int rfbi_module, int bpp, int lines) -{ - u32 l; - int cycle1 = 0, cycle2 = 0, cycle3 = 0; - enum omap_rfbi_cycleformat cycleformat; - enum omap_rfbi_datatype datatype; - enum omap_rfbi_parallelmode parallelmode; - - switch (bpp) { - case 12: - datatype = OMAP_DSS_RFBI_DATATYPE_12; - break; - case 16: - datatype = OMAP_DSS_RFBI_DATATYPE_16; - break; - case 18: - datatype = OMAP_DSS_RFBI_DATATYPE_18; - break; - case 24: - datatype = OMAP_DSS_RFBI_DATATYPE_24; - break; - default: - BUG(); - return 1; - } - rfbi.datatype = datatype; - - switch (lines) { - case 8: - parallelmode = OMAP_DSS_RFBI_PARALLELMODE_8; - break; - case 9: - parallelmode = OMAP_DSS_RFBI_PARALLELMODE_9; - break; - case 12: - parallelmode = OMAP_DSS_RFBI_PARALLELMODE_12; - break; - case 16: - parallelmode = OMAP_DSS_RFBI_PARALLELMODE_16; - break; - default: - BUG(); - return 1; - } - rfbi.parallelmode = parallelmode; - - if ((bpp % lines) == 0) { - switch (bpp / lines) { - case 1: - cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_1_1; - break; - case 2: - cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_2_1; - break; - case 3: - cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_1; - break; - default: - BUG(); - return 1; - } - } else if ((2 * bpp % lines) == 0) { - if ((2 * bpp / lines) == 3) - cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_2; - else { - BUG(); - return 1; - } - } else { - BUG(); - return 1; - } - - switch (cycleformat) { - case OMAP_DSS_RFBI_CYCLEFORMAT_1_1: - cycle1 = lines; - break; - - case OMAP_DSS_RFBI_CYCLEFORMAT_2_1: - cycle1 = lines; - cycle2 = lines; - break; - - case OMAP_DSS_RFBI_CYCLEFORMAT_3_1: - cycle1 = lines; - cycle2 = lines; - cycle3 = lines; - break; - - case OMAP_DSS_RFBI_CYCLEFORMAT_3_2: - cycle1 = lines; - cycle2 = (lines / 2) | ((lines / 2) << 16); - cycle3 = (lines << 16); - break; - } - - REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */ - - l = 0; - l |= FLD_VAL(parallelmode, 1, 0); - l |= FLD_VAL(0, 3, 2); /* TRIGGERMODE: ITE */ - l |= FLD_VAL(0, 4, 4); /* TIMEGRANULARITY */ - l |= FLD_VAL(datatype, 6, 5); - /* l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */ - l |= FLD_VAL(0, 8, 7); /* L4FORMAT, 1pix/L4 */ - l |= FLD_VAL(cycleformat, 10, 9); - l |= FLD_VAL(0, 12, 11); /* UNUSEDBITS */ - l |= FLD_VAL(0, 16, 16); /* A0POLARITY */ - l |= FLD_VAL(0, 17, 17); /* REPOLARITY */ - l |= FLD_VAL(0, 18, 18); /* WEPOLARITY */ - l |= FLD_VAL(0, 19, 19); /* CSPOLARITY */ - l |= FLD_VAL(1, 20, 20); /* TE_VSYNC_POLARITY */ - l |= FLD_VAL(1, 21, 21); /* HSYNCPOLARITY */ - rfbi_write_reg(RFBI_CONFIG(rfbi_module), l); - - rfbi_write_reg(RFBI_DATA_CYCLE1(rfbi_module), cycle1); - rfbi_write_reg(RFBI_DATA_CYCLE2(rfbi_module), cycle2); - rfbi_write_reg(RFBI_DATA_CYCLE3(rfbi_module), cycle3); - - - l = rfbi_read_reg(RFBI_CONTROL); - l = FLD_MOD(l, rfbi_module+1, 3, 2); /* Select CSx */ - l = FLD_MOD(l, 0, 1, 1); /* clear bypass */ - rfbi_write_reg(RFBI_CONTROL, l); - - - DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n", - bpp, lines, cycle1, cycle2, cycle3); - - return 0; -} - -static int rfbi_configure(struct omap_dss_device *dssdev) -{ - return rfbi_configure_bus(dssdev->phy.rfbi.channel, rfbi.pixel_size, - rfbi.data_lines); -} - -static int rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *), - void *data) -{ - return rfbi_transfer_area(dssdev, callback, data); -} - -static void rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h) -{ - rfbi.timings.x_res = w; - rfbi.timings.y_res = h; -} - -static void rfbi_set_pixel_size(struct omap_dss_device *dssdev, int pixel_size) -{ - rfbi.pixel_size = pixel_size; -} - -static void rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) -{ - rfbi.data_lines = data_lines; -} - -static void rfbi_set_interface_timings(struct omap_dss_device *dssdev, - struct rfbi_timings *timings) -{ - rfbi.intf_timings = *timings; -} - -static void rfbi_dump_regs(struct seq_file *s) -{ -#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r)) - - if (rfbi_runtime_get()) - return; - - DUMPREG(RFBI_REVISION); - DUMPREG(RFBI_SYSCONFIG); - DUMPREG(RFBI_SYSSTATUS); - DUMPREG(RFBI_CONTROL); - DUMPREG(RFBI_PIXEL_CNT); - DUMPREG(RFBI_LINE_NUMBER); - DUMPREG(RFBI_CMD); - DUMPREG(RFBI_PARAM); - DUMPREG(RFBI_DATA); - DUMPREG(RFBI_READ); - DUMPREG(RFBI_STATUS); - - DUMPREG(RFBI_CONFIG(0)); - DUMPREG(RFBI_ONOFF_TIME(0)); - DUMPREG(RFBI_CYCLE_TIME(0)); - DUMPREG(RFBI_DATA_CYCLE1(0)); - DUMPREG(RFBI_DATA_CYCLE2(0)); - DUMPREG(RFBI_DATA_CYCLE3(0)); - - DUMPREG(RFBI_CONFIG(1)); - DUMPREG(RFBI_ONOFF_TIME(1)); - DUMPREG(RFBI_CYCLE_TIME(1)); - DUMPREG(RFBI_DATA_CYCLE1(1)); - DUMPREG(RFBI_DATA_CYCLE2(1)); - DUMPREG(RFBI_DATA_CYCLE3(1)); - - DUMPREG(RFBI_VSYNC_WIDTH); - DUMPREG(RFBI_HSYNC_WIDTH); - - rfbi_runtime_put(); -#undef DUMPREG -} - -static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) -{ - struct omap_overlay_manager *mgr = rfbi.output.manager; - struct dss_lcd_mgr_config mgr_config; - - mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI; - - mgr_config.stallmode = true; - /* Do we need fifohandcheck for RFBI? */ - mgr_config.fifohandcheck = false; - - mgr_config.video_port_width = rfbi.pixel_size; - mgr_config.lcden_sig_polarity = 0; - - dss_mgr_set_lcd_config(mgr, &mgr_config); - - /* - * Set rfbi.timings with default values, the x_res and y_res fields - * are expected to be already configured by the panel driver via - * omapdss_rfbi_set_size() - */ - rfbi.timings.hsw = 1; - rfbi.timings.hfp = 1; - rfbi.timings.hbp = 1; - rfbi.timings.vsw = 1; - rfbi.timings.vfp = 0; - rfbi.timings.vbp = 0; - - rfbi.timings.interlace = false; - rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; - rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; - rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; - rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; - rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE; - - dss_mgr_set_timings(mgr, &rfbi.timings); -} - -static int rfbi_display_enable(struct omap_dss_device *dssdev) -{ - struct omap_dss_device *out = &rfbi.output; - int r; - - if (out->manager == NULL) { - DSSERR("failed to enable display: no output/manager\n"); - return -ENODEV; - } - - r = rfbi_runtime_get(); - if (r) - return r; - - r = dss_mgr_register_framedone_handler(out->manager, - framedone_callback, NULL); - if (r) { - DSSERR("can't get FRAMEDONE irq\n"); - goto err1; - } - - rfbi_config_lcd_manager(dssdev); - - rfbi_configure_bus(dssdev->phy.rfbi.channel, rfbi.pixel_size, - rfbi.data_lines); - - rfbi_set_timings(dssdev->phy.rfbi.channel, &rfbi.intf_timings); - - return 0; -err1: - rfbi_runtime_put(); - return r; -} - -static void rfbi_display_disable(struct omap_dss_device *dssdev) -{ - struct omap_dss_device *out = &rfbi.output; - - dss_mgr_unregister_framedone_handler(out->manager, - framedone_callback, NULL); - - rfbi_runtime_put(); -} - -static int rfbi_init_display(struct omap_dss_device *dssdev) -{ - rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev; - return 0; -} - -static void rfbi_init_output(struct platform_device *pdev) -{ - struct omap_dss_device *out = &rfbi.output; - - out->dev = &pdev->dev; - out->id = OMAP_DSS_OUTPUT_DBI; - out->output_type = OMAP_DISPLAY_TYPE_DBI; - out->name = "rfbi.0"; - out->dispc_channel = OMAP_DSS_CHANNEL_LCD; - out->owner = THIS_MODULE; - - omapdss_register_output(out); -} - -static void rfbi_uninit_output(struct platform_device *pdev) -{ - struct omap_dss_device *out = &rfbi.output; - - omapdss_unregister_output(out); -} - -/* RFBI HW IP initialisation */ -static int rfbi_bind(struct device *dev, struct device *master, void *data) -{ - struct platform_device *pdev = to_platform_device(dev); - u32 rev; - struct resource *rfbi_mem; - struct clk *clk; - int r; - - rfbi.pdev = pdev; - - sema_init(&rfbi.bus_lock, 1); - - rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0); - if (!rfbi_mem) { - DSSERR("can't get IORESOURCE_MEM RFBI\n"); - return -EINVAL; - } - - rfbi.base = devm_ioremap(&pdev->dev, rfbi_mem->start, - resource_size(rfbi_mem)); - if (!rfbi.base) { - DSSERR("can't ioremap RFBI\n"); - return -ENOMEM; - } - - clk = clk_get(&pdev->dev, "ick"); - if (IS_ERR(clk)) { - DSSERR("can't get ick\n"); - return PTR_ERR(clk); - } - - rfbi.l4_khz = clk_get_rate(clk) / 1000; - - clk_put(clk); - - pm_runtime_enable(&pdev->dev); - - r = rfbi_runtime_get(); - if (r) - goto err_runtime_get; - - msleep(10); - - rev = rfbi_read_reg(RFBI_REVISION); - dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n", - FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - - rfbi_runtime_put(); - - dss_debugfs_create_file("rfbi", rfbi_dump_regs); - - rfbi_init_output(pdev); - - return 0; - -err_runtime_get: - pm_runtime_disable(&pdev->dev); - return r; -} - -static void rfbi_unbind(struct device *dev, struct device *master, void *data) -{ - struct platform_device *pdev = to_platform_device(dev); - - rfbi_uninit_output(pdev); - - pm_runtime_disable(&pdev->dev); - - return 0; -} - -static const struct component_ops rfbi_component_ops = { - .bind = rfbi_bind, - .unbind = rfbi_unbind, -}; - -static int rfbi_probe(struct platform_device *pdev) -{ - return component_add(&pdev->dev, &rfbi_component_ops); -} - -static int rfbi_remove(struct platform_device *pdev) -{ - component_del(&pdev->dev, &rfbi_component_ops); - return 0; -} - -static int rfbi_runtime_suspend(struct device *dev) -{ - dispc_runtime_put(); - - return 0; -} - -static int rfbi_runtime_resume(struct device *dev) -{ - int r; - - r = dispc_runtime_get(); - if (r < 0) - return r; - - return 0; -} - -static const struct dev_pm_ops rfbi_pm_ops = { - .runtime_suspend = rfbi_runtime_suspend, - .runtime_resume = rfbi_runtime_resume, -}; - -static struct platform_driver omap_rfbihw_driver = { - .probe = rfbi_probe, - .remove = rfbi_remove, - .driver = { - .name = "omapdss_rfbi", - .pm = &rfbi_pm_ops, - .suppress_bind_attrs = true, - }, -}; - -int __init rfbi_init_platform_driver(void) -{ - return platform_driver_register(&omap_rfbihw_driver); -} - -void rfbi_uninit_platform_driver(void) -{ - platform_driver_unregister(&omap_rfbihw_driver); -} diff --git a/drivers/video/fbdev/omap2/omapfb/dss/sdi.c b/drivers/video/fbdev/omap2/omapfb/dss/sdi.c index c4be732a4714..002f07f5480f 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/sdi.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/sdi.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/dss/sdi.c * * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "SDI" diff --git a/drivers/video/fbdev/omap2/omapfb/dss/venc.c b/drivers/video/fbdev/omap2/omapfb/dss/venc.c index 392464da12e4..f81e2a46366d 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/venc.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/venc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/dss/venc.c * @@ -5,18 +6,6 @@ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> * * VENC settings from TI's DSS driver - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #define DSS_SUBSYS_NAME "VENC" diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c b/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c index 8e23160ec59f..56995f44e76d 100644 --- a/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/omapfb-ioctl.c * @@ -6,18 +7,6 @@ * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/fb.h> diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c index b8b5b4ac0e09..858c2c011d19 100644 --- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/omapfb-main.c * @@ -6,18 +7,6 @@ * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> @@ -1892,12 +1881,8 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) fbi = framebuffer_alloc(sizeof(struct omapfb_info), fbdev->dev); - - if (fbi == NULL) { - dev_err(fbdev->dev, - "unable to allocate memory for plane info\n"); + if (!fbi) return -ENOMEM; - } clear_fb_info(fbi); diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c b/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c index 8087a009c54f..4a5db170ef59 100644 --- a/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/omapfb-sysfs.c * @@ -6,18 +7,6 @@ * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/fb.h> @@ -60,8 +49,7 @@ static ssize_t store_rotate_type(struct device *dev, if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB) return -EINVAL; - if (!lock_fb_info(fbi)) - return -ENODEV; + lock_fb_info(fbi); r = 0; if (rot_type == ofbi->rotation_type) @@ -112,8 +100,7 @@ static ssize_t store_mirror(struct device *dev, if (r) return r; - if (!lock_fb_info(fbi)) - return -ENODEV; + lock_fb_info(fbi); ofbi->mirror = mirror; @@ -149,8 +136,7 @@ static ssize_t show_overlays(struct device *dev, ssize_t l = 0; int t; - if (!lock_fb_info(fbi)) - return -ENODEV; + lock_fb_info(fbi); omapfb_lock(fbdev); for (t = 0; t < ofbi->num_overlays; t++) { @@ -208,8 +194,7 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, if (buf[len - 1] == '\n') len = len - 1; - if (!lock_fb_info(fbi)) - return -ENODEV; + lock_fb_info(fbi); omapfb_lock(fbdev); if (len > 0) { @@ -340,8 +325,7 @@ static ssize_t show_overlays_rotate(struct device *dev, ssize_t l = 0; int t; - if (!lock_fb_info(fbi)) - return -ENODEV; + lock_fb_info(fbi); for (t = 0; t < ofbi->num_overlays; t++) { l += snprintf(buf + l, PAGE_SIZE - l, "%s%d", @@ -369,8 +353,7 @@ static ssize_t store_overlays_rotate(struct device *dev, if (buf[len - 1] == '\n') len = len - 1; - if (!lock_fb_info(fbi)) - return -ENODEV; + lock_fb_info(fbi); if (len > 0) { char *p = (char *)buf; @@ -453,8 +436,7 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, size = PAGE_ALIGN(size); - if (!lock_fb_info(fbi)) - return -ENODEV; + lock_fb_info(fbi); if (display && display->driver->sync) display->driver->sync(display); diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb.h b/drivers/video/fbdev/omap2/omapfb/omapfb.h index 555487d6dbea..d27abccb37bc 100644 --- a/drivers/video/fbdev/omap2/omapfb/omapfb.h +++ b/drivers/video/fbdev/omap2/omapfb/omapfb.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/video/omap2/omapfb.h * @@ -6,18 +7,6 @@ * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __DRIVERS_VIDEO_OMAP2_OMAPFB_H__ diff --git a/drivers/video/fbdev/platinumfb.c b/drivers/video/fbdev/platinumfb.c index 76f299375a00..632b246ca35f 100644 --- a/drivers/video/fbdev/platinumfb.c +++ b/drivers/video/fbdev/platinumfb.c @@ -538,10 +538,9 @@ static int platinumfb_probe(struct platform_device* odev) dev_info(&odev->dev, "Found Apple Platinum video hardware\n"); info = framebuffer_alloc(sizeof(*pinfo), &odev->dev); - if (info == NULL) { - dev_err(&odev->dev, "Failed to allocate fbdev !\n"); + if (!info) return -ENOMEM; - } + pinfo = info->par; if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) || diff --git a/drivers/video/fbdev/pmag-aa-fb.c b/drivers/video/fbdev/pmag-aa-fb.c index ca7e9390d1e7..d1e78ce3a9c2 100644 --- a/drivers/video/fbdev/pmag-aa-fb.c +++ b/drivers/video/fbdev/pmag-aa-fb.c @@ -165,10 +165,8 @@ static int pmagaafb_probe(struct device *dev) int err; info = framebuffer_alloc(sizeof(struct aafb_par), dev); - if (!info) { - printk(KERN_ERR "%s: Cannot allocate memory\n", dev_name(dev)); + if (!info) return -ENOMEM; - } par = info->par; dev_set_drvdata(dev, info); diff --git a/drivers/video/fbdev/pmag-ba-fb.c b/drivers/video/fbdev/pmag-ba-fb.c index 3b9249449ea6..56b912bb28de 100644 --- a/drivers/video/fbdev/pmag-ba-fb.c +++ b/drivers/video/fbdev/pmag-ba-fb.c @@ -150,10 +150,8 @@ static int pmagbafb_probe(struct device *dev) int err; info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev); - if (!info) { - printk(KERN_ERR "%s: Cannot allocate memory\n", dev_name(dev)); + if (!info) return -ENOMEM; - } par = info->par; dev_set_drvdata(dev, info); diff --git a/drivers/video/fbdev/pmagb-b-fb.c b/drivers/video/fbdev/pmagb-b-fb.c index e58df36233c4..2822b2225924 100644 --- a/drivers/video/fbdev/pmagb-b-fb.c +++ b/drivers/video/fbdev/pmagb-b-fb.c @@ -257,10 +257,8 @@ static int pmagbbfb_probe(struct device *dev) int err; info = framebuffer_alloc(sizeof(struct pmagbbfb_par), dev); - if (!info) { - printk(KERN_ERR "%s: Cannot allocate memory\n", dev_name(dev)); + if (!info) return -ENOMEM; - } par = info->par; dev_set_drvdata(dev, info); diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c index 73d92d8a85cc..7ff4b6b84282 100644 --- a/drivers/video/fbdev/pvr2fb.c +++ b/drivers/video/fbdev/pvr2fb.c @@ -140,7 +140,7 @@ static struct pvr2fb_par { unsigned char is_doublescan; /* Are scanlines output twice? (doublescan) */ unsigned char is_lowres; /* Is horizontal pixel-doubling enabled? */ - unsigned long mmio_base; /* MMIO base */ + void __iomem *mmio_base; /* MMIO base */ u32 palette[16]; } *currentpar; @@ -194,39 +194,6 @@ static unsigned int shdma = PVR2_CASCADE_CHAN; static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS; #endif -static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, - unsigned int transp, struct fb_info *info); -static int pvr2fb_blank(int blank, struct fb_info *info); -static unsigned long get_line_length(int xres_virtual, int bpp); -static void set_color_bitfields(struct fb_var_screeninfo *var); -static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); -static int pvr2fb_set_par(struct fb_info *info); -static void pvr2_update_display(struct fb_info *info); -static void pvr2_init_display(struct fb_info *info); -static void pvr2_do_blank(void); -static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id); -static int pvr2_init_cable(void); -static int pvr2_get_param(const struct pvr2_params *p, const char *s, - int val, int size); -#ifdef CONFIG_PVR2_DMA -static ssize_t pvr2fb_write(struct fb_info *info, const char *buf, - size_t count, loff_t *ppos); -#endif - -static struct fb_ops pvr2fb_ops = { - .owner = THIS_MODULE, - .fb_setcolreg = pvr2fb_setcolreg, - .fb_blank = pvr2fb_blank, - .fb_check_var = pvr2fb_check_var, - .fb_set_par = pvr2fb_set_par, -#ifdef CONFIG_PVR2_DMA - .fb_write = pvr2fb_write, -#endif - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, -}; - static struct fb_videomode pvr2_modedb[] = { /* * Broadcast video modes (PAL and NTSC). I'm unfamiliar with @@ -354,6 +321,36 @@ static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, return 0; } +/* + * Determine the cable type and initialize the cable output format. Don't do + * anything if the cable type has been overidden (via "cable:XX"). + */ + +#define PCTRA ((void __iomem *)0xff80002c) +#define PDTRA ((void __iomem *)0xff800030) +#define VOUTC ((void __iomem *)0xa0702c00) + +static int pvr2_init_cable(void) +{ + if (cable_type < 0) { + fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000, + PCTRA); + cable_type = (fb_readw(PDTRA) >> 8) & 3; + } + + /* Now select the output format (either composite or other) */ + /* XXX: Save the previous val first, as this reg is also AICA + related */ + if (cable_type == CT_COMPOSITE) + fb_writel(3 << 8, VOUTC); + else if (cable_type == CT_RGB) + fb_writel(1 << 9, VOUTC); + else + fb_writel(0, VOUTC); + + return cable_type; +} + static int pvr2fb_set_par(struct fb_info *info) { struct pvr2fb_par *par = (struct pvr2fb_par *)info->par; @@ -623,7 +620,7 @@ static void pvr2_do_blank(void) is_blanked = do_blank > 0 ? do_blank : 0; } -static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id) +static irqreturn_t __maybe_unused pvr2fb_interrupt(int irq, void *dev_id) { struct fb_info *info = dev_id; @@ -642,36 +639,6 @@ static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -/* - * Determine the cable type and initialize the cable output format. Don't do - * anything if the cable type has been overidden (via "cable:XX"). - */ - -#define PCTRA 0xff80002c -#define PDTRA 0xff800030 -#define VOUTC 0xa0702c00 - -static int pvr2_init_cable(void) -{ - if (cable_type < 0) { - fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000, - PCTRA); - cable_type = (fb_readw(PDTRA) >> 8) & 3; - } - - /* Now select the output format (either composite or other) */ - /* XXX: Save the previous val first, as this reg is also AICA - related */ - if (cable_type == CT_COMPOSITE) - fb_writel(3 << 8, VOUTC); - else if (cable_type == CT_RGB) - fb_writel(1 << 9, VOUTC); - else - fb_writel(0, VOUTC); - - return cable_type; -} - #ifdef CONFIG_PVR2_DMA static ssize_t pvr2fb_write(struct fb_info *info, const char *buf, size_t count, loff_t *ppos) @@ -742,6 +709,46 @@ out_unmap: } #endif /* CONFIG_PVR2_DMA */ +static struct fb_ops pvr2fb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = pvr2fb_setcolreg, + .fb_blank = pvr2fb_blank, + .fb_check_var = pvr2fb_check_var, + .fb_set_par = pvr2fb_set_par, +#ifdef CONFIG_PVR2_DMA + .fb_write = pvr2fb_write, +#endif + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +#ifndef MODULE +static int pvr2_get_param_val(const struct pvr2_params *p, const char *s, + int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (!strncasecmp(p[i].name, s, strlen(s))) + return p[i].val; + } + return -1; +} +#endif + +static char *pvr2_get_param_name(const struct pvr2_params *p, int val, + int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (p[i].val == val) + return p[i].name; + } + return NULL; +} + /** * pvr2fb_common_init * @@ -760,7 +767,7 @@ out_unmap: * in for flexibility anyways. Who knows, maybe someone has tv-out on a * PCI-based version of these things ;-) */ -static int pvr2fb_common_init(void) +static int __maybe_unused pvr2fb_common_init(void) { struct pvr2fb_par *par = currentpar; unsigned long modememused, rev; @@ -773,8 +780,8 @@ static int pvr2fb_common_init(void) goto out_err; } - par->mmio_base = (unsigned long)ioremap_nocache(pvr2_fix.mmio_start, - pvr2_fix.mmio_len); + par->mmio_base = ioremap_nocache(pvr2_fix.mmio_start, + pvr2_fix.mmio_len); if (!par->mmio_base) { printk(KERN_ERR "pvr2fb: Failed to remap mmio space\n"); goto out_err; @@ -822,8 +829,8 @@ static int pvr2fb_common_init(void) fb_info->var.xres, fb_info->var.yres, fb_info->var.bits_per_pixel, get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel), - (char *)pvr2_get_param(cables, NULL, cable_type, 3), - (char *)pvr2_get_param(outputs, NULL, video_output, 3)); + pvr2_get_param_name(cables, cable_type, 3), + pvr2_get_param_name(outputs, video_output, 3)); #ifdef CONFIG_SH_STORE_QUEUES fb_notice(fb_info, "registering with SQ API\n"); @@ -841,7 +848,7 @@ out_err: if (fb_info->screen_base) iounmap(fb_info->screen_base); if (par->mmio_base) - iounmap((void *)par->mmio_base); + iounmap(par->mmio_base); return -ENXIO; } @@ -901,15 +908,15 @@ static int __init pvr2fb_dc_init(void) return pvr2fb_common_init(); } -static void __exit pvr2fb_dc_exit(void) +static void pvr2fb_dc_exit(void) { if (fb_info->screen_base) { iounmap(fb_info->screen_base); fb_info->screen_base = NULL; } if (currentpar->mmio_base) { - iounmap((void *)currentpar->mmio_base); - currentpar->mmio_base = 0; + iounmap(currentpar->mmio_base); + currentpar->mmio_base = NULL; } free_irq(HW_EVENT_VSYNC, fb_info); @@ -958,8 +965,8 @@ static void pvr2fb_pci_remove(struct pci_dev *pdev) fb_info->screen_base = NULL; } if (currentpar->mmio_base) { - iounmap((void *)currentpar->mmio_base); - currentpar->mmio_base = 0; + iounmap(currentpar->mmio_base); + currentpar->mmio_base = NULL; } pci_release_regions(pdev); @@ -985,29 +992,12 @@ static int __init pvr2fb_pci_init(void) return pci_register_driver(&pvr2fb_pci_driver); } -static void __exit pvr2fb_pci_exit(void) +static void pvr2fb_pci_exit(void) { pci_unregister_driver(&pvr2fb_pci_driver); } #endif /* CONFIG_PCI */ -static int pvr2_get_param(const struct pvr2_params *p, const char *s, int val, - int size) -{ - int i; - - for (i = 0 ; i < size ; i++ ) { - if (s != NULL) { - if (!strncasecmp(p[i].name, s, strlen(s))) - return p[i].val; - } else { - if (p[i].val == val) - return (int)p[i].name; - } - } - return -1; -} - /* * Parse command arguments. Supported arguments are: * inverse Use inverse color maps @@ -1047,9 +1037,9 @@ static int __init pvr2fb_setup(char *options) } if (*cable_arg) - cable_type = pvr2_get_param(cables, cable_arg, 0, 3); + cable_type = pvr2_get_param_val(cables, cable_arg, 3); if (*output_arg) - video_output = pvr2_get_param(outputs, output_arg, 0, 3); + video_output = pvr2_get_param_val(outputs, output_arg, 3); return 0; } @@ -1082,12 +1072,8 @@ static int __init pvr2fb_init(void) #endif fb_info = framebuffer_alloc(sizeof(struct pvr2fb_par), NULL); - - if (!fb_info) { - printk(KERN_ERR "Failed to allocate memory for fb_info\n"); + if (!fb_info) return -ENOMEM; - } - currentpar = fb_info->par; diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c index cc242ba057d3..ca593a3e41d7 100644 --- a/drivers/video/fbdev/riva/fbdev.c +++ b/drivers/video/fbdev/riva/fbdev.c @@ -1902,7 +1902,6 @@ static int rivafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) info = framebuffer_alloc(sizeof(struct riva_par), &pd->dev); if (!info) { - printk (KERN_ERR PFX "could not allocate memory\n"); ret = -ENOMEM; goto err_ret; } diff --git a/drivers/video/fbdev/s3c-fb.c b/drivers/video/fbdev/s3c-fb.c index 9ec85ccd0ce9..ba04d7a67829 100644 --- a/drivers/video/fbdev/s3c-fb.c +++ b/drivers/video/fbdev/s3c-fb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* linux/drivers/video/s3c-fb.c * * Copyright 2008 Openmoko Inc. @@ -6,10 +7,6 @@ * http://armlinux.simtec.co.uk/ * * Samsung SoC Framebuffer driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software FoundatIon. */ #include <linux/kernel.h> @@ -287,7 +284,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var, /* 666 with one bit alpha/transparency */ var->transp.offset = 18; var->transp.length = 1; - /* drop through */ + /* fall through */ case 18: var->bits_per_pixel = 32; @@ -315,7 +312,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var, case 25: var->transp.length = var->bits_per_pixel - 24; var->transp.offset = 24; - /* drop through */ + /* fall through */ case 24: /* our 24bpp is unpacked, so 32bpp */ var->bits_per_pixel = 32; @@ -812,7 +809,7 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) case FB_BLANK_POWERDOWN: wincon &= ~WINCONx_ENWIN; sfb->enabled &= ~(1 << index); - /* fall through to FB_BLANK_NORMAL */ + /* fall through - to FB_BLANK_NORMAL */ case FB_BLANK_NORMAL: /* disable the DMA and display 0x0 (black) */ @@ -1105,14 +1102,14 @@ static int s3c_fb_alloc_memory(struct s3c_fb *sfb, struct s3c_fb_win *win) dev_dbg(sfb->dev, "want %u bytes for window\n", size); - fbi->screen_base = dma_alloc_wc(sfb->dev, size, &map_dma, GFP_KERNEL); - if (!fbi->screen_base) + fbi->screen_buffer = dma_alloc_wc(sfb->dev, size, &map_dma, GFP_KERNEL); + if (!fbi->screen_buffer) return -ENOMEM; dev_dbg(sfb->dev, "mapped %x to %p\n", - (unsigned int)map_dma, fbi->screen_base); + (unsigned int)map_dma, fbi->screen_buffer); - memset(fbi->screen_base, 0x0, size); + memset(fbi->screen_buffer, 0x0, size); fbi->fix.smem_start = map_dma; return 0; @@ -1129,9 +1126,9 @@ static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win) { struct fb_info *fbi = win->fbinfo; - if (fbi->screen_base) + if (fbi->screen_buffer) dma_free_wc(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len), - fbi->screen_base, fbi->fix.smem_start); + fbi->screen_buffer, fbi->fix.smem_start); } /** @@ -1189,10 +1186,8 @@ static int s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) + palette_size * sizeof(u32), sfb->dev); - if (!fbinfo) { - dev_err(sfb->dev, "failed to allocate framebuffer\n"); - return -ENOENT; - } + if (!fbinfo) + return -ENOMEM; windata = sfb->pdata->win[win_no]; initmode = *sfb->pdata->vtiming; diff --git a/drivers/video/fbdev/s3fb.c b/drivers/video/fbdev/s3fb.c index d63f23e26f7d..be16c349c10f 100644 --- a/drivers/video/fbdev/s3fb.c +++ b/drivers/video/fbdev/s3fb.c @@ -1128,10 +1128,8 @@ static int s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) /* Allocate and fill driver data structure */ info = framebuffer_alloc(sizeof(struct s3fb_info), &(dev->dev)); - if (!info) { - dev_err(&(dev->dev), "cannot allocate memory\n"); + if (!info) return -ENOMEM; - } par = info->par; mutex_init(&par->open_lock); diff --git a/drivers/video/fbdev/sa1100fb.c b/drivers/video/fbdev/sa1100fb.c index 15ae50063296..f7f8dee044b1 100644 --- a/drivers/video/fbdev/sa1100fb.c +++ b/drivers/video/fbdev/sa1100fb.c @@ -974,35 +974,10 @@ static void sa1100fb_task(struct work_struct *w) */ static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi) { -#if 0 - unsigned int min_period = (unsigned int)-1; - int i; - - for (i = 0; i < MAX_NR_CONSOLES; i++) { - struct display *disp = &fb_display[i]; - unsigned int period; - - /* - * Do we own this display? - */ - if (disp->fb_info != &fbi->fb) - continue; - - /* - * Ok, calculate its DMA period - */ - period = sa1100fb_display_dma_period(&disp->var); - if (period < min_period) - min_period = period; - } - - return min_period; -#else /* * FIXME: we need to verify _all_ consoles. */ return sa1100fb_display_dma_period(&fbi->fb.var); -#endif } /* diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c index 47b78f0138c3..512789f5f884 100644 --- a/drivers/video/fbdev/savage/savagefb_driver.c +++ b/drivers/video/fbdev/savage/savagefb_driver.c @@ -2333,14 +2333,7 @@ static void savagefb_remove(struct pci_dev *dev) DBG("savagefb_remove"); if (info) { - /* - * If unregister_framebuffer fails, then - * we will be leaving hooks that could cause - * oopsen laying around. - */ - if (unregister_framebuffer(info)) - printk(KERN_WARNING "savagefb: danger danger! " - "Oopsen imminent!\n"); + unregister_framebuffer(info); #ifdef CONFIG_FB_SAVAGE_I2C savagefb_delete_i2c_busses(info); diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c index dc46be38c970..ac0bcac9a865 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c @@ -15,6 +15,7 @@ #include <linux/ctype.h> #include <linux/dma-mapping.h> #include <linux/delay.h> +#include <linux/fbcon.h> #include <linux/gpio.h> #include <linux/init.h> #include <linux/interrupt.h> @@ -213,7 +214,6 @@ struct sh_mobile_lcdc_priv { struct sh_mobile_lcdc_chan ch[2]; struct sh_mobile_lcdc_overlay overlays[4]; - struct notifier_block notifier; int started; int forced_fourcc; /* 2 channel LCDC must share fourcc setting */ }; @@ -534,89 +534,9 @@ static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch) ch->tx_dev->ops->display_off(ch->tx_dev); } -static bool -sh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch, - const struct fb_videomode *new_mode) -{ - dev_dbg(ch->info->dev, "Old %ux%u, new %ux%u\n", - ch->display.mode.xres, ch->display.mode.yres, - new_mode->xres, new_mode->yres); - - /* It can be a different monitor with an equal video-mode */ - if (fb_mode_is_equal(&ch->display.mode, new_mode)) - return false; - - dev_dbg(ch->info->dev, "Switching %u -> %u lines\n", - ch->display.mode.yres, new_mode->yres); - ch->display.mode = *new_mode; - - return true; -} - static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var, struct fb_info *info); -static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch, - enum sh_mobile_lcdc_entity_event event, - const struct fb_videomode *mode, - const struct fb_monspecs *monspec) -{ - struct fb_info *info = ch->info; - struct fb_var_screeninfo var; - int ret = 0; - - switch (event) { - case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT: - /* HDMI plug in */ - console_lock(); - if (lock_fb_info(info)) { - - - ch->display.width = monspec->max_x * 10; - ch->display.height = monspec->max_y * 10; - - if (!sh_mobile_lcdc_must_reconfigure(ch, mode) && - info->state == FBINFO_STATE_RUNNING) { - /* First activation with the default monitor. - * Just turn on, if we run a resume here, the - * logo disappears. - */ - info->var.width = ch->display.width; - info->var.height = ch->display.height; - sh_mobile_lcdc_display_on(ch); - } else { - /* New monitor or have to wake up */ - fb_set_suspend(info, 0); - } - - - unlock_fb_info(info); - } - console_unlock(); - break; - - case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT: - /* HDMI disconnect */ - console_lock(); - if (lock_fb_info(info)) { - fb_set_suspend(info, 1); - unlock_fb_info(info); - } - console_unlock(); - break; - - case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE: - /* Validate a proposed new mode */ - fb_videomode_to_var(&var, mode); - var.bits_per_pixel = info->var.bits_per_pixel; - var.grayscale = info->var.grayscale; - ret = sh_mobile_lcdc_check_var(&var, info); - break; - } - - return ret; -} - /* ----------------------------------------------------------------------------- * Format helpers */ @@ -1644,10 +1564,8 @@ sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl) /* Allocate and initialize the frame buffer device. */ info = framebuffer_alloc(0, priv->dev); - if (info == NULL) { - dev_err(priv->dev, "unable to allocate fb_info\n"); + if (!info) return -ENOMEM; - } ovl->info = info; @@ -1838,8 +1756,6 @@ static void sh_mobile_fb_reconfig(struct fb_info *info) struct sh_mobile_lcdc_chan *ch = info->par; struct fb_var_screeninfo var; struct fb_videomode mode; - struct fb_event event; - int evnt = FB_EVENT_MODE_CHANGE_ALL; if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par)) /* More framebuffer users are active */ @@ -1861,14 +1777,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info) /* Couldn't reconfigure, hopefully, can continue as before */ return; - /* - * fb_set_var() calls the notifier change internally, only if - * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a - * user event, we have to call the chain ourselves. - */ - event.info = info; - event.data = &ch->display.mode; - fb_notifier_call_chain(evnt, &event); + fbcon_update_vcs(info, true); } /* @@ -2138,10 +2047,8 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch, * list and allocate the color map. */ info = framebuffer_alloc(0, priv->dev); - if (info == NULL) { - dev_err(priv->dev, "unable to allocate fb_info\n"); + if (!info) return -ENOMEM; - } ch->info = info; @@ -2319,37 +2226,6 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { * Framebuffer notifier */ -/* locking: called with info->lock held */ -static int sh_mobile_lcdc_notify(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct fb_event *event = data; - struct fb_info *info = event->info; - struct sh_mobile_lcdc_chan *ch = info->par; - - if (&ch->lcdc->notifier != nb) - return NOTIFY_DONE; - - dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", - __func__, action, event->data); - - switch(action) { - case FB_EVENT_SUSPEND: - sh_mobile_lcdc_display_off(ch); - sh_mobile_lcdc_stop(ch->lcdc); - break; - case FB_EVENT_RESUME: - mutex_lock(&ch->open_lock); - sh_mobile_fb_reconfig(info); - mutex_unlock(&ch->open_lock); - - sh_mobile_lcdc_display_on(ch); - sh_mobile_lcdc_start(ch->lcdc); - } - - return NOTIFY_OK; -} - /* ----------------------------------------------------------------------------- * Probe/remove and driver init/exit */ @@ -2377,8 +2253,6 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev) struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); unsigned int i; - fb_unregister_client(&priv->notifier); - for (i = 0; i < ARRAY_SIZE(priv->overlays); i++) sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]); for (i = 0; i < ARRAY_SIZE(priv->ch); i++) @@ -2540,8 +2414,6 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch) unsigned int max_size; unsigned int i; - ch->notify = sh_mobile_lcdc_display_notify; - /* Validate the format. */ format = sh_mobile_format_info(cfg->fourcc); if (format == NULL) { @@ -2770,10 +2642,6 @@ static int sh_mobile_lcdc_probe(struct platform_device *pdev) goto err1; } - /* Failure ignored */ - priv->notifier.notifier_call = sh_mobile_lcdc_notify; - fb_register_client(&priv->notifier); - return 0; err1: sh_mobile_lcdc_remove(pdev); diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.h b/drivers/video/fbdev/sh_mobile_lcdcfb.h index b8e47a8bd8ab..589400372098 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.h +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.h @@ -87,11 +87,6 @@ struct sh_mobile_lcdc_chan { unsigned long base_addr_c; unsigned int line_size; - int (*notify)(struct sh_mobile_lcdc_chan *ch, - enum sh_mobile_lcdc_entity_event event, - const struct fb_videomode *mode, - const struct fb_monspecs *monspec); - /* Backlight */ struct backlight_device *bl; unsigned int bl_brightness; diff --git a/drivers/video/fbdev/sm501fb.c b/drivers/video/fbdev/sm501fb.c index dde52d027416..6edb4492e675 100644 --- a/drivers/video/fbdev/sm501fb.c +++ b/drivers/video/fbdev/sm501fb.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* linux/drivers/video/sm501fb.c * * Copyright (c) 2006 Simtec Electronics * Vincent Sanders <vince@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Framebuffer driver for the Silicon Motion SM501 */ @@ -1868,10 +1865,8 @@ static int sm501fb_probe_one(struct sm501fb_info *info, } fbi = framebuffer_alloc(sizeof(struct sm501fb_par), info->dev); - if (fbi == NULL) { - dev_err(info->dev, "cannot allocate %s framebuffer\n", name); + if (!fbi) return -ENOMEM; - } par = fbi->par; par->info = info; diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c index f1dcc6766d1e..7b1b0d8d27a7 100644 --- a/drivers/video/fbdev/sm712fb.c +++ b/drivers/video/fbdev/sm712fb.c @@ -1538,7 +1538,6 @@ static int smtcfb_pci_probe(struct pci_dev *pdev, info = framebuffer_alloc(sizeof(*sfb), &pdev->dev); if (!info) { - dev_err(&pdev->dev, "framebuffer_alloc failed\n"); err = -ENOMEM; goto failed_free; } diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c index 8cd7892a0b0d..0e0f5bbfc5ef 100644 --- a/drivers/video/fbdev/smscufx.c +++ b/drivers/video/fbdev/smscufx.c @@ -1650,10 +1650,8 @@ static int ufx_usb_probe(struct usb_interface *interface, /* allocates framebuffer driver structure, not framebuffer memory */ info = framebuffer_alloc(0, &usbdev->dev); - if (!info) { - dev_err(dev->gdev, "framebuffer_alloc failed\n"); + if (!info) goto e_nomem; - } dev->info = info; info->par = dev; diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index 021b727e8b5c..b674948e3bb8 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -555,10 +555,8 @@ static int ssd1307fb_probe(struct i2c_client *client, } info = framebuffer_alloc(sizeof(struct ssd1307fb_par), &client->dev); - if (!info) { - dev_err(&client->dev, "Couldn't allocate framebuffer.\n"); + if (!info) return -ENOMEM; - } par = info->par; par->info = info; diff --git a/drivers/video/fbdev/sunxvr1000.c b/drivers/video/fbdev/sunxvr1000.c index 8fe37c0ef2f5..784c9bd5d502 100644 --- a/drivers/video/fbdev/sunxvr1000.c +++ b/drivers/video/fbdev/sunxvr1000.c @@ -121,7 +121,6 @@ static int gfb_probe(struct platform_device *op) info = framebuffer_alloc(sizeof(struct gfb_info), &op->dev); if (!info) { - printk(KERN_ERR "gfb: Cannot allocate fb_info\n"); err = -ENOMEM; goto err_out; } diff --git a/drivers/video/fbdev/sunxvr2500.c b/drivers/video/fbdev/sunxvr2500.c index 544465ba1dc0..31683e5a8b79 100644 --- a/drivers/video/fbdev/sunxvr2500.c +++ b/drivers/video/fbdev/sunxvr2500.c @@ -132,7 +132,6 @@ static int s3d_pci_register(struct pci_dev *pdev, info = framebuffer_alloc(sizeof(struct s3d_info), &pdev->dev); if (!info) { - printk(KERN_ERR "s3d: Cannot allocate fb_info\n"); err = -ENOMEM; goto err_disable; } diff --git a/drivers/video/fbdev/sunxvr500.c b/drivers/video/fbdev/sunxvr500.c index bc595937df08..d392976126a6 100644 --- a/drivers/video/fbdev/sunxvr500.c +++ b/drivers/video/fbdev/sunxvr500.c @@ -272,7 +272,6 @@ static int e3d_pci_register(struct pci_dev *pdev, info = framebuffer_alloc(sizeof(struct e3d_info), &pdev->dev); if (!info) { - printk(KERN_ERR "e3d: Cannot allocate fb_info\n"); err = -ENOMEM; goto err_disable; } diff --git a/drivers/video/fbdev/tgafb.c b/drivers/video/fbdev/tgafb.c index 65ba9921506e..286b2371c7dd 100644 --- a/drivers/video/fbdev/tgafb.c +++ b/drivers/video/fbdev/tgafb.c @@ -1416,10 +1416,8 @@ static int tgafb_register(struct device *dev) /* Allocate the fb and par structures. */ info = framebuffer_alloc(sizeof(struct tga_par), dev); - if (!info) { - printk(KERN_ERR "tgafb: Cannot allocate memory\n"); + if (!info) return -ENOMEM; - } par = info->par; dev_set_drvdata(dev, info); diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index 00b99363e528..c328e8265cb1 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -1686,10 +1686,8 @@ static int dlfb_usb_probe(struct usb_interface *intf, /* allocates framebuffer driver structure, not framebuffer memory */ info = framebuffer_alloc(0, &dlfb->udev->dev); - if (!info) { - dev_err(&dlfb->udev->dev, "framebuffer_alloc failed\n"); + if (!info) goto error; - } dlfb->info = info; info->par = dlfb; diff --git a/drivers/video/fbdev/via/viafbdev.c b/drivers/video/fbdev/via/viafbdev.c index 8db5de13e2b7..f815f98190bc 100644 --- a/drivers/video/fbdev/via/viafbdev.c +++ b/drivers/video/fbdev/via/viafbdev.c @@ -1742,10 +1742,8 @@ int via_fb_pci_probe(struct viafb_dev *vdev) viafbinfo = framebuffer_alloc(viafb_par_length + ALIGN(sizeof(struct viafb_shared), BITS_PER_LONG/8), &vdev->pdev->dev); - if (!viafbinfo) { - printk(KERN_ERR"Could not allocate memory for viafb_info.\n"); + if (!viafbinfo) return -ENOMEM; - } viaparinfo = (struct viafb_par *)viafbinfo->par; viaparinfo->shared = viafbinfo->par + viafb_par_length; @@ -1820,8 +1818,6 @@ int via_fb_pci_probe(struct viafb_dev *vdev) viafbinfo1 = framebuffer_alloc(viafb_par_length, &vdev->pdev->dev); if (!viafbinfo1) { - printk(KERN_ERR - "allocate the second framebuffer struct error\n"); rc = -ENOMEM; goto out_fb_release; } diff --git a/drivers/video/fbdev/vt8623fb.c b/drivers/video/fbdev/vt8623fb.c index 5cac871db3ee..c339a8fbad81 100644 --- a/drivers/video/fbdev/vt8623fb.c +++ b/drivers/video/fbdev/vt8623fb.c @@ -669,10 +669,8 @@ static int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) /* Allocate and fill driver data structure */ info = framebuffer_alloc(sizeof(struct vt8623fb_info), &(dev->dev)); - if (! info) { - dev_err(&(dev->dev), "cannot allocate memory\n"); + if (!info) return -ENOMEM; - } par = info->par; mutex_init(&par->open_lock); diff --git a/drivers/video/fbdev/w100fb.c b/drivers/video/fbdev/w100fb.c index 696106ecdff0..597ffaa13cd2 100644 --- a/drivers/video/fbdev/w100fb.c +++ b/drivers/video/fbdev/w100fb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/w100fb.c * @@ -17,11 +18,6 @@ * * Hardware acceleration support by Alberto Mardegan * <mardy@users.sourceforge.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/delay.h> diff --git a/drivers/video/fbdev/w100fb.h b/drivers/video/fbdev/w100fb.h index fffae7b4f6e9..52c96d155b4c 100644 --- a/drivers/video/fbdev/w100fb.h +++ b/drivers/video/fbdev/w100fb.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/video/w100fb.h * @@ -10,11 +11,6 @@ * Modified to work with 2.6 by Richard Purdie <rpurdie@rpsys.net> * * w32xx support by Ian Molton - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #if !defined (_W100FB_H) diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index 55e11bf8ebaf..d4632aace402 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * w1-gpio - GPIO w1 bus master driver * * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. */ #include <linux/init.h> diff --git a/drivers/w1/slaves/w1_ds2406.c b/drivers/w1/slaves/w1_ds2406.c index fac266366ca3..762e5e4e2b48 100644 --- a/drivers/w1/slaves/w1_ds2406.c +++ b/drivers/w1/slaves/w1_ds2406.c @@ -1,11 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * w1_ds2406.c - w1 family 12 (DS2406) driver * based on w1_ds2413.c by Mariusz Bialonczyk <manio@skyboo.net> * * Copyright (c) 2014 Scott Alfter <scott@alfter.us> - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. */ #include <linux/kernel.h> diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c index edf0bc98012c..83f8d94bb814 100644 --- a/drivers/w1/slaves/w1_ds2408.c +++ b/drivers/w1/slaves/w1_ds2408.c @@ -1,10 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * w1_ds2408.c - w1 family 29 (DS2408) driver * * Copyright (c) 2010 Jean-Francois Dagenais <dagenaisj@sonatest.com> - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. */ #include <linux/kernel.h> diff --git a/drivers/w1/slaves/w1_ds2413.c b/drivers/w1/slaves/w1_ds2413.c index 492e3d010321..5ae74d5545e6 100644 --- a/drivers/w1/slaves/w1_ds2413.c +++ b/drivers/w1/slaves/w1_ds2413.c @@ -1,11 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * w1_ds2413.c - w1 family 3a (DS2413) driver * based on w1_ds2408.c by Jean-Francois Dagenais <dagenaisj@sonatest.com> * * Copyright (c) 2013 Mariusz Bialonczyk <manio@skyboo.net> - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. */ #include <linux/kernel.h> diff --git a/drivers/w1/slaves/w1_ds2431.c b/drivers/w1/slaves/w1_ds2431.c index 5adecd3face1..e5bd7e2354d7 100644 --- a/drivers/w1/slaves/w1_ds2431.c +++ b/drivers/w1/slaves/w1_ds2431.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * w1_ds2431.c - w1 family 2d (DS2431) driver * * Copyright (c) 2008 Bernhard Weirich <bernhard.weirich@riedel.net> * * Heavily inspired by w1_DS2433 driver from Ben Gardner <bgardner@wabtec.com> - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. */ #include <linux/kernel.h> diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c index 75ad70cfe8e8..1f805c86517a 100644 --- a/drivers/w1/slaves/w1_ds2433.c +++ b/drivers/w1/slaves/w1_ds2433.c @@ -1,10 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * w1_ds2433.c - w1 family 23 (DS2433) driver * * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com> - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. */ #include <linux/kernel.h> diff --git a/drivers/w1/slaves/w1_ds2438.c b/drivers/w1/slaves/w1_ds2438.c index 7c4e33dbee4d..d199e5a25cc0 100644 --- a/drivers/w1/slaves/w1_ds2438.c +++ b/drivers/w1/slaves/w1_ds2438.c @@ -1,10 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 1-Wire implementation for the ds2438 chip * * Copyright (c) 2017 Mariusz Bialonczyk <manio@skyboo.net> - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. */ #include <linux/kernel.h> diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c index a60528131154..c689b1b987b8 100644 --- a/drivers/w1/slaves/w1_ds2780.c +++ b/drivers/w1/slaves/w1_ds2780.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 1-Wire implementation for the ds2780 chip * @@ -6,11 +7,6 @@ * Author: Clifton Barnes <cabarnes@indesign-llc.com> * * Based on w1-ds2760 driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/w1/slaves/w1_ds2780.h b/drivers/w1/slaves/w1_ds2780.h index a1fba79eb1b5..99e38ed788a5 100644 --- a/drivers/w1/slaves/w1_ds2780.h +++ b/drivers/w1/slaves/w1_ds2780.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * 1-Wire implementation for the ds2780 chip * @@ -6,11 +7,6 @@ * Author: Clifton Barnes <cabarnes@indesign-llc.com> * * Based on w1-ds2760 driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef _W1_DS2780_H diff --git a/drivers/w1/slaves/w1_ds2781.c b/drivers/w1/slaves/w1_ds2781.c index 645be6e0b24a..84d6ceec5da5 100644 --- a/drivers/w1/slaves/w1_ds2781.c +++ b/drivers/w1/slaves/w1_ds2781.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 1-Wire implementation for the ds2781 chip * * Author: Renata Sayakhova <renata@oktetlabs.ru> * * Based on w1-ds2780 driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> diff --git a/drivers/w1/slaves/w1_ds2781.h b/drivers/w1/slaves/w1_ds2781.h index 557dfb0b4f64..fa902dfa0136 100644 --- a/drivers/w1/slaves/w1_ds2781.h +++ b/drivers/w1/slaves/w1_ds2781.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * 1-Wire implementation for the ds2780 chip * * Author: Renata Sayakhova <renata@oktetlabs.ru> * * Based on w1-ds2760 driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef _W1_DS2781_H diff --git a/drivers/w1/slaves/w1_ds2805.c b/drivers/w1/slaves/w1_ds2805.c index 29348d283a65..ee1ec9867a78 100644 --- a/drivers/w1/slaves/w1_ds2805.c +++ b/drivers/w1/slaves/w1_ds2805.c @@ -1,10 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * w1_ds2805 - w1 family 0d (DS28E05) driver * * Copyright (c) 2016 Andrew Worsley amworsley@gmail.com - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. */ #include <linux/kernel.h> diff --git a/drivers/w1/slaves/w1_ds28e04.c b/drivers/w1/slaves/w1_ds28e04.c index ec234b846eb3..8a640f159078 100644 --- a/drivers/w1/slaves/w1_ds28e04.c +++ b/drivers/w1/slaves/w1_ds28e04.c @@ -1,10 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * w1_ds28e04.c - w1 family 1C (DS28E04) driver * * Copyright (c) 2012 Markus Franke <franke.m@sebakmt.com> - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. */ #include <linux/kernel.h> diff --git a/drivers/w1/slaves/w1_ds28e17.c b/drivers/w1/slaves/w1_ds28e17.c index e78b63ea4daf..046ddda83df9 100644 --- a/drivers/w1/slaves/w1_ds28e17.c +++ b/drivers/w1/slaves/w1_ds28e17.c @@ -1,10 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * w1_ds28e17.c - w1 family 19 (DS28E17) driver * * Copyright (c) 2016 Jan Kandziora <jjj@gmx.de> - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. */ #include <linux/crc16.h> diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c index 02234c254b10..2e09981fe978 100644 --- a/drivers/watchdog/ath79_wdt.c +++ b/drivers/watchdog/ath79_wdt.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Atheros AR71XX/AR724X/AR913X built-in hardware watchdog timer. * @@ -10,11 +11,6 @@ * * which again was based on sa1100 driver, * Copyright (C) 2000 Oleg Drokin <green@crimea.edu> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/watchdog/ftwdt010_wdt.c b/drivers/watchdog/ftwdt010_wdt.c index 9ea0e56fa7ee..d9626ef9b9ae 100644 --- a/drivers/watchdog/ftwdt010_wdt.c +++ b/drivers/watchdog/ftwdt010_wdt.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Watchdog driver for Faraday Technology FTWDT010 * @@ -5,10 +6,6 @@ * * Inspired by the out-of-tree drivers from OpenWRT: * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index db1bf6f546ae..8a90f159ffb1 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HPE WatchDog Driver * based on @@ -6,11 +7,6 @@ * * (c) Copyright 2018 Hewlett Packard Enterprise Development LP * Thomas Mingarelli <thomas.mingarelli@hpe.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c index 0fc31aadeee3..b57ff3787052 100644 --- a/drivers/watchdog/imgpdc_wdt.c +++ b/drivers/watchdog/imgpdc_wdt.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Imagination Technologies PowerDown Controller Watchdog Timer. * * Copyright (c) 2014 Imagination Technologies Ltd. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Based on drivers/watchdog/sunxi_wdt.c Copyright (c) 2013 Carlo Caione * 2012 Henrik Nordstrom * diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c index 0565cf30017b..1550ce3c5702 100644 --- a/drivers/watchdog/ks8695_wdt.c +++ b/drivers/watchdog/ks8695_wdt.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Watchdog driver for Kendin/Micrel KS8695. * * (C) 2007 Andrew Victor - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c index 4caf02ba5d49..6fab504af88b 100644 --- a/drivers/watchdog/lantiq_wdt.c +++ b/drivers/watchdog/lantiq_wdt.c @@ -1,7 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. * * Copyright (C) 2010 John Crispin <john@phrozen.org> * Copyright (C) 2017 Hauke Mehrtens <hauke@hauke-m.de> diff --git a/drivers/watchdog/lpc18xx_wdt.c b/drivers/watchdog/lpc18xx_wdt.c index 0e82abd71d35..78cf11c94941 100644 --- a/drivers/watchdog/lpc18xx_wdt.c +++ b/drivers/watchdog/lpc18xx_wdt.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP LPC18xx Watchdog Timer (WDT) * * Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com> * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * * Notes * ----- * The Watchdog consists of a fixed divide-by-4 clock pre-scaler and a 24-bit diff --git a/drivers/watchdog/max77620_wdt.c b/drivers/watchdog/max77620_wdt.c index 3ca6b9337932..9937f9fccd2e 100644 --- a/drivers/watchdog/max77620_wdt.c +++ b/drivers/watchdog/max77620_wdt.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Maxim MAX77620 Watchdog Driver * * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. * * Author: Laxman Dewangan <ldewangan@nvidia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/watchdog/mt7621_wdt.c b/drivers/watchdog/mt7621_wdt.c index cbb3c0dde136..a8aa3522cfda 100644 --- a/drivers/watchdog/mt7621_wdt.c +++ b/drivers/watchdog/mt7621_wdt.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Ralink MT7621/MT7628 built-in hardware watchdog timer * * Copyright (C) 2014 John Crispin <john@phrozen.org> * * This driver was based on: drivers/watchdog/rt2880_wdt.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/watchdog/rt2880_wdt.c b/drivers/watchdog/rt2880_wdt.c index 905e60f45eec..49aff800824d 100644 --- a/drivers/watchdog/rt2880_wdt.c +++ b/drivers/watchdog/rt2880_wdt.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Ralink RT288x/RT3xxx/MT76xx built-in hardware watchdog timer * @@ -5,10 +6,6 @@ * Copyright (C) 2013 John Crispin <john@phrozen.org> * * This driver was based on: drivers/watchdog/softdog.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c index fcb4da5b1f4c..89a54b6645bd 100644 --- a/drivers/watchdog/txx9wdt.c +++ b/drivers/watchdog/txx9wdt.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * txx9wdt: A Hardware Watchdog Driver for TXx9 SoCs * * Copyright (C) 2007 Atsushi Nemoto <anemo@mba.ocn.ne.jp> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/watchdog/wdat_wdt.c b/drivers/watchdog/wdat_wdt.c index 430ee4e9b185..e7cf41aa26c3 100644 --- a/drivers/watchdog/wdat_wdt.c +++ b/drivers/watchdog/wdat_wdt.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ACPI Hardware Watchdog (WDAT) driver. * * Copyright (C) 2016, Intel Corporation * Author: Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> diff --git a/drivers/xen/sys-hypervisor.c b/drivers/xen/sys-hypervisor.c index 9d314bba7c4e..feb1d16252e7 100644 --- a/drivers/xen/sys-hypervisor.c +++ b/drivers/xen/sys-hypervisor.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * copyright (c) 2006 IBM Corporation * Authored by: Mike D. Day <ncmike@us.ibm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/slab.h> |