diff options
Diffstat (limited to 'drivers')
1035 files changed, 14979 insertions, 50322 deletions
diff --git a/drivers/accessibility/speakup/spk_ttyio.c b/drivers/accessibility/speakup/spk_ttyio.c index 08cf8a17754b..07373b3debd1 100644 --- a/drivers/accessibility/speakup/spk_ttyio.c +++ b/drivers/accessibility/speakup/spk_ttyio.c @@ -354,6 +354,9 @@ void spk_ttyio_release(struct spk_synth *in_synth) { struct tty_struct *tty = in_synth->dev; + if (tty == NULL) + return; + tty_lock(tty); if (tty->ops->close) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 30d8fd03fec7..97b711e57bff 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -70,11 +70,7 @@ module_param(device_id_scheme, bool, 0444); static int only_lcd = -1; module_param(only_lcd, int, 0444); -/* - * Display probing is known to take up to 5 seconds, so delay the fallback - * backlight registration by 5 seconds + 3 seconds for some extra margin. - */ -static int register_backlight_delay = 8; +static int register_backlight_delay; module_param(register_backlight_delay, int, 0444); MODULE_PARM_DESC(register_backlight_delay, "Delay in seconds before doing fallback (non GPU driver triggered) " @@ -2176,6 +2172,17 @@ static bool should_check_lcd_flag(void) return false; } +/* + * At least one graphics driver has reported that no LCD is connected + * via the native interface. cancel the registration for fallback acpi_video0. + * If another driver still deems this necessary, it can explicitly register it. + */ +void acpi_video_report_nolcd(void) +{ + cancel_delayed_work(&video_bus_register_backlight_work); +} +EXPORT_SYMBOL(acpi_video_report_nolcd); + int acpi_video_register(void) { int ret = 0; diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 204fe94c7e45..a194f30876c5 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -75,7 +75,8 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev) } #define FIND_CHILD_MIN_SCORE 1 -#define FIND_CHILD_MAX_SCORE 2 +#define FIND_CHILD_MID_SCORE 2 +#define FIND_CHILD_MAX_SCORE 3 static int match_any(struct acpi_device *adev, void *not_used) { @@ -96,8 +97,17 @@ static int find_child_checks(struct acpi_device *adev, bool check_children) return -ENODEV; status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); - if (status == AE_NOT_FOUND) + if (status == AE_NOT_FOUND) { + /* + * Special case: backlight device objects without _STA are + * preferred to other objects with the same _ADR value, because + * it is more likely that they are actually useful. + */ + if (adev->pnp.type.backlight) + return FIND_CHILD_MID_SCORE; + return FIND_CHILD_MIN_SCORE; + } if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED)) return -ENODEV; diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index f1cc5ec6a3b6..4e48d6db05eb 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -3297,8 +3297,8 @@ void acpi_nfit_shutdown(void *data) mutex_lock(&acpi_desc->init_mutex); set_bit(ARS_CANCEL, &acpi_desc->scrub_flags); - cancel_delayed_work_sync(&acpi_desc->dwork); mutex_unlock(&acpi_desc->init_mutex); + cancel_delayed_work_sync(&acpi_desc->dwork); /* * Bounce the nvdimm bus lock to make sure any in-flight diff --git a/drivers/acpi/prmt.c b/drivers/acpi/prmt.c index 998101cf16e4..3d4c4620f9f9 100644 --- a/drivers/acpi/prmt.c +++ b/drivers/acpi/prmt.c @@ -236,6 +236,11 @@ static acpi_status acpi_platformrt_space_handler(u32 function, efi_status_t status; struct prm_context_buffer context; + if (!efi_enabled(EFI_RUNTIME_SERVICES)) { + pr_err_ratelimited("PRM: EFI runtime services no longer available\n"); + return AE_NO_HANDLER; + } + /* * The returned acpi_status will always be AE_OK. Error values will be * saved in the first byte of the PRM message buffer to be used by ASL. @@ -325,6 +330,11 @@ void __init init_prmt(void) pr_info("PRM: found %u modules\n", mc); + if (!efi_enabled(EFI_RUNTIME_SERVICES)) { + pr_err("PRM: EFI runtime services unavailable\n"); + return; + } + status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_PLATFORM_RT, &acpi_platformrt_space_handler, diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 7bf882fcd64b..7f77710c86fc 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -109,8 +109,8 @@ static const struct dmi_system_id processor_power_dmi_table[] = { static void __cpuidle acpi_safe_halt(void) { if (!tif_need_resched()) { - safe_halt(); - local_irq_disable(); + raw_safe_halt(); + raw_local_irq_disable(); } } @@ -523,8 +523,11 @@ static int acpi_idle_bm_check(void) return bm_status; } -static void wait_for_freeze(void) +static __cpuidle void io_idle(unsigned long addr) { + /* IO port based C-state */ + inb(addr); + #ifdef CONFIG_X86 /* No delay is needed if we are in guest */ if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) @@ -569,9 +572,7 @@ static void __cpuidle acpi_idle_do_entry(struct acpi_processor_cx *cx) } else if (cx->entry_method == ACPI_CSTATE_HALT) { acpi_safe_halt(); } else { - /* IO port based C-state */ - inb(cx->address); - wait_for_freeze(); + io_idle(cx->address); } perf_lopwr_cb(false); @@ -593,8 +594,7 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) if (cx->entry_method == ACPI_CSTATE_HALT) safe_halt(); else if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) { - inb(cx->address); - wait_for_freeze(); + io_idle(cx->address); } else return -ENODEV; @@ -607,7 +607,7 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) return 0; } -static bool acpi_idle_fallback_to_c1(struct acpi_processor *pr) +static __always_inline bool acpi_idle_fallback_to_c1(struct acpi_processor *pr) { return IS_ENABLED(CONFIG_HOTPLUG_CPU) && !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED); @@ -642,6 +642,8 @@ static int __cpuidle acpi_idle_enter_bm(struct cpuidle_driver *drv, */ bool dis_bm = pr->flags.bm_control; + instrumentation_begin(); + /* If we can skip BM, demote to a safe state. */ if (!cx->bm_sts_skip && acpi_idle_bm_check()) { dis_bm = false; @@ -663,11 +665,11 @@ static int __cpuidle acpi_idle_enter_bm(struct cpuidle_driver *drv, raw_spin_unlock(&c3_lock); } - ct_idle_enter(); + ct_cpuidle_enter(); acpi_idle_do_entry(cx); - ct_idle_exit(); + ct_cpuidle_exit(); /* Re-enable bus master arbitration */ if (dis_bm) { @@ -677,6 +679,8 @@ static int __cpuidle acpi_idle_enter_bm(struct cpuidle_driver *drv, raw_spin_unlock(&c3_lock); } + instrumentation_end(); + return index; } @@ -1219,6 +1223,8 @@ static int acpi_processor_setup_lpi_states(struct acpi_processor *pr) state->target_residency = lpi->min_residency; if (lpi->arch_flags) state->flags |= CPUIDLE_FLAG_TIMER_STOP; + if (i != 0 && lpi->entry_method == ACPI_CSTATE_FFH) + state->flags |= CPUIDLE_FLAG_RCU_IDLE; state->enter = acpi_idle_lpi_enter; drv->safe_state_index = i; } diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index f27914aedbd5..192d1784e409 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -432,10 +432,31 @@ static const struct dmi_system_id asus_laptop[] = { DMI_MATCH(DMI_BOARD_NAME, "S5602ZA"), }, }, + { + .ident = "Asus ExpertBook B2402CBA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "B2402CBA"), + }, + }, + { + .ident = "Asus ExpertBook B2502", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "B2502CBA"), + }, + }, { } }; -static const struct dmi_system_id lenovo_82ra[] = { +static const struct dmi_system_id lenovo_laptop[] = { + { + .ident = "LENOVO IdeaPad Flex 5 14ALC7", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "82R9"), + }, + }, { .ident = "LENOVO IdeaPad Flex 5 16ALC7", .matches = { @@ -446,6 +467,17 @@ static const struct dmi_system_id lenovo_82ra[] = { { } }; +static const struct dmi_system_id schenker_gm_rg[] = { + { + .ident = "XMG CORE 15 (M22)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"), + DMI_MATCH(DMI_BOARD_NAME, "GMxRGxx"), + }, + }, + { } +}; + struct irq_override_cmp { const struct dmi_system_id *system; unsigned char irq; @@ -458,8 +490,9 @@ struct irq_override_cmp { static const struct irq_override_cmp override_table[] = { { medion_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, { asus_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, - { lenovo_82ra, 6, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, true }, - { lenovo_82ra, 10, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, true }, + { lenovo_laptop, 6, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, true }, + { lenovo_laptop, 10, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, true }, + { schenker_gm_rg, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, }; static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity, diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 274344434282..0c6f06abe3f4 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1370,9 +1370,12 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, * Some devices don't reliably have _HIDs & _CIDs, so add * synthetic HIDs to make sure drivers can find them. */ - if (acpi_is_video_device(handle)) + if (acpi_is_video_device(handle)) { acpi_add_id(pnp, ACPI_VIDEO_HID); - else if (acpi_bay_match(handle)) + pnp->type.backlight = 1; + break; + } + if (acpi_bay_match(handle)) acpi_add_id(pnp, ACPI_BAY_HID); else if (acpi_dock_match(handle)) acpi_add_id(pnp, ACPI_DOCK_HID); diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 0b557c0d405e..4ca667251272 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -60,13 +60,17 @@ static struct notifier_block tts_notifier = { .priority = 0, }; +#ifndef acpi_skip_set_wakeup_address +#define acpi_skip_set_wakeup_address() false +#endif + static int acpi_sleep_prepare(u32 acpi_state) { #ifdef CONFIG_ACPI_SLEEP unsigned long acpi_wakeup_address; /* do we have a wakeup address for S2 and S3? */ - if (acpi_state == ACPI_STATE_S3) { + if (acpi_state == ACPI_STATE_S3 && !acpi_skip_set_wakeup_address()) { acpi_wakeup_address = acpi_get_wakeup_address(); if (!acpi_wakeup_address) return -EFAULT; diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index a934bbc9dd37..a8c02608dde4 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -34,6 +34,7 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/platform_data/x86/nvidia-wmi-ec-backlight.h> +#include <linux/pnp.h> #include <linux/types.h> #include <linux/workqueue.h> #include <acpi/video.h> @@ -49,6 +50,10 @@ static void acpi_video_parse_cmdline(void) acpi_backlight_cmdline = acpi_backlight_video; if (!strcmp("native", acpi_video_backlight_string)) acpi_backlight_cmdline = acpi_backlight_native; + if (!strcmp("nvidia_wmi_ec", acpi_video_backlight_string)) + acpi_backlight_cmdline = acpi_backlight_nvidia_wmi_ec; + if (!strcmp("apple_gmux", acpi_video_backlight_string)) + acpi_backlight_cmdline = acpi_backlight_apple_gmux; if (!strcmp("none", acpi_video_backlight_string)) acpi_backlight_cmdline = acpi_backlight_none; } @@ -492,6 +497,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { }, { .callback = video_detect_force_native, + /* Acer Aspire 4810T */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 4810T"), + }, + }, + { + .callback = video_detect_force_native, /* Acer Aspire 5738z */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), @@ -579,6 +592,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { }, { .callback = video_detect_force_native, + /* Asus U46E */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "U46E"), + }, + }, + { + .callback = video_detect_force_native, /* Asus UX303UB */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), @@ -587,6 +608,23 @@ static const struct dmi_system_id video_detect_dmi_table[] = { }, { .callback = video_detect_force_native, + /* HP EliteBook 8460p */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8460p"), + }, + }, + { + .callback = video_detect_force_native, + /* HP Pavilion g6-1d80nr / B4U19UA */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion g6 Notebook PC"), + DMI_MATCH(DMI_PRODUCT_SKU, "B4U19UA"), + }, + }, + { + .callback = video_detect_force_native, /* Samsung N150P */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), @@ -733,6 +771,7 @@ static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native) { static DEFINE_MUTEX(init_mutex); static bool nvidia_wmi_ec_present; + static bool apple_gmux_present; static bool native_available; static bool init_done; static long video_caps; @@ -746,6 +785,7 @@ static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native) ACPI_UINT32_MAX, find_video, NULL, &video_caps, NULL); nvidia_wmi_ec_present = nvidia_wmi_ec_supported(); + apple_gmux_present = apple_gmux_detect(NULL, NULL); init_done = true; } if (native) @@ -767,7 +807,7 @@ static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native) if (nvidia_wmi_ec_present) return acpi_backlight_nvidia_wmi_ec; - if (apple_gmux_present()) + if (apple_gmux_present) return acpi_backlight_apple_gmux; /* Use ACPI video if available, except when native should be preferred. */ diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c index 5350c73564b6..c7afce465a07 100644 --- a/drivers/acpi/x86/s2idle.c +++ b/drivers/acpi/x86/s2idle.c @@ -28,10 +28,6 @@ static bool sleep_no_lps0 __read_mostly; module_param(sleep_no_lps0, bool, 0644); MODULE_PARM_DESC(sleep_no_lps0, "Do not use the special LPS0 device interface"); -static bool prefer_microsoft_dsm_guid __read_mostly; -module_param(prefer_microsoft_dsm_guid, bool, 0644); -MODULE_PARM_DESC(prefer_microsoft_dsm_guid, "Prefer using Microsoft GUID in LPS0 device _DSM evaluation"); - static const struct acpi_device_id lps0_device_ids[] = { {"PNP0D80", }, {"", }, @@ -369,27 +365,15 @@ out: } struct amd_lps0_hid_device_data { - const unsigned int rev_id; const bool check_off_by_one; - const bool prefer_amd_guid; }; static const struct amd_lps0_hid_device_data amd_picasso = { - .rev_id = 0, .check_off_by_one = true, - .prefer_amd_guid = false, }; static const struct amd_lps0_hid_device_data amd_cezanne = { - .rev_id = 0, - .check_off_by_one = false, - .prefer_amd_guid = false, -}; - -static const struct amd_lps0_hid_device_data amd_rembrandt = { - .rev_id = 2, .check_off_by_one = false, - .prefer_amd_guid = true, }; static const struct acpi_device_id amd_hid_ids[] = { @@ -397,69 +381,27 @@ static const struct acpi_device_id amd_hid_ids[] = { {"AMD0005", (kernel_ulong_t)&amd_picasso, }, {"AMDI0005", (kernel_ulong_t)&amd_picasso, }, {"AMDI0006", (kernel_ulong_t)&amd_cezanne, }, - {"AMDI0007", (kernel_ulong_t)&amd_rembrandt, }, {} }; -static int lps0_prefer_microsoft(const struct dmi_system_id *id) +static int lps0_prefer_amd(const struct dmi_system_id *id) { - pr_debug("Preferring Microsoft GUID.\n"); - prefer_microsoft_dsm_guid = true; + pr_debug("Using AMD GUID w/ _REV 2.\n"); + rev_id = 2; return 0; } - static const struct dmi_system_id s2idle_dmi_table[] __initconst = { { /* - * ASUS TUF Gaming A17 FA707RE - * https://bugzilla.kernel.org/show_bug.cgi?id=216101 - */ - .callback = lps0_prefer_microsoft, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "ASUS TUF Gaming A17"), - }, - }, - { - /* ASUS ROG Zephyrus G14 (2022) */ - .callback = lps0_prefer_microsoft, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "ROG Zephyrus G14 GA402"), - }, - }, - { - /* - * Lenovo Yoga Slim 7 Pro X 14ARH7 - * https://bugzilla.kernel.org/show_bug.cgi?id=216473 : 82V2 - * https://bugzilla.kernel.org/show_bug.cgi?id=216438 : 82TL - */ - .callback = lps0_prefer_microsoft, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "82"), - }, - }, - { - /* - * ASUSTeK COMPUTER INC. ROG Flow X13 GV301RE_GV301RE - * https://gitlab.freedesktop.org/drm/amd/-/issues/2148 + * AMD Rembrandt based HP EliteBook 835/845/865 G9 + * Contains specialized AML in AMD/_REV 2 path to avoid + * triggering a bug in Qualcomm WLAN firmware. This may be + * removed in the future if that firmware is fixed. */ - .callback = lps0_prefer_microsoft, + .callback = lps0_prefer_amd, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "ROG Flow X13 GV301"), - }, - }, - { - /* - * ASUSTeK COMPUTER INC. ROG Flow X16 GV601RW_GV601RW - * https://gitlab.freedesktop.org/drm/amd/-/issues/2148 - */ - .callback = lps0_prefer_microsoft, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "ROG Flow X16 GV601"), + DMI_MATCH(DMI_BOARD_VENDOR, "HP"), + DMI_MATCH(DMI_BOARD_NAME, "8990"), }, }, {} @@ -484,16 +426,14 @@ static int lps0_device_attach(struct acpi_device *adev, if (dev_id->id[0]) data = (const struct amd_lps0_hid_device_data *) dev_id->driver_data; else - data = &amd_rembrandt; - rev_id = data->rev_id; + data = &amd_cezanne; lps0_dsm_func_mask = validate_dsm(adev->handle, ACPI_LPS0_DSM_UUID_AMD, rev_id, &lps0_dsm_guid); if (lps0_dsm_func_mask > 0x3 && data->check_off_by_one) { lps0_dsm_func_mask = (lps0_dsm_func_mask << 1) | 0x1; acpi_handle_debug(adev->handle, "_DSM UUID %s: Adjusted function mask: 0x%x\n", ACPI_LPS0_DSM_UUID_AMD, lps0_dsm_func_mask); - } else if (lps0_dsm_func_mask_microsoft > 0 && data->prefer_amd_guid && - !prefer_microsoft_dsm_guid) { + } else if (lps0_dsm_func_mask_microsoft > 0 && rev_id) { lps0_dsm_func_mask_microsoft = -EINVAL; acpi_handle_debug(adev->handle, "_DSM Using AMD method\n"); } @@ -501,8 +441,7 @@ static int lps0_device_attach(struct acpi_device *adev, rev_id = 1; lps0_dsm_func_mask = validate_dsm(adev->handle, ACPI_LPS0_DSM_UUID, rev_id, &lps0_dsm_guid); - if (!prefer_microsoft_dsm_guid) - lps0_dsm_func_mask_microsoft = -EINVAL; + lps0_dsm_func_mask_microsoft = -EINVAL; } if (lps0_dsm_func_mask < 0 && lps0_dsm_func_mask_microsoft < 0) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 09b2ce7e4c34..348d63d1e3d3 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -352,7 +352,7 @@ static inline bool is_binderfs_control_device(const struct dentry *dentry) return info->control_dentry == dentry; } -static int binderfs_rename(struct user_namespace *mnt_userns, +static int binderfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) @@ -361,7 +361,7 @@ static int binderfs_rename(struct user_namespace *mnt_userns, is_binderfs_control_device(new_dentry)) return -EPERM; - return simple_rename(&init_user_ns, old_dir, old_dentry, new_dir, + return simple_rename(idmap, old_dir, old_dentry, new_dir, new_dentry, flags); } diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index eceaec33af65..0b6358a5b315 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -640,6 +640,7 @@ config PATA_CS5530 config PATA_CS5535 tristate "CS5535 PATA support (Experimental)" depends on PCI && (X86_32 || (X86_64 && COMPILE_TEST)) + depends on !UML help This option enables support for the NatSemi/AMD CS5535 companion chip used with the Geode processor family. @@ -1082,15 +1083,6 @@ config PATA_OPTI If unsure, say N. -config PATA_PALMLD - tristate "Palm LifeDrive PATA support" - depends on MACH_PALMLD - help - This option enables support for Palm LifeDrive's internal ATA - port via the new ATA layer. - - If unsure, say N. - config PATA_PCMCIA tristate "PCMCIA PATA support" depends on PCMCIA @@ -1144,16 +1136,6 @@ config PATA_RZ1000 If unsure, say N. -config PATA_SAMSUNG_CF - tristate "Samsung SoC PATA support" - depends on SAMSUNG_DEV_IDE || COMPILE_TEST - select PATA_TIMINGS - help - This option enables basic support for Samsung's S3C/S5P board - PATA controllers via the new ATA layer - - If unsure, say N. - config PATA_WINBOND_VLB tristate "Winbond W83759A VLB PATA support (Experimental)" depends on ISA diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index d2e36d367274..4ee5c0761d90 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -105,12 +105,10 @@ obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o obj-$(CONFIG_PATA_OPTI) += pata_opti.o obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o -obj-$(CONFIG_PATA_PALMLD) += pata_palmld.o obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o -obj-$(CONFIG_PATA_SAMSUNG_CF) += pata_samsung_cf.o obj-$(CONFIG_PATA_PXA) += pata_pxa.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 0cfd0ec6229b..3bb9bb483fe3 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -83,6 +83,7 @@ enum board_ids { static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static void ahci_remove_one(struct pci_dev *dev); static void ahci_shutdown_one(struct pci_dev *dev); +static void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hpriv); static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class, @@ -420,6 +421,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x34d3), board_ahci_low_power }, /* Ice Lake LP AHCI */ { PCI_VDEVICE(INTEL, 0x02d3), board_ahci_low_power }, /* Comet Lake PCH-U AHCI */ { PCI_VDEVICE(INTEL, 0x02d7), board_ahci_low_power }, /* Comet Lake PCH RAID */ + { PCI_VDEVICE(INTEL, 0xa0d3), board_ahci_low_power }, /* Tiger Lake UP{3,4} AHCI */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -676,6 +678,25 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev, ahci_save_initial_config(&pdev->dev, hpriv); } +static int ahci_pci_reset_controller(struct ata_host *host) +{ + struct pci_dev *pdev = to_pci_dev(host->dev); + struct ahci_host_priv *hpriv = host->private_data; + int rc; + + rc = ahci_reset_controller(host); + if (rc) + return rc; + + /* + * If platform firmware failed to enable ports, try to enable + * them here. + */ + ahci_intel_pcs_quirk(pdev, hpriv); + + return 0; +} + static void ahci_pci_init_controller(struct ata_host *host) { struct ahci_host_priv *hpriv = host->private_data; @@ -870,7 +891,7 @@ static int ahci_pci_device_runtime_resume(struct device *dev) struct ata_host *host = pci_get_drvdata(pdev); int rc; - rc = ahci_reset_controller(host); + rc = ahci_pci_reset_controller(host); if (rc) return rc; ahci_pci_init_controller(host); @@ -906,7 +927,7 @@ static int ahci_pci_device_resume(struct device *dev) ahci_mcp89_apple_enable(pdev); if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { - rc = ahci_reset_controller(host); + rc = ahci_pci_reset_controller(host); if (rc) return rc; @@ -1784,12 +1805,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* save initial config */ ahci_pci_save_initial_config(pdev, hpriv); - /* - * If platform firmware failed to enable ports, try to enable - * them here. - */ - ahci_intel_pcs_quirk(pdev, hpriv); - /* prepare host */ if (hpriv->cap & HOST_CAP_NCQ) { pi.flags |= ATA_FLAG_NCQ; @@ -1899,7 +1914,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - rc = ahci_reset_controller(host); + rc = ahci_pci_reset_controller(host); if (rc) return rc; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 884ae73b11ea..c4c89d24f84c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3109,7 +3109,7 @@ int sata_down_spd_limit(struct ata_link *link, u32 spd_limit) */ if (spd > 1) mask &= (1 << (spd - 1)) - 1; - else + else if (link->sata_spd) return -EINVAL; /* were we already at the bottom? */ @@ -4045,6 +4045,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "Samsung SSD 870*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM | ATA_HORKAGE_NO_NCQ_ON_ATI }, + { "SAMSUNG*MZ7LH*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM | + ATA_HORKAGE_NO_NCQ_ON_ATI, }, { "FCCT*M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM }, diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c index 35608a0cf552..4cbcdc5da038 100644 --- a/drivers/ata/pata_octeon_cf.c +++ b/drivers/ata/pata_octeon_cf.c @@ -67,7 +67,7 @@ module_param(enable_dma, int, 0444); MODULE_PARM_DESC(enable_dma, "Enable use of DMA on interfaces that support it (0=no dma [default], 1=use dma)"); -/** +/* * Convert nanosecond based time to setting used in the * boot bus timing register, based on timing multiple */ @@ -114,7 +114,7 @@ static void octeon_cf_set_boot_reg_cfg(int cs, unsigned int multiplier) cvmx_write_csr(CVMX_MIO_BOOT_REG_CFGX(cs), reg_cfg.u64); } -/** +/* * Called after libata determines the needed PIO mode. This * function programs the Octeon bootbus regions to support the * timing requirements of the PIO mode. @@ -278,7 +278,7 @@ static void octeon_cf_set_dmamode(struct ata_port *ap, struct ata_device *dev) cvmx_write_csr(cf_port->dma_base + DMA_TIM, dma_tim.u64); } -/** +/* * Handle an 8 bit I/O request. * * @qc: Queued command @@ -317,7 +317,7 @@ static unsigned int octeon_cf_data_xfer8(struct ata_queued_cmd *qc, return buflen; } -/** +/* * Handle a 16 bit I/O request. * * @qc: Queued command @@ -372,7 +372,7 @@ static unsigned int octeon_cf_data_xfer16(struct ata_queued_cmd *qc, return buflen; } -/** +/* * Read the taskfile for 16bit non-True IDE only. */ static void octeon_cf_tf_read16(struct ata_port *ap, struct ata_taskfile *tf) @@ -453,7 +453,7 @@ static int octeon_cf_softreset16(struct ata_link *link, unsigned int *classes, return 0; } -/** +/* * Load the taskfile for 16bit non-True IDE only. The device_addr is * not loaded, we do this as part of octeon_cf_exec_command16. */ @@ -525,7 +525,7 @@ static void octeon_cf_dma_setup(struct ata_queued_cmd *qc) ap->ops->sff_exec_command(ap, &qc->tf); } -/** +/* * Start a DMA transfer that was already setup * * @qc: Information about the DMA @@ -580,7 +580,7 @@ static void octeon_cf_dma_start(struct ata_queued_cmd *qc) cvmx_write_csr(cf_port->dma_base + DMA_CFG, mio_boot_dma_cfg.u64); } -/** +/* * * LOCKING: * spin_lock_irqsave(host lock) diff --git a/drivers/ata/pata_palmld.c b/drivers/ata/pata_palmld.c deleted file mode 100644 index 51caa2a427dd..000000000000 --- a/drivers/ata/pata_palmld.c +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/ata/pata_palmld.c - * - * Driver for IDE channel in Palm LifeDrive - * - * Based on research of: - * Alex Osborne <ato@meshy.org> - * - * Rewrite for mainline: - * Marek Vasut <marek.vasut@gmail.com> - * - * Rewritten version based on pata_ixp4xx_cf.c: - * ixp4xx PATA/Compact Flash driver - * Copyright (C) 2006-07 Tower Technologies - * Author: Alessandro Zummo <a.zummo@towertech.it> - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/libata.h> -#include <linux/irq.h> -#include <linux/platform_device.h> -#include <linux/delay.h> -#include <linux/gpio/consumer.h> - -#include <scsi/scsi_host.h> - -#define DRV_NAME "pata_palmld" - -struct palmld_pata { - struct ata_host *host; - struct gpio_desc *power; - struct gpio_desc *reset; -}; - -static struct scsi_host_template palmld_sht = { - ATA_PIO_SHT(DRV_NAME), -}; - -static struct ata_port_operations palmld_port_ops = { - .inherits = &ata_sff_port_ops, - .sff_data_xfer = ata_sff_data_xfer32, - .cable_detect = ata_cable_40wire, -}; - -static int palmld_pata_probe(struct platform_device *pdev) -{ - struct palmld_pata *lda; - struct ata_port *ap; - void __iomem *mem; - struct device *dev = &pdev->dev; - int ret; - - lda = devm_kzalloc(dev, sizeof(*lda), GFP_KERNEL); - if (!lda) - return -ENOMEM; - - /* allocate host */ - lda->host = ata_host_alloc(dev, 1); - if (!lda->host) - return -ENOMEM; - - /* remap drive's physical memory address */ - mem = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(mem)) - return PTR_ERR(mem); - - /* request and activate power and reset GPIOs */ - lda->power = devm_gpiod_get(dev, "power", GPIOD_OUT_HIGH); - if (IS_ERR(lda->power)) - return PTR_ERR(lda->power); - lda->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(lda->reset)) { - gpiod_set_value(lda->power, 0); - return PTR_ERR(lda->reset); - } - - /* Assert reset to reset the drive */ - gpiod_set_value(lda->reset, 1); - msleep(30); - gpiod_set_value(lda->reset, 0); - msleep(30); - - /* setup the ata port */ - ap = lda->host->ports[0]; - ap->ops = &palmld_port_ops; - ap->pio_mask = ATA_PIO4; - ap->flags |= ATA_FLAG_PIO_POLLING; - - /* memory mapping voodoo */ - ap->ioaddr.cmd_addr = mem + 0x10; - ap->ioaddr.altstatus_addr = mem + 0xe; - ap->ioaddr.ctl_addr = mem + 0xe; - - /* start the port */ - ata_sff_std_ports(&ap->ioaddr); - - /* activate host */ - ret = ata_host_activate(lda->host, 0, NULL, IRQF_TRIGGER_RISING, - &palmld_sht); - /* power down on failure */ - if (ret) { - gpiod_set_value(lda->power, 0); - return ret; - } - - platform_set_drvdata(pdev, lda); - return 0; -} - -static int palmld_pata_remove(struct platform_device *pdev) -{ - struct palmld_pata *lda = platform_get_drvdata(pdev); - - ata_platform_remove_one(pdev); - - /* power down the HDD */ - gpiod_set_value(lda->power, 0); - - return 0; -} - -static struct platform_driver palmld_pata_platform_driver = { - .driver = { - .name = DRV_NAME, - }, - .probe = palmld_pata_probe, - .remove = palmld_pata_remove, -}; - -module_platform_driver(palmld_pata_platform_driver); - -MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); -MODULE_DESCRIPTION("PalmLD PATA driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c deleted file mode 100644 index aba1536ddd44..000000000000 --- a/drivers/ata/pata_samsung_cf.c +++ /dev/null @@ -1,662 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * PATA driver for Samsung SoCs. - * Supports CF Interface in True IDE mode. Currently only PIO mode has been - * implemented; UDMA support has to be added. - * - * Based on: - * PATA driver for AT91SAM9260 Static Memory Controller - * PATA driver for Toshiba SCC controller -*/ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/init.h> -#include <linux/clk.h> -#include <linux/libata.h> -#include <linux/platform_device.h> -#include <linux/slab.h> - -#include <linux/platform_data/ata-samsung_cf.h> - -#define DRV_NAME "pata_samsung_cf" -#define DRV_VERSION "0.1" - -#define S3C_CFATA_REG(x) (x) -#define S3C_CFATA_MUX S3C_CFATA_REG(0x0) -#define S3C_ATA_CTRL S3C_CFATA_REG(0x0) -#define S3C_ATA_CMD S3C_CFATA_REG(0x8) -#define S3C_ATA_IRQ S3C_CFATA_REG(0x10) -#define S3C_ATA_IRQ_MSK S3C_CFATA_REG(0x14) -#define S3C_ATA_CFG S3C_CFATA_REG(0x18) - -#define S3C_ATA_PIO_TIME S3C_CFATA_REG(0x2c) -#define S3C_ATA_PIO_DTR S3C_CFATA_REG(0x54) -#define S3C_ATA_PIO_FED S3C_CFATA_REG(0x58) -#define S3C_ATA_PIO_SCR S3C_CFATA_REG(0x5c) -#define S3C_ATA_PIO_LLR S3C_CFATA_REG(0x60) -#define S3C_ATA_PIO_LMR S3C_CFATA_REG(0x64) -#define S3C_ATA_PIO_LHR S3C_CFATA_REG(0x68) -#define S3C_ATA_PIO_DVR S3C_CFATA_REG(0x6c) -#define S3C_ATA_PIO_CSD S3C_CFATA_REG(0x70) -#define S3C_ATA_PIO_DAD S3C_CFATA_REG(0x74) -#define S3C_ATA_PIO_RDATA S3C_CFATA_REG(0x7c) - -#define S3C_CFATA_MUX_TRUEIDE 0x01 -#define S3C_ATA_CFG_SWAP 0x40 -#define S3C_ATA_CFG_IORDYEN 0x02 - -enum s3c_cpu_type { - TYPE_S3C64XX, - TYPE_S5PV210, -}; - -/* - * struct s3c_ide_info - S3C PATA instance. - * @clk: The clock resource for this controller. - * @ide_addr: The area mapped for the hardware registers. - * @sfr_addr: The area mapped for the special function registers. - * @irq: The IRQ number we are using. - * @cpu_type: The exact type of this controller. - * @fifo_status_reg: The ATA_FIFO_STATUS register offset. - */ -struct s3c_ide_info { - struct clk *clk; - void __iomem *ide_addr; - void __iomem *sfr_addr; - int irq; - enum s3c_cpu_type cpu_type; - unsigned int fifo_status_reg; -}; - -static void pata_s3c_set_endian(void __iomem *s3c_ide_regbase, u8 mode) -{ - u32 reg = readl(s3c_ide_regbase + S3C_ATA_CFG); - reg = mode ? (reg & ~S3C_ATA_CFG_SWAP) : (reg | S3C_ATA_CFG_SWAP); - writel(reg, s3c_ide_regbase + S3C_ATA_CFG); -} - -static void pata_s3c_cfg_mode(void __iomem *s3c_ide_sfrbase) -{ - /* Select true-ide as the internal operating mode */ - writel(readl(s3c_ide_sfrbase + S3C_CFATA_MUX) | S3C_CFATA_MUX_TRUEIDE, - s3c_ide_sfrbase + S3C_CFATA_MUX); -} - -static unsigned long -pata_s3c_setup_timing(struct s3c_ide_info *info, const struct ata_timing *ata) -{ - int t1 = ata->setup; - int t2 = ata->act8b; - int t2i = ata->rec8b; - ulong piotime; - - piotime = ((t2i & 0xff) << 12) | ((t2 & 0xff) << 4) | (t1 & 0xf); - - return piotime; -} - -static void pata_s3c_set_piomode(struct ata_port *ap, struct ata_device *adev) -{ - struct s3c_ide_info *info = ap->host->private_data; - struct ata_timing timing; - int cycle_time; - ulong ata_cfg = readl(info->ide_addr + S3C_ATA_CFG); - ulong piotime; - - /* Enables IORDY if mode requires it */ - if (ata_pio_need_iordy(adev)) - ata_cfg |= S3C_ATA_CFG_IORDYEN; - else - ata_cfg &= ~S3C_ATA_CFG_IORDYEN; - - cycle_time = (int)(1000000000UL / clk_get_rate(info->clk)); - - ata_timing_compute(adev, adev->pio_mode, &timing, - cycle_time * 1000, 0); - - piotime = pata_s3c_setup_timing(info, &timing); - - writel(ata_cfg, info->ide_addr + S3C_ATA_CFG); - writel(piotime, info->ide_addr + S3C_ATA_PIO_TIME); -} - -/* - * Waits until the IDE controller is able to perform next read/write - * operation to the disk. Needed for 64XX series boards only. - */ -static int wait_for_host_ready(struct s3c_ide_info *info) -{ - ulong timeout; - void __iomem *fifo_reg = info->ide_addr + info->fifo_status_reg; - - /* wait for maximum of 20 msec */ - timeout = jiffies + msecs_to_jiffies(20); - while (time_before(jiffies, timeout)) { - if ((readl(fifo_reg) >> 28) == 0) - return 0; - } - return -EBUSY; -} - -/* - * Writes to one of the task file registers. - */ -static void ata_outb(struct ata_host *host, u8 addr, void __iomem *reg) -{ - struct s3c_ide_info *info = host->private_data; - - wait_for_host_ready(info); - writeb(addr, reg); -} - -/* - * Reads from one of the task file registers. - */ -static u8 ata_inb(struct ata_host *host, void __iomem *reg) -{ - struct s3c_ide_info *info = host->private_data; - u8 temp; - - wait_for_host_ready(info); - (void) readb(reg); - wait_for_host_ready(info); - temp = readb(info->ide_addr + S3C_ATA_PIO_RDATA); - return temp; -} - -/* - * pata_s3c_tf_load - send taskfile registers to host controller - */ -static void pata_s3c_tf_load(struct ata_port *ap, - const struct ata_taskfile *tf) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; - - if (tf->ctl != ap->last_ctl) { - ata_outb(ap->host, tf->ctl, ioaddr->ctl_addr); - ap->last_ctl = tf->ctl; - ata_wait_idle(ap); - } - - if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - ata_outb(ap->host, tf->hob_feature, ioaddr->feature_addr); - ata_outb(ap->host, tf->hob_nsect, ioaddr->nsect_addr); - ata_outb(ap->host, tf->hob_lbal, ioaddr->lbal_addr); - ata_outb(ap->host, tf->hob_lbam, ioaddr->lbam_addr); - ata_outb(ap->host, tf->hob_lbah, ioaddr->lbah_addr); - } - - if (is_addr) { - ata_outb(ap->host, tf->feature, ioaddr->feature_addr); - ata_outb(ap->host, tf->nsect, ioaddr->nsect_addr); - ata_outb(ap->host, tf->lbal, ioaddr->lbal_addr); - ata_outb(ap->host, tf->lbam, ioaddr->lbam_addr); - ata_outb(ap->host, tf->lbah, ioaddr->lbah_addr); - } - - if (tf->flags & ATA_TFLAG_DEVICE) - ata_outb(ap->host, tf->device, ioaddr->device_addr); - - ata_wait_idle(ap); -} - -/* - * pata_s3c_tf_read - input device's ATA taskfile shadow registers - */ -static void pata_s3c_tf_read(struct ata_port *ap, struct ata_taskfile *tf) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - - tf->error = ata_inb(ap->host, ioaddr->error_addr); - tf->nsect = ata_inb(ap->host, ioaddr->nsect_addr); - tf->lbal = ata_inb(ap->host, ioaddr->lbal_addr); - tf->lbam = ata_inb(ap->host, ioaddr->lbam_addr); - tf->lbah = ata_inb(ap->host, ioaddr->lbah_addr); - tf->device = ata_inb(ap->host, ioaddr->device_addr); - - if (tf->flags & ATA_TFLAG_LBA48) { - ata_outb(ap->host, tf->ctl | ATA_HOB, ioaddr->ctl_addr); - tf->hob_feature = ata_inb(ap->host, ioaddr->error_addr); - tf->hob_nsect = ata_inb(ap->host, ioaddr->nsect_addr); - tf->hob_lbal = ata_inb(ap->host, ioaddr->lbal_addr); - tf->hob_lbam = ata_inb(ap->host, ioaddr->lbam_addr); - tf->hob_lbah = ata_inb(ap->host, ioaddr->lbah_addr); - ata_outb(ap->host, tf->ctl, ioaddr->ctl_addr); - ap->last_ctl = tf->ctl; - } -} - -/* - * pata_s3c_exec_command - issue ATA command to host controller - */ -static void pata_s3c_exec_command(struct ata_port *ap, - const struct ata_taskfile *tf) -{ - ata_outb(ap->host, tf->command, ap->ioaddr.command_addr); - ata_sff_pause(ap); -} - -/* - * pata_s3c_check_status - Read device status register - */ -static u8 pata_s3c_check_status(struct ata_port *ap) -{ - return ata_inb(ap->host, ap->ioaddr.status_addr); -} - -/* - * pata_s3c_check_altstatus - Read alternate device status register - */ -static u8 pata_s3c_check_altstatus(struct ata_port *ap) -{ - return ata_inb(ap->host, ap->ioaddr.altstatus_addr); -} - -/* - * pata_s3c_data_xfer - Transfer data by PIO - */ -static unsigned int pata_s3c_data_xfer(struct ata_queued_cmd *qc, - unsigned char *buf, unsigned int buflen, int rw) -{ - struct ata_port *ap = qc->dev->link->ap; - struct s3c_ide_info *info = ap->host->private_data; - void __iomem *data_addr = ap->ioaddr.data_addr; - unsigned int words = buflen >> 1, i; - u16 *data_ptr = (u16 *)buf; - - /* Requires wait same as in ata_inb/ata_outb */ - if (rw == READ) - for (i = 0; i < words; i++, data_ptr++) { - wait_for_host_ready(info); - (void) readw(data_addr); - wait_for_host_ready(info); - *data_ptr = readw(info->ide_addr - + S3C_ATA_PIO_RDATA); - } - else - for (i = 0; i < words; i++, data_ptr++) { - wait_for_host_ready(info); - writew(*data_ptr, data_addr); - } - - if (buflen & 0x01) - dev_err(ap->dev, "unexpected trailing data\n"); - - return words << 1; -} - -/* - * pata_s3c_dev_select - Select device on ATA bus - */ -static void pata_s3c_dev_select(struct ata_port *ap, unsigned int device) -{ - u8 tmp = ATA_DEVICE_OBS; - - if (device != 0) - tmp |= ATA_DEV1; - - ata_outb(ap->host, tmp, ap->ioaddr.device_addr); - ata_sff_pause(ap); -} - -/* - * pata_s3c_devchk - PATA device presence detection - */ -static bool pata_s3c_devchk(struct ata_port *ap, unsigned int device) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - u8 nsect, lbal; - - pata_s3c_dev_select(ap, device); - - ata_outb(ap->host, 0x55, ioaddr->nsect_addr); - ata_outb(ap->host, 0xaa, ioaddr->lbal_addr); - - ata_outb(ap->host, 0xaa, ioaddr->nsect_addr); - ata_outb(ap->host, 0x55, ioaddr->lbal_addr); - - ata_outb(ap->host, 0x55, ioaddr->nsect_addr); - ata_outb(ap->host, 0xaa, ioaddr->lbal_addr); - - nsect = ata_inb(ap->host, ioaddr->nsect_addr); - lbal = ata_inb(ap->host, ioaddr->lbal_addr); - - if ((nsect == 0x55) && (lbal == 0xaa)) - return true; /* we found a device */ - - return false; /* nothing found */ -} - -/* - * pata_s3c_wait_after_reset - wait for devices to become ready after reset - */ -static int pata_s3c_wait_after_reset(struct ata_link *link, - unsigned long deadline) -{ - int rc; - - ata_msleep(link->ap, ATA_WAIT_AFTER_RESET); - - /* always check readiness of the master device */ - rc = ata_sff_wait_ready(link, deadline); - /* -ENODEV means the odd clown forgot the D7 pulldown resistor - * and TF status is 0xff, bail out on it too. - */ - if (rc) - return rc; - - return 0; -} - -/* - * pata_s3c_bus_softreset - PATA device software reset - */ -static int pata_s3c_bus_softreset(struct ata_port *ap, - unsigned long deadline) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - - /* software reset. causes dev0 to be selected */ - ata_outb(ap->host, ap->ctl, ioaddr->ctl_addr); - udelay(20); - ata_outb(ap->host, ap->ctl | ATA_SRST, ioaddr->ctl_addr); - udelay(20); - ata_outb(ap->host, ap->ctl, ioaddr->ctl_addr); - ap->last_ctl = ap->ctl; - - return pata_s3c_wait_after_reset(&ap->link, deadline); -} - -/* - * pata_s3c_softreset - reset host port via ATA SRST - */ -static int pata_s3c_softreset(struct ata_link *link, unsigned int *classes, - unsigned long deadline) -{ - struct ata_port *ap = link->ap; - unsigned int devmask = 0; - int rc; - u8 err; - - /* determine if device 0 is present */ - if (pata_s3c_devchk(ap, 0)) - devmask |= (1 << 0); - - /* select device 0 again */ - pata_s3c_dev_select(ap, 0); - - /* issue bus reset */ - rc = pata_s3c_bus_softreset(ap, deadline); - /* if link is occupied, -ENODEV too is an error */ - if (rc && rc != -ENODEV) { - ata_link_err(link, "SRST failed (errno=%d)\n", rc); - return rc; - } - - /* determine by signature whether we have ATA or ATAPI devices */ - classes[0] = ata_sff_dev_classify(&ap->link.device[0], - devmask & (1 << 0), &err); - - return 0; -} - -/* - * pata_s3c_set_devctl - Write device control register - */ -static void pata_s3c_set_devctl(struct ata_port *ap, u8 ctl) -{ - ata_outb(ap->host, ctl, ap->ioaddr.ctl_addr); -} - -static struct scsi_host_template pata_s3c_sht = { - ATA_PIO_SHT(DRV_NAME), -}; - -static struct ata_port_operations pata_s3c_port_ops = { - .inherits = &ata_sff_port_ops, - .sff_check_status = pata_s3c_check_status, - .sff_check_altstatus = pata_s3c_check_altstatus, - .sff_tf_load = pata_s3c_tf_load, - .sff_tf_read = pata_s3c_tf_read, - .sff_data_xfer = pata_s3c_data_xfer, - .sff_exec_command = pata_s3c_exec_command, - .sff_dev_select = pata_s3c_dev_select, - .sff_set_devctl = pata_s3c_set_devctl, - .softreset = pata_s3c_softreset, - .set_piomode = pata_s3c_set_piomode, -}; - -static struct ata_port_operations pata_s5p_port_ops = { - .inherits = &ata_sff_port_ops, - .set_piomode = pata_s3c_set_piomode, -}; - -static void pata_s3c_enable(void __iomem *s3c_ide_regbase, bool state) -{ - u32 temp = readl(s3c_ide_regbase + S3C_ATA_CTRL); - temp = state ? (temp | 1) : (temp & ~1); - writel(temp, s3c_ide_regbase + S3C_ATA_CTRL); -} - -static irqreturn_t pata_s3c_irq(int irq, void *dev_instance) -{ - struct ata_host *host = dev_instance; - struct s3c_ide_info *info = host->private_data; - u32 reg; - - reg = readl(info->ide_addr + S3C_ATA_IRQ); - writel(reg, info->ide_addr + S3C_ATA_IRQ); - - return ata_sff_interrupt(irq, dev_instance); -} - -static void pata_s3c_hwinit(struct s3c_ide_info *info, - struct s3c_ide_platdata *pdata) -{ - switch (info->cpu_type) { - case TYPE_S3C64XX: - /* Configure as big endian */ - pata_s3c_cfg_mode(info->sfr_addr); - pata_s3c_set_endian(info->ide_addr, 1); - pata_s3c_enable(info->ide_addr, true); - msleep(100); - - /* Remove IRQ Status */ - writel(0x1f, info->ide_addr + S3C_ATA_IRQ); - writel(0x1b, info->ide_addr + S3C_ATA_IRQ_MSK); - break; - - case TYPE_S5PV210: - /* Configure as little endian */ - pata_s3c_set_endian(info->ide_addr, 0); - pata_s3c_enable(info->ide_addr, true); - msleep(100); - - /* Remove IRQ Status */ - writel(0x3f, info->ide_addr + S3C_ATA_IRQ); - writel(0x3f, info->ide_addr + S3C_ATA_IRQ_MSK); - break; - - default: - BUG(); - } -} - -static int __init pata_s3c_probe(struct platform_device *pdev) -{ - struct s3c_ide_platdata *pdata = dev_get_platdata(&pdev->dev); - struct device *dev = &pdev->dev; - struct s3c_ide_info *info; - struct resource *res; - struct ata_port *ap; - struct ata_host *host; - enum s3c_cpu_type cpu_type; - int ret; - - cpu_type = platform_get_device_id(pdev)->driver_data; - - info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->irq = platform_get_irq(pdev, 0); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - info->ide_addr = devm_ioremap_resource(dev, res); - if (IS_ERR(info->ide_addr)) - return PTR_ERR(info->ide_addr); - - info->clk = devm_clk_get(&pdev->dev, "cfcon"); - if (IS_ERR(info->clk)) { - dev_err(dev, "failed to get access to cf controller clock\n"); - ret = PTR_ERR(info->clk); - info->clk = NULL; - return ret; - } - - clk_enable(info->clk); - - /* init ata host */ - host = ata_host_alloc(dev, 1); - if (!host) { - dev_err(dev, "failed to allocate ide host\n"); - ret = -ENOMEM; - goto stop_clk; - } - - ap = host->ports[0]; - ap->pio_mask = ATA_PIO4; - - if (cpu_type == TYPE_S3C64XX) { - ap->ops = &pata_s3c_port_ops; - info->sfr_addr = info->ide_addr + 0x1800; - info->ide_addr += 0x1900; - info->fifo_status_reg = 0x94; - } else { - ap->ops = &pata_s5p_port_ops; - info->fifo_status_reg = 0x84; - } - - info->cpu_type = cpu_type; - - if (info->irq <= 0) { - ap->flags |= ATA_FLAG_PIO_POLLING; - info->irq = 0; - ata_port_desc(ap, "no IRQ, using PIO polling\n"); - } - - ap->ioaddr.cmd_addr = info->ide_addr + S3C_ATA_CMD; - ap->ioaddr.data_addr = info->ide_addr + S3C_ATA_PIO_DTR; - ap->ioaddr.error_addr = info->ide_addr + S3C_ATA_PIO_FED; - ap->ioaddr.feature_addr = info->ide_addr + S3C_ATA_PIO_FED; - ap->ioaddr.nsect_addr = info->ide_addr + S3C_ATA_PIO_SCR; - ap->ioaddr.lbal_addr = info->ide_addr + S3C_ATA_PIO_LLR; - ap->ioaddr.lbam_addr = info->ide_addr + S3C_ATA_PIO_LMR; - ap->ioaddr.lbah_addr = info->ide_addr + S3C_ATA_PIO_LHR; - ap->ioaddr.device_addr = info->ide_addr + S3C_ATA_PIO_DVR; - ap->ioaddr.status_addr = info->ide_addr + S3C_ATA_PIO_CSD; - ap->ioaddr.command_addr = info->ide_addr + S3C_ATA_PIO_CSD; - ap->ioaddr.altstatus_addr = info->ide_addr + S3C_ATA_PIO_DAD; - ap->ioaddr.ctl_addr = info->ide_addr + S3C_ATA_PIO_DAD; - - ata_port_desc(ap, "mmio cmd 0x%llx ", - (unsigned long long)res->start); - - host->private_data = info; - - if (pdata && pdata->setup_gpio) - pdata->setup_gpio(); - - /* Set endianness and enable the interface */ - pata_s3c_hwinit(info, pdata); - - ret = ata_host_activate(host, info->irq, - info->irq ? pata_s3c_irq : NULL, - 0, &pata_s3c_sht); - if (ret) - goto stop_clk; - - return 0; - -stop_clk: - clk_disable(info->clk); - return ret; -} - -static int __exit pata_s3c_remove(struct platform_device *pdev) -{ - struct ata_host *host = platform_get_drvdata(pdev); - struct s3c_ide_info *info = host->private_data; - - ata_host_detach(host); - - clk_disable(info->clk); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int pata_s3c_suspend(struct device *dev) -{ - struct ata_host *host = dev_get_drvdata(dev); - - ata_host_suspend(host, PMSG_SUSPEND); - return 0; -} - -static int pata_s3c_resume(struct device *dev) -{ - struct ata_host *host = dev_get_drvdata(dev); - struct s3c_ide_platdata *pdata = dev_get_platdata(dev); - struct s3c_ide_info *info = host->private_data; - - pata_s3c_hwinit(info, pdata); - ata_host_resume(host); - - return 0; -} - -static const struct dev_pm_ops pata_s3c_pm_ops = { - .suspend = pata_s3c_suspend, - .resume = pata_s3c_resume, -}; -#endif - -/* driver device registration */ -static const struct platform_device_id pata_s3c_driver_ids[] = { - { - .name = "s3c64xx-pata", - .driver_data = TYPE_S3C64XX, - }, { - .name = "s5pv210-pata", - .driver_data = TYPE_S5PV210, - }, - { } -}; - -MODULE_DEVICE_TABLE(platform, pata_s3c_driver_ids); - -static struct platform_driver pata_s3c_driver = { - .remove = __exit_p(pata_s3c_remove), - .id_table = pata_s3c_driver_ids, - .driver = { - .name = DRV_NAME, -#ifdef CONFIG_PM_SLEEP - .pm = &pata_s3c_pm_ops, -#endif - }, -}; - -module_platform_driver_probe(pata_s3c_driver, pata_s3c_probe); - -MODULE_AUTHOR("Abhilash Kesavan, <a.kesavan@samsung.com>"); -MODULE_DESCRIPTION("low-level driver for Samsung PATA controller"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index e4bffeabf344..03e8a95f1f35 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -173,7 +173,7 @@ static int dev_mkdir(const char *name, umode_t mode) if (IS_ERR(dentry)) return PTR_ERR(dentry); - err = vfs_mkdir(&init_user_ns, d_inode(path.dentry), dentry, mode); + err = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode); if (!err) /* mark as kernel-created inode */ d_inode(dentry)->i_private = &thread; @@ -223,7 +223,7 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid, if (IS_ERR(dentry)) return PTR_ERR(dentry); - err = vfs_mknod(&init_user_ns, d_inode(path.dentry), dentry, mode, + err = vfs_mknod(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode, dev->devt); if (!err) { struct iattr newattrs; @@ -233,7 +233,7 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid, newattrs.ia_gid = gid; newattrs.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID; inode_lock(d_inode(dentry)); - notify_change(&init_user_ns, dentry, &newattrs, NULL); + notify_change(&nop_mnt_idmap, dentry, &newattrs, NULL); inode_unlock(d_inode(dentry)); /* mark as kernel-created inode */ @@ -254,7 +254,7 @@ static int dev_rmdir(const char *name) return PTR_ERR(dentry); if (d_really_is_positive(dentry)) { if (d_inode(dentry)->i_private == &thread) - err = vfs_rmdir(&init_user_ns, d_inode(parent.dentry), + err = vfs_rmdir(&nop_mnt_idmap, d_inode(parent.dentry), dentry); else err = -EPERM; @@ -341,9 +341,9 @@ static int handle_remove(const char *nodename, struct device *dev) newattrs.ia_valid = ATTR_UID|ATTR_GID|ATTR_MODE; inode_lock(d_inode(dentry)); - notify_change(&init_user_ns, dentry, &newattrs, NULL); + notify_change(&nop_mnt_idmap, dentry, &newattrs, NULL); inode_unlock(d_inode(dentry)); - err = vfs_unlink(&init_user_ns, d_inode(parent.dentry), + err = vfs_unlink(&nop_mnt_idmap, d_inode(parent.dentry), dentry, NULL); if (!err || err == -ENOENT) deleted = 1; diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 50e726b6c2cf..98f7b3d7d669 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -468,7 +468,7 @@ static int rpm_idle(struct device *dev, int rpmflags) int (*callback)(struct device *); int retval; - trace_rpm_idle_rcuidle(dev, rpmflags); + trace_rpm_idle(dev, rpmflags); retval = rpm_check_suspend_allowed(dev); if (retval < 0) ; /* Conditions are wrong. */ @@ -508,7 +508,7 @@ static int rpm_idle(struct device *dev, int rpmflags) dev->power.request_pending = true; queue_work(pm_wq, &dev->power.work); } - trace_rpm_return_int_rcuidle(dev, _THIS_IP_, 0); + trace_rpm_return_int(dev, _THIS_IP_, 0); return 0; } @@ -530,7 +530,7 @@ static int rpm_idle(struct device *dev, int rpmflags) wake_up_all(&dev->power.wait_queue); out: - trace_rpm_return_int_rcuidle(dev, _THIS_IP_, retval); + trace_rpm_return_int(dev, _THIS_IP_, retval); return retval ? retval : rpm_suspend(dev, rpmflags | RPM_AUTO); } @@ -562,7 +562,7 @@ static int rpm_suspend(struct device *dev, int rpmflags) struct device *parent = NULL; int retval; - trace_rpm_suspend_rcuidle(dev, rpmflags); + trace_rpm_suspend(dev, rpmflags); repeat: retval = rpm_check_suspend_allowed(dev); @@ -713,7 +713,7 @@ static int rpm_suspend(struct device *dev, int rpmflags) } out: - trace_rpm_return_int_rcuidle(dev, _THIS_IP_, retval); + trace_rpm_return_int(dev, _THIS_IP_, retval); return retval; @@ -765,7 +765,7 @@ static int rpm_resume(struct device *dev, int rpmflags) struct device *parent = NULL; int retval = 0; - trace_rpm_resume_rcuidle(dev, rpmflags); + trace_rpm_resume(dev, rpmflags); repeat: if (dev->power.runtime_error) { @@ -935,7 +935,7 @@ static int rpm_resume(struct device *dev, int rpmflags) spin_lock_irq(&dev->power.lock); } - trace_rpm_return_int_rcuidle(dev, _THIS_IP_, retval); + trace_rpm_return_int(dev, _THIS_IP_, retval); return retval; } @@ -1091,7 +1091,7 @@ int __pm_runtime_idle(struct device *dev, int rpmflags) if (retval < 0) { return retval; } else if (retval > 0) { - trace_rpm_usage_rcuidle(dev, rpmflags); + trace_rpm_usage(dev, rpmflags); return 0; } } @@ -1129,7 +1129,7 @@ int __pm_runtime_suspend(struct device *dev, int rpmflags) if (retval < 0) { return retval; } else if (retval > 0) { - trace_rpm_usage_rcuidle(dev, rpmflags); + trace_rpm_usage(dev, rpmflags); return 0; } } @@ -1212,7 +1212,7 @@ int pm_runtime_get_if_active(struct device *dev, bool ign_usage_count) } else { retval = atomic_inc_not_zero(&dev->power.usage_count); } - trace_rpm_usage_rcuidle(dev, 0); + trace_rpm_usage(dev, 0); spin_unlock_irqrestore(&dev->power.lock, flags); return retval; @@ -1576,7 +1576,7 @@ void pm_runtime_allow(struct device *dev) if (ret == 0) rpm_idle(dev, RPM_AUTO | RPM_ASYNC); else if (ret > 0) - trace_rpm_usage_rcuidle(dev, RPM_AUTO | RPM_ASYNC); + trace_rpm_usage(dev, RPM_AUTO | RPM_ASYNC); out: spin_unlock_irq(&dev->power.lock); @@ -1646,7 +1646,7 @@ static void update_autosuspend(struct device *dev, int old_delay, int old_use) atomic_inc(&dev->power.usage_count); rpm_resume(dev, 0); } else { - trace_rpm_usage_rcuidle(dev, 0); + trace_rpm_usage(dev, 0); } } diff --git a/drivers/base/property.c b/drivers/base/property.c index bbb3e499ff4a..083a95791d3b 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -997,26 +997,32 @@ struct fwnode_handle * fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode, struct fwnode_handle *prev) { + struct fwnode_handle *ep, *port_parent = NULL; const struct fwnode_handle *parent; - struct fwnode_handle *ep; /* * If this function is in a loop and the previous iteration returned * an endpoint from fwnode->secondary, then we need to use the secondary * as parent rather than @fwnode. */ - if (prev) - parent = fwnode_graph_get_port_parent(prev); - else + if (prev) { + port_parent = fwnode_graph_get_port_parent(prev); + parent = port_parent; + } else { parent = fwnode; + } if (IS_ERR_OR_NULL(parent)) return NULL; ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev); if (ep) - return ep; + goto out_put_port_parent; + + ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL); - return fwnode_graph_get_next_endpoint(parent->secondary, NULL); +out_put_port_parent: + fwnode_handle_put(port_parent); + return ep; } EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint); diff --git a/drivers/base/test/test_async_driver_probe.c b/drivers/base/test/test_async_driver_probe.c index 4d1976ca5072..929410d0dd6f 100644 --- a/drivers/base/test/test_async_driver_probe.c +++ b/drivers/base/test/test_async_driver_probe.c @@ -145,7 +145,7 @@ static int __init test_async_probe_init(void) calltime = ktime_get(); for_each_online_cpu(cpu) { nid = cpu_to_node(cpu); - pdev = &sync_dev[sync_id]; + pdev = &async_dev[async_id]; *pdev = test_platform_device_register_node("test_async_driver", async_id, diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index a2184b428493..a41145d52de9 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -285,6 +285,49 @@ config BLK_DEV_RAM_SIZE The default value is 4096 kilobytes. Only change this if you know what you are doing. +config CDROM_PKTCDVD + tristate "Packet writing on CD/DVD media (DEPRECATED)" + depends on !UML + depends on SCSI + select CDROM + help + Note: This driver is deprecated and will be removed from the + kernel in the near future! + + If you have a CDROM/DVD drive that supports packet writing, say + Y to include support. It should work with any MMC/Mt Fuji + compliant ATAPI or SCSI drive, which is just about any newer + DVD/CD writer. + + Currently only writing to CD-RW, DVD-RW, DVD+RW and DVDRAM discs + is possible. + DVD-RW disks must be in restricted overwrite mode. + + See the file <file:Documentation/cdrom/packet-writing.rst> + for further information on the use of this driver. + + To compile this driver as a module, choose M here: the + module will be called pktcdvd. + +config CDROM_PKTCDVD_BUFFERS + int "Free buffers for data gathering" + depends on CDROM_PKTCDVD + default "8" + help + This controls the maximum number of active concurrent packets. More + concurrent packets can increase write performance, but also require + more memory. Each concurrent packet will require approximately 64Kb + of non-swappable kernel memory, memory which will be allocated when + a disc is opened for writing. + +config CDROM_PKTCDVD_WCACHE + bool "Enable write caching" + depends on CDROM_PKTCDVD + help + If enabled, write caching will be set for the CD-R/W device. For now + this option is dangerous unless the CD-RW media is known good, as we + don't do deferred write error handling yet. + config ATA_OVER_ETH tristate "ATA over Ethernet support" depends on NET diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 962ee65d8ca3..101612cba303 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o obj-$(CONFIG_N64CART) += n64cart.o obj-$(CONFIG_BLK_DEV_RAM) += brd.o obj-$(CONFIG_BLK_DEV_LOOP) += loop.o +obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o obj-$(CONFIG_SUNVDC) += sunvdc.o obj-$(CONFIG_BLK_DEV_NBD) += nbd.o diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 20acc4a1fd6d..a8a77a1efe1e 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -78,32 +78,25 @@ static struct page *brd_lookup_page(struct brd_device *brd, sector_t sector) } /* - * Look up and return a brd's page for a given sector. - * If one does not exist, allocate an empty page, and insert that. Then - * return it. + * Insert a new page for a given sector, if one does not already exist. */ -static struct page *brd_insert_page(struct brd_device *brd, sector_t sector) +static int brd_insert_page(struct brd_device *brd, sector_t sector, gfp_t gfp) { pgoff_t idx; struct page *page; - gfp_t gfp_flags; + int ret = 0; page = brd_lookup_page(brd, sector); if (page) - return page; + return 0; - /* - * Must use NOIO because we don't want to recurse back into the - * block or filesystem layers from page reclaim. - */ - gfp_flags = GFP_NOIO | __GFP_ZERO | __GFP_HIGHMEM; - page = alloc_page(gfp_flags); + page = alloc_page(gfp | __GFP_ZERO | __GFP_HIGHMEM); if (!page) - return NULL; + return -ENOMEM; - if (radix_tree_preload(GFP_NOIO)) { + if (radix_tree_maybe_preload(gfp)) { __free_page(page); - return NULL; + return -ENOMEM; } spin_lock(&brd->brd_lock); @@ -112,16 +105,17 @@ static struct page *brd_insert_page(struct brd_device *brd, sector_t sector) if (radix_tree_insert(&brd->brd_pages, idx, page)) { __free_page(page); page = radix_tree_lookup(&brd->brd_pages, idx); - BUG_ON(!page); - BUG_ON(page->index != idx); + if (!page) + ret = -ENOMEM; + else if (page->index != idx) + ret = -EIO; } else { brd->brd_nr_pages++; } spin_unlock(&brd->brd_lock); radix_tree_preload_end(); - - return page; + return ret; } /* @@ -170,20 +164,22 @@ static void brd_free_pages(struct brd_device *brd) /* * copy_to_brd_setup must be called before copy_to_brd. It may sleep. */ -static int copy_to_brd_setup(struct brd_device *brd, sector_t sector, size_t n) +static int copy_to_brd_setup(struct brd_device *brd, sector_t sector, size_t n, + gfp_t gfp) { unsigned int offset = (sector & (PAGE_SECTORS-1)) << SECTOR_SHIFT; size_t copy; + int ret; copy = min_t(size_t, n, PAGE_SIZE - offset); - if (!brd_insert_page(brd, sector)) - return -ENOSPC; + ret = brd_insert_page(brd, sector, gfp); + if (ret) + return ret; if (copy < n) { sector += copy >> SECTOR_SHIFT; - if (!brd_insert_page(brd, sector)) - return -ENOSPC; + ret = brd_insert_page(brd, sector, gfp); } - return 0; + return ret; } /* @@ -256,20 +252,26 @@ static void copy_from_brd(void *dst, struct brd_device *brd, * Process a single bvec of a bio. */ static int brd_do_bvec(struct brd_device *brd, struct page *page, - unsigned int len, unsigned int off, enum req_op op, + unsigned int len, unsigned int off, blk_opf_t opf, sector_t sector) { void *mem; int err = 0; - if (op_is_write(op)) { - err = copy_to_brd_setup(brd, sector, len); + if (op_is_write(opf)) { + /* + * Must use NOIO because we don't want to recurse back into the + * block or filesystem layers from page reclaim. + */ + gfp_t gfp = opf & REQ_NOWAIT ? GFP_NOWAIT : GFP_NOIO; + + err = copy_to_brd_setup(brd, sector, len, gfp); if (err) goto out; } mem = kmap_atomic(page); - if (!op_is_write(op)) { + if (!op_is_write(opf)) { copy_from_brd(mem + off, brd, sector, len); flush_dcache_page(page); } else { @@ -298,8 +300,12 @@ static void brd_submit_bio(struct bio *bio) (len & (SECTOR_SIZE - 1))); err = brd_do_bvec(brd, bvec.bv_page, len, bvec.bv_offset, - bio_op(bio), sector); + bio->bi_opf, sector); if (err) { + if (err == -ENOMEM && bio->bi_opf & REQ_NOWAIT) { + bio_wouldblock_error(bio); + return; + } bio_io_error(bio); return; } @@ -412,6 +418,7 @@ static int brd_alloc(int i) /* Tell the block layer that this is not a rotational device */ blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue); blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, disk->queue); + blk_queue_flag_set(QUEUE_FLAG_NOWAIT, disk->queue); err = add_disk(disk); if (err) goto out_cleanup_disk; diff --git a/drivers/block/drbd/Makefile b/drivers/block/drbd/Makefile index c93e462130ff..67a8b352a1d5 100644 --- a/drivers/block/drbd/Makefile +++ b/drivers/block/drbd/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -drbd-y := drbd_bitmap.o drbd_proc.o +drbd-y := drbd_buildtag.o drbd_bitmap.o drbd_proc.o drbd-y += drbd_worker.o drbd_receiver.o drbd_req.o drbd_actlog.o drbd-y += drbd_main.o drbd_strings.o drbd_nl.o drbd-y += drbd_interval.o drbd_state.o diff --git a/drivers/block/drbd/drbd_buildtag.c b/drivers/block/drbd/drbd_buildtag.c new file mode 100644 index 000000000000..cb1aa66d7d5d --- /dev/null +++ b/drivers/block/drbd/drbd_buildtag.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <linux/drbd_config.h> +#include <linux/module.h> + +const char *drbd_buildtag(void) +{ + /* DRBD built from external sources has here a reference to the + * git hash of the source code. + */ + + static char buildtag[38] = "\0uilt-in"; + + if (buildtag[0] == 0) { +#ifdef MODULE + sprintf(buildtag, "srcversion: %-24s", THIS_MODULE->srcversion); +#else + buildtag[0] = 'b'; +#endif + } + + return buildtag; +} diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c index a72c096aa5b1..12460b584bcb 100644 --- a/drivers/block/drbd/drbd_debugfs.c +++ b/drivers/block/drbd/drbd_debugfs.c @@ -844,7 +844,7 @@ static int drbd_version_show(struct seq_file *m, void *ignored) { seq_printf(m, "# %s\n", drbd_buildtag()); seq_printf(m, "VERSION=%s\n", REL_VERSION); - seq_printf(m, "API_VERSION=%u\n", API_VERSION); + seq_printf(m, "API_VERSION=%u\n", GENL_MAGIC_VERSION); seq_printf(m, "PRO_VERSION_MIN=%u\n", PRO_VERSION_MIN); seq_printf(m, "PRO_VERSION_MAX=%u\n", PRO_VERSION_MAX); return 0; diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index ae713338aa46..d89b7d03d4c8 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -34,21 +34,12 @@ #include <linux/prefetch.h> #include <linux/drbd_genl_api.h> #include <linux/drbd.h> +#include <linux/drbd_config.h> #include "drbd_strings.h" #include "drbd_state.h" #include "drbd_protocol.h" #include "drbd_polymorph_printk.h" -#ifdef __CHECKER__ -# define __protected_by(x) __attribute__((require_context(x,1,999,"rdwr"))) -# define __protected_read_by(x) __attribute__((require_context(x,1,999,"read"))) -# define __protected_write_by(x) __attribute__((require_context(x,1,999,"write"))) -#else -# define __protected_by(x) -# define __protected_read_by(x) -# define __protected_write_by(x) -#endif - /* shared module parameters, defined in drbd_main.c */ #ifdef CONFIG_DRBD_FAULT_INJECTION extern int drbd_enable_faults; @@ -774,7 +765,7 @@ struct drbd_device { unsigned long flags; /* configured by drbdsetup */ - struct drbd_backing_dev *ldev __protected_by(local); + struct drbd_backing_dev *ldev; sector_t p_size; /* partner's disk size */ struct request_queue *rq_queue; diff --git a/drivers/block/drbd/drbd_interval.c b/drivers/block/drbd/drbd_interval.c index 5024ffd6143d..873beda6de24 100644 --- a/drivers/block/drbd/drbd_interval.c +++ b/drivers/block/drbd/drbd_interval.c @@ -58,7 +58,7 @@ drbd_insert_interval(struct rb_root *root, struct drbd_interval *this) * drbd_contains_interval - check if a tree contains a given interval * @root: red black tree root * @sector: start sector of @interval - * @interval: may not be a valid pointer + * @interval: may be an invalid pointer * * Returns if the tree contains the node @interval with start sector @start. * Does not dereference @interval until @interval is known to be a valid object @@ -95,6 +95,10 @@ drbd_contains_interval(struct rb_root *root, sector_t sector, void drbd_remove_interval(struct rb_root *root, struct drbd_interval *this) { + /* avoid endless loop */ + if (drbd_interval_empty(this)) + return; + rb_erase_augmented(&this->rb, root, &augment_callbacks); } diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index e43dfb9eb6ad..2c764f7ee4a7 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2899,7 +2899,7 @@ static int __init drbd_init(void) pr_info("initialized. " "Version: " REL_VERSION " (api:%d/proto:%d-%d)\n", - API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX); + GENL_MAGIC_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX); pr_info("%s\n", drbd_buildtag()); pr_info("registered as block device major %d\n", DRBD_MAJOR); return 0; /* Success! */ @@ -3776,24 +3776,6 @@ _drbd_insert_fault(struct drbd_device *device, unsigned int type) } #endif -const char *drbd_buildtag(void) -{ - /* DRBD built from external sources has here a reference to the - git hash of the source code. */ - - static char buildtag[38] = "\0uilt-in"; - - if (buildtag[0] == 0) { -#ifdef MODULE - sprintf(buildtag, "srcversion: %-24s", THIS_MODULE->srcversion); -#else - buildtag[0] = 'b'; -#endif - } - - return buildtag; -} - module_init(drbd_init) module_exit(drbd_cleanup) diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index 2227fb0db1ce..1d0feafceadc 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -228,7 +228,7 @@ int drbd_seq_show(struct seq_file *seq, void *v) }; seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n", - API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag()); + GENL_MAGIC_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag()); /* cs .. connection state diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index eb14ec8ec04c..e36216d50753 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1607,6 +1607,8 @@ void drbd_submit_bio(struct bio *bio) struct drbd_device *device = bio->bi_bdev->bd_disk->private_data; bio = bio_split_to_limits(bio); + if (!bio) + return; /* * what we "blindly" assume: diff --git a/drivers/block/drbd/drbd_vli.h b/drivers/block/drbd/drbd_vli.h index 1ee81e3c2152..941c511cc4da 100644 --- a/drivers/block/drbd/drbd_vli.h +++ b/drivers/block/drbd/drbd_vli.h @@ -327,7 +327,7 @@ static inline int bitstream_get_bits(struct bitstream *bs, u64 *out, int bits) */ static inline int vli_encode_bits(struct bitstream *bs, u64 in) { - u64 code = code; + u64 code; int bits = __vli_encode_bits(&code, in); if (bits <= 0) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 1518a6423279..5f04235e4ff7 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -90,7 +90,7 @@ struct loop_cmd { }; #define LOOP_IDLE_WORKER_TIMEOUT (60 * HZ) -#define LOOP_DEFAULT_HW_Q_DEPTH (128) +#define LOOP_DEFAULT_HW_Q_DEPTH 128 static DEFINE_IDR(loop_index_idr); static DEFINE_MUTEX(loop_ctl_mutex); @@ -1792,9 +1792,15 @@ static int hw_queue_depth = LOOP_DEFAULT_HW_Q_DEPTH; static int loop_set_hw_queue_depth(const char *s, const struct kernel_param *p) { - int ret = kstrtoint(s, 10, &hw_queue_depth); + int qd, ret; - return (ret || (hw_queue_depth < 1)) ? -EINVAL : 0; + ret = kstrtoint(s, 0, &qd); + if (ret < 0) + return ret; + if (qd < 1) + return -EINVAL; + hw_queue_depth = qd; + return 0; } static const struct kernel_param_ops loop_hw_qdepth_param_ops = { @@ -1803,7 +1809,7 @@ static const struct kernel_param_ops loop_hw_qdepth_param_ops = { }; device_param_cb(hw_queue_depth, &loop_hw_qdepth_param_ops, &hw_queue_depth, 0444); -MODULE_PARM_DESC(hw_queue_depth, "Queue depth for each hardware queue. Default: 128"); +MODULE_PARM_DESC(hw_queue_depth, "Queue depth for each hardware queue. Default: " __stringify(LOOP_DEFAULT_HW_Q_DEPTH)); MODULE_LICENSE("GPL"); MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR); diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c index 7d28e3aa406c..4c601ca9552a 100644 --- a/drivers/block/null_blk/main.c +++ b/drivers/block/null_blk/main.c @@ -2123,8 +2123,7 @@ static int null_add_dev(struct nullb_device *dev) blk_queue_physical_block_size(nullb->q, dev->blocksize); if (!dev->max_sectors) dev->max_sectors = queue_max_hw_sectors(nullb->q); - dev->max_sectors = min_t(unsigned int, dev->max_sectors, - BLK_DEF_MAX_SECTORS); + dev->max_sectors = min(dev->max_sectors, BLK_DEF_MAX_SECTORS); blk_queue_max_hw_sectors(nullb->q, dev->max_sectors); if (dev->virt_boundary) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c new file mode 100644 index 000000000000..2f1a92509271 --- /dev/null +++ b/drivers/block/pktcdvd.c @@ -0,0 +1,2946 @@ +/* + * Copyright (C) 2000 Jens Axboe <axboe@suse.de> + * Copyright (C) 2001-2004 Peter Osterlund <petero2@telia.com> + * Copyright (C) 2006 Thomas Maier <balagi@justmail.de> + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Packet writing layer for ATAPI and SCSI CD-RW, DVD+RW, DVD-RW and + * DVD-RAM devices. + * + * Theory of operation: + * + * At the lowest level, there is the standard driver for the CD/DVD device, + * such as drivers/scsi/sr.c. This driver can handle read and write requests, + * but it doesn't know anything about the special restrictions that apply to + * packet writing. One restriction is that write requests must be aligned to + * packet boundaries on the physical media, and the size of a write request + * must be equal to the packet size. Another restriction is that a + * GPCMD_FLUSH_CACHE command has to be issued to the drive before a read + * command, if the previous command was a write. + * + * The purpose of the packet writing driver is to hide these restrictions from + * higher layers, such as file systems, and present a block device that can be + * randomly read and written using 2kB-sized blocks. + * + * The lowest layer in the packet writing driver is the packet I/O scheduler. + * Its data is defined by the struct packet_iosched and includes two bio + * queues with pending read and write requests. These queues are processed + * by the pkt_iosched_process_queue() function. The write requests in this + * queue are already properly aligned and sized. This layer is responsible for + * issuing the flush cache commands and scheduling the I/O in a good order. + * + * The next layer transforms unaligned write requests to aligned writes. This + * transformation requires reading missing pieces of data from the underlying + * block device, assembling the pieces to full packets and queuing them to the + * packet I/O scheduler. + * + * At the top layer there is a custom ->submit_bio function that forwards + * read requests directly to the iosched queue and puts write requests in the + * unaligned write queue. A kernel thread performs the necessary read + * gathering to convert the unaligned writes to aligned writes and then feeds + * them to the packet I/O scheduler. + * + *************************************************************************/ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/pktcdvd.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/compat.h> +#include <linux/kthread.h> +#include <linux/errno.h> +#include <linux/spinlock.h> +#include <linux/file.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/miscdevice.h> +#include <linux/freezer.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/backing-dev.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_ioctl.h> +#include <scsi/scsi.h> +#include <linux/debugfs.h> +#include <linux/device.h> +#include <linux/nospec.h> +#include <linux/uaccess.h> + +#define DRIVER_NAME "pktcdvd" + +#define pkt_err(pd, fmt, ...) \ + pr_err("%s: " fmt, pd->name, ##__VA_ARGS__) +#define pkt_notice(pd, fmt, ...) \ + pr_notice("%s: " fmt, pd->name, ##__VA_ARGS__) +#define pkt_info(pd, fmt, ...) \ + pr_info("%s: " fmt, pd->name, ##__VA_ARGS__) + +#define pkt_dbg(level, pd, fmt, ...) \ +do { \ + if (level == 2 && PACKET_DEBUG >= 2) \ + pr_notice("%s: %s():" fmt, \ + pd->name, __func__, ##__VA_ARGS__); \ + else if (level == 1 && PACKET_DEBUG >= 1) \ + pr_notice("%s: " fmt, pd->name, ##__VA_ARGS__); \ +} while (0) + +#define MAX_SPEED 0xffff + +static DEFINE_MUTEX(pktcdvd_mutex); +static struct pktcdvd_device *pkt_devs[MAX_WRITERS]; +static struct proc_dir_entry *pkt_proc; +static int pktdev_major; +static int write_congestion_on = PKT_WRITE_CONGESTION_ON; +static int write_congestion_off = PKT_WRITE_CONGESTION_OFF; +static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */ +static mempool_t psd_pool; +static struct bio_set pkt_bio_set; + +static struct class *class_pktcdvd = NULL; /* /sys/class/pktcdvd */ +static struct dentry *pkt_debugfs_root = NULL; /* /sys/kernel/debug/pktcdvd */ + +/* forward declaration */ +static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev); +static int pkt_remove_dev(dev_t pkt_dev); +static int pkt_seq_show(struct seq_file *m, void *p); + +static sector_t get_zone(sector_t sector, struct pktcdvd_device *pd) +{ + return (sector + pd->offset) & ~(sector_t)(pd->settings.size - 1); +} + +/********************************************************** + * sysfs interface for pktcdvd + * by (C) 2006 Thomas Maier <balagi@justmail.de> + + /sys/class/pktcdvd/pktcdvd[0-7]/ + stat/reset + stat/packets_started + stat/packets_finished + stat/kb_written + stat/kb_read + stat/kb_read_gather + write_queue/size + write_queue/congestion_off + write_queue/congestion_on + **********************************************************/ + +static ssize_t packets_started_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pktcdvd_device *pd = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%lu\n", pd->stats.pkt_started); +} +static DEVICE_ATTR_RO(packets_started); + +static ssize_t packets_finished_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pktcdvd_device *pd = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%lu\n", pd->stats.pkt_ended); +} +static DEVICE_ATTR_RO(packets_finished); + +static ssize_t kb_written_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pktcdvd_device *pd = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%lu\n", pd->stats.secs_w >> 1); +} +static DEVICE_ATTR_RO(kb_written); + +static ssize_t kb_read_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pktcdvd_device *pd = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%lu\n", pd->stats.secs_r >> 1); +} +static DEVICE_ATTR_RO(kb_read); + +static ssize_t kb_read_gather_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pktcdvd_device *pd = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%lu\n", pd->stats.secs_rg >> 1); +} +static DEVICE_ATTR_RO(kb_read_gather); + +static ssize_t reset_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +{ + struct pktcdvd_device *pd = dev_get_drvdata(dev); + + if (len > 0) { + pd->stats.pkt_started = 0; + pd->stats.pkt_ended = 0; + pd->stats.secs_w = 0; + pd->stats.secs_rg = 0; + pd->stats.secs_r = 0; + } + return len; +} +static DEVICE_ATTR_WO(reset); + +static struct attribute *pkt_stat_attrs[] = { + &dev_attr_packets_finished.attr, + &dev_attr_packets_started.attr, + &dev_attr_kb_read.attr, + &dev_attr_kb_written.attr, + &dev_attr_kb_read_gather.attr, + &dev_attr_reset.attr, + NULL, +}; + +static const struct attribute_group pkt_stat_group = { + .name = "stat", + .attrs = pkt_stat_attrs, +}; + +static ssize_t size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pktcdvd_device *pd = dev_get_drvdata(dev); + int n; + + spin_lock(&pd->lock); + n = sysfs_emit(buf, "%d\n", pd->bio_queue_size); + spin_unlock(&pd->lock); + return n; +} +static DEVICE_ATTR_RO(size); + +static void init_write_congestion_marks(int* lo, int* hi) +{ + if (*hi > 0) { + *hi = max(*hi, 500); + *hi = min(*hi, 1000000); + if (*lo <= 0) + *lo = *hi - 100; + else { + *lo = min(*lo, *hi - 100); + *lo = max(*lo, 100); + } + } else { + *hi = -1; + *lo = -1; + } +} + +static ssize_t congestion_off_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pktcdvd_device *pd = dev_get_drvdata(dev); + int n; + + spin_lock(&pd->lock); + n = sysfs_emit(buf, "%d\n", pd->write_congestion_off); + spin_unlock(&pd->lock); + return n; +} + +static ssize_t congestion_off_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct pktcdvd_device *pd = dev_get_drvdata(dev); + int val; + + if (sscanf(buf, "%d", &val) == 1) { + spin_lock(&pd->lock); + pd->write_congestion_off = val; + init_write_congestion_marks(&pd->write_congestion_off, + &pd->write_congestion_on); + spin_unlock(&pd->lock); + } + return len; +} +static DEVICE_ATTR_RW(congestion_off); + +static ssize_t congestion_on_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pktcdvd_device *pd = dev_get_drvdata(dev); + int n; + + spin_lock(&pd->lock); + n = sysfs_emit(buf, "%d\n", pd->write_congestion_on); + spin_unlock(&pd->lock); + return n; +} + +static ssize_t congestion_on_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct pktcdvd_device *pd = dev_get_drvdata(dev); + int val; + + if (sscanf(buf, "%d", &val) == 1) { + spin_lock(&pd->lock); + pd->write_congestion_on = val; + init_write_congestion_marks(&pd->write_congestion_off, + &pd->write_congestion_on); + spin_unlock(&pd->lock); + } + return len; +} +static DEVICE_ATTR_RW(congestion_on); + +static struct attribute *pkt_wq_attrs[] = { + &dev_attr_congestion_on.attr, + &dev_attr_congestion_off.attr, + &dev_attr_size.attr, + NULL, +}; + +static const struct attribute_group pkt_wq_group = { + .name = "write_queue", + .attrs = pkt_wq_attrs, +}; + +static const struct attribute_group *pkt_groups[] = { + &pkt_stat_group, + &pkt_wq_group, + NULL, +}; + +static void pkt_sysfs_dev_new(struct pktcdvd_device *pd) +{ + if (class_pktcdvd) { + pd->dev = device_create_with_groups(class_pktcdvd, NULL, + MKDEV(0, 0), pd, pkt_groups, + "%s", pd->name); + if (IS_ERR(pd->dev)) + pd->dev = NULL; + } +} + +static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd) +{ + if (class_pktcdvd) + device_unregister(pd->dev); +} + + +/******************************************************************** + /sys/class/pktcdvd/ + add map block device + remove unmap packet dev + device_map show mappings + *******************************************************************/ + +static void class_pktcdvd_release(struct class *cls) +{ + kfree(cls); +} + +static ssize_t device_map_show(struct class *c, struct class_attribute *attr, + char *data) +{ + int n = 0; + int idx; + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + for (idx = 0; idx < MAX_WRITERS; idx++) { + struct pktcdvd_device *pd = pkt_devs[idx]; + if (!pd) + continue; + n += sprintf(data+n, "%s %u:%u %u:%u\n", + pd->name, + MAJOR(pd->pkt_dev), MINOR(pd->pkt_dev), + MAJOR(pd->bdev->bd_dev), + MINOR(pd->bdev->bd_dev)); + } + mutex_unlock(&ctl_mutex); + return n; +} +static CLASS_ATTR_RO(device_map); + +static ssize_t add_store(struct class *c, struct class_attribute *attr, + const char *buf, size_t count) +{ + unsigned int major, minor; + + if (sscanf(buf, "%u:%u", &major, &minor) == 2) { + /* pkt_setup_dev() expects caller to hold reference to self */ + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + + pkt_setup_dev(MKDEV(major, minor), NULL); + + module_put(THIS_MODULE); + + return count; + } + + return -EINVAL; +} +static CLASS_ATTR_WO(add); + +static ssize_t remove_store(struct class *c, struct class_attribute *attr, + const char *buf, size_t count) +{ + unsigned int major, minor; + if (sscanf(buf, "%u:%u", &major, &minor) == 2) { + pkt_remove_dev(MKDEV(major, minor)); + return count; + } + return -EINVAL; +} +static CLASS_ATTR_WO(remove); + +static struct attribute *class_pktcdvd_attrs[] = { + &class_attr_add.attr, + &class_attr_remove.attr, + &class_attr_device_map.attr, + NULL, +}; +ATTRIBUTE_GROUPS(class_pktcdvd); + +static int pkt_sysfs_init(void) +{ + int ret = 0; + + /* + * create control files in sysfs + * /sys/class/pktcdvd/... + */ + class_pktcdvd = kzalloc(sizeof(*class_pktcdvd), GFP_KERNEL); + if (!class_pktcdvd) + return -ENOMEM; + class_pktcdvd->name = DRIVER_NAME; + class_pktcdvd->owner = THIS_MODULE; + class_pktcdvd->class_release = class_pktcdvd_release; + class_pktcdvd->class_groups = class_pktcdvd_groups; + ret = class_register(class_pktcdvd); + if (ret) { + kfree(class_pktcdvd); + class_pktcdvd = NULL; + pr_err("failed to create class pktcdvd\n"); + return ret; + } + return 0; +} + +static void pkt_sysfs_cleanup(void) +{ + if (class_pktcdvd) + class_destroy(class_pktcdvd); + class_pktcdvd = NULL; +} + +/******************************************************************** + entries in debugfs + + /sys/kernel/debug/pktcdvd[0-7]/ + info + + *******************************************************************/ + +static int pkt_debugfs_seq_show(struct seq_file *m, void *p) +{ + return pkt_seq_show(m, p); +} + +static int pkt_debugfs_fops_open(struct inode *inode, struct file *file) +{ + return single_open(file, pkt_debugfs_seq_show, inode->i_private); +} + +static const struct file_operations debug_fops = { + .open = pkt_debugfs_fops_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static void pkt_debugfs_dev_new(struct pktcdvd_device *pd) +{ + if (!pkt_debugfs_root) + return; + pd->dfs_d_root = debugfs_create_dir(pd->name, pkt_debugfs_root); + if (!pd->dfs_d_root) + return; + + pd->dfs_f_info = debugfs_create_file("info", 0444, + pd->dfs_d_root, pd, &debug_fops); +} + +static void pkt_debugfs_dev_remove(struct pktcdvd_device *pd) +{ + if (!pkt_debugfs_root) + return; + debugfs_remove(pd->dfs_f_info); + debugfs_remove(pd->dfs_d_root); + pd->dfs_f_info = NULL; + pd->dfs_d_root = NULL; +} + +static void pkt_debugfs_init(void) +{ + pkt_debugfs_root = debugfs_create_dir(DRIVER_NAME, NULL); +} + +static void pkt_debugfs_cleanup(void) +{ + debugfs_remove(pkt_debugfs_root); + pkt_debugfs_root = NULL; +} + +/* ----------------------------------------------------------*/ + + +static void pkt_bio_finished(struct pktcdvd_device *pd) +{ + BUG_ON(atomic_read(&pd->cdrw.pending_bios) <= 0); + if (atomic_dec_and_test(&pd->cdrw.pending_bios)) { + pkt_dbg(2, pd, "queue empty\n"); + atomic_set(&pd->iosched.attention, 1); + wake_up(&pd->wqueue); + } +} + +/* + * Allocate a packet_data struct + */ +static struct packet_data *pkt_alloc_packet_data(int frames) +{ + int i; + struct packet_data *pkt; + + pkt = kzalloc(sizeof(struct packet_data), GFP_KERNEL); + if (!pkt) + goto no_pkt; + + pkt->frames = frames; + pkt->w_bio = bio_kmalloc(frames, GFP_KERNEL); + if (!pkt->w_bio) + goto no_bio; + + for (i = 0; i < frames / FRAMES_PER_PAGE; i++) { + pkt->pages[i] = alloc_page(GFP_KERNEL|__GFP_ZERO); + if (!pkt->pages[i]) + goto no_page; + } + + spin_lock_init(&pkt->lock); + bio_list_init(&pkt->orig_bios); + + for (i = 0; i < frames; i++) { + pkt->r_bios[i] = bio_kmalloc(1, GFP_KERNEL); + if (!pkt->r_bios[i]) + goto no_rd_bio; + } + + return pkt; + +no_rd_bio: + for (i = 0; i < frames; i++) + kfree(pkt->r_bios[i]); +no_page: + for (i = 0; i < frames / FRAMES_PER_PAGE; i++) + if (pkt->pages[i]) + __free_page(pkt->pages[i]); + kfree(pkt->w_bio); +no_bio: + kfree(pkt); +no_pkt: + return NULL; +} + +/* + * Free a packet_data struct + */ +static void pkt_free_packet_data(struct packet_data *pkt) +{ + int i; + + for (i = 0; i < pkt->frames; i++) + kfree(pkt->r_bios[i]); + for (i = 0; i < pkt->frames / FRAMES_PER_PAGE; i++) + __free_page(pkt->pages[i]); + kfree(pkt->w_bio); + kfree(pkt); +} + +static void pkt_shrink_pktlist(struct pktcdvd_device *pd) +{ + struct packet_data *pkt, *next; + + BUG_ON(!list_empty(&pd->cdrw.pkt_active_list)); + + list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_free_list, list) { + pkt_free_packet_data(pkt); + } + INIT_LIST_HEAD(&pd->cdrw.pkt_free_list); +} + +static int pkt_grow_pktlist(struct pktcdvd_device *pd, int nr_packets) +{ + struct packet_data *pkt; + + BUG_ON(!list_empty(&pd->cdrw.pkt_free_list)); + + while (nr_packets > 0) { + pkt = pkt_alloc_packet_data(pd->settings.size >> 2); + if (!pkt) { + pkt_shrink_pktlist(pd); + return 0; + } + pkt->id = nr_packets; + pkt->pd = pd; + list_add(&pkt->list, &pd->cdrw.pkt_free_list); + nr_packets--; + } + return 1; +} + +static inline struct pkt_rb_node *pkt_rbtree_next(struct pkt_rb_node *node) +{ + struct rb_node *n = rb_next(&node->rb_node); + if (!n) + return NULL; + return rb_entry(n, struct pkt_rb_node, rb_node); +} + +static void pkt_rbtree_erase(struct pktcdvd_device *pd, struct pkt_rb_node *node) +{ + rb_erase(&node->rb_node, &pd->bio_queue); + mempool_free(node, &pd->rb_pool); + pd->bio_queue_size--; + BUG_ON(pd->bio_queue_size < 0); +} + +/* + * Find the first node in the pd->bio_queue rb tree with a starting sector >= s. + */ +static struct pkt_rb_node *pkt_rbtree_find(struct pktcdvd_device *pd, sector_t s) +{ + struct rb_node *n = pd->bio_queue.rb_node; + struct rb_node *next; + struct pkt_rb_node *tmp; + + if (!n) { + BUG_ON(pd->bio_queue_size > 0); + return NULL; + } + + for (;;) { + tmp = rb_entry(n, struct pkt_rb_node, rb_node); + if (s <= tmp->bio->bi_iter.bi_sector) + next = n->rb_left; + else + next = n->rb_right; + if (!next) + break; + n = next; + } + + if (s > tmp->bio->bi_iter.bi_sector) { + tmp = pkt_rbtree_next(tmp); + if (!tmp) + return NULL; + } + BUG_ON(s > tmp->bio->bi_iter.bi_sector); + return tmp; +} + +/* + * Insert a node into the pd->bio_queue rb tree. + */ +static void pkt_rbtree_insert(struct pktcdvd_device *pd, struct pkt_rb_node *node) +{ + struct rb_node **p = &pd->bio_queue.rb_node; + struct rb_node *parent = NULL; + sector_t s = node->bio->bi_iter.bi_sector; + struct pkt_rb_node *tmp; + + while (*p) { + parent = *p; + tmp = rb_entry(parent, struct pkt_rb_node, rb_node); + if (s < tmp->bio->bi_iter.bi_sector) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + rb_link_node(&node->rb_node, parent, p); + rb_insert_color(&node->rb_node, &pd->bio_queue); + pd->bio_queue_size++; +} + +/* + * Send a packet_command to the underlying block device and + * wait for completion. + */ +static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *cgc) +{ + struct request_queue *q = bdev_get_queue(pd->bdev); + struct scsi_cmnd *scmd; + struct request *rq; + int ret = 0; + + rq = scsi_alloc_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? + REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); + if (IS_ERR(rq)) + return PTR_ERR(rq); + scmd = blk_mq_rq_to_pdu(rq); + + if (cgc->buflen) { + ret = blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, + GFP_NOIO); + if (ret) + goto out; + } + + scmd->cmd_len = COMMAND_SIZE(cgc->cmd[0]); + memcpy(scmd->cmnd, cgc->cmd, CDROM_PACKET_SIZE); + + rq->timeout = 60*HZ; + if (cgc->quiet) + rq->rq_flags |= RQF_QUIET; + + blk_execute_rq(rq, false); + if (scmd->result) + ret = -EIO; +out: + blk_mq_free_request(rq); + return ret; +} + +static const char *sense_key_string(__u8 index) +{ + static const char * const info[] = { + "No sense", "Recovered error", "Not ready", + "Medium error", "Hardware error", "Illegal request", + "Unit attention", "Data protect", "Blank check", + }; + + return index < ARRAY_SIZE(info) ? info[index] : "INVALID"; +} + +/* + * A generic sense dump / resolve mechanism should be implemented across + * all ATAPI + SCSI devices. + */ +static void pkt_dump_sense(struct pktcdvd_device *pd, + struct packet_command *cgc) +{ + struct scsi_sense_hdr *sshdr = cgc->sshdr; + + if (sshdr) + pkt_err(pd, "%*ph - sense %02x.%02x.%02x (%s)\n", + CDROM_PACKET_SIZE, cgc->cmd, + sshdr->sense_key, sshdr->asc, sshdr->ascq, + sense_key_string(sshdr->sense_key)); + else + pkt_err(pd, "%*ph - no sense\n", CDROM_PACKET_SIZE, cgc->cmd); +} + +/* + * flush the drive cache to media + */ +static int pkt_flush_cache(struct pktcdvd_device *pd) +{ + struct packet_command cgc; + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.cmd[0] = GPCMD_FLUSH_CACHE; + cgc.quiet = 1; + + /* + * the IMMED bit -- we default to not setting it, although that + * would allow a much faster close, this is safer + */ +#if 0 + cgc.cmd[1] = 1 << 1; +#endif + return pkt_generic_packet(pd, &cgc); +} + +/* + * speed is given as the normal factor, e.g. 4 for 4x + */ +static noinline_for_stack int pkt_set_speed(struct pktcdvd_device *pd, + unsigned write_speed, unsigned read_speed) +{ + struct packet_command cgc; + struct scsi_sense_hdr sshdr; + int ret; + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.sshdr = &sshdr; + cgc.cmd[0] = GPCMD_SET_SPEED; + cgc.cmd[2] = (read_speed >> 8) & 0xff; + cgc.cmd[3] = read_speed & 0xff; + cgc.cmd[4] = (write_speed >> 8) & 0xff; + cgc.cmd[5] = write_speed & 0xff; + + ret = pkt_generic_packet(pd, &cgc); + if (ret) + pkt_dump_sense(pd, &cgc); + + return ret; +} + +/* + * Queue a bio for processing by the low-level CD device. Must be called + * from process context. + */ +static void pkt_queue_bio(struct pktcdvd_device *pd, struct bio *bio) +{ + spin_lock(&pd->iosched.lock); + if (bio_data_dir(bio) == READ) + bio_list_add(&pd->iosched.read_queue, bio); + else + bio_list_add(&pd->iosched.write_queue, bio); + spin_unlock(&pd->iosched.lock); + + atomic_set(&pd->iosched.attention, 1); + wake_up(&pd->wqueue); +} + +/* + * Process the queued read/write requests. This function handles special + * requirements for CDRW drives: + * - A cache flush command must be inserted before a read request if the + * previous request was a write. + * - Switching between reading and writing is slow, so don't do it more often + * than necessary. + * - Optimize for throughput at the expense of latency. This means that streaming + * writes will never be interrupted by a read, but if the drive has to seek + * before the next write, switch to reading instead if there are any pending + * read requests. + * - Set the read speed according to current usage pattern. When only reading + * from the device, it's best to use the highest possible read speed, but + * when switching often between reading and writing, it's better to have the + * same read and write speeds. + */ +static void pkt_iosched_process_queue(struct pktcdvd_device *pd) +{ + + if (atomic_read(&pd->iosched.attention) == 0) + return; + atomic_set(&pd->iosched.attention, 0); + + for (;;) { + struct bio *bio; + int reads_queued, writes_queued; + + spin_lock(&pd->iosched.lock); + reads_queued = !bio_list_empty(&pd->iosched.read_queue); + writes_queued = !bio_list_empty(&pd->iosched.write_queue); + spin_unlock(&pd->iosched.lock); + + if (!reads_queued && !writes_queued) + break; + + if (pd->iosched.writing) { + int need_write_seek = 1; + spin_lock(&pd->iosched.lock); + bio = bio_list_peek(&pd->iosched.write_queue); + spin_unlock(&pd->iosched.lock); + if (bio && (bio->bi_iter.bi_sector == + pd->iosched.last_write)) + need_write_seek = 0; + if (need_write_seek && reads_queued) { + if (atomic_read(&pd->cdrw.pending_bios) > 0) { + pkt_dbg(2, pd, "write, waiting\n"); + break; + } + pkt_flush_cache(pd); + pd->iosched.writing = 0; + } + } else { + if (!reads_queued && writes_queued) { + if (atomic_read(&pd->cdrw.pending_bios) > 0) { + pkt_dbg(2, pd, "read, waiting\n"); + break; + } + pd->iosched.writing = 1; + } + } + + spin_lock(&pd->iosched.lock); + if (pd->iosched.writing) + bio = bio_list_pop(&pd->iosched.write_queue); + else + bio = bio_list_pop(&pd->iosched.read_queue); + spin_unlock(&pd->iosched.lock); + + if (!bio) + continue; + + if (bio_data_dir(bio) == READ) + pd->iosched.successive_reads += + bio->bi_iter.bi_size >> 10; + else { + pd->iosched.successive_reads = 0; + pd->iosched.last_write = bio_end_sector(bio); + } + if (pd->iosched.successive_reads >= HI_SPEED_SWITCH) { + if (pd->read_speed == pd->write_speed) { + pd->read_speed = MAX_SPEED; + pkt_set_speed(pd, pd->write_speed, pd->read_speed); + } + } else { + if (pd->read_speed != pd->write_speed) { + pd->read_speed = pd->write_speed; + pkt_set_speed(pd, pd->write_speed, pd->read_speed); + } + } + + atomic_inc(&pd->cdrw.pending_bios); + submit_bio_noacct(bio); + } +} + +/* + * Special care is needed if the underlying block device has a small + * max_phys_segments value. + */ +static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_queue *q) +{ + if ((pd->settings.size << 9) / CD_FRAMESIZE + <= queue_max_segments(q)) { + /* + * The cdrom device can handle one segment/frame + */ + clear_bit(PACKET_MERGE_SEGS, &pd->flags); + return 0; + } else if ((pd->settings.size << 9) / PAGE_SIZE + <= queue_max_segments(q)) { + /* + * We can handle this case at the expense of some extra memory + * copies during write operations + */ + set_bit(PACKET_MERGE_SEGS, &pd->flags); + return 0; + } else { + pkt_err(pd, "cdrom max_phys_segments too small\n"); + return -EIO; + } +} + +static void pkt_end_io_read(struct bio *bio) +{ + struct packet_data *pkt = bio->bi_private; + struct pktcdvd_device *pd = pkt->pd; + BUG_ON(!pd); + + pkt_dbg(2, pd, "bio=%p sec0=%llx sec=%llx err=%d\n", + bio, (unsigned long long)pkt->sector, + (unsigned long long)bio->bi_iter.bi_sector, bio->bi_status); + + if (bio->bi_status) + atomic_inc(&pkt->io_errors); + bio_uninit(bio); + if (atomic_dec_and_test(&pkt->io_wait)) { + atomic_inc(&pkt->run_sm); + wake_up(&pd->wqueue); + } + pkt_bio_finished(pd); +} + +static void pkt_end_io_packet_write(struct bio *bio) +{ + struct packet_data *pkt = bio->bi_private; + struct pktcdvd_device *pd = pkt->pd; + BUG_ON(!pd); + + pkt_dbg(2, pd, "id=%d, err=%d\n", pkt->id, bio->bi_status); + + pd->stats.pkt_ended++; + + bio_uninit(bio); + pkt_bio_finished(pd); + atomic_dec(&pkt->io_wait); + atomic_inc(&pkt->run_sm); + wake_up(&pd->wqueue); +} + +/* + * Schedule reads for the holes in a packet + */ +static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) +{ + int frames_read = 0; + struct bio *bio; + int f; + char written[PACKET_MAX_SIZE]; + + BUG_ON(bio_list_empty(&pkt->orig_bios)); + + atomic_set(&pkt->io_wait, 0); + atomic_set(&pkt->io_errors, 0); + + /* + * Figure out which frames we need to read before we can write. + */ + memset(written, 0, sizeof(written)); + spin_lock(&pkt->lock); + bio_list_for_each(bio, &pkt->orig_bios) { + int first_frame = (bio->bi_iter.bi_sector - pkt->sector) / + (CD_FRAMESIZE >> 9); + int num_frames = bio->bi_iter.bi_size / CD_FRAMESIZE; + pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9); + BUG_ON(first_frame < 0); + BUG_ON(first_frame + num_frames > pkt->frames); + for (f = first_frame; f < first_frame + num_frames; f++) + written[f] = 1; + } + spin_unlock(&pkt->lock); + + if (pkt->cache_valid) { + pkt_dbg(2, pd, "zone %llx cached\n", + (unsigned long long)pkt->sector); + goto out_account; + } + + /* + * Schedule reads for missing parts of the packet. + */ + for (f = 0; f < pkt->frames; f++) { + int p, offset; + + if (written[f]) + continue; + + bio = pkt->r_bios[f]; + bio_init(bio, pd->bdev, bio->bi_inline_vecs, 1, REQ_OP_READ); + bio->bi_iter.bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9); + bio->bi_end_io = pkt_end_io_read; + bio->bi_private = pkt; + + p = (f * CD_FRAMESIZE) / PAGE_SIZE; + offset = (f * CD_FRAMESIZE) % PAGE_SIZE; + pkt_dbg(2, pd, "Adding frame %d, page:%p offs:%d\n", + f, pkt->pages[p], offset); + if (!bio_add_page(bio, pkt->pages[p], CD_FRAMESIZE, offset)) + BUG(); + + atomic_inc(&pkt->io_wait); + pkt_queue_bio(pd, bio); + frames_read++; + } + +out_account: + pkt_dbg(2, pd, "need %d frames for zone %llx\n", + frames_read, (unsigned long long)pkt->sector); + pd->stats.pkt_started++; + pd->stats.secs_rg += frames_read * (CD_FRAMESIZE >> 9); +} + +/* + * Find a packet matching zone, or the least recently used packet if + * there is no match. + */ +static struct packet_data *pkt_get_packet_data(struct pktcdvd_device *pd, int zone) +{ + struct packet_data *pkt; + + list_for_each_entry(pkt, &pd->cdrw.pkt_free_list, list) { + if (pkt->sector == zone || pkt->list.next == &pd->cdrw.pkt_free_list) { + list_del_init(&pkt->list); + if (pkt->sector != zone) + pkt->cache_valid = 0; + return pkt; + } + } + BUG(); + return NULL; +} + +static void pkt_put_packet_data(struct pktcdvd_device *pd, struct packet_data *pkt) +{ + if (pkt->cache_valid) { + list_add(&pkt->list, &pd->cdrw.pkt_free_list); + } else { + list_add_tail(&pkt->list, &pd->cdrw.pkt_free_list); + } +} + +static inline void pkt_set_state(struct packet_data *pkt, enum packet_data_state state) +{ +#if PACKET_DEBUG > 1 + static const char *state_name[] = { + "IDLE", "WAITING", "READ_WAIT", "WRITE_WAIT", "RECOVERY", "FINISHED" + }; + enum packet_data_state old_state = pkt->state; + pkt_dbg(2, pd, "pkt %2d : s=%6llx %s -> %s\n", + pkt->id, (unsigned long long)pkt->sector, + state_name[old_state], state_name[state]); +#endif + pkt->state = state; +} + +/* + * Scan the work queue to see if we can start a new packet. + * returns non-zero if any work was done. + */ +static int pkt_handle_queue(struct pktcdvd_device *pd) +{ + struct packet_data *pkt, *p; + struct bio *bio = NULL; + sector_t zone = 0; /* Suppress gcc warning */ + struct pkt_rb_node *node, *first_node; + struct rb_node *n; + + atomic_set(&pd->scan_queue, 0); + + if (list_empty(&pd->cdrw.pkt_free_list)) { + pkt_dbg(2, pd, "no pkt\n"); + return 0; + } + + /* + * Try to find a zone we are not already working on. + */ + spin_lock(&pd->lock); + first_node = pkt_rbtree_find(pd, pd->current_sector); + if (!first_node) { + n = rb_first(&pd->bio_queue); + if (n) + first_node = rb_entry(n, struct pkt_rb_node, rb_node); + } + node = first_node; + while (node) { + bio = node->bio; + zone = get_zone(bio->bi_iter.bi_sector, pd); + list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) { + if (p->sector == zone) { + bio = NULL; + goto try_next_bio; + } + } + break; +try_next_bio: + node = pkt_rbtree_next(node); + if (!node) { + n = rb_first(&pd->bio_queue); + if (n) + node = rb_entry(n, struct pkt_rb_node, rb_node); + } + if (node == first_node) + node = NULL; + } + spin_unlock(&pd->lock); + if (!bio) { + pkt_dbg(2, pd, "no bio\n"); + return 0; + } + + pkt = pkt_get_packet_data(pd, zone); + + pd->current_sector = zone + pd->settings.size; + pkt->sector = zone; + BUG_ON(pkt->frames != pd->settings.size >> 2); + pkt->write_size = 0; + + /* + * Scan work queue for bios in the same zone and link them + * to this packet. + */ + spin_lock(&pd->lock); + pkt_dbg(2, pd, "looking for zone %llx\n", (unsigned long long)zone); + while ((node = pkt_rbtree_find(pd, zone)) != NULL) { + bio = node->bio; + pkt_dbg(2, pd, "found zone=%llx\n", (unsigned long long) + get_zone(bio->bi_iter.bi_sector, pd)); + if (get_zone(bio->bi_iter.bi_sector, pd) != zone) + break; + pkt_rbtree_erase(pd, node); + spin_lock(&pkt->lock); + bio_list_add(&pkt->orig_bios, bio); + pkt->write_size += bio->bi_iter.bi_size / CD_FRAMESIZE; + spin_unlock(&pkt->lock); + } + /* check write congestion marks, and if bio_queue_size is + * below, wake up any waiters + */ + if (pd->congested && + pd->bio_queue_size <= pd->write_congestion_off) { + pd->congested = false; + wake_up_var(&pd->congested); + } + spin_unlock(&pd->lock); + + pkt->sleep_time = max(PACKET_WAIT_TIME, 1); + pkt_set_state(pkt, PACKET_WAITING_STATE); + atomic_set(&pkt->run_sm, 1); + + spin_lock(&pd->cdrw.active_list_lock); + list_add(&pkt->list, &pd->cdrw.pkt_active_list); + spin_unlock(&pd->cdrw.active_list_lock); + + return 1; +} + +/** + * bio_list_copy_data - copy contents of data buffers from one chain of bios to + * another + * @src: source bio list + * @dst: destination bio list + * + * Stops when it reaches the end of either the @src list or @dst list - that is, + * copies min(src->bi_size, dst->bi_size) bytes (or the equivalent for lists of + * bios). + */ +static void bio_list_copy_data(struct bio *dst, struct bio *src) +{ + struct bvec_iter src_iter = src->bi_iter; + struct bvec_iter dst_iter = dst->bi_iter; + + while (1) { + if (!src_iter.bi_size) { + src = src->bi_next; + if (!src) + break; + + src_iter = src->bi_iter; + } + + if (!dst_iter.bi_size) { + dst = dst->bi_next; + if (!dst) + break; + + dst_iter = dst->bi_iter; + } + + bio_copy_data_iter(dst, &dst_iter, src, &src_iter); + } +} + +/* + * Assemble a bio to write one packet and queue the bio for processing + * by the underlying block device. + */ +static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) +{ + int f; + + bio_init(pkt->w_bio, pd->bdev, pkt->w_bio->bi_inline_vecs, pkt->frames, + REQ_OP_WRITE); + pkt->w_bio->bi_iter.bi_sector = pkt->sector; + pkt->w_bio->bi_end_io = pkt_end_io_packet_write; + pkt->w_bio->bi_private = pkt; + + /* XXX: locking? */ + for (f = 0; f < pkt->frames; f++) { + struct page *page = pkt->pages[(f * CD_FRAMESIZE) / PAGE_SIZE]; + unsigned offset = (f * CD_FRAMESIZE) % PAGE_SIZE; + + if (!bio_add_page(pkt->w_bio, page, CD_FRAMESIZE, offset)) + BUG(); + } + pkt_dbg(2, pd, "vcnt=%d\n", pkt->w_bio->bi_vcnt); + + /* + * Fill-in bvec with data from orig_bios. + */ + spin_lock(&pkt->lock); + bio_list_copy_data(pkt->w_bio, pkt->orig_bios.head); + + pkt_set_state(pkt, PACKET_WRITE_WAIT_STATE); + spin_unlock(&pkt->lock); + + pkt_dbg(2, pd, "Writing %d frames for zone %llx\n", + pkt->write_size, (unsigned long long)pkt->sector); + + if (test_bit(PACKET_MERGE_SEGS, &pd->flags) || (pkt->write_size < pkt->frames)) + pkt->cache_valid = 1; + else + pkt->cache_valid = 0; + + /* Start the write request */ + atomic_set(&pkt->io_wait, 1); + pkt_queue_bio(pd, pkt->w_bio); +} + +static void pkt_finish_packet(struct packet_data *pkt, blk_status_t status) +{ + struct bio *bio; + + if (status) + pkt->cache_valid = 0; + + /* Finish all bios corresponding to this packet */ + while ((bio = bio_list_pop(&pkt->orig_bios))) { + bio->bi_status = status; + bio_endio(bio); + } +} + +static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data *pkt) +{ + pkt_dbg(2, pd, "pkt %d\n", pkt->id); + + for (;;) { + switch (pkt->state) { + case PACKET_WAITING_STATE: + if ((pkt->write_size < pkt->frames) && (pkt->sleep_time > 0)) + return; + + pkt->sleep_time = 0; + pkt_gather_data(pd, pkt); + pkt_set_state(pkt, PACKET_READ_WAIT_STATE); + break; + + case PACKET_READ_WAIT_STATE: + if (atomic_read(&pkt->io_wait) > 0) + return; + + if (atomic_read(&pkt->io_errors) > 0) { + pkt_set_state(pkt, PACKET_RECOVERY_STATE); + } else { + pkt_start_write(pd, pkt); + } + break; + + case PACKET_WRITE_WAIT_STATE: + if (atomic_read(&pkt->io_wait) > 0) + return; + + if (!pkt->w_bio->bi_status) { + pkt_set_state(pkt, PACKET_FINISHED_STATE); + } else { + pkt_set_state(pkt, PACKET_RECOVERY_STATE); + } + break; + + case PACKET_RECOVERY_STATE: + pkt_dbg(2, pd, "No recovery possible\n"); + pkt_set_state(pkt, PACKET_FINISHED_STATE); + break; + + case PACKET_FINISHED_STATE: + pkt_finish_packet(pkt, pkt->w_bio->bi_status); + return; + + default: + BUG(); + break; + } + } +} + +static void pkt_handle_packets(struct pktcdvd_device *pd) +{ + struct packet_data *pkt, *next; + + /* + * Run state machine for active packets + */ + list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { + if (atomic_read(&pkt->run_sm) > 0) { + atomic_set(&pkt->run_sm, 0); + pkt_run_state_machine(pd, pkt); + } + } + + /* + * Move no longer active packets to the free list + */ + spin_lock(&pd->cdrw.active_list_lock); + list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_active_list, list) { + if (pkt->state == PACKET_FINISHED_STATE) { + list_del(&pkt->list); + pkt_put_packet_data(pd, pkt); + pkt_set_state(pkt, PACKET_IDLE_STATE); + atomic_set(&pd->scan_queue, 1); + } + } + spin_unlock(&pd->cdrw.active_list_lock); +} + +static void pkt_count_states(struct pktcdvd_device *pd, int *states) +{ + struct packet_data *pkt; + int i; + + for (i = 0; i < PACKET_NUM_STATES; i++) + states[i] = 0; + + spin_lock(&pd->cdrw.active_list_lock); + list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { + states[pkt->state]++; + } + spin_unlock(&pd->cdrw.active_list_lock); +} + +/* + * kcdrwd is woken up when writes have been queued for one of our + * registered devices + */ +static int kcdrwd(void *foobar) +{ + struct pktcdvd_device *pd = foobar; + struct packet_data *pkt; + long min_sleep_time, residue; + + set_user_nice(current, MIN_NICE); + set_freezable(); + + for (;;) { + DECLARE_WAITQUEUE(wait, current); + + /* + * Wait until there is something to do + */ + add_wait_queue(&pd->wqueue, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + + /* Check if we need to run pkt_handle_queue */ + if (atomic_read(&pd->scan_queue) > 0) + goto work_to_do; + + /* Check if we need to run the state machine for some packet */ + list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { + if (atomic_read(&pkt->run_sm) > 0) + goto work_to_do; + } + + /* Check if we need to process the iosched queues */ + if (atomic_read(&pd->iosched.attention) != 0) + goto work_to_do; + + /* Otherwise, go to sleep */ + if (PACKET_DEBUG > 1) { + int states[PACKET_NUM_STATES]; + pkt_count_states(pd, states); + pkt_dbg(2, pd, "i:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n", + states[0], states[1], states[2], + states[3], states[4], states[5]); + } + + min_sleep_time = MAX_SCHEDULE_TIMEOUT; + list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { + if (pkt->sleep_time && pkt->sleep_time < min_sleep_time) + min_sleep_time = pkt->sleep_time; + } + + pkt_dbg(2, pd, "sleeping\n"); + residue = schedule_timeout(min_sleep_time); + pkt_dbg(2, pd, "wake up\n"); + + /* make swsusp happy with our thread */ + try_to_freeze(); + + list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { + if (!pkt->sleep_time) + continue; + pkt->sleep_time -= min_sleep_time - residue; + if (pkt->sleep_time <= 0) { + pkt->sleep_time = 0; + atomic_inc(&pkt->run_sm); + } + } + + if (kthread_should_stop()) + break; + } +work_to_do: + set_current_state(TASK_RUNNING); + remove_wait_queue(&pd->wqueue, &wait); + + if (kthread_should_stop()) + break; + + /* + * if pkt_handle_queue returns true, we can queue + * another request. + */ + while (pkt_handle_queue(pd)) + ; + + /* + * Handle packet state machine + */ + pkt_handle_packets(pd); + + /* + * Handle iosched queues + */ + pkt_iosched_process_queue(pd); + } + + return 0; +} + +static void pkt_print_settings(struct pktcdvd_device *pd) +{ + pkt_info(pd, "%s packets, %u blocks, Mode-%c disc\n", + pd->settings.fp ? "Fixed" : "Variable", + pd->settings.size >> 2, + pd->settings.block_mode == 8 ? '1' : '2'); +} + +static int pkt_mode_sense(struct pktcdvd_device *pd, struct packet_command *cgc, int page_code, int page_control) +{ + memset(cgc->cmd, 0, sizeof(cgc->cmd)); + + cgc->cmd[0] = GPCMD_MODE_SENSE_10; + cgc->cmd[2] = page_code | (page_control << 6); + cgc->cmd[7] = cgc->buflen >> 8; + cgc->cmd[8] = cgc->buflen & 0xff; + cgc->data_direction = CGC_DATA_READ; + return pkt_generic_packet(pd, cgc); +} + +static int pkt_mode_select(struct pktcdvd_device *pd, struct packet_command *cgc) +{ + memset(cgc->cmd, 0, sizeof(cgc->cmd)); + memset(cgc->buffer, 0, 2); + cgc->cmd[0] = GPCMD_MODE_SELECT_10; + cgc->cmd[1] = 0x10; /* PF */ + cgc->cmd[7] = cgc->buflen >> 8; + cgc->cmd[8] = cgc->buflen & 0xff; + cgc->data_direction = CGC_DATA_WRITE; + return pkt_generic_packet(pd, cgc); +} + +static int pkt_get_disc_info(struct pktcdvd_device *pd, disc_information *di) +{ + struct packet_command cgc; + int ret; + + /* set up command and get the disc info */ + init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ); + cgc.cmd[0] = GPCMD_READ_DISC_INFO; + cgc.cmd[8] = cgc.buflen = 2; + cgc.quiet = 1; + + ret = pkt_generic_packet(pd, &cgc); + if (ret) + return ret; + + /* not all drives have the same disc_info length, so requeue + * packet with the length the drive tells us it can supply + */ + cgc.buflen = be16_to_cpu(di->disc_information_length) + + sizeof(di->disc_information_length); + + if (cgc.buflen > sizeof(disc_information)) + cgc.buflen = sizeof(disc_information); + + cgc.cmd[8] = cgc.buflen; + return pkt_generic_packet(pd, &cgc); +} + +static int pkt_get_track_info(struct pktcdvd_device *pd, __u16 track, __u8 type, track_information *ti) +{ + struct packet_command cgc; + int ret; + + init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ); + cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; + cgc.cmd[1] = type & 3; + cgc.cmd[4] = (track & 0xff00) >> 8; + cgc.cmd[5] = track & 0xff; + cgc.cmd[8] = 8; + cgc.quiet = 1; + + ret = pkt_generic_packet(pd, &cgc); + if (ret) + return ret; + + cgc.buflen = be16_to_cpu(ti->track_information_length) + + sizeof(ti->track_information_length); + + if (cgc.buflen > sizeof(track_information)) + cgc.buflen = sizeof(track_information); + + cgc.cmd[8] = cgc.buflen; + return pkt_generic_packet(pd, &cgc); +} + +static noinline_for_stack int pkt_get_last_written(struct pktcdvd_device *pd, + long *last_written) +{ + disc_information di; + track_information ti; + __u32 last_track; + int ret; + + ret = pkt_get_disc_info(pd, &di); + if (ret) + return ret; + + last_track = (di.last_track_msb << 8) | di.last_track_lsb; + ret = pkt_get_track_info(pd, last_track, 1, &ti); + if (ret) + return ret; + + /* if this track is blank, try the previous. */ + if (ti.blank) { + last_track--; + ret = pkt_get_track_info(pd, last_track, 1, &ti); + if (ret) + return ret; + } + + /* if last recorded field is valid, return it. */ + if (ti.lra_v) { + *last_written = be32_to_cpu(ti.last_rec_address); + } else { + /* make it up instead */ + *last_written = be32_to_cpu(ti.track_start) + + be32_to_cpu(ti.track_size); + if (ti.free_blocks) + *last_written -= (be32_to_cpu(ti.free_blocks) + 7); + } + return 0; +} + +/* + * write mode select package based on pd->settings + */ +static noinline_for_stack int pkt_set_write_settings(struct pktcdvd_device *pd) +{ + struct packet_command cgc; + struct scsi_sense_hdr sshdr; + write_param_page *wp; + char buffer[128]; + int ret, size; + + /* doesn't apply to DVD+RW or DVD-RAM */ + if ((pd->mmc3_profile == 0x1a) || (pd->mmc3_profile == 0x12)) + return 0; + + memset(buffer, 0, sizeof(buffer)); + init_cdrom_command(&cgc, buffer, sizeof(*wp), CGC_DATA_READ); + cgc.sshdr = &sshdr; + ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0); + if (ret) { + pkt_dump_sense(pd, &cgc); + return ret; + } + + size = 2 + ((buffer[0] << 8) | (buffer[1] & 0xff)); + pd->mode_offset = (buffer[6] << 8) | (buffer[7] & 0xff); + if (size > sizeof(buffer)) + size = sizeof(buffer); + + /* + * now get it all + */ + init_cdrom_command(&cgc, buffer, size, CGC_DATA_READ); + cgc.sshdr = &sshdr; + ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0); + if (ret) { + pkt_dump_sense(pd, &cgc); + return ret; + } + + /* + * write page is offset header + block descriptor length + */ + wp = (write_param_page *) &buffer[sizeof(struct mode_page_header) + pd->mode_offset]; + + wp->fp = pd->settings.fp; + wp->track_mode = pd->settings.track_mode; + wp->write_type = pd->settings.write_type; + wp->data_block_type = pd->settings.block_mode; + + wp->multi_session = 0; + +#ifdef PACKET_USE_LS + wp->link_size = 7; + wp->ls_v = 1; +#endif + + if (wp->data_block_type == PACKET_BLOCK_MODE1) { + wp->session_format = 0; + wp->subhdr2 = 0x20; + } else if (wp->data_block_type == PACKET_BLOCK_MODE2) { + wp->session_format = 0x20; + wp->subhdr2 = 8; +#if 0 + wp->mcn[0] = 0x80; + memcpy(&wp->mcn[1], PACKET_MCN, sizeof(wp->mcn) - 1); +#endif + } else { + /* + * paranoia + */ + pkt_err(pd, "write mode wrong %d\n", wp->data_block_type); + return 1; + } + wp->packet_size = cpu_to_be32(pd->settings.size >> 2); + + cgc.buflen = cgc.cmd[8] = size; + ret = pkt_mode_select(pd, &cgc); + if (ret) { + pkt_dump_sense(pd, &cgc); + return ret; + } + + pkt_print_settings(pd); + return 0; +} + +/* + * 1 -- we can write to this track, 0 -- we can't + */ +static int pkt_writable_track(struct pktcdvd_device *pd, track_information *ti) +{ + switch (pd->mmc3_profile) { + case 0x1a: /* DVD+RW */ + case 0x12: /* DVD-RAM */ + /* The track is always writable on DVD+RW/DVD-RAM */ + return 1; + default: + break; + } + + if (!ti->packet || !ti->fp) + return 0; + + /* + * "good" settings as per Mt Fuji. + */ + if (ti->rt == 0 && ti->blank == 0) + return 1; + + if (ti->rt == 0 && ti->blank == 1) + return 1; + + if (ti->rt == 1 && ti->blank == 0) + return 1; + + pkt_err(pd, "bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet); + return 0; +} + +/* + * 1 -- we can write to this disc, 0 -- we can't + */ +static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di) +{ + switch (pd->mmc3_profile) { + case 0x0a: /* CD-RW */ + case 0xffff: /* MMC3 not supported */ + break; + case 0x1a: /* DVD+RW */ + case 0x13: /* DVD-RW */ + case 0x12: /* DVD-RAM */ + return 1; + default: + pkt_dbg(2, pd, "Wrong disc profile (%x)\n", + pd->mmc3_profile); + return 0; + } + + /* + * for disc type 0xff we should probably reserve a new track. + * but i'm not sure, should we leave this to user apps? probably. + */ + if (di->disc_type == 0xff) { + pkt_notice(pd, "unknown disc - no track?\n"); + return 0; + } + + if (di->disc_type != 0x20 && di->disc_type != 0) { + pkt_err(pd, "wrong disc type (%x)\n", di->disc_type); + return 0; + } + + if (di->erasable == 0) { + pkt_notice(pd, "disc not erasable\n"); + return 0; + } + + if (di->border_status == PACKET_SESSION_RESERVED) { + pkt_err(pd, "can't write to last track (reserved)\n"); + return 0; + } + + return 1; +} + +static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd) +{ + struct packet_command cgc; + unsigned char buf[12]; + disc_information di; + track_information ti; + int ret, track; + + init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); + cgc.cmd[0] = GPCMD_GET_CONFIGURATION; + cgc.cmd[8] = 8; + ret = pkt_generic_packet(pd, &cgc); + pd->mmc3_profile = ret ? 0xffff : buf[6] << 8 | buf[7]; + + memset(&di, 0, sizeof(disc_information)); + memset(&ti, 0, sizeof(track_information)); + + ret = pkt_get_disc_info(pd, &di); + if (ret) { + pkt_err(pd, "failed get_disc\n"); + return ret; + } + + if (!pkt_writable_disc(pd, &di)) + return -EROFS; + + pd->type = di.erasable ? PACKET_CDRW : PACKET_CDR; + + track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */ + ret = pkt_get_track_info(pd, track, 1, &ti); + if (ret) { + pkt_err(pd, "failed get_track\n"); + return ret; + } + + if (!pkt_writable_track(pd, &ti)) { + pkt_err(pd, "can't write to this track\n"); + return -EROFS; + } + + /* + * we keep packet size in 512 byte units, makes it easier to + * deal with request calculations. + */ + pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2; + if (pd->settings.size == 0) { + pkt_notice(pd, "detected zero packet size!\n"); + return -ENXIO; + } + if (pd->settings.size > PACKET_MAX_SECTORS) { + pkt_err(pd, "packet size is too big\n"); + return -EROFS; + } + pd->settings.fp = ti.fp; + pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1); + + if (ti.nwa_v) { + pd->nwa = be32_to_cpu(ti.next_writable); + set_bit(PACKET_NWA_VALID, &pd->flags); + } + + /* + * in theory we could use lra on -RW media as well and just zero + * blocks that haven't been written yet, but in practice that + * is just a no-go. we'll use that for -R, naturally. + */ + if (ti.lra_v) { + pd->lra = be32_to_cpu(ti.last_rec_address); + set_bit(PACKET_LRA_VALID, &pd->flags); + } else { + pd->lra = 0xffffffff; + set_bit(PACKET_LRA_VALID, &pd->flags); + } + + /* + * fine for now + */ + pd->settings.link_loss = 7; + pd->settings.write_type = 0; /* packet */ + pd->settings.track_mode = ti.track_mode; + + /* + * mode1 or mode2 disc + */ + switch (ti.data_mode) { + case PACKET_MODE1: + pd->settings.block_mode = PACKET_BLOCK_MODE1; + break; + case PACKET_MODE2: + pd->settings.block_mode = PACKET_BLOCK_MODE2; + break; + default: + pkt_err(pd, "unknown data mode\n"); + return -EROFS; + } + return 0; +} + +/* + * enable/disable write caching on drive + */ +static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd, + int set) +{ + struct packet_command cgc; + struct scsi_sense_hdr sshdr; + unsigned char buf[64]; + int ret; + + init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); + cgc.sshdr = &sshdr; + cgc.buflen = pd->mode_offset + 12; + + /* + * caching mode page might not be there, so quiet this command + */ + cgc.quiet = 1; + + ret = pkt_mode_sense(pd, &cgc, GPMODE_WCACHING_PAGE, 0); + if (ret) + return ret; + + buf[pd->mode_offset + 10] |= (!!set << 2); + + cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff)); + ret = pkt_mode_select(pd, &cgc); + if (ret) { + pkt_err(pd, "write caching control failed\n"); + pkt_dump_sense(pd, &cgc); + } else if (!ret && set) + pkt_notice(pd, "enabled write caching\n"); + return ret; +} + +static int pkt_lock_door(struct pktcdvd_device *pd, int lockflag) +{ + struct packet_command cgc; + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; + cgc.cmd[4] = lockflag ? 1 : 0; + return pkt_generic_packet(pd, &cgc); +} + +/* + * Returns drive maximum write speed + */ +static noinline_for_stack int pkt_get_max_speed(struct pktcdvd_device *pd, + unsigned *write_speed) +{ + struct packet_command cgc; + struct scsi_sense_hdr sshdr; + unsigned char buf[256+18]; + unsigned char *cap_buf; + int ret, offset; + + cap_buf = &buf[sizeof(struct mode_page_header) + pd->mode_offset]; + init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_UNKNOWN); + cgc.sshdr = &sshdr; + + ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0); + if (ret) { + cgc.buflen = pd->mode_offset + cap_buf[1] + 2 + + sizeof(struct mode_page_header); + ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0); + if (ret) { + pkt_dump_sense(pd, &cgc); + return ret; + } + } + + offset = 20; /* Obsoleted field, used by older drives */ + if (cap_buf[1] >= 28) + offset = 28; /* Current write speed selected */ + if (cap_buf[1] >= 30) { + /* If the drive reports at least one "Logical Unit Write + * Speed Performance Descriptor Block", use the information + * in the first block. (contains the highest speed) + */ + int num_spdb = (cap_buf[30] << 8) + cap_buf[31]; + if (num_spdb > 0) + offset = 34; + } + + *write_speed = (cap_buf[offset] << 8) | cap_buf[offset + 1]; + return 0; +} + +/* These tables from cdrecord - I don't have orange book */ +/* standard speed CD-RW (1-4x) */ +static char clv_to_speed[16] = { + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ + 0, 2, 4, 6, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +/* high speed CD-RW (-10x) */ +static char hs_clv_to_speed[16] = { + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ + 0, 2, 4, 6, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +/* ultra high speed CD-RW */ +static char us_clv_to_speed[16] = { + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ + 0, 2, 4, 8, 0, 0,16, 0,24,32,40,48, 0, 0, 0, 0 +}; + +/* + * reads the maximum media speed from ATIP + */ +static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd, + unsigned *speed) +{ + struct packet_command cgc; + struct scsi_sense_hdr sshdr; + unsigned char buf[64]; + unsigned int size, st, sp; + int ret; + + init_cdrom_command(&cgc, buf, 2, CGC_DATA_READ); + cgc.sshdr = &sshdr; + cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; + cgc.cmd[1] = 2; + cgc.cmd[2] = 4; /* READ ATIP */ + cgc.cmd[8] = 2; + ret = pkt_generic_packet(pd, &cgc); + if (ret) { + pkt_dump_sense(pd, &cgc); + return ret; + } + size = ((unsigned int) buf[0]<<8) + buf[1] + 2; + if (size > sizeof(buf)) + size = sizeof(buf); + + init_cdrom_command(&cgc, buf, size, CGC_DATA_READ); + cgc.sshdr = &sshdr; + cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; + cgc.cmd[1] = 2; + cgc.cmd[2] = 4; + cgc.cmd[8] = size; + ret = pkt_generic_packet(pd, &cgc); + if (ret) { + pkt_dump_sense(pd, &cgc); + return ret; + } + + if (!(buf[6] & 0x40)) { + pkt_notice(pd, "disc type is not CD-RW\n"); + return 1; + } + if (!(buf[6] & 0x4)) { + pkt_notice(pd, "A1 values on media are not valid, maybe not CDRW?\n"); + return 1; + } + + st = (buf[6] >> 3) & 0x7; /* disc sub-type */ + + sp = buf[16] & 0xf; /* max speed from ATIP A1 field */ + + /* Info from cdrecord */ + switch (st) { + case 0: /* standard speed */ + *speed = clv_to_speed[sp]; + break; + case 1: /* high speed */ + *speed = hs_clv_to_speed[sp]; + break; + case 2: /* ultra high speed */ + *speed = us_clv_to_speed[sp]; + break; + default: + pkt_notice(pd, "unknown disc sub-type %d\n", st); + return 1; + } + if (*speed) { + pkt_info(pd, "maximum media speed: %d\n", *speed); + return 0; + } else { + pkt_notice(pd, "unknown speed %d for sub-type %d\n", sp, st); + return 1; + } +} + +static noinline_for_stack int pkt_perform_opc(struct pktcdvd_device *pd) +{ + struct packet_command cgc; + struct scsi_sense_hdr sshdr; + int ret; + + pkt_dbg(2, pd, "Performing OPC\n"); + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.sshdr = &sshdr; + cgc.timeout = 60*HZ; + cgc.cmd[0] = GPCMD_SEND_OPC; + cgc.cmd[1] = 1; + ret = pkt_generic_packet(pd, &cgc); + if (ret) + pkt_dump_sense(pd, &cgc); + return ret; +} + +static int pkt_open_write(struct pktcdvd_device *pd) +{ + int ret; + unsigned int write_speed, media_write_speed, read_speed; + + ret = pkt_probe_settings(pd); + if (ret) { + pkt_dbg(2, pd, "failed probe\n"); + return ret; + } + + ret = pkt_set_write_settings(pd); + if (ret) { + pkt_dbg(1, pd, "failed saving write settings\n"); + return -EIO; + } + + pkt_write_caching(pd, USE_WCACHING); + + ret = pkt_get_max_speed(pd, &write_speed); + if (ret) + write_speed = 16 * 177; + switch (pd->mmc3_profile) { + case 0x13: /* DVD-RW */ + case 0x1a: /* DVD+RW */ + case 0x12: /* DVD-RAM */ + pkt_dbg(1, pd, "write speed %ukB/s\n", write_speed); + break; + default: + ret = pkt_media_speed(pd, &media_write_speed); + if (ret) + media_write_speed = 16; + write_speed = min(write_speed, media_write_speed * 177); + pkt_dbg(1, pd, "write speed %ux\n", write_speed / 176); + break; + } + read_speed = write_speed; + + ret = pkt_set_speed(pd, write_speed, read_speed); + if (ret) { + pkt_dbg(1, pd, "couldn't set write speed\n"); + return -EIO; + } + pd->write_speed = write_speed; + pd->read_speed = read_speed; + + ret = pkt_perform_opc(pd); + if (ret) { + pkt_dbg(1, pd, "Optimum Power Calibration failed\n"); + } + + return 0; +} + +/* + * called at open time. + */ +static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write) +{ + int ret; + long lba; + struct request_queue *q; + struct block_device *bdev; + + /* + * We need to re-open the cdrom device without O_NONBLOCK to be able + * to read/write from/to it. It is already opened in O_NONBLOCK mode + * so open should not fail. + */ + bdev = blkdev_get_by_dev(pd->bdev->bd_dev, FMODE_READ | FMODE_EXCL, pd); + if (IS_ERR(bdev)) { + ret = PTR_ERR(bdev); + goto out; + } + + ret = pkt_get_last_written(pd, &lba); + if (ret) { + pkt_err(pd, "pkt_get_last_written failed\n"); + goto out_putdev; + } + + set_capacity(pd->disk, lba << 2); + set_capacity_and_notify(pd->bdev->bd_disk, lba << 2); + + q = bdev_get_queue(pd->bdev); + if (write) { + ret = pkt_open_write(pd); + if (ret) + goto out_putdev; + /* + * Some CDRW drives can not handle writes larger than one packet, + * even if the size is a multiple of the packet size. + */ + blk_queue_max_hw_sectors(q, pd->settings.size); + set_bit(PACKET_WRITABLE, &pd->flags); + } else { + pkt_set_speed(pd, MAX_SPEED, MAX_SPEED); + clear_bit(PACKET_WRITABLE, &pd->flags); + } + + ret = pkt_set_segment_merging(pd, q); + if (ret) + goto out_putdev; + + if (write) { + if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) { + pkt_err(pd, "not enough memory for buffers\n"); + ret = -ENOMEM; + goto out_putdev; + } + pkt_info(pd, "%lukB available on disc\n", lba << 1); + } + + return 0; + +out_putdev: + blkdev_put(bdev, FMODE_READ | FMODE_EXCL); +out: + return ret; +} + +/* + * called when the device is closed. makes sure that the device flushes + * the internal cache before we close. + */ +static void pkt_release_dev(struct pktcdvd_device *pd, int flush) +{ + if (flush && pkt_flush_cache(pd)) + pkt_dbg(1, pd, "not flushing cache\n"); + + pkt_lock_door(pd, 0); + + pkt_set_speed(pd, MAX_SPEED, MAX_SPEED); + blkdev_put(pd->bdev, FMODE_READ | FMODE_EXCL); + + pkt_shrink_pktlist(pd); +} + +static struct pktcdvd_device *pkt_find_dev_from_minor(unsigned int dev_minor) +{ + if (dev_minor >= MAX_WRITERS) + return NULL; + + dev_minor = array_index_nospec(dev_minor, MAX_WRITERS); + return pkt_devs[dev_minor]; +} + +static int pkt_open(struct block_device *bdev, fmode_t mode) +{ + struct pktcdvd_device *pd = NULL; + int ret; + + mutex_lock(&pktcdvd_mutex); + mutex_lock(&ctl_mutex); + pd = pkt_find_dev_from_minor(MINOR(bdev->bd_dev)); + if (!pd) { + ret = -ENODEV; + goto out; + } + BUG_ON(pd->refcnt < 0); + + pd->refcnt++; + if (pd->refcnt > 1) { + if ((mode & FMODE_WRITE) && + !test_bit(PACKET_WRITABLE, &pd->flags)) { + ret = -EBUSY; + goto out_dec; + } + } else { + ret = pkt_open_dev(pd, mode & FMODE_WRITE); + if (ret) + goto out_dec; + /* + * needed here as well, since ext2 (among others) may change + * the blocksize at mount time + */ + set_blocksize(bdev, CD_FRAMESIZE); + } + + mutex_unlock(&ctl_mutex); + mutex_unlock(&pktcdvd_mutex); + return 0; + +out_dec: + pd->refcnt--; +out: + mutex_unlock(&ctl_mutex); + mutex_unlock(&pktcdvd_mutex); + return ret; +} + +static void pkt_close(struct gendisk *disk, fmode_t mode) +{ + struct pktcdvd_device *pd = disk->private_data; + + mutex_lock(&pktcdvd_mutex); + mutex_lock(&ctl_mutex); + pd->refcnt--; + BUG_ON(pd->refcnt < 0); + if (pd->refcnt == 0) { + int flush = test_bit(PACKET_WRITABLE, &pd->flags); + pkt_release_dev(pd, flush); + } + mutex_unlock(&ctl_mutex); + mutex_unlock(&pktcdvd_mutex); +} + + +static void pkt_end_io_read_cloned(struct bio *bio) +{ + struct packet_stacked_data *psd = bio->bi_private; + struct pktcdvd_device *pd = psd->pd; + + psd->bio->bi_status = bio->bi_status; + bio_put(bio); + bio_endio(psd->bio); + mempool_free(psd, &psd_pool); + pkt_bio_finished(pd); +} + +static void pkt_make_request_read(struct pktcdvd_device *pd, struct bio *bio) +{ + struct bio *cloned_bio = + bio_alloc_clone(pd->bdev, bio, GFP_NOIO, &pkt_bio_set); + struct packet_stacked_data *psd = mempool_alloc(&psd_pool, GFP_NOIO); + + psd->pd = pd; + psd->bio = bio; + cloned_bio->bi_private = psd; + cloned_bio->bi_end_io = pkt_end_io_read_cloned; + pd->stats.secs_r += bio_sectors(bio); + pkt_queue_bio(pd, cloned_bio); +} + +static void pkt_make_request_write(struct request_queue *q, struct bio *bio) +{ + struct pktcdvd_device *pd = q->queuedata; + sector_t zone; + struct packet_data *pkt; + int was_empty, blocked_bio; + struct pkt_rb_node *node; + + zone = get_zone(bio->bi_iter.bi_sector, pd); + + /* + * If we find a matching packet in state WAITING or READ_WAIT, we can + * just append this bio to that packet. + */ + spin_lock(&pd->cdrw.active_list_lock); + blocked_bio = 0; + list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { + if (pkt->sector == zone) { + spin_lock(&pkt->lock); + if ((pkt->state == PACKET_WAITING_STATE) || + (pkt->state == PACKET_READ_WAIT_STATE)) { + bio_list_add(&pkt->orig_bios, bio); + pkt->write_size += + bio->bi_iter.bi_size / CD_FRAMESIZE; + if ((pkt->write_size >= pkt->frames) && + (pkt->state == PACKET_WAITING_STATE)) { + atomic_inc(&pkt->run_sm); + wake_up(&pd->wqueue); + } + spin_unlock(&pkt->lock); + spin_unlock(&pd->cdrw.active_list_lock); + return; + } else { + blocked_bio = 1; + } + spin_unlock(&pkt->lock); + } + } + spin_unlock(&pd->cdrw.active_list_lock); + + /* + * Test if there is enough room left in the bio work queue + * (queue size >= congestion on mark). + * If not, wait till the work queue size is below the congestion off mark. + */ + spin_lock(&pd->lock); + if (pd->write_congestion_on > 0 + && pd->bio_queue_size >= pd->write_congestion_on) { + struct wait_bit_queue_entry wqe; + + init_wait_var_entry(&wqe, &pd->congested, 0); + for (;;) { + prepare_to_wait_event(__var_waitqueue(&pd->congested), + &wqe.wq_entry, + TASK_UNINTERRUPTIBLE); + if (pd->bio_queue_size <= pd->write_congestion_off) + break; + pd->congested = true; + spin_unlock(&pd->lock); + schedule(); + spin_lock(&pd->lock); + } + } + spin_unlock(&pd->lock); + + /* + * No matching packet found. Store the bio in the work queue. + */ + node = mempool_alloc(&pd->rb_pool, GFP_NOIO); + node->bio = bio; + spin_lock(&pd->lock); + BUG_ON(pd->bio_queue_size < 0); + was_empty = (pd->bio_queue_size == 0); + pkt_rbtree_insert(pd, node); + spin_unlock(&pd->lock); + + /* + * Wake up the worker thread. + */ + atomic_set(&pd->scan_queue, 1); + if (was_empty) { + /* This wake_up is required for correct operation */ + wake_up(&pd->wqueue); + } else if (!list_empty(&pd->cdrw.pkt_free_list) && !blocked_bio) { + /* + * This wake up is not required for correct operation, + * but improves performance in some cases. + */ + wake_up(&pd->wqueue); + } +} + +static void pkt_submit_bio(struct bio *bio) +{ + struct pktcdvd_device *pd = bio->bi_bdev->bd_disk->queue->queuedata; + struct bio *split; + + bio = bio_split_to_limits(bio); + if (!bio) + return; + + pkt_dbg(2, pd, "start = %6llx stop = %6llx\n", + (unsigned long long)bio->bi_iter.bi_sector, + (unsigned long long)bio_end_sector(bio)); + + /* + * Clone READ bios so we can have our own bi_end_io callback. + */ + if (bio_data_dir(bio) == READ) { + pkt_make_request_read(pd, bio); + return; + } + + if (!test_bit(PACKET_WRITABLE, &pd->flags)) { + pkt_notice(pd, "WRITE for ro device (%llu)\n", + (unsigned long long)bio->bi_iter.bi_sector); + goto end_io; + } + + if (!bio->bi_iter.bi_size || (bio->bi_iter.bi_size % CD_FRAMESIZE)) { + pkt_err(pd, "wrong bio size\n"); + goto end_io; + } + + do { + sector_t zone = get_zone(bio->bi_iter.bi_sector, pd); + sector_t last_zone = get_zone(bio_end_sector(bio) - 1, pd); + + if (last_zone != zone) { + BUG_ON(last_zone != zone + pd->settings.size); + + split = bio_split(bio, last_zone - + bio->bi_iter.bi_sector, + GFP_NOIO, &pkt_bio_set); + bio_chain(split, bio); + } else { + split = bio; + } + + pkt_make_request_write(bio->bi_bdev->bd_disk->queue, split); + } while (split != bio); + + return; +end_io: + bio_io_error(bio); +} + +static void pkt_init_queue(struct pktcdvd_device *pd) +{ + struct request_queue *q = pd->disk->queue; + + blk_queue_logical_block_size(q, CD_FRAMESIZE); + blk_queue_max_hw_sectors(q, PACKET_MAX_SECTORS); + q->queuedata = pd; +} + +static int pkt_seq_show(struct seq_file *m, void *p) +{ + struct pktcdvd_device *pd = m->private; + char *msg; + int states[PACKET_NUM_STATES]; + + seq_printf(m, "Writer %s mapped to %pg:\n", pd->name, pd->bdev); + + seq_printf(m, "\nSettings:\n"); + seq_printf(m, "\tpacket size:\t\t%dkB\n", pd->settings.size / 2); + + if (pd->settings.write_type == 0) + msg = "Packet"; + else + msg = "Unknown"; + seq_printf(m, "\twrite type:\t\t%s\n", msg); + + seq_printf(m, "\tpacket type:\t\t%s\n", pd->settings.fp ? "Fixed" : "Variable"); + seq_printf(m, "\tlink loss:\t\t%d\n", pd->settings.link_loss); + + seq_printf(m, "\ttrack mode:\t\t%d\n", pd->settings.track_mode); + + if (pd->settings.block_mode == PACKET_BLOCK_MODE1) + msg = "Mode 1"; + else if (pd->settings.block_mode == PACKET_BLOCK_MODE2) + msg = "Mode 2"; + else + msg = "Unknown"; + seq_printf(m, "\tblock mode:\t\t%s\n", msg); + + seq_printf(m, "\nStatistics:\n"); + seq_printf(m, "\tpackets started:\t%lu\n", pd->stats.pkt_started); + seq_printf(m, "\tpackets ended:\t\t%lu\n", pd->stats.pkt_ended); + seq_printf(m, "\twritten:\t\t%lukB\n", pd->stats.secs_w >> 1); + seq_printf(m, "\tread gather:\t\t%lukB\n", pd->stats.secs_rg >> 1); + seq_printf(m, "\tread:\t\t\t%lukB\n", pd->stats.secs_r >> 1); + + seq_printf(m, "\nMisc:\n"); + seq_printf(m, "\treference count:\t%d\n", pd->refcnt); + seq_printf(m, "\tflags:\t\t\t0x%lx\n", pd->flags); + seq_printf(m, "\tread speed:\t\t%ukB/s\n", pd->read_speed); + seq_printf(m, "\twrite speed:\t\t%ukB/s\n", pd->write_speed); + seq_printf(m, "\tstart offset:\t\t%lu\n", pd->offset); + seq_printf(m, "\tmode page offset:\t%u\n", pd->mode_offset); + + seq_printf(m, "\nQueue state:\n"); + seq_printf(m, "\tbios queued:\t\t%d\n", pd->bio_queue_size); + seq_printf(m, "\tbios pending:\t\t%d\n", atomic_read(&pd->cdrw.pending_bios)); + seq_printf(m, "\tcurrent sector:\t\t0x%llx\n", (unsigned long long)pd->current_sector); + + pkt_count_states(pd, states); + seq_printf(m, "\tstate:\t\t\ti:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n", + states[0], states[1], states[2], states[3], states[4], states[5]); + + seq_printf(m, "\twrite congestion marks:\toff=%d on=%d\n", + pd->write_congestion_off, + pd->write_congestion_on); + return 0; +} + +static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) +{ + int i; + struct block_device *bdev; + struct scsi_device *sdev; + + if (pd->pkt_dev == dev) { + pkt_err(pd, "recursive setup not allowed\n"); + return -EBUSY; + } + for (i = 0; i < MAX_WRITERS; i++) { + struct pktcdvd_device *pd2 = pkt_devs[i]; + if (!pd2) + continue; + if (pd2->bdev->bd_dev == dev) { + pkt_err(pd, "%pg already setup\n", pd2->bdev); + return -EBUSY; + } + if (pd2->pkt_dev == dev) { + pkt_err(pd, "can't chain pktcdvd devices\n"); + return -EBUSY; + } + } + + bdev = blkdev_get_by_dev(dev, FMODE_READ | FMODE_NDELAY, NULL); + if (IS_ERR(bdev)) + return PTR_ERR(bdev); + sdev = scsi_device_from_queue(bdev->bd_disk->queue); + if (!sdev) { + blkdev_put(bdev, FMODE_READ | FMODE_NDELAY); + return -EINVAL; + } + put_device(&sdev->sdev_gendev); + + /* This is safe, since we have a reference from open(). */ + __module_get(THIS_MODULE); + + pd->bdev = bdev; + set_blocksize(bdev, CD_FRAMESIZE); + + pkt_init_queue(pd); + + atomic_set(&pd->cdrw.pending_bios, 0); + pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name); + if (IS_ERR(pd->cdrw.thread)) { + pkt_err(pd, "can't start kernel thread\n"); + goto out_mem; + } + + proc_create_single_data(pd->name, 0, pkt_proc, pkt_seq_show, pd); + pkt_dbg(1, pd, "writer mapped to %pg\n", bdev); + return 0; + +out_mem: + blkdev_put(bdev, FMODE_READ | FMODE_NDELAY); + /* This is safe: open() is still holding a reference. */ + module_put(THIS_MODULE); + return -ENOMEM; +} + +static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) +{ + struct pktcdvd_device *pd = bdev->bd_disk->private_data; + int ret; + + pkt_dbg(2, pd, "cmd %x, dev %d:%d\n", + cmd, MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev)); + + mutex_lock(&pktcdvd_mutex); + switch (cmd) { + case CDROMEJECT: + /* + * The door gets locked when the device is opened, so we + * have to unlock it or else the eject command fails. + */ + if (pd->refcnt == 1) + pkt_lock_door(pd, 0); + fallthrough; + /* + * forward selected CDROM ioctls to CD-ROM, for UDF + */ + case CDROMMULTISESSION: + case CDROMREADTOCENTRY: + case CDROM_LAST_WRITTEN: + case CDROM_SEND_PACKET: + case SCSI_IOCTL_SEND_COMMAND: + if (!bdev->bd_disk->fops->ioctl) + ret = -ENOTTY; + else + ret = bdev->bd_disk->fops->ioctl(bdev, mode, cmd, arg); + break; + default: + pkt_dbg(2, pd, "Unknown ioctl (%x)\n", cmd); + ret = -ENOTTY; + } + mutex_unlock(&pktcdvd_mutex); + + return ret; +} + +static unsigned int pkt_check_events(struct gendisk *disk, + unsigned int clearing) +{ + struct pktcdvd_device *pd = disk->private_data; + struct gendisk *attached_disk; + + if (!pd) + return 0; + if (!pd->bdev) + return 0; + attached_disk = pd->bdev->bd_disk; + if (!attached_disk || !attached_disk->fops->check_events) + return 0; + return attached_disk->fops->check_events(attached_disk, clearing); +} + +static char *pkt_devnode(struct gendisk *disk, umode_t *mode) +{ + return kasprintf(GFP_KERNEL, "pktcdvd/%s", disk->disk_name); +} + +static const struct block_device_operations pktcdvd_ops = { + .owner = THIS_MODULE, + .submit_bio = pkt_submit_bio, + .open = pkt_open, + .release = pkt_close, + .ioctl = pkt_ioctl, + .compat_ioctl = blkdev_compat_ptr_ioctl, + .check_events = pkt_check_events, + .devnode = pkt_devnode, +}; + +/* + * Set up mapping from pktcdvd device to CD-ROM device. + */ +static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) +{ + int idx; + int ret = -ENOMEM; + struct pktcdvd_device *pd; + struct gendisk *disk; + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + + for (idx = 0; idx < MAX_WRITERS; idx++) + if (!pkt_devs[idx]) + break; + if (idx == MAX_WRITERS) { + pr_err("max %d writers supported\n", MAX_WRITERS); + ret = -EBUSY; + goto out_mutex; + } + + pd = kzalloc(sizeof(struct pktcdvd_device), GFP_KERNEL); + if (!pd) + goto out_mutex; + + ret = mempool_init_kmalloc_pool(&pd->rb_pool, PKT_RB_POOL_SIZE, + sizeof(struct pkt_rb_node)); + if (ret) + goto out_mem; + + INIT_LIST_HEAD(&pd->cdrw.pkt_free_list); + INIT_LIST_HEAD(&pd->cdrw.pkt_active_list); + spin_lock_init(&pd->cdrw.active_list_lock); + + spin_lock_init(&pd->lock); + spin_lock_init(&pd->iosched.lock); + bio_list_init(&pd->iosched.read_queue); + bio_list_init(&pd->iosched.write_queue); + sprintf(pd->name, DRIVER_NAME"%d", idx); + init_waitqueue_head(&pd->wqueue); + pd->bio_queue = RB_ROOT; + + pd->write_congestion_on = write_congestion_on; + pd->write_congestion_off = write_congestion_off; + + ret = -ENOMEM; + disk = blk_alloc_disk(NUMA_NO_NODE); + if (!disk) + goto out_mem; + pd->disk = disk; + disk->major = pktdev_major; + disk->first_minor = idx; + disk->minors = 1; + disk->fops = &pktcdvd_ops; + disk->flags = GENHD_FL_REMOVABLE | GENHD_FL_NO_PART; + strcpy(disk->disk_name, pd->name); + disk->private_data = pd; + + pd->pkt_dev = MKDEV(pktdev_major, idx); + ret = pkt_new_dev(pd, dev); + if (ret) + goto out_mem2; + + /* inherit events of the host device */ + disk->events = pd->bdev->bd_disk->events; + + ret = add_disk(disk); + if (ret) + goto out_mem2; + + pkt_sysfs_dev_new(pd); + pkt_debugfs_dev_new(pd); + + pkt_devs[idx] = pd; + if (pkt_dev) + *pkt_dev = pd->pkt_dev; + + mutex_unlock(&ctl_mutex); + return 0; + +out_mem2: + put_disk(disk); +out_mem: + mempool_exit(&pd->rb_pool); + kfree(pd); +out_mutex: + mutex_unlock(&ctl_mutex); + pr_err("setup of pktcdvd device failed\n"); + return ret; +} + +/* + * Tear down mapping from pktcdvd device to CD-ROM device. + */ +static int pkt_remove_dev(dev_t pkt_dev) +{ + struct pktcdvd_device *pd; + int idx; + int ret = 0; + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + + for (idx = 0; idx < MAX_WRITERS; idx++) { + pd = pkt_devs[idx]; + if (pd && (pd->pkt_dev == pkt_dev)) + break; + } + if (idx == MAX_WRITERS) { + pr_debug("dev not setup\n"); + ret = -ENXIO; + goto out; + } + + if (pd->refcnt > 0) { + ret = -EBUSY; + goto out; + } + if (!IS_ERR(pd->cdrw.thread)) + kthread_stop(pd->cdrw.thread); + + pkt_devs[idx] = NULL; + + pkt_debugfs_dev_remove(pd); + pkt_sysfs_dev_remove(pd); + + blkdev_put(pd->bdev, FMODE_READ | FMODE_NDELAY); + + remove_proc_entry(pd->name, pkt_proc); + pkt_dbg(1, pd, "writer unmapped\n"); + + del_gendisk(pd->disk); + put_disk(pd->disk); + + mempool_exit(&pd->rb_pool); + kfree(pd); + + /* This is safe: open() is still holding a reference. */ + module_put(THIS_MODULE); + +out: + mutex_unlock(&ctl_mutex); + return ret; +} + +static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd) +{ + struct pktcdvd_device *pd; + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + + pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index); + if (pd) { + ctrl_cmd->dev = new_encode_dev(pd->bdev->bd_dev); + ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev); + } else { + ctrl_cmd->dev = 0; + ctrl_cmd->pkt_dev = 0; + } + ctrl_cmd->num_devices = MAX_WRITERS; + + mutex_unlock(&ctl_mutex); +} + +static long pkt_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct pkt_ctrl_command ctrl_cmd; + int ret = 0; + dev_t pkt_dev = 0; + + if (cmd != PACKET_CTRL_CMD) + return -ENOTTY; + + if (copy_from_user(&ctrl_cmd, argp, sizeof(struct pkt_ctrl_command))) + return -EFAULT; + + switch (ctrl_cmd.command) { + case PKT_CTRL_CMD_SETUP: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + ret = pkt_setup_dev(new_decode_dev(ctrl_cmd.dev), &pkt_dev); + ctrl_cmd.pkt_dev = new_encode_dev(pkt_dev); + break; + case PKT_CTRL_CMD_TEARDOWN: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + ret = pkt_remove_dev(new_decode_dev(ctrl_cmd.pkt_dev)); + break; + case PKT_CTRL_CMD_STATUS: + pkt_get_status(&ctrl_cmd); + break; + default: + return -ENOTTY; + } + + if (copy_to_user(argp, &ctrl_cmd, sizeof(struct pkt_ctrl_command))) + return -EFAULT; + return ret; +} + +#ifdef CONFIG_COMPAT +static long pkt_ctl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return pkt_ctl_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + +static const struct file_operations pkt_ctl_fops = { + .open = nonseekable_open, + .unlocked_ioctl = pkt_ctl_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = pkt_ctl_compat_ioctl, +#endif + .owner = THIS_MODULE, + .llseek = no_llseek, +}; + +static struct miscdevice pkt_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = DRIVER_NAME, + .nodename = "pktcdvd/control", + .fops = &pkt_ctl_fops +}; + +static int __init pkt_init(void) +{ + int ret; + + mutex_init(&ctl_mutex); + + ret = mempool_init_kmalloc_pool(&psd_pool, PSD_POOL_SIZE, + sizeof(struct packet_stacked_data)); + if (ret) + return ret; + ret = bioset_init(&pkt_bio_set, BIO_POOL_SIZE, 0, 0); + if (ret) { + mempool_exit(&psd_pool); + return ret; + } + + ret = register_blkdev(pktdev_major, DRIVER_NAME); + if (ret < 0) { + pr_err("unable to register block device\n"); + goto out2; + } + if (!pktdev_major) + pktdev_major = ret; + + ret = pkt_sysfs_init(); + if (ret) + goto out; + + pkt_debugfs_init(); + + ret = misc_register(&pkt_misc); + if (ret) { + pr_err("unable to register misc device\n"); + goto out_misc; + } + + pkt_proc = proc_mkdir("driver/"DRIVER_NAME, NULL); + + return 0; + +out_misc: + pkt_debugfs_cleanup(); + pkt_sysfs_cleanup(); +out: + unregister_blkdev(pktdev_major, DRIVER_NAME); +out2: + mempool_exit(&psd_pool); + bioset_exit(&pkt_bio_set); + return ret; +} + +static void __exit pkt_exit(void) +{ + remove_proc_entry("driver/"DRIVER_NAME, NULL); + misc_deregister(&pkt_misc); + + pkt_debugfs_cleanup(); + pkt_sysfs_cleanup(); + + unregister_blkdev(pktdev_major, DRIVER_NAME); + mempool_exit(&psd_pool); + bioset_exit(&pkt_bio_set); +} + +MODULE_DESCRIPTION("Packet writing layer for CD/DVD drives"); +MODULE_AUTHOR("Jens Axboe <axboe@suse.de>"); +MODULE_LICENSE("GPL"); + +module_init(pkt_init); +module_exit(pkt_exit); diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index c76e0148eada..38d42af01b25 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -586,8 +586,6 @@ static void ps3vram_submit_bio(struct bio *bio) dev_dbg(&dev->core, "%s\n", __func__); - bio = bio_split_to_limits(bio); - spin_lock_irq(&priv->lock); busy = !bio_list_empty(&priv->list); bio_list_add(&priv->list, bio); @@ -747,9 +745,6 @@ static int ps3vram_probe(struct ps3_system_bus_device *dev) gendisk->private_data = dev; strscpy(gendisk->disk_name, DEVICE_NAME, sizeof(gendisk->disk_name)); set_capacity(gendisk, priv->size >> 9); - blk_queue_max_segments(gendisk->queue, BLK_MAX_SEGMENTS); - blk_queue_max_segment_size(gendisk->queue, BLK_MAX_SEGMENT_SIZE); - blk_queue_max_hw_sectors(gendisk->queue, BLK_SAFE_MAX_SECTORS); dev_info(&dev->core, "%s: Using %llu MiB of GPU memory\n", gendisk->disk_name, get_capacity(gendisk) >> 11); diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 04453f4a319c..1faca7e07a4d 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3068,13 +3068,12 @@ static int setup_copyup_bvecs(struct rbd_obj_request *obj_req, u64 obj_overlap) for (i = 0; i < obj_req->copyup_bvec_count; i++) { unsigned int len = min(obj_overlap, (u64)PAGE_SIZE); + struct page *page = alloc_page(GFP_NOIO); - obj_req->copyup_bvecs[i].bv_page = alloc_page(GFP_NOIO); - if (!obj_req->copyup_bvecs[i].bv_page) + if (!page) return -ENOMEM; - obj_req->copyup_bvecs[i].bv_offset = 0; - obj_req->copyup_bvecs[i].bv_len = len; + bvec_set_page(&obj_req->copyup_bvecs[i], page, len, 0); obj_overlap -= len; } diff --git a/drivers/block/rnbd/rnbd-clt.c b/drivers/block/rnbd/rnbd-clt.c index 78334da74d8b..5eb8c7855970 100644 --- a/drivers/block/rnbd/rnbd-clt.c +++ b/drivers/block/rnbd/rnbd-clt.c @@ -1440,7 +1440,7 @@ static struct rnbd_clt_dev *init_dev(struct rnbd_clt_session *sess, goto out_alloc; } - ret = ida_alloc_max(&index_ida, 1 << (MINORBITS - RNBD_PART_BITS), + ret = ida_alloc_max(&index_ida, (1 << (MINORBITS - RNBD_PART_BITS)) - 1, GFP_KERNEL); if (ret < 0) { pr_err("Failed to initialize device '%s' from session %s, allocating idr failed, err: %d\n", diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index e9de9d846b73..b9c759cef00e 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -42,6 +42,7 @@ #include <linux/mm.h> #include <asm/page.h> #include <linux/task_work.h> +#include <linux/namei.h> #include <uapi/linux/ublk_cmd.h> #define UBLK_MINORS (1U << MINORBITS) @@ -51,10 +52,12 @@ | UBLK_F_URING_CMD_COMP_IN_TASK \ | UBLK_F_NEED_GET_DATA \ | UBLK_F_USER_RECOVERY \ - | UBLK_F_USER_RECOVERY_REISSUE) + | UBLK_F_USER_RECOVERY_REISSUE \ + | UBLK_F_UNPRIVILEGED_DEV) /* All UBLK_PARAM_TYPE_* should be included here */ -#define UBLK_PARAM_TYPE_ALL (UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DISCARD) +#define UBLK_PARAM_TYPE_ALL (UBLK_PARAM_TYPE_BASIC | \ + UBLK_PARAM_TYPE_DISCARD | UBLK_PARAM_TYPE_DEVT) struct ublk_rq_data { struct llist_node node; @@ -137,7 +140,7 @@ struct ublk_device { char *__queues; - unsigned short queue_size; + unsigned int queue_size; struct ublksrv_ctrl_dev_info dev_info; struct blk_mq_tag_set tag_set; @@ -147,6 +150,7 @@ struct ublk_device { #define UB_STATE_OPEN 0 #define UB_STATE_USED 1 +#define UB_STATE_DELETED 2 unsigned long state; int ub_number; @@ -159,7 +163,7 @@ struct ublk_device { struct completion completion; unsigned int nr_queues_ready; - atomic_t nr_aborted_queues; + unsigned int nr_privileged_daemon; /* * Our ubq->daemon may be killed without any notification, so @@ -185,6 +189,15 @@ static wait_queue_head_t ublk_idr_wq; /* wait until one idr is freed */ static DEFINE_MUTEX(ublk_ctl_mutex); +/* + * Max ublk devices allowed to add + * + * It can be extended to one per-user limit in future or even controlled + * by cgroup. + */ +static unsigned int ublks_max = 64; +static unsigned int ublks_added; /* protected by ublk_ctl_mutex */ + static struct miscdevice ublk_misc; static void ublk_dev_param_basic_apply(struct ublk_device *ub) @@ -255,6 +268,10 @@ static int ublk_validate_params(const struct ublk_device *ub) return -EINVAL; } + /* dev_t is read-only */ + if (ub->params.types & UBLK_PARAM_TYPE_DEVT) + return -EINVAL; + return 0; } @@ -306,7 +323,7 @@ static inline struct ublk_queue *ublk_get_queue(struct ublk_device *dev, static inline bool ublk_rq_has_data(const struct request *rq) { - return rq->bio && bio_has_data(rq->bio); + return bio_has_data(rq->bio); } static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq, @@ -361,8 +378,50 @@ static void ublk_free_disk(struct gendisk *disk) put_device(&ub->cdev_dev); } +static void ublk_store_owner_uid_gid(unsigned int *owner_uid, + unsigned int *owner_gid) +{ + kuid_t uid; + kgid_t gid; + + current_uid_gid(&uid, &gid); + + *owner_uid = from_kuid(&init_user_ns, uid); + *owner_gid = from_kgid(&init_user_ns, gid); +} + +static int ublk_open(struct block_device *bdev, fmode_t mode) +{ + struct ublk_device *ub = bdev->bd_disk->private_data; + + if (capable(CAP_SYS_ADMIN)) + return 0; + + /* + * If it is one unprivileged device, only owner can open + * the disk. Otherwise it could be one trap made by one + * evil user who grants this disk's privileges to other + * users deliberately. + * + * This way is reasonable too given anyone can create + * unprivileged device, and no need other's grant. + */ + if (ub->dev_info.flags & UBLK_F_UNPRIVILEGED_DEV) { + unsigned int curr_uid, curr_gid; + + ublk_store_owner_uid_gid(&curr_uid, &curr_gid); + + if (curr_uid != ub->dev_info.owner_uid || curr_gid != + ub->dev_info.owner_gid) + return -EPERM; + } + + return 0; +} + static const struct block_device_operations ub_fops = { .owner = THIS_MODULE, + .open = ublk_open, .free_disk = ublk_free_disk, }; @@ -607,7 +666,7 @@ static void ublk_complete_rq(struct request *req) } /* - * FLUSH or DISCARD usually won't return bytes returned, so end them + * FLUSH, DISCARD or WRITE_ZEROES usually won't return bytes returned, so end them * directly. * * Both the two needn't unmap. @@ -1179,6 +1238,9 @@ static void ublk_mark_io_ready(struct ublk_device *ub, struct ublk_queue *ubq) ubq->ubq_daemon = current; get_task_struct(ubq->ubq_daemon); ub->nr_queues_ready++; + + if (capable(CAP_SYS_ADMIN)) + ub->nr_privileged_daemon++; } if (ub->nr_queues_ready == ub->dev_info.nr_hw_queues) complete_all(&ub->completion); @@ -1203,6 +1265,7 @@ static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) u32 cmd_op = cmd->cmd_op; unsigned tag = ub_cmd->tag; int ret = -EINVAL; + struct request *req; pr_devel("%s: received: cmd op %d queue %d tag %d result %d\n", __func__, cmd->cmd_op, ub_cmd->q_id, tag, @@ -1253,8 +1316,8 @@ static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) */ if (io->flags & UBLK_IO_FLAG_OWNED_BY_SRV) goto out; - /* FETCH_RQ has to provide IO buffer */ - if (!ub_cmd->addr) + /* FETCH_RQ has to provide IO buffer if NEED GET DATA is not enabled */ + if (!ub_cmd->addr && !ublk_need_get_data(ubq)) goto out; io->cmd = cmd; io->flags |= UBLK_IO_FLAG_ACTIVE; @@ -1263,8 +1326,12 @@ static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) ublk_mark_io_ready(ub, ubq); break; case UBLK_IO_COMMIT_AND_FETCH_REQ: - /* FETCH_RQ has to provide IO buffer */ - if (!ub_cmd->addr) + req = blk_mq_tag_to_rq(ub->tag_set.tags[ub_cmd->q_id], tag); + /* + * COMMIT_AND_FETCH_REQ has to provide IO buffer if NEED GET DATA is + * not enabled or it is Read IO. + */ + if (!ub_cmd->addr && (!ublk_need_get_data(ubq) || req_op(req) == REQ_OP_READ)) goto out; if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV)) goto out; @@ -1433,6 +1500,8 @@ static int ublk_add_chdev(struct ublk_device *ub) ret = cdev_device_add(&ub->cdev, dev); if (ret) goto fail; + + ublks_added++; return 0; fail: put_device(dev); @@ -1475,6 +1544,7 @@ static void ublk_remove(struct ublk_device *ub) cancel_work_sync(&ub->quiesce_work); cdev_device_del(&ub->cdev, &ub->cdev_dev); put_device(&ub->cdev_dev); + ublks_added--; } static struct ublk_device *ublk_get_device_from_id(int idx) @@ -1493,21 +1563,16 @@ static struct ublk_device *ublk_get_device_from_id(int idx) return ub; } -static int ublk_ctrl_start_dev(struct io_uring_cmd *cmd) +static int ublk_ctrl_start_dev(struct ublk_device *ub, struct io_uring_cmd *cmd) { struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; int ublksrv_pid = (int)header->data[0]; - struct ublk_device *ub; struct gendisk *disk; int ret = -EINVAL; if (ublksrv_pid <= 0) return -EINVAL; - ub = ublk_get_device_from_id(header->dev_id); - if (!ub) - return -EINVAL; - wait_for_completion_interruptible(&ub->completion); schedule_delayed_work(&ub->monitor_work, UBLK_DAEMON_MONITOR_PERIOD); @@ -1519,7 +1584,7 @@ static int ublk_ctrl_start_dev(struct io_uring_cmd *cmd) goto out_unlock; } - disk = blk_mq_alloc_disk(&ub->tag_set, ub); + disk = blk_mq_alloc_disk(&ub->tag_set, NULL); if (IS_ERR(disk)) { ret = PTR_ERR(disk); goto out_unlock; @@ -1535,6 +1600,10 @@ static int ublk_ctrl_start_dev(struct io_uring_cmd *cmd) if (ret) goto out_put_disk; + /* don't probe partitions if any one ubq daemon is un-trusted */ + if (ub->nr_privileged_daemon != ub->nr_queues_ready) + set_bit(GD_SUPPRESS_PART_SCAN, &disk->state); + get_device(&ub->cdev_dev); ret = add_disk(disk); if (ret) { @@ -1552,21 +1621,20 @@ out_put_disk: put_disk(disk); out_unlock: mutex_unlock(&ub->mutex); - ublk_put_device(ub); return ret; } -static int ublk_ctrl_get_queue_affinity(struct io_uring_cmd *cmd) +static int ublk_ctrl_get_queue_affinity(struct ublk_device *ub, + struct io_uring_cmd *cmd) { struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; void __user *argp = (void __user *)(unsigned long)header->addr; - struct ublk_device *ub; cpumask_var_t cpumask; unsigned long queue; unsigned int retlen; unsigned int i; - int ret = -EINVAL; - + int ret; + if (header->len * BITS_PER_BYTE < nr_cpu_ids) return -EINVAL; if (header->len & (sizeof(unsigned long)-1)) @@ -1574,17 +1642,12 @@ static int ublk_ctrl_get_queue_affinity(struct io_uring_cmd *cmd) if (!header->addr) return -EINVAL; - ub = ublk_get_device_from_id(header->dev_id); - if (!ub) - return -EINVAL; - queue = header->data[0]; if (queue >= ub->dev_info.nr_hw_queues) - goto out_put_device; + return -EINVAL; - ret = -ENOMEM; if (!zalloc_cpumask_var(&cpumask, GFP_KERNEL)) - goto out_put_device; + return -ENOMEM; for_each_possible_cpu(i) { if (ub->tag_set.map[HCTX_TYPE_DEFAULT].mq_map[i] == queue) @@ -1602,8 +1665,6 @@ static int ublk_ctrl_get_queue_affinity(struct io_uring_cmd *cmd) ret = 0; out_free_cpumask: free_cpumask_var(cpumask); -out_put_device: - ublk_put_device(ub); return ret; } @@ -1630,19 +1691,34 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd) __func__, header->queue_id); return -EINVAL; } + if (copy_from_user(&info, argp, sizeof(info))) return -EFAULT; - ublk_dump_dev_info(&info); + + if (capable(CAP_SYS_ADMIN)) + info.flags &= ~UBLK_F_UNPRIVILEGED_DEV; + else if (!(info.flags & UBLK_F_UNPRIVILEGED_DEV)) + return -EPERM; + + /* the created device is always owned by current user */ + ublk_store_owner_uid_gid(&info.owner_uid, &info.owner_gid); + if (header->dev_id != info.dev_id) { pr_warn("%s: dev id not match %u %u\n", __func__, header->dev_id, info.dev_id); return -EINVAL; } + ublk_dump_dev_info(&info); + ret = mutex_lock_killable(&ublk_ctl_mutex); if (ret) return ret; + ret = -EACCES; + if (ublks_added >= ublks_max) + goto out_unlock; + ret = -ENOMEM; ub = kzalloc(sizeof(*ub), GFP_KERNEL); if (!ub) @@ -1724,33 +1800,43 @@ static inline bool ublk_idr_freed(int id) return ptr == NULL; } -static int ublk_ctrl_del_dev(int idx) +static int ublk_ctrl_del_dev(struct ublk_device **p_ub) { - struct ublk_device *ub; + struct ublk_device *ub = *p_ub; + int idx = ub->ub_number; int ret; ret = mutex_lock_killable(&ublk_ctl_mutex); if (ret) return ret; - ub = ublk_get_device_from_id(idx); - if (ub) { + if (!test_bit(UB_STATE_DELETED, &ub->state)) { ublk_remove(ub); - ublk_put_device(ub); - ret = 0; - } else { - ret = -ENODEV; + set_bit(UB_STATE_DELETED, &ub->state); } + /* Mark the reference as consumed */ + *p_ub = NULL; + ublk_put_device(ub); + mutex_unlock(&ublk_ctl_mutex); + /* * Wait until the idr is removed, then it can be reused after * DEL_DEV command is returned. + * + * If we returns because of user interrupt, future delete command + * may come: + * + * - the device number isn't freed, this device won't or needn't + * be deleted again, since UB_STATE_DELETED is set, and device + * will be released after the last reference is dropped + * + * - the device number is freed already, we will not find this + * device via ublk_get_device_from_id() */ - if (!ret) - wait_event(ublk_idr_wq, ublk_idr_freed(idx)); - mutex_unlock(&ublk_ctl_mutex); + wait_event_interruptible(ublk_idr_wq, ublk_idr_freed(idx)); - return ret; + return 0; } static inline void ublk_ctrl_cmd_dump(struct io_uring_cmd *cmd) @@ -1762,50 +1848,52 @@ static inline void ublk_ctrl_cmd_dump(struct io_uring_cmd *cmd) header->data[0], header->addr, header->len); } -static int ublk_ctrl_stop_dev(struct io_uring_cmd *cmd) +static int ublk_ctrl_stop_dev(struct ublk_device *ub) { - struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; - struct ublk_device *ub; - - ub = ublk_get_device_from_id(header->dev_id); - if (!ub) - return -EINVAL; - ublk_stop_dev(ub); cancel_work_sync(&ub->stop_work); cancel_work_sync(&ub->quiesce_work); - ublk_put_device(ub); return 0; } -static int ublk_ctrl_get_dev_info(struct io_uring_cmd *cmd) +static int ublk_ctrl_get_dev_info(struct ublk_device *ub, + struct io_uring_cmd *cmd) { struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; void __user *argp = (void __user *)(unsigned long)header->addr; - struct ublk_device *ub; - int ret = 0; if (header->len < sizeof(struct ublksrv_ctrl_dev_info) || !header->addr) return -EINVAL; - ub = ublk_get_device_from_id(header->dev_id); - if (!ub) - return -EINVAL; - if (copy_to_user(argp, &ub->dev_info, sizeof(ub->dev_info))) - ret = -EFAULT; - ublk_put_device(ub); + return -EFAULT; - return ret; + return 0; +} + +/* TYPE_DEVT is readonly, so fill it up before returning to userspace */ +static void ublk_ctrl_fill_params_devt(struct ublk_device *ub) +{ + ub->params.devt.char_major = MAJOR(ub->cdev_dev.devt); + ub->params.devt.char_minor = MINOR(ub->cdev_dev.devt); + + if (ub->ub_disk) { + ub->params.devt.disk_major = MAJOR(disk_devt(ub->ub_disk)); + ub->params.devt.disk_minor = MINOR(disk_devt(ub->ub_disk)); + } else { + ub->params.devt.disk_major = 0; + ub->params.devt.disk_minor = 0; + } + ub->params.types |= UBLK_PARAM_TYPE_DEVT; } -static int ublk_ctrl_get_params(struct io_uring_cmd *cmd) +static int ublk_ctrl_get_params(struct ublk_device *ub, + struct io_uring_cmd *cmd) { struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; void __user *argp = (void __user *)(unsigned long)header->addr; struct ublk_params_header ph; - struct ublk_device *ub; int ret; if (header->len <= sizeof(ph) || !header->addr) @@ -1820,27 +1908,23 @@ static int ublk_ctrl_get_params(struct io_uring_cmd *cmd) if (ph.len > sizeof(struct ublk_params)) ph.len = sizeof(struct ublk_params); - ub = ublk_get_device_from_id(header->dev_id); - if (!ub) - return -EINVAL; - mutex_lock(&ub->mutex); + ublk_ctrl_fill_params_devt(ub); if (copy_to_user(argp, &ub->params, ph.len)) ret = -EFAULT; else ret = 0; mutex_unlock(&ub->mutex); - ublk_put_device(ub); return ret; } -static int ublk_ctrl_set_params(struct io_uring_cmd *cmd) +static int ublk_ctrl_set_params(struct ublk_device *ub, + struct io_uring_cmd *cmd) { struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; void __user *argp = (void __user *)(unsigned long)header->addr; struct ublk_params_header ph; - struct ublk_device *ub; int ret = -EFAULT; if (header->len <= sizeof(ph) || !header->addr) @@ -1855,10 +1939,6 @@ static int ublk_ctrl_set_params(struct io_uring_cmd *cmd) if (ph.len > sizeof(struct ublk_params)) ph.len = sizeof(struct ublk_params); - ub = ublk_get_device_from_id(header->dev_id); - if (!ub) - return -EINVAL; - /* parameters can only be changed when device isn't live */ mutex_lock(&ub->mutex); if (ub->dev_info.state == UBLK_S_DEV_LIVE) { @@ -1871,7 +1951,6 @@ static int ublk_ctrl_set_params(struct io_uring_cmd *cmd) ret = ublk_validate_params(ub); } mutex_unlock(&ub->mutex); - ublk_put_device(ub); return ret; } @@ -1898,17 +1977,13 @@ static void ublk_queue_reinit(struct ublk_device *ub, struct ublk_queue *ubq) } } -static int ublk_ctrl_start_recovery(struct io_uring_cmd *cmd) +static int ublk_ctrl_start_recovery(struct ublk_device *ub, + struct io_uring_cmd *cmd) { struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; - struct ublk_device *ub; int ret = -EINVAL; int i; - ub = ublk_get_device_from_id(header->dev_id); - if (!ub) - return ret; - mutex_lock(&ub->mutex); if (!ublk_can_use_recovery(ub)) goto out_unlock; @@ -1936,25 +2011,21 @@ static int ublk_ctrl_start_recovery(struct io_uring_cmd *cmd) /* set to NULL, otherwise new ubq_daemon cannot mmap the io_cmd_buf */ ub->mm = NULL; ub->nr_queues_ready = 0; + ub->nr_privileged_daemon = 0; init_completion(&ub->completion); ret = 0; out_unlock: mutex_unlock(&ub->mutex); - ublk_put_device(ub); return ret; } -static int ublk_ctrl_end_recovery(struct io_uring_cmd *cmd) +static int ublk_ctrl_end_recovery(struct ublk_device *ub, + struct io_uring_cmd *cmd) { struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; int ublksrv_pid = (int)header->data[0]; - struct ublk_device *ub; int ret = -EINVAL; - ub = ublk_get_device_from_id(header->dev_id); - if (!ub) - return ret; - pr_devel("%s: Waiting for new ubq_daemons(nr: %d) are ready, dev id %d...\n", __func__, ub->dev_info.nr_hw_queues, header->dev_id); /* wait until new ubq_daemon sending all FETCH_REQ */ @@ -1982,7 +2053,115 @@ static int ublk_ctrl_end_recovery(struct io_uring_cmd *cmd) ret = 0; out_unlock: mutex_unlock(&ub->mutex); - ublk_put_device(ub); + return ret; +} + +/* + * All control commands are sent via /dev/ublk-control, so we have to check + * the destination device's permission + */ +static int ublk_char_dev_permission(struct ublk_device *ub, + const char *dev_path, int mask) +{ + int err; + struct path path; + struct kstat stat; + + err = kern_path(dev_path, LOOKUP_FOLLOW, &path); + if (err) + return err; + + err = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT); + if (err) + goto exit; + + err = -EPERM; + if (stat.rdev != ub->cdev_dev.devt || !S_ISCHR(stat.mode)) + goto exit; + + err = inode_permission(&nop_mnt_idmap, + d_backing_inode(path.dentry), mask); +exit: + path_put(&path); + return err; +} + +static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub, + struct io_uring_cmd *cmd) +{ + struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + bool unprivileged = ub->dev_info.flags & UBLK_F_UNPRIVILEGED_DEV; + void __user *argp = (void __user *)(unsigned long)header->addr; + char *dev_path = NULL; + int ret = 0; + int mask; + + if (!unprivileged) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + /* + * The new added command of UBLK_CMD_GET_DEV_INFO2 includes + * char_dev_path in payload too, since userspace may not + * know if the specified device is created as unprivileged + * mode. + */ + if (cmd->cmd_op != UBLK_CMD_GET_DEV_INFO2) + return 0; + } + + /* + * User has to provide the char device path for unprivileged ublk + * + * header->addr always points to the dev path buffer, and + * header->dev_path_len records length of dev path buffer. + */ + if (!header->dev_path_len || header->dev_path_len > PATH_MAX) + return -EINVAL; + + if (header->len < header->dev_path_len) + return -EINVAL; + + dev_path = kmalloc(header->dev_path_len + 1, GFP_KERNEL); + if (!dev_path) + return -ENOMEM; + + ret = -EFAULT; + if (copy_from_user(dev_path, argp, header->dev_path_len)) + goto exit; + dev_path[header->dev_path_len] = 0; + + ret = -EINVAL; + switch (cmd->cmd_op) { + case UBLK_CMD_GET_DEV_INFO: + case UBLK_CMD_GET_DEV_INFO2: + case UBLK_CMD_GET_QUEUE_AFFINITY: + case UBLK_CMD_GET_PARAMS: + mask = MAY_READ; + break; + case UBLK_CMD_START_DEV: + case UBLK_CMD_STOP_DEV: + case UBLK_CMD_ADD_DEV: + case UBLK_CMD_DEL_DEV: + case UBLK_CMD_SET_PARAMS: + case UBLK_CMD_START_USER_RECOVERY: + case UBLK_CMD_END_USER_RECOVERY: + mask = MAY_READ | MAY_WRITE; + break; + default: + goto exit; + } + + ret = ublk_char_dev_permission(ub, dev_path, mask); + if (!ret) { + header->len -= header->dev_path_len; + header->addr += header->dev_path_len; + } + pr_devel("%s: dev id %d cmd_op %x uid %d gid %d path %s ret %d\n", + __func__, ub->ub_number, cmd->cmd_op, + ub->dev_info.owner_uid, ub->dev_info.owner_gid, + dev_path, ret); +exit: + kfree(dev_path); return ret; } @@ -1990,52 +2169,72 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) { struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + struct ublk_device *ub = NULL; int ret = -EINVAL; + if (issue_flags & IO_URING_F_NONBLOCK) + return -EAGAIN; + ublk_ctrl_cmd_dump(cmd); if (!(issue_flags & IO_URING_F_SQE128)) goto out; - ret = -EPERM; - if (!capable(CAP_SYS_ADMIN)) - goto out; + if (cmd->cmd_op != UBLK_CMD_ADD_DEV) { + ret = -ENODEV; + ub = ublk_get_device_from_id(header->dev_id); + if (!ub) + goto out; + + ret = ublk_ctrl_uring_cmd_permission(ub, cmd); + } else { + /* ADD_DEV permission check is done in command handler */ + ret = 0; + } + + if (ret) + goto put_dev; - ret = -ENODEV; switch (cmd->cmd_op) { case UBLK_CMD_START_DEV: - ret = ublk_ctrl_start_dev(cmd); + ret = ublk_ctrl_start_dev(ub, cmd); break; case UBLK_CMD_STOP_DEV: - ret = ublk_ctrl_stop_dev(cmd); + ret = ublk_ctrl_stop_dev(ub); break; case UBLK_CMD_GET_DEV_INFO: - ret = ublk_ctrl_get_dev_info(cmd); + case UBLK_CMD_GET_DEV_INFO2: + ret = ublk_ctrl_get_dev_info(ub, cmd); break; case UBLK_CMD_ADD_DEV: ret = ublk_ctrl_add_dev(cmd); break; case UBLK_CMD_DEL_DEV: - ret = ublk_ctrl_del_dev(header->dev_id); + ret = ublk_ctrl_del_dev(&ub); break; case UBLK_CMD_GET_QUEUE_AFFINITY: - ret = ublk_ctrl_get_queue_affinity(cmd); + ret = ublk_ctrl_get_queue_affinity(ub, cmd); break; case UBLK_CMD_GET_PARAMS: - ret = ublk_ctrl_get_params(cmd); + ret = ublk_ctrl_get_params(ub, cmd); break; case UBLK_CMD_SET_PARAMS: - ret = ublk_ctrl_set_params(cmd); + ret = ublk_ctrl_set_params(ub, cmd); break; case UBLK_CMD_START_USER_RECOVERY: - ret = ublk_ctrl_start_recovery(cmd); + ret = ublk_ctrl_start_recovery(ub, cmd); break; case UBLK_CMD_END_USER_RECOVERY: - ret = ublk_ctrl_end_recovery(cmd); + ret = ublk_ctrl_end_recovery(ub, cmd); break; default: + ret = -ENOTSUPP; break; } + + put_dev: + if (ub) + ublk_put_device(ub); out: io_uring_cmd_done(cmd, ret, 0); pr_devel("%s: cmd done ret %d cmd_op %x, dev id %d qid %d\n", @@ -2089,13 +2288,12 @@ static void __exit ublk_exit(void) struct ublk_device *ub; int id; - class_destroy(ublk_chr_class); - - misc_deregister(&ublk_misc); - idr_for_each_entry(&ublk_index_idr, ub, id) ublk_remove(ub); + class_destroy(ublk_chr_class); + misc_deregister(&ublk_misc); + idr_destroy(&ublk_index_idr); unregister_chrdev_region(ublk_chr_devt, UBLK_MINORS); } @@ -2103,5 +2301,8 @@ static void __exit ublk_exit(void) module_init(ublk_init); module_exit(ublk_exit); +module_param(ublks_max, int, 0444); +MODULE_PARM_DESC(ublks_max, "max number of ublk devices allowed to add(default: 64)"); + MODULE_AUTHOR("Ming Lei <ming.lei@redhat.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 68bd2f7961b3..dc6e9b989910 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -170,9 +170,7 @@ static int virtblk_setup_discard_write_zeroes_erase(struct request *req, bool un WARN_ON_ONCE(n != segments); - req->special_vec.bv_page = virt_to_page(range); - req->special_vec.bv_offset = offset_in_page(range); - req->special_vec.bv_len = sizeof(*range) * segments; + bvec_set_virt(&req->special_vec, range, sizeof(*range) * segments); req->rq_flags |= RQF_SPECIAL_PAYLOAD; return 0; @@ -315,22 +313,35 @@ static void virtio_commit_rqs(struct blk_mq_hw_ctx *hctx) virtqueue_notify(vq->vq); } +static blk_status_t virtblk_fail_to_queue(struct request *req, int rc) +{ + virtblk_cleanup_cmd(req); + switch (rc) { + case -ENOSPC: + return BLK_STS_DEV_RESOURCE; + case -ENOMEM: + return BLK_STS_RESOURCE; + default: + return BLK_STS_IOERR; + } +} + static blk_status_t virtblk_prep_rq(struct blk_mq_hw_ctx *hctx, struct virtio_blk *vblk, struct request *req, struct virtblk_req *vbr) { blk_status_t status; + int num; status = virtblk_setup_cmd(vblk->vdev, req, vbr); if (unlikely(status)) return status; - vbr->sg_table.nents = virtblk_map_data(hctx, req, vbr); - if (unlikely(vbr->sg_table.nents < 0)) { - virtblk_cleanup_cmd(req); - return BLK_STS_RESOURCE; - } + num = virtblk_map_data(hctx, req, vbr); + if (unlikely(num < 0)) + return virtblk_fail_to_queue(req, -ENOMEM); + vbr->sg_table.nents = num; blk_mq_start_request(req); @@ -364,15 +375,7 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx, blk_mq_stop_hw_queue(hctx); spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags); virtblk_unmap_data(req, vbr); - virtblk_cleanup_cmd(req); - switch (err) { - case -ENOSPC: - return BLK_STS_DEV_RESOURCE; - case -ENOMEM: - return BLK_STS_RESOURCE; - default: - return BLK_STS_IOERR; - } + return virtblk_fail_to_queue(req, err); } if (bd->last && virtqueue_kick_prepare(vblk->vqs[qid].vq)) @@ -991,7 +994,7 @@ static int virtblk_probe(struct virtio_device *vdev) blk_queue_max_segments(q, sg_elems); /* No real sector limit. */ - blk_queue_max_hw_sectors(q, -1U); + blk_queue_max_hw_sectors(q, UINT_MAX); max_size = virtio_max_dma_size(vdev); diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index c0227dfa4688..4807af1d5805 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -524,7 +524,7 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle, return 0; } -static int xen_blkbk_remove(struct xenbus_device *dev) +static void xen_blkbk_remove(struct xenbus_device *dev) { struct backend_info *be = dev_get_drvdata(&dev->dev); @@ -547,8 +547,6 @@ static int xen_blkbk_remove(struct xenbus_device *dev) /* Put the reference we set in xen_blkif_alloc(). */ xen_blkif_put(be->blkif); } - - return 0; } int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt, diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index b28489290323..23ed258b57f0 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -2467,7 +2467,7 @@ static void blkback_changed(struct xenbus_device *dev, } } -static int blkfront_remove(struct xenbus_device *xbdev) +static void blkfront_remove(struct xenbus_device *xbdev) { struct blkfront_info *info = dev_get_drvdata(&xbdev->dev); @@ -2488,7 +2488,6 @@ static int blkfront_remove(struct xenbus_device *xbdev) } kfree(info); - return 0; } static int blkfront_is_ready(struct xenbus_device *dev) diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index e290d6d97047..bd8ae4822dc3 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -703,9 +703,7 @@ static ssize_t writeback_store(struct device *dev, for (; nr_pages != 0; index++, nr_pages--) { struct bio_vec bvec; - bvec.bv_page = page; - bvec.bv_len = PAGE_SIZE; - bvec.bv_offset = 0; + bvec_set_page(&bvec, page, PAGE_SIZE, 0); spin_lock(&zram->wb_limit_lock); if (zram->wb_limit_enable && !zram->bd_wb_limit) { @@ -1380,12 +1378,9 @@ out: static int zram_bvec_read_from_bdev(struct zram *zram, struct page *page, u32 index, struct bio *bio, bool partial_io) { - struct bio_vec bvec = { - .bv_page = page, - .bv_len = PAGE_SIZE, - .bv_offset = 0, - }; + struct bio_vec bvec; + bvec_set_page(&bvec, page, PAGE_SIZE, 0); return read_from_bdev(zram, &bvec, zram_get_element(zram, index), bio, partial_io); } @@ -1652,9 +1647,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, memcpy_from_bvec(dst + offset, bvec); kunmap_atomic(dst); - vec.bv_page = page; - vec.bv_len = PAGE_SIZE; - vec.bv_offset = 0; + bvec_set_page(&vec, page, PAGE_SIZE, 0); } ret = __zram_bvec_write(zram, &vec, index, bio); diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 6eddc23e49d9..bbe9cf1cae27 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -2164,10 +2164,17 @@ static void qca_serdev_shutdown(struct device *dev) int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS); struct serdev_device *serdev = to_serdev_device(dev); struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); + struct hci_uart *hu = &qcadev->serdev_hu; + struct hci_dev *hdev = hu->hdev; + struct qca_data *qca = hu->priv; const u8 ibs_wake_cmd[] = { 0xFD }; const u8 edl_reset_soc_cmd[] = { 0x01, 0x00, 0xFC, 0x01, 0x05 }; if (qcadev->btsoc_type == QCA_QCA6390) { + if (test_bit(QCA_BT_OFF, &qca->flags) || + !test_bit(HCI_RUNNING, &hdev->flags)) + return; + serdev_device_write_flush(serdev); ret = serdev_device_write_buf(serdev, ibs_wake_cmd, sizeof(ibs_wake_cmd)); diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c index 3aa91aed3bf7..226e87b85116 100644 --- a/drivers/bus/sunxi-rsb.c +++ b/drivers/bus/sunxi-rsb.c @@ -857,7 +857,13 @@ static int __init sunxi_rsb_init(void) return ret; } - return platform_driver_register(&sunxi_rsb_driver); + ret = platform_driver_register(&sunxi_rsb_driver); + if (ret) { + bus_unregister(&sunxi_rsb_bus); + return ret; + } + + return 0; } module_init(sunxi_rsb_init); diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index bb09d64cd51e..8771dcc9b8e2 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -236,6 +236,12 @@ void agp3_generic_tlbflush(struct agp_memory *mem); int agp3_generic_configure(void); void agp3_generic_cleanup(void); +/* GATT allocation. Returns/accepts GATT kernel virtual address. */ +#define alloc_gatt_pages(order) \ + ((char *)__get_free_pages(GFP_KERNEL, (order))) +#define free_gatt_pages(table, order) \ + free_pages((unsigned long)(table), (order)) + /* aperture sizes have been standardised since v3 */ #define AGP_GENERIC_SIZES_ENTRIES 11 extern const struct aper_size_info_16 agp3_generic_sizes[]; diff --git a/drivers/char/tpm/eventlog/acpi.c b/drivers/char/tpm/eventlog/acpi.c index 0913d3eb8d51..40360e599bc3 100644 --- a/drivers/char/tpm/eventlog/acpi.c +++ b/drivers/char/tpm/eventlog/acpi.c @@ -14,6 +14,7 @@ * Access to the event log extended by the TCG BIOS of PC platform */ +#include <linux/device.h> #include <linux/seq_file.h> #include <linux/fs.h> #include <linux/security.h> @@ -135,7 +136,7 @@ int tpm_read_log_acpi(struct tpm_chip *chip) } /* malloc EventLog space */ - log->bios_event_log = kmalloc(len, GFP_KERNEL); + log->bios_event_log = devm_kmalloc(&chip->dev, len, GFP_KERNEL); if (!log->bios_event_log) return -ENOMEM; @@ -160,7 +161,7 @@ int tpm_read_log_acpi(struct tpm_chip *chip) return format; err: - kfree(log->bios_event_log); + devm_kfree(&chip->dev, log->bios_event_log); log->bios_event_log = NULL; return ret; } diff --git a/drivers/char/tpm/eventlog/efi.c b/drivers/char/tpm/eventlog/efi.c index e6cb9d525e30..4e9d7c2bf32e 100644 --- a/drivers/char/tpm/eventlog/efi.c +++ b/drivers/char/tpm/eventlog/efi.c @@ -6,6 +6,7 @@ * Thiebaud Weksteen <tweek@google.com> */ +#include <linux/device.h> #include <linux/efi.h> #include <linux/tpm_eventlog.h> @@ -55,7 +56,7 @@ int tpm_read_log_efi(struct tpm_chip *chip) } /* malloc EventLog space */ - log->bios_event_log = kmemdup(log_tbl->log, log_size, GFP_KERNEL); + log->bios_event_log = devm_kmemdup(&chip->dev, log_tbl->log, log_size, GFP_KERNEL); if (!log->bios_event_log) { ret = -ENOMEM; goto out; @@ -76,7 +77,7 @@ int tpm_read_log_efi(struct tpm_chip *chip) MEMREMAP_WB); if (!final_tbl) { pr_err("Could not map UEFI TPM final log\n"); - kfree(log->bios_event_log); + devm_kfree(&chip->dev, log->bios_event_log); ret = -ENOMEM; goto out; } @@ -91,11 +92,11 @@ int tpm_read_log_efi(struct tpm_chip *chip) * Allocate memory for the 'combined log' where we will append the * 'final events log' to. */ - tmp = krealloc(log->bios_event_log, - log_size + final_events_log_size, - GFP_KERNEL); + tmp = devm_krealloc(&chip->dev, log->bios_event_log, + log_size + final_events_log_size, + GFP_KERNEL); if (!tmp) { - kfree(log->bios_event_log); + devm_kfree(&chip->dev, log->bios_event_log); ret = -ENOMEM; goto out; } diff --git a/drivers/char/tpm/eventlog/of.c b/drivers/char/tpm/eventlog/of.c index a9ce66d09a75..930fe43d5daf 100644 --- a/drivers/char/tpm/eventlog/of.c +++ b/drivers/char/tpm/eventlog/of.c @@ -10,13 +10,44 @@ * Read the event log created by the firmware on PPC64 */ +#include <linux/device.h> #include <linux/slab.h> +#include <linux/io.h> +#include <linux/ioport.h> #include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_reserved_mem.h> #include <linux/tpm_eventlog.h> #include "../tpm.h" #include "common.h" +static int tpm_read_log_memory_region(struct tpm_chip *chip) +{ + struct device_node *node; + struct resource res; + int rc; + + node = of_parse_phandle(chip->dev.parent->of_node, "memory-region", 0); + if (!node) + return -ENODEV; + + rc = of_address_to_resource(node, 0, &res); + of_node_put(node); + if (rc) + return rc; + + chip->log.bios_event_log = devm_memremap(&chip->dev, res.start, resource_size(&res), + MEMREMAP_WB); + if (IS_ERR(chip->log.bios_event_log)) + return -ENOMEM; + + chip->log.bios_event_log_end = chip->log.bios_event_log + resource_size(&res); + + return chip->flags & TPM_CHIP_FLAG_TPM2 ? EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 : + EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; +} + int tpm_read_log_of(struct tpm_chip *chip) { struct device_node *np; @@ -38,7 +69,7 @@ int tpm_read_log_of(struct tpm_chip *chip) sizep = of_get_property(np, "linux,sml-size", NULL); basep = of_get_property(np, "linux,sml-base", NULL); if (sizep == NULL && basep == NULL) - return -ENODEV; + return tpm_read_log_memory_region(chip); if (sizep == NULL || basep == NULL) return -EIO; @@ -65,7 +96,7 @@ int tpm_read_log_of(struct tpm_chip *chip) return -EIO; } - log->bios_event_log = kmemdup(__va(base), size, GFP_KERNEL); + log->bios_event_log = devm_kmemdup(&chip->dev, __va(base), size, GFP_KERNEL); if (!log->bios_event_log) return -ENOMEM; diff --git a/drivers/char/tpm/st33zp24/i2c.c b/drivers/char/tpm/st33zp24/i2c.c index 8156bb2af78c..c4d0b744e3cc 100644 --- a/drivers/char/tpm/st33zp24/i2c.c +++ b/drivers/char/tpm/st33zp24/i2c.c @@ -101,8 +101,7 @@ static const struct st33zp24_phy_ops i2c_phy_ops = { * @return: 0 in case of success. * -1 in other case. */ -static int st33zp24_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int st33zp24_i2c_probe(struct i2c_client *client) { struct st33zp24_i2c_phy *phy; @@ -161,7 +160,7 @@ static struct i2c_driver st33zp24_i2c_driver = { .of_match_table = of_match_ptr(of_st33zp24_i2c_match), .acpi_match_table = ACPI_PTR(st33zp24_i2c_acpi_match), }, - .probe = st33zp24_i2c_probe, + .probe_new = st33zp24_i2c_probe, .remove = st33zp24_i2c_remove, .id_table = st33zp24_i2c_id }; diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 741d8f3e8fb3..b99f55f2d4fd 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -267,7 +267,6 @@ static void tpm_dev_release(struct device *dev) idr_remove(&dev_nums_idr, chip->dev_num); mutex_unlock(&idr_lock); - kfree(chip->log.bios_event_log); kfree(chip->work_space.context_buf); kfree(chip->work_space.session_buf); kfree(chip->allocated_banks); diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index d69905233aff..7e513b771832 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -412,7 +412,9 @@ int tpm_pm_suspend(struct device *dev) } suspended: - return rc; + if (rc) + dev_err(dev, "Ignoring error %d while suspending\n", rc); + return 0; } EXPORT_SYMBOL_GPL(tpm_pm_suspend); diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 65d03867e114..93545be190a5 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -777,10 +777,12 @@ out: int tpm2_find_cc(struct tpm_chip *chip, u32 cc) { + u32 cc_mask; int i; + cc_mask = 1 << TPM2_CC_ATTR_VENDOR | GENMASK(15, 0); for (i = 0; i < chip->nr_commands; i++) - if (cc == (chip->cc_attrs_tbl[i] & GENMASK(15, 0))) + if (cc == (chip->cc_attrs_tbl[i] & cc_mask)) return i; return -1; diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 7e9da671a0e8..d43a0d7b97a8 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -98,6 +98,8 @@ struct crb_priv { u8 __iomem *rsp; u32 cmd_size; u32 smc_func_id; + u32 __iomem *pluton_start_addr; + u32 __iomem *pluton_reply_addr; }; struct tpm2_crb_smc { @@ -108,6 +110,11 @@ struct tpm2_crb_smc { u32 smc_func_id; }; +struct tpm2_crb_pluton { + u64 start_addr; + u64 reply_addr; +}; + static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, unsigned long timeout) { @@ -127,6 +134,25 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, return ((ioread32(reg) & mask) == value); } +static int crb_try_pluton_doorbell(struct crb_priv *priv, bool wait_for_complete) +{ + if (priv->sm != ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) + return 0; + + if (!crb_wait_for_reg_32(priv->pluton_reply_addr, ~0, 1, TPM2_TIMEOUT_C)) + return -ETIME; + + iowrite32(1, priv->pluton_start_addr); + if (wait_for_complete == false) + return 0; + + if (!crb_wait_for_reg_32(priv->pluton_start_addr, + 0xffffffff, 0, 200)) + return -ETIME; + + return 0; +} + /** * __crb_go_idle - request tpm crb device to go the idle state * @@ -145,6 +171,8 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, */ static int __crb_go_idle(struct device *dev, struct crb_priv *priv) { + int rc; + if ((priv->sm == ACPI_TPM2_START_METHOD) || (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) || (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC)) @@ -152,6 +180,10 @@ static int __crb_go_idle(struct device *dev, struct crb_priv *priv) iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs_t->ctrl_req); + rc = crb_try_pluton_doorbell(priv, true); + if (rc) + return rc; + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_req, CRB_CTRL_REQ_GO_IDLE/* mask */, 0, /* value */ @@ -188,12 +220,19 @@ static int crb_go_idle(struct tpm_chip *chip) */ static int __crb_cmd_ready(struct device *dev, struct crb_priv *priv) { + int rc; + if ((priv->sm == ACPI_TPM2_START_METHOD) || (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) || (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC)) return 0; iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->regs_t->ctrl_req); + + rc = crb_try_pluton_doorbell(priv, true); + if (rc) + return rc; + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_req, CRB_CTRL_REQ_CMD_READY /* mask */, 0, /* value */ @@ -371,6 +410,10 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len) return -E2BIG; } + /* Seems to be necessary for every command */ + if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) + __crb_cmd_ready(&chip->dev, priv); + memcpy_toio(priv->cmd, buf, len); /* Make sure that cmd is populated before issuing start. */ @@ -394,7 +437,10 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len) rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id); } - return rc; + if (rc) + return rc; + + return crb_try_pluton_doorbell(priv, false); } static void crb_cancel(struct tpm_chip *chip) @@ -524,15 +570,18 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, return ret; acpi_dev_free_resource_list(&acpi_resource_list); - if (resource_type(iores_array) != IORESOURCE_MEM) { - dev_err(dev, FW_BUG "TPM2 ACPI table does not define a memory resource\n"); - return -EINVAL; - } else if (resource_type(iores_array + TPM_CRB_MAX_RESOURCES) == - IORESOURCE_MEM) { - dev_warn(dev, "TPM2 ACPI table defines too many memory resources\n"); - memset(iores_array + TPM_CRB_MAX_RESOURCES, - 0, sizeof(*iores_array)); - iores_array[TPM_CRB_MAX_RESOURCES].flags = 0; + /* Pluton doesn't appear to define ACPI memory regions */ + if (priv->sm != ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) { + if (resource_type(iores_array) != IORESOURCE_MEM) { + dev_err(dev, FW_BUG "TPM2 ACPI table does not define a memory resource\n"); + return -EINVAL; + } else if (resource_type(iores_array + TPM_CRB_MAX_RESOURCES) == + IORESOURCE_MEM) { + dev_warn(dev, "TPM2 ACPI table defines too many memory resources\n"); + memset(iores_array + TPM_CRB_MAX_RESOURCES, + 0, sizeof(*iores_array)); + iores_array[TPM_CRB_MAX_RESOURCES].flags = 0; + } } iores = NULL; @@ -656,6 +705,22 @@ out_relinquish_locality: return ret; } +static int crb_map_pluton(struct device *dev, struct crb_priv *priv, + struct acpi_table_tpm2 *buf, struct tpm2_crb_pluton *crb_pluton) +{ + priv->pluton_start_addr = crb_map_res(dev, NULL, NULL, + crb_pluton->start_addr, 4); + if (IS_ERR(priv->pluton_start_addr)) + return PTR_ERR(priv->pluton_start_addr); + + priv->pluton_reply_addr = crb_map_res(dev, NULL, NULL, + crb_pluton->reply_addr, 4); + if (IS_ERR(priv->pluton_reply_addr)) + return PTR_ERR(priv->pluton_reply_addr); + + return 0; +} + static int crb_acpi_add(struct acpi_device *device) { struct acpi_table_tpm2 *buf; @@ -663,6 +728,7 @@ static int crb_acpi_add(struct acpi_device *device) struct tpm_chip *chip; struct device *dev = &device->dev; struct tpm2_crb_smc *crb_smc; + struct tpm2_crb_pluton *crb_pluton; acpi_status status; u32 sm; int rc; @@ -700,6 +766,20 @@ static int crb_acpi_add(struct acpi_device *device) priv->smc_func_id = crb_smc->smc_func_id; } + if (sm == ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) { + if (buf->header.length < (sizeof(*buf) + sizeof(*crb_pluton))) { + dev_err(dev, + FW_BUG "TPM2 ACPI table has wrong size %u for start method type %d\n", + buf->header.length, + ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON); + return -EINVAL; + } + crb_pluton = ACPI_ADD_PTR(struct tpm2_crb_pluton, buf, sizeof(*buf)); + rc = crb_map_pluton(dev, priv, buf, crb_pluton); + if (rc) + return rc; + } + priv->sm = sm; priv->hid = acpi_device_hid(device); diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c index 4be3677c1463..8f77154e0550 100644 --- a/drivers/char/tpm/tpm_i2c_atmel.c +++ b/drivers/char/tpm/tpm_i2c_atmel.c @@ -146,8 +146,7 @@ static const struct tpm_class_ops i2c_atmel = { .req_canceled = i2c_atmel_req_canceled, }; -static int i2c_atmel_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int i2c_atmel_probe(struct i2c_client *client) { struct tpm_chip *chip; struct device *dev = &client->dev; @@ -204,7 +203,7 @@ static SIMPLE_DEV_PM_OPS(i2c_atmel_pm_ops, tpm_pm_suspend, tpm_pm_resume); static struct i2c_driver i2c_atmel_driver = { .id_table = i2c_atmel_id, - .probe = i2c_atmel_probe, + .probe_new = i2c_atmel_probe, .remove = i2c_atmel_remove, .driver = { .name = I2C_DRIVER_NAME, diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index fd3c3661e646..7cdaff52a96d 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -681,8 +681,7 @@ MODULE_DEVICE_TABLE(of, tpm_tis_i2c_of_match); static SIMPLE_DEV_PM_OPS(tpm_tis_i2c_ops, tpm_pm_suspend, tpm_pm_resume); -static int tpm_tis_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tpm_tis_i2c_probe(struct i2c_client *client) { int rc; struct device *dev = &(client->dev); @@ -717,7 +716,7 @@ static void tpm_tis_i2c_remove(struct i2c_client *client) static struct i2c_driver tpm_tis_i2c_driver = { .id_table = tpm_tis_i2c_table, - .probe = tpm_tis_i2c_probe, + .probe_new = tpm_tis_i2c_probe, .remove = tpm_tis_i2c_remove, .driver = { .name = "tpm_i2c_infineon", diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index 95c37350cc8e..a026e98add50 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -522,9 +522,9 @@ static int get_vid(struct i2c_client *client, u32 *res) return 0; } -static int i2c_nuvoton_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int i2c_nuvoton_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); int rc; struct tpm_chip *chip; struct device *dev = &client->dev; @@ -650,7 +650,7 @@ static SIMPLE_DEV_PM_OPS(i2c_nuvoton_pm_ops, tpm_pm_suspend, tpm_pm_resume); static struct i2c_driver i2c_nuvoton_driver = { .id_table = i2c_nuvoton_id, - .probe = i2c_nuvoton_probe, + .probe_new = i2c_nuvoton_probe, .remove = i2c_nuvoton_remove, .driver = { .name = "tpm_i2c_nuvoton", diff --git a/drivers/char/tpm/tpm_tis_i2c.c b/drivers/char/tpm/tpm_tis_i2c.c index f3a7251c8e38..c8c34adc14c0 100644 --- a/drivers/char/tpm/tpm_tis_i2c.c +++ b/drivers/char/tpm/tpm_tis_i2c.c @@ -312,8 +312,7 @@ static const struct tpm_tis_phy_ops tpm_i2c_phy_ops = { .verify_crc = tpm_tis_i2c_verify_crc, }; -static int tpm_tis_i2c_probe(struct i2c_client *dev, - const struct i2c_device_id *id) +static int tpm_tis_i2c_probe(struct i2c_client *dev) { struct tpm_tis_i2c_phy *phy; const u8 crc_enable = 1; @@ -380,7 +379,7 @@ static struct i2c_driver tpm_tis_i2c_driver = { .pm = &tpm_tis_pm, .of_match_table = of_match_ptr(of_tis_i2c_match), }, - .probe = tpm_tis_i2c_probe, + .probe_new = tpm_tis_i2c_probe, .remove = tpm_tis_i2c_remove, .id_table = tpm_tis_i2c_id, }; diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index 379291826261..80cca3b83b22 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c @@ -360,14 +360,13 @@ static int tpmfront_probe(struct xenbus_device *dev, return tpm_chip_register(priv->chip); } -static int tpmfront_remove(struct xenbus_device *dev) +static void tpmfront_remove(struct xenbus_device *dev) { struct tpm_chip *chip = dev_get_drvdata(&dev->dev); struct tpm_private *priv = dev_get_drvdata(&chip->dev); tpm_chip_unregister(chip); ring_free(priv); dev_set_drvdata(&chip->dev, NULL); - return 0; } static int tpmfront_resume(struct xenbus_device *dev) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index e62552a75f08..f6d7c6a9a654 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1055,12 +1055,12 @@ static void clk_core_disable(struct clk_core *core) if (--core->enable_count > 0) return; - trace_clk_disable_rcuidle(core); + trace_clk_disable(core); if (core->ops->disable) core->ops->disable(core->hw); - trace_clk_disable_complete_rcuidle(core); + trace_clk_disable_complete(core); clk_core_disable(core->parent); } @@ -1114,12 +1114,12 @@ static int clk_core_enable(struct clk_core *core) if (ret) return ret; - trace_clk_enable_rcuidle(core); + trace_clk_enable(core); if (core->ops->enable) ret = core->ops->enable(core->hw); - trace_clk_enable_complete_rcuidle(core); + trace_clk_enable_complete(core); if (ret) { clk_core_disable(core->parent); diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index be6f55d37b49..5d0ae1ee72ec 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -6,12 +6,8 @@ obj-$(CONFIG_ARCH_DAVINCI_DA8XX) += da8xx-cfgchip.o obj-y += pll.o obj-$(CONFIG_ARCH_DAVINCI_DA830) += pll-da830.o obj-$(CONFIG_ARCH_DAVINCI_DA850) += pll-da850.o -obj-$(CONFIG_ARCH_DAVINCI_DM355) += pll-dm355.o -obj-$(CONFIG_ARCH_DAVINCI_DM365) += pll-dm365.o obj-y += psc.o obj-$(CONFIG_ARCH_DAVINCI_DA830) += psc-da830.o obj-$(CONFIG_ARCH_DAVINCI_DA850) += psc-da850.o -obj-$(CONFIG_ARCH_DAVINCI_DM355) += psc-dm355.o -obj-$(CONFIG_ARCH_DAVINCI_DM365) += psc-dm365.o endif diff --git a/drivers/clk/davinci/pll-dm355.c b/drivers/clk/davinci/pll-dm355.c deleted file mode 100644 index 505aed80be9a..000000000000 --- a/drivers/clk/davinci/pll-dm355.c +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * PLL clock descriptions for TI DM355 - * - * Copyright (C) 2018 David Lechner <david@lechnology.com> - */ - -#include <linux/bitops.h> -#include <linux/clk/davinci.h> -#include <linux/clkdev.h> -#include <linux/init.h> -#include <linux/types.h> - -#include "pll.h" - -static const struct davinci_pll_clk_info dm355_pll1_info = { - .name = "pll1", - .pllm_mask = GENMASK(7, 0), - .pllm_min = 92, - .pllm_max = 184, - .flags = PLL_HAS_CLKMODE | PLL_HAS_PREDIV | PLL_PREDIV_ALWAYS_ENABLED | - PLL_PREDIV_FIXED8 | PLL_HAS_POSTDIV | - PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV, -}; - -SYSCLK(1, pll1_sysclk1, pll1_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED); -SYSCLK(2, pll1_sysclk2, pll1_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED); -SYSCLK(3, pll1_sysclk3, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); -SYSCLK(4, pll1_sysclk4, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); - -int dm355_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip) -{ - struct clk *clk; - - davinci_pll_clk_register(dev, &dm355_pll1_info, "ref_clk", base, cfgchip); - - clk = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base); - clk_register_clkdev(clk, "pll1_sysclk1", "dm355-psc"); - - clk = davinci_pll_sysclk_register(dev, &pll1_sysclk2, base); - clk_register_clkdev(clk, "pll1_sysclk2", "dm355-psc"); - - clk = davinci_pll_sysclk_register(dev, &pll1_sysclk3, base); - clk_register_clkdev(clk, "pll1_sysclk3", "dm355-psc"); - - clk = davinci_pll_sysclk_register(dev, &pll1_sysclk4, base); - clk_register_clkdev(clk, "pll1_sysclk4", "dm355-psc"); - - clk = davinci_pll_auxclk_register(dev, "pll1_auxclk", base); - clk_register_clkdev(clk, "pll1_auxclk", "dm355-psc"); - - davinci_pll_sysclkbp_clk_register(dev, "pll1_sysclkbp", base); - - return 0; -} - -static const struct davinci_pll_clk_info dm355_pll2_info = { - .name = "pll2", - .pllm_mask = GENMASK(7, 0), - .pllm_min = 92, - .pllm_max = 184, - .flags = PLL_HAS_PREDIV | PLL_PREDIV_ALWAYS_ENABLED | PLL_HAS_POSTDIV | - PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV, -}; - -SYSCLK(1, pll2_sysclk1, pll2_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED); - -int dm355_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip) -{ - davinci_pll_clk_register(dev, &dm355_pll2_info, "oscin", base, cfgchip); - - davinci_pll_sysclk_register(dev, &pll2_sysclk1, base); - - davinci_pll_sysclkbp_clk_register(dev, "pll2_sysclkbp", base); - - return 0; -} diff --git a/drivers/clk/davinci/pll-dm365.c b/drivers/clk/davinci/pll-dm365.c deleted file mode 100644 index 2d29712753a3..000000000000 --- a/drivers/clk/davinci/pll-dm365.c +++ /dev/null @@ -1,146 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * PLL clock descriptions for TI DM365 - * - * Copyright (C) 2018 David Lechner <david@lechnology.com> - */ - -#include <linux/bitops.h> -#include <linux/clkdev.h> -#include <linux/clk/davinci.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/types.h> - -#include "pll.h" - -#define OCSEL_OCSRC_ENABLE 0 - -static const struct davinci_pll_clk_info dm365_pll1_info = { - .name = "pll1", - .pllm_mask = GENMASK(9, 0), - .pllm_min = 1, - .pllm_max = 1023, - .flags = PLL_HAS_CLKMODE | PLL_HAS_PREDIV | PLL_HAS_POSTDIV | - PLL_POSTDIV_ALWAYS_ENABLED | PLL_PLLM_2X, -}; - -SYSCLK(1, pll1_sysclk1, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); -SYSCLK(2, pll1_sysclk2, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); -SYSCLK(3, pll1_sysclk3, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); -SYSCLK(4, pll1_sysclk4, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); -SYSCLK(5, pll1_sysclk5, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); -SYSCLK(6, pll1_sysclk6, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); -SYSCLK(7, pll1_sysclk7, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); -SYSCLK(8, pll1_sysclk8, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); -SYSCLK(9, pll1_sysclk9, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); - -/* - * This is a bit of a hack to make OCSEL[OCSRC] on DM365 look like OCSEL[OCSRC] - * on DA850. On DM365, OCSEL[OCSRC] is just an enable/disable bit instead of a - * multiplexer. By modeling it as a single parent mux clock, the clock code will - * still do the right thing in this case. - */ -static const char * const dm365_pll_obsclk_parent_names[] = { - "oscin", -}; - -static u32 dm365_pll_obsclk_table[] = { - OCSEL_OCSRC_ENABLE, -}; - -static const struct davinci_pll_obsclk_info dm365_pll1_obsclk_info = { - .name = "pll1_obsclk", - .parent_names = dm365_pll_obsclk_parent_names, - .num_parents = ARRAY_SIZE(dm365_pll_obsclk_parent_names), - .table = dm365_pll_obsclk_table, - .ocsrc_mask = BIT(4), -}; - -int dm365_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip) -{ - struct clk *clk; - - davinci_pll_clk_register(dev, &dm365_pll1_info, "ref_clk", base, cfgchip); - - clk = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base); - clk_register_clkdev(clk, "pll1_sysclk1", "dm365-psc"); - - clk = davinci_pll_sysclk_register(dev, &pll1_sysclk2, base); - clk_register_clkdev(clk, "pll1_sysclk2", "dm365-psc"); - - clk = davinci_pll_sysclk_register(dev, &pll1_sysclk3, base); - clk_register_clkdev(clk, "pll1_sysclk3", "dm365-psc"); - - clk = davinci_pll_sysclk_register(dev, &pll1_sysclk4, base); - clk_register_clkdev(clk, "pll1_sysclk4", "dm365-psc"); - - clk = davinci_pll_sysclk_register(dev, &pll1_sysclk5, base); - clk_register_clkdev(clk, "pll1_sysclk5", "dm365-psc"); - - davinci_pll_sysclk_register(dev, &pll1_sysclk6, base); - - davinci_pll_sysclk_register(dev, &pll1_sysclk7, base); - - clk = davinci_pll_sysclk_register(dev, &pll1_sysclk8, base); - clk_register_clkdev(clk, "pll1_sysclk8", "dm365-psc"); - - davinci_pll_sysclk_register(dev, &pll1_sysclk9, base); - - clk = davinci_pll_auxclk_register(dev, "pll1_auxclk", base); - clk_register_clkdev(clk, "pll1_auxclk", "dm355-psc"); - - davinci_pll_sysclkbp_clk_register(dev, "pll1_sysclkbp", base); - - davinci_pll_obsclk_register(dev, &dm365_pll1_obsclk_info, base); - - return 0; -} - -static const struct davinci_pll_clk_info dm365_pll2_info = { - .name = "pll2", - .pllm_mask = GENMASK(9, 0), - .pllm_min = 1, - .pllm_max = 1023, - .flags = PLL_HAS_PREDIV | PLL_HAS_POSTDIV | PLL_POSTDIV_ALWAYS_ENABLED | - PLL_PLLM_2X, -}; - -SYSCLK(1, pll2_sysclk1, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED); -SYSCLK(2, pll2_sysclk2, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED); -SYSCLK(3, pll2_sysclk3, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED); -SYSCLK(4, pll2_sysclk4, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED); -SYSCLK(5, pll2_sysclk5, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED); - -static const struct davinci_pll_obsclk_info dm365_pll2_obsclk_info = { - .name = "pll2_obsclk", - .parent_names = dm365_pll_obsclk_parent_names, - .num_parents = ARRAY_SIZE(dm365_pll_obsclk_parent_names), - .table = dm365_pll_obsclk_table, - .ocsrc_mask = BIT(4), -}; - -int dm365_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip) -{ - struct clk *clk; - - davinci_pll_clk_register(dev, &dm365_pll2_info, "oscin", base, cfgchip); - - davinci_pll_sysclk_register(dev, &pll2_sysclk1, base); - - clk = davinci_pll_sysclk_register(dev, &pll2_sysclk2, base); - clk_register_clkdev(clk, "pll1_sysclk2", "dm365-psc"); - - davinci_pll_sysclk_register(dev, &pll2_sysclk3, base); - - clk = davinci_pll_sysclk_register(dev, &pll2_sysclk4, base); - clk_register_clkdev(clk, "pll1_sysclk4", "dm365-psc"); - - davinci_pll_sysclk_register(dev, &pll2_sysclk5, base); - - davinci_pll_auxclk_register(dev, "pll2_auxclk", base); - - davinci_pll_obsclk_register(dev, &dm365_pll2_obsclk_info, base); - - return 0; -} diff --git a/drivers/clk/davinci/pll.c b/drivers/clk/davinci/pll.c index f862f5e2b3fc..87bdf8879045 100644 --- a/drivers/clk/davinci/pll.c +++ b/drivers/clk/davinci/pll.c @@ -882,14 +882,6 @@ static const struct platform_device_id davinci_pll_id_table[] = { { .name = "da850-pll0", .driver_data = (kernel_ulong_t)da850_pll0_init }, { .name = "da850-pll1", .driver_data = (kernel_ulong_t)da850_pll1_init }, #endif -#ifdef CONFIG_ARCH_DAVINCI_DM355 - { .name = "dm355-pll1", .driver_data = (kernel_ulong_t)dm355_pll1_init }, - { .name = "dm355-pll2", .driver_data = (kernel_ulong_t)dm355_pll2_init }, -#endif -#ifdef CONFIG_ARCH_DAVINCI_DM365 - { .name = "dm365-pll1", .driver_data = (kernel_ulong_t)dm365_pll1_init }, - { .name = "dm365-pll2", .driver_data = (kernel_ulong_t)dm365_pll2_init }, -#endif { } }; diff --git a/drivers/clk/davinci/pll.h b/drivers/clk/davinci/pll.h index 1773277bc690..20bfcec2d3b5 100644 --- a/drivers/clk/davinci/pll.h +++ b/drivers/clk/davinci/pll.h @@ -122,13 +122,8 @@ int of_davinci_pll_init(struct device *dev, struct device_node *node, /* Platform-specific callbacks */ -#ifdef CONFIG_ARCH_DAVINCI_DA850 int da850_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip); void of_da850_pll0_init(struct device_node *node); int of_da850_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip); -#endif -#ifdef CONFIG_ARCH_DAVINCI_DM355 -int dm355_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip); -#endif #endif /* __CLK_DAVINCI_PLL_H___ */ diff --git a/drivers/clk/davinci/psc-dm355.c b/drivers/clk/davinci/psc-dm355.c deleted file mode 100644 index ddd250107c4e..000000000000 --- a/drivers/clk/davinci/psc-dm355.c +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * PSC clock descriptions for TI DaVinci DM355 - * - * Copyright (C) 2018 David Lechner <david@lechnology.com> - */ - -#include <linux/clk-provider.h> -#include <linux/clk/davinci.h> -#include <linux/clk.h> -#include <linux/clkdev.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/types.h> - -#include "psc.h" - -LPSC_CLKDEV1(vpss_master_clkdev, "master", "vpss"); -LPSC_CLKDEV1(vpss_slave_clkdev, "slave", "vpss"); -LPSC_CLKDEV1(spi1_clkdev, NULL, "spi_davinci.1"); -LPSC_CLKDEV1(mmcsd1_clkdev, NULL, "dm6441-mmc.1"); -LPSC_CLKDEV1(mcbsp1_clkdev, NULL, "davinci-mcbsp.1"); -LPSC_CLKDEV1(usb_clkdev, "usb", NULL); -LPSC_CLKDEV1(spi2_clkdev, NULL, "spi_davinci.2"); -LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL); -LPSC_CLKDEV1(mmcsd0_clkdev, NULL, "dm6441-mmc.0"); -LPSC_CLKDEV1(mcbsp0_clkdev, NULL, "davinci-mcbsp.0"); -LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1"); -LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); -LPSC_CLKDEV1(uart1_clkdev, NULL, "serial8250.1"); -LPSC_CLKDEV1(uart2_clkdev, NULL, "serial8250.2"); -LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0"); -/* REVISIT: gpio-davinci.c should be modified to drop con_id */ -LPSC_CLKDEV1(gpio_clkdev, "gpio", NULL); -LPSC_CLKDEV1(timer0_clkdev, "timer0", NULL); -LPSC_CLKDEV1(timer2_clkdev, NULL, "davinci-wdt"); -LPSC_CLKDEV1(vpss_dac_clkdev, "vpss_dac", NULL); - -static const struct davinci_lpsc_clk_info dm355_psc_info[] = { - LPSC(0, 0, vpss_master, pll1_sysclk4, vpss_master_clkdev, 0), - LPSC(1, 0, vpss_slave, pll1_sysclk4, vpss_slave_clkdev, 0), - LPSC(5, 0, timer3, pll1_auxclk, NULL, 0), - LPSC(6, 0, spi1, pll1_sysclk2, spi1_clkdev, 0), - LPSC(7, 0, mmcsd1, pll1_sysclk2, mmcsd1_clkdev, 0), - LPSC(8, 0, asp1, pll1_sysclk2, mcbsp1_clkdev, 0), - LPSC(9, 0, usb, pll1_sysclk2, usb_clkdev, 0), - LPSC(10, 0, pwm3, pll1_auxclk, NULL, 0), - LPSC(11, 0, spi2, pll1_sysclk2, spi2_clkdev, 0), - LPSC(12, 0, rto, pll1_auxclk, NULL, 0), - LPSC(14, 0, aemif, pll1_sysclk2, aemif_clkdev, 0), - LPSC(15, 0, mmcsd0, pll1_sysclk2, mmcsd0_clkdev, 0), - LPSC(17, 0, asp0, pll1_sysclk2, mcbsp0_clkdev, 0), - LPSC(18, 0, i2c, pll1_auxclk, i2c_clkdev, 0), - LPSC(19, 0, uart0, pll1_auxclk, uart0_clkdev, 0), - LPSC(20, 0, uart1, pll1_auxclk, uart1_clkdev, 0), - LPSC(21, 0, uart2, pll1_sysclk2, uart2_clkdev, 0), - LPSC(22, 0, spi0, pll1_sysclk2, spi0_clkdev, 0), - LPSC(23, 0, pwm0, pll1_auxclk, NULL, 0), - LPSC(24, 0, pwm1, pll1_auxclk, NULL, 0), - LPSC(25, 0, pwm2, pll1_auxclk, NULL, 0), - LPSC(26, 0, gpio, pll1_sysclk2, gpio_clkdev, 0), - LPSC(27, 0, timer0, pll1_auxclk, timer0_clkdev, LPSC_ALWAYS_ENABLED), - LPSC(28, 0, timer1, pll1_auxclk, NULL, 0), - /* REVISIT: why can't this be disabled? */ - LPSC(29, 0, timer2, pll1_auxclk, timer2_clkdev, LPSC_ALWAYS_ENABLED), - LPSC(31, 0, arm, pll1_sysclk1, NULL, LPSC_ALWAYS_ENABLED), - LPSC(40, 0, mjcp, pll1_sysclk1, NULL, 0), - LPSC(41, 0, vpss_dac, pll1_sysclk3, vpss_dac_clkdev, 0), - { } -}; - -int dm355_psc_init(struct device *dev, void __iomem *base) -{ - return davinci_psc_register_clocks(dev, dm355_psc_info, 42, base); -} - -static struct clk_bulk_data dm355_psc_parent_clks[] = { - { .id = "pll1_sysclk1" }, - { .id = "pll1_sysclk2" }, - { .id = "pll1_sysclk3" }, - { .id = "pll1_sysclk4" }, - { .id = "pll1_auxclk" }, -}; - -const struct davinci_psc_init_data dm355_psc_init_data = { - .parent_clks = dm355_psc_parent_clks, - .num_parent_clks = ARRAY_SIZE(dm355_psc_parent_clks), - .psc_init = &dm355_psc_init, -}; diff --git a/drivers/clk/davinci/psc-dm365.c b/drivers/clk/davinci/psc-dm365.c deleted file mode 100644 index c75424f4ea3b..000000000000 --- a/drivers/clk/davinci/psc-dm365.c +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * PSC clock descriptions for TI DaVinci DM365 - * - * Copyright (C) 2018 David Lechner <david@lechnology.com> - */ - -#include <linux/clk-provider.h> -#include <linux/clk/davinci.h> -#include <linux/clk.h> -#include <linux/clkdev.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/types.h> - -#include "psc.h" - -LPSC_CLKDEV1(vpss_slave_clkdev, "slave", "vpss"); -LPSC_CLKDEV1(spi1_clkdev, NULL, "spi_davinci.1"); -LPSC_CLKDEV1(mmcsd1_clkdev, NULL, "da830-mmc.1"); -LPSC_CLKDEV1(asp0_clkdev, NULL, "davinci-mcbsp"); -LPSC_CLKDEV1(usb_clkdev, "usb", NULL); -LPSC_CLKDEV1(spi2_clkdev, NULL, "spi_davinci.2"); -LPSC_CLKDEV2(aemif_clkdev, "aemif", NULL, - NULL, "ti-aemif"); -LPSC_CLKDEV1(mmcsd0_clkdev, NULL, "da830-mmc.0"); -LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1"); -LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); -LPSC_CLKDEV1(uart1_clkdev, NULL, "serial8250.1"); -LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0"); -/* REVISIT: gpio-davinci.c should be modified to drop con_id */ -LPSC_CLKDEV1(gpio_clkdev, "gpio", NULL); -LPSC_CLKDEV1(timer0_clkdev, "timer0", NULL); -LPSC_CLKDEV1(timer2_clkdev, NULL, "davinci-wdt"); -LPSC_CLKDEV1(spi3_clkdev, NULL, "spi_davinci.3"); -LPSC_CLKDEV1(spi4_clkdev, NULL, "spi_davinci.4"); -LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1", - "fck", "davinci_mdio.0"); -LPSC_CLKDEV1(voice_codec_clkdev, NULL, "davinci_voicecodec"); -LPSC_CLKDEV1(vpss_dac_clkdev, "vpss_dac", NULL); -LPSC_CLKDEV1(vpss_master_clkdev, "master", "vpss"); - -static const struct davinci_lpsc_clk_info dm365_psc_info[] = { - LPSC(1, 0, vpss_slave, pll1_sysclk5, vpss_slave_clkdev, 0), - LPSC(5, 0, timer3, pll1_auxclk, NULL, 0), - LPSC(6, 0, spi1, pll1_sysclk4, spi1_clkdev, 0), - LPSC(7, 0, mmcsd1, pll1_sysclk4, mmcsd1_clkdev, 0), - LPSC(8, 0, asp0, pll1_sysclk4, asp0_clkdev, 0), - LPSC(9, 0, usb, pll1_auxclk, usb_clkdev, 0), - LPSC(10, 0, pwm3, pll1_auxclk, NULL, 0), - LPSC(11, 0, spi2, pll1_sysclk4, spi2_clkdev, 0), - LPSC(12, 0, rto, pll1_sysclk4, NULL, 0), - LPSC(14, 0, aemif, pll1_sysclk4, aemif_clkdev, 0), - LPSC(15, 0, mmcsd0, pll1_sysclk8, mmcsd0_clkdev, 0), - LPSC(18, 0, i2c, pll1_auxclk, i2c_clkdev, 0), - LPSC(19, 0, uart0, pll1_auxclk, uart0_clkdev, 0), - LPSC(20, 0, uart1, pll1_sysclk4, uart1_clkdev, 0), - LPSC(22, 0, spi0, pll1_sysclk4, spi0_clkdev, 0), - LPSC(23, 0, pwm0, pll1_auxclk, NULL, 0), - LPSC(24, 0, pwm1, pll1_auxclk, NULL, 0), - LPSC(25, 0, pwm2, pll1_auxclk, NULL, 0), - LPSC(26, 0, gpio, pll1_sysclk4, gpio_clkdev, 0), - LPSC(27, 0, timer0, pll1_auxclk, timer0_clkdev, LPSC_ALWAYS_ENABLED), - LPSC(28, 0, timer1, pll1_auxclk, NULL, 0), - /* REVISIT: why can't this be disabled? */ - LPSC(29, 0, timer2, pll1_auxclk, timer2_clkdev, LPSC_ALWAYS_ENABLED), - LPSC(31, 0, arm, pll2_sysclk2, NULL, LPSC_ALWAYS_ENABLED), - LPSC(38, 0, spi3, pll1_sysclk4, spi3_clkdev, 0), - LPSC(39, 0, spi4, pll1_auxclk, spi4_clkdev, 0), - LPSC(40, 0, emac, pll1_sysclk4, emac_clkdev, 0), - /* - * The TRM (ARM Subsystem User's Guide) shows two clocks input into - * voice codec module (PLL2 SYSCLK4 with a DIV2 and PLL1 SYSCLK4). Its - * not fully clear from documentation which clock should be considered - * as parent for PSC. The clock chosen here is to maintain - * compatibility with existing code in arch/arm/mach-davinci/dm365.c - */ - LPSC(44, 0, voice_codec, pll2_sysclk4, voice_codec_clkdev, 0), - /* - * Its not fully clear from TRM (ARM Subsystem User's Guide) as to what - * the parent of VPSS DAC LPSC should actually be. PLL1 SYSCLK3 feeds - * into HDVICP and MJCP. The clock chosen here is to remain compatible - * with code existing in arch/arm/mach-davinci/dm365.c - */ - LPSC(46, 0, vpss_dac, pll1_sysclk3, vpss_dac_clkdev, 0), - LPSC(47, 0, vpss_master, pll1_sysclk5, vpss_master_clkdev, 0), - LPSC(50, 0, mjcp, pll1_sysclk3, NULL, 0), - { } -}; - -int dm365_psc_init(struct device *dev, void __iomem *base) -{ - return davinci_psc_register_clocks(dev, dm365_psc_info, 52, base); -} - -static struct clk_bulk_data dm365_psc_parent_clks[] = { - { .id = "pll1_sysclk1" }, - { .id = "pll1_sysclk3" }, - { .id = "pll1_sysclk4" }, - { .id = "pll1_sysclk5" }, - { .id = "pll1_sysclk8" }, - { .id = "pll2_sysclk2" }, - { .id = "pll2_sysclk4" }, - { .id = "pll1_auxclk" }, -}; - -const struct davinci_psc_init_data dm365_psc_init_data = { - .parent_clks = dm365_psc_parent_clks, - .num_parent_clks = ARRAY_SIZE(dm365_psc_parent_clks), - .psc_init = &dm365_psc_init, -}; diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c index 42a59dbd49c8..cd85d9f158b0 100644 --- a/drivers/clk/davinci/psc.c +++ b/drivers/clk/davinci/psc.c @@ -511,12 +511,6 @@ static const struct platform_device_id davinci_psc_id_table[] = { { .name = "da850-psc0", .driver_data = (kernel_ulong_t)&da850_psc0_init_data }, { .name = "da850-psc1", .driver_data = (kernel_ulong_t)&da850_psc1_init_data }, #endif -#ifdef CONFIG_ARCH_DAVINCI_DM355 - { .name = "dm355-psc", .driver_data = (kernel_ulong_t)&dm355_psc_init_data }, -#endif -#ifdef CONFIG_ARCH_DAVINCI_DM365 - { .name = "dm365-psc", .driver_data = (kernel_ulong_t)&dm365_psc_init_data }, -#endif { } }; diff --git a/drivers/clk/davinci/psc.h b/drivers/clk/davinci/psc.h index 5e382b675518..bd23f6fd56df 100644 --- a/drivers/clk/davinci/psc.h +++ b/drivers/clk/davinci/psc.h @@ -104,11 +104,4 @@ extern const struct davinci_psc_init_data da850_psc1_init_data; extern const struct davinci_psc_init_data of_da850_psc0_init_data; extern const struct davinci_psc_init_data of_da850_psc1_init_data; #endif -#ifdef CONFIG_ARCH_DAVINCI_DM355 -extern const struct davinci_psc_init_data dm355_psc_init_data; -#endif -#ifdef CONFIG_ARCH_DAVINCI_DM365 -extern const struct davinci_psc_init_data dm365_psc_init_data; -#endif - #endif /* __CLK_DAVINCI_PSC_H__ */ diff --git a/drivers/clk/ingenic/jz4760-cgu.c b/drivers/clk/ingenic/jz4760-cgu.c index ecd395ac8a28..e407f00bd594 100644 --- a/drivers/clk/ingenic/jz4760-cgu.c +++ b/drivers/clk/ingenic/jz4760-cgu.c @@ -58,7 +58,7 @@ jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info, unsigned long rate, unsigned long parent_rate, unsigned int *pm, unsigned int *pn, unsigned int *pod) { - unsigned int m, n, od, m_max = (1 << pll_info->m_bits) - 2; + unsigned int m, n, od, m_max = (1 << pll_info->m_bits) - 1; /* The frequency after the N divider must be between 1 and 50 MHz. */ n = parent_rate / (1 * MHZ); @@ -66,19 +66,17 @@ jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info, /* The N divider must be >= 2. */ n = clamp_val(n, 2, 1 << pll_info->n_bits); - for (;; n >>= 1) { - od = (unsigned int)-1; + rate /= MHZ; + parent_rate /= MHZ; - do { - m = (rate / MHZ) * (1 << ++od) * n / (parent_rate / MHZ); - } while ((m > m_max || m & 1) && (od < 4)); - - if (od < 4 && m >= 4 && m <= m_max) - break; + for (m = m_max; m >= m_max && n >= 2; n--) { + m = rate * n / parent_rate; + od = m & 1; + m <<= od; } *pm = m; - *pn = n; + *pn = n + 1; *pod = 1 << od; } diff --git a/drivers/clk/microchip/clk-mpfs-ccc.c b/drivers/clk/microchip/clk-mpfs-ccc.c index 32aae880a14f..0ddc73e07be4 100644 --- a/drivers/clk/microchip/clk-mpfs-ccc.c +++ b/drivers/clk/microchip/clk-mpfs-ccc.c @@ -164,12 +164,11 @@ static int mpfs_ccc_register_outputs(struct device *dev, struct mpfs_ccc_out_hw_ for (unsigned int i = 0; i < num_clks; i++) { struct mpfs_ccc_out_hw_clock *out_hw = &out_hws[i]; - char *name = devm_kzalloc(dev, 23, GFP_KERNEL); + char *name = devm_kasprintf(dev, GFP_KERNEL, "%s_out%u", parent->name, i); if (!name) return -ENOMEM; - snprintf(name, 23, "%s_out%u", parent->name, i); out_hw->divider.hw.init = CLK_HW_INIT_HW(name, &parent->hw, &clk_divider_ops, 0); out_hw->divider.reg = data->pll_base[i / MPFS_CCC_OUTPUTS_PER_PLL] + out_hw->reg_offset; @@ -201,14 +200,13 @@ static int mpfs_ccc_register_plls(struct device *dev, struct mpfs_ccc_pll_hw_clo for (unsigned int i = 0; i < num_clks; i++) { struct mpfs_ccc_pll_hw_clock *pll_hw = &pll_hws[i]; - char *name = devm_kzalloc(dev, 18, GFP_KERNEL); - if (!name) + pll_hw->name = devm_kasprintf(dev, GFP_KERNEL, "ccc%s_pll%u", + strchrnul(dev->of_node->full_name, '@'), i); + if (!pll_hw->name) return -ENOMEM; pll_hw->base = data->pll_base[i]; - snprintf(name, 18, "ccc%s_pll%u", strchrnul(dev->of_node->full_name, '@'), i); - pll_hw->name = (const char *)name; pll_hw->hw.init = CLK_HW_INIT_PARENTS_DATA_FIXED_SIZE(pll_hw->name, pll_hw->parents, &mpfs_ccc_pll_ops, 0); diff --git a/drivers/clk/samsung/Kconfig b/drivers/clk/samsung/Kconfig index 8e8245ab3fd1..c07bb50513bf 100644 --- a/drivers/clk/samsung/Kconfig +++ b/drivers/clk/samsung/Kconfig @@ -94,38 +94,6 @@ config EXYNOS_CLKOUT status of the certains clocks from SoC, but it could also be tied to other devices as an input clock. -# For S3C24XX platforms, select following symbols: -config S3C2410_COMMON_CLK - bool "Samsung S3C2410 clock controller support" if COMPILE_TEST - select COMMON_CLK_SAMSUNG - help - Support for the clock controller present on the Samsung - S3C2410/S3C2440/S3C2442 SoCs. Choose Y here only if you build for - this SoC. - -config S3C2410_COMMON_DCLK - bool - select COMMON_CLK_SAMSUNG - select REGMAP_MMIO - help - Support for the dclk clock controller present on the Samsung - S3C2410/S3C2412/S3C2440/S3C2443 SoCs. Choose Y here only if you build - for this SoC. - -config S3C2412_COMMON_CLK - bool "Samsung S3C2412 clock controller support" if COMPILE_TEST - select COMMON_CLK_SAMSUNG - help - Support for the clock controller present on the Samsung S3C2412 SoCs. - Choose Y here only if you build for this SoC. - -config S3C2443_COMMON_CLK - bool "Samsung S3C2443 clock controller support" if COMPILE_TEST - select COMMON_CLK_SAMSUNG - help - Support for the clock controller present on the Samsung - S3C2416/S3C2443 SoCs. Choose Y here only if you build for this SoC. - config TESLA_FSD_COMMON_CLK bool "Tesla FSD clock controller support" if COMPILE_TEST depends on COMMON_CLK_SAMSUNG diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index 239d9eead77f..ebbeacabe88f 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -21,10 +21,6 @@ obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7885.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos850.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynosautov9.o -obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o -obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o -obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o -obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o obj-$(CONFIG_S3C64XX_COMMON_CLK) += clk-s3c64xx.o obj-$(CONFIG_S5PV210_COMMON_CLK) += clk-s5pv210.o clk-s5pv210-audss.o obj-$(CONFIG_TESLA_FSD_COMMON_CLK) += clk-fsd.o diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 0ff28938943f..df7812371d70 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -941,169 +941,6 @@ static const struct clk_ops samsung_pll6553_clk_ops = { }; /* - * PLL Clock Type of S3C24XX before S3C2443 - */ - -#define PLLS3C2410_MDIV_MASK (0xff) -#define PLLS3C2410_PDIV_MASK (0x1f) -#define PLLS3C2410_SDIV_MASK (0x3) -#define PLLS3C2410_MDIV_SHIFT (12) -#define PLLS3C2410_PDIV_SHIFT (4) -#define PLLS3C2410_SDIV_SHIFT (0) - -#define PLLS3C2410_ENABLE_REG_OFFSET 0x10 - -static unsigned long samsung_s3c2410_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct samsung_clk_pll *pll = to_clk_pll(hw); - u32 pll_con, mdiv, pdiv, sdiv; - u64 fvco = parent_rate; - - pll_con = readl_relaxed(pll->con_reg); - mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK; - pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK; - sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK; - - fvco *= (mdiv + 8); - do_div(fvco, (pdiv + 2) << sdiv); - - return (unsigned int)fvco; -} - -static unsigned long samsung_s3c2440_mpll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct samsung_clk_pll *pll = to_clk_pll(hw); - u32 pll_con, mdiv, pdiv, sdiv; - u64 fvco = parent_rate; - - pll_con = readl_relaxed(pll->con_reg); - mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK; - pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK; - sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK; - - fvco *= (2 * (mdiv + 8)); - do_div(fvco, (pdiv + 2) << sdiv); - - return (unsigned int)fvco; -} - -static int samsung_s3c2410_pll_set_rate(struct clk_hw *hw, unsigned long drate, - unsigned long prate) -{ - struct samsung_clk_pll *pll = to_clk_pll(hw); - const struct samsung_pll_rate_table *rate; - u32 tmp; - - /* Get required rate settings from table */ - rate = samsung_get_pll_settings(pll, drate); - if (!rate) { - pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, - drate, clk_hw_get_name(hw)); - return -EINVAL; - } - - tmp = readl_relaxed(pll->con_reg); - - /* Change PLL PMS values */ - tmp &= ~((PLLS3C2410_MDIV_MASK << PLLS3C2410_MDIV_SHIFT) | - (PLLS3C2410_PDIV_MASK << PLLS3C2410_PDIV_SHIFT) | - (PLLS3C2410_SDIV_MASK << PLLS3C2410_SDIV_SHIFT)); - tmp |= (rate->mdiv << PLLS3C2410_MDIV_SHIFT) | - (rate->pdiv << PLLS3C2410_PDIV_SHIFT) | - (rate->sdiv << PLLS3C2410_SDIV_SHIFT); - writel_relaxed(tmp, pll->con_reg); - - /* Time to settle according to the manual */ - udelay(300); - - return 0; -} - -static int samsung_s3c2410_pll_enable(struct clk_hw *hw, int bit, bool enable) -{ - struct samsung_clk_pll *pll = to_clk_pll(hw); - u32 pll_en = readl_relaxed(pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET); - u32 pll_en_orig = pll_en; - - if (enable) - pll_en &= ~BIT(bit); - else - pll_en |= BIT(bit); - - writel_relaxed(pll_en, pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET); - - /* if we started the UPLL, then allow to settle */ - if (enable && (pll_en_orig & BIT(bit))) - udelay(300); - - return 0; -} - -static int samsung_s3c2410_mpll_enable(struct clk_hw *hw) -{ - return samsung_s3c2410_pll_enable(hw, 5, true); -} - -static void samsung_s3c2410_mpll_disable(struct clk_hw *hw) -{ - samsung_s3c2410_pll_enable(hw, 5, false); -} - -static int samsung_s3c2410_upll_enable(struct clk_hw *hw) -{ - return samsung_s3c2410_pll_enable(hw, 7, true); -} - -static void samsung_s3c2410_upll_disable(struct clk_hw *hw) -{ - samsung_s3c2410_pll_enable(hw, 7, false); -} - -static const struct clk_ops samsung_s3c2410_mpll_clk_min_ops = { - .recalc_rate = samsung_s3c2410_pll_recalc_rate, - .enable = samsung_s3c2410_mpll_enable, - .disable = samsung_s3c2410_mpll_disable, -}; - -static const struct clk_ops samsung_s3c2410_upll_clk_min_ops = { - .recalc_rate = samsung_s3c2410_pll_recalc_rate, - .enable = samsung_s3c2410_upll_enable, - .disable = samsung_s3c2410_upll_disable, -}; - -static const struct clk_ops samsung_s3c2440_mpll_clk_min_ops = { - .recalc_rate = samsung_s3c2440_mpll_recalc_rate, - .enable = samsung_s3c2410_mpll_enable, - .disable = samsung_s3c2410_mpll_disable, -}; - -static const struct clk_ops samsung_s3c2410_mpll_clk_ops = { - .recalc_rate = samsung_s3c2410_pll_recalc_rate, - .enable = samsung_s3c2410_mpll_enable, - .disable = samsung_s3c2410_mpll_disable, - .round_rate = samsung_pll_round_rate, - .set_rate = samsung_s3c2410_pll_set_rate, -}; - -static const struct clk_ops samsung_s3c2410_upll_clk_ops = { - .recalc_rate = samsung_s3c2410_pll_recalc_rate, - .enable = samsung_s3c2410_upll_enable, - .disable = samsung_s3c2410_upll_disable, - .round_rate = samsung_pll_round_rate, - .set_rate = samsung_s3c2410_pll_set_rate, -}; - -static const struct clk_ops samsung_s3c2440_mpll_clk_ops = { - .recalc_rate = samsung_s3c2440_mpll_recalc_rate, - .enable = samsung_s3c2410_mpll_enable, - .disable = samsung_s3c2410_mpll_disable, - .round_rate = samsung_pll_round_rate, - .set_rate = samsung_s3c2410_pll_set_rate, -}; - -/* * PLL2550x Clock Type */ @@ -1530,24 +1367,6 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, else init.ops = &samsung_pll46xx_clk_ops; break; - case pll_s3c2410_mpll: - if (!pll->rate_table) - init.ops = &samsung_s3c2410_mpll_clk_min_ops; - else - init.ops = &samsung_s3c2410_mpll_clk_ops; - break; - case pll_s3c2410_upll: - if (!pll->rate_table) - init.ops = &samsung_s3c2410_upll_clk_min_ops; - else - init.ops = &samsung_s3c2410_upll_clk_ops; - break; - case pll_s3c2440_mpll: - if (!pll->rate_table) - init.ops = &samsung_s3c2440_mpll_clk_min_ops; - else - init.ops = &samsung_s3c2440_mpll_clk_ops; - break; case pll_2550x: init.ops = &samsung_pll2550x_clk_ops; break; diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index a9892c2d1f57..5d5a58d40e7e 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -25,9 +25,6 @@ enum samsung_pll_type { pll_6552, pll_6552_s3c2416, pll_6553, - pll_s3c2410_mpll, - pll_s3c2410_upll, - pll_s3c2440_mpll, pll_2550x, pll_2550xx, pll_2650x, @@ -56,24 +53,6 @@ enum samsung_pll_type { .sdiv = (_s), \ } -#define PLL_S3C2410_MPLL_RATE(_fin, _rate, _m, _p, _s) \ - { \ - .rate = PLL_VALID_RATE(_fin, _rate, \ - _m + 8, _p + 2, _s, 0, 16), \ - .mdiv = (_m), \ - .pdiv = (_p), \ - .sdiv = (_s), \ - } - -#define PLL_S3C2440_MPLL_RATE(_fin, _rate, _m, _p, _s) \ - { \ - .rate = PLL_VALID_RATE(_fin, _rate, \ - 2 * (_m + 8), _p + 2, _s, 0, 16), \ - .mdiv = (_m), \ - .pdiv = (_p), \ - .sdiv = (_s), \ - } - #define PLL_36XX_RATE(_fin, _rate, _m, _p, _s, _k) \ { \ .rate = PLL_VALID_RATE(_fin, _rate, \ diff --git a/drivers/clk/samsung/clk-s3c2410-dclk.c b/drivers/clk/samsung/clk-s3c2410-dclk.c deleted file mode 100644 index f5e0a6ba2d12..000000000000 --- a/drivers/clk/samsung/clk-s3c2410-dclk.c +++ /dev/null @@ -1,440 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de> - * - * Common Clock Framework support for s3c24xx external clock output. - */ - -#include <linux/clkdev.h> -#include <linux/slab.h> -#include <linux/clk.h> -#include <linux/clk-provider.h> -#include <linux/io.h> -#include <linux/platform_device.h> -#include <linux/platform_data/clk-s3c2410.h> -#include <linux/module.h> -#include "clk.h" - -#define MUX_DCLK0 0 -#define MUX_DCLK1 1 -#define DIV_DCLK0 2 -#define DIV_DCLK1 3 -#define GATE_DCLK0 4 -#define GATE_DCLK1 5 -#define MUX_CLKOUT0 6 -#define MUX_CLKOUT1 7 -#define DCLK_MAX_CLKS (MUX_CLKOUT1 + 1) - -enum supported_socs { - S3C2410, - S3C2412, - S3C2440, - S3C2443, -}; - -struct s3c24xx_dclk_drv_data { - const char **clkout0_parent_names; - int clkout0_num_parents; - const char **clkout1_parent_names; - int clkout1_num_parents; - const char **mux_parent_names; - int mux_num_parents; -}; - -/* - * Clock for output-parent selection in misccr - */ - -struct s3c24xx_clkout { - struct clk_hw hw; - u32 mask; - u8 shift; - unsigned int (*modify_misccr)(unsigned int clr, unsigned int chg); -}; - -#define to_s3c24xx_clkout(_hw) container_of(_hw, struct s3c24xx_clkout, hw) - -static u8 s3c24xx_clkout_get_parent(struct clk_hw *hw) -{ - struct s3c24xx_clkout *clkout = to_s3c24xx_clkout(hw); - int num_parents = clk_hw_get_num_parents(hw); - u32 val; - - val = clkout->modify_misccr(0, 0) >> clkout->shift; - val >>= clkout->shift; - val &= clkout->mask; - - if (val >= num_parents) - return -EINVAL; - - return val; -} - -static int s3c24xx_clkout_set_parent(struct clk_hw *hw, u8 index) -{ - struct s3c24xx_clkout *clkout = to_s3c24xx_clkout(hw); - - clkout->modify_misccr((clkout->mask << clkout->shift), - (index << clkout->shift)); - - return 0; -} - -static const struct clk_ops s3c24xx_clkout_ops = { - .get_parent = s3c24xx_clkout_get_parent, - .set_parent = s3c24xx_clkout_set_parent, - .determine_rate = __clk_mux_determine_rate, -}; - -static struct clk_hw *s3c24xx_register_clkout(struct device *dev, - const char *name, const char **parent_names, u8 num_parents, - u8 shift, u32 mask) -{ - struct s3c2410_clk_platform_data *pdata = dev_get_platdata(dev); - struct s3c24xx_clkout *clkout; - struct clk_init_data init; - int ret; - - if (!pdata) - return ERR_PTR(-EINVAL); - - /* allocate the clkout */ - clkout = kzalloc(sizeof(*clkout), GFP_KERNEL); - if (!clkout) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.ops = &s3c24xx_clkout_ops; - init.flags = 0; - init.parent_names = parent_names; - init.num_parents = num_parents; - - clkout->shift = shift; - clkout->mask = mask; - clkout->hw.init = &init; - clkout->modify_misccr = pdata->modify_misccr; - - ret = clk_hw_register(dev, &clkout->hw); - if (ret) - return ERR_PTR(ret); - - return &clkout->hw; -} - -/* - * dclk and clkout init - */ - -struct s3c24xx_dclk { - struct device *dev; - void __iomem *base; - struct notifier_block dclk0_div_change_nb; - struct notifier_block dclk1_div_change_nb; - spinlock_t dclk_lock; - unsigned long reg_save; - /* clk_data must be the last entry in the structure */ - struct clk_hw_onecell_data clk_data; -}; - -#define to_s3c24xx_dclk0(x) \ - container_of(x, struct s3c24xx_dclk, dclk0_div_change_nb) - -#define to_s3c24xx_dclk1(x) \ - container_of(x, struct s3c24xx_dclk, dclk1_div_change_nb) - -static const char *dclk_s3c2410_p[] = { "pclk", "uclk" }; -static const char *clkout0_s3c2410_p[] = { "mpll", "upll", "fclk", "hclk", "pclk", - "gate_dclk0" }; -static const char *clkout1_s3c2410_p[] = { "mpll", "upll", "fclk", "hclk", "pclk", - "gate_dclk1" }; - -static const char *clkout0_s3c2412_p[] = { "mpll", "upll", "rtc_clkout", - "hclk", "pclk", "gate_dclk0" }; -static const char *clkout1_s3c2412_p[] = { "xti", "upll", "fclk", "hclk", "pclk", - "gate_dclk1" }; - -static const char *clkout0_s3c2440_p[] = { "xti", "upll", "fclk", "hclk", "pclk", - "gate_dclk0" }; -static const char *clkout1_s3c2440_p[] = { "mpll", "upll", "rtc_clkout", - "hclk", "pclk", "gate_dclk1" }; - -static const char *dclk_s3c2443_p[] = { "pclk", "epll" }; -static const char *clkout0_s3c2443_p[] = { "xti", "epll", "armclk", "hclk", "pclk", - "gate_dclk0" }; -static const char *clkout1_s3c2443_p[] = { "dummy", "epll", "rtc_clkout", - "hclk", "pclk", "gate_dclk1" }; - -#define DCLKCON_DCLK_DIV_MASK 0xf -#define DCLKCON_DCLK0_DIV_SHIFT 4 -#define DCLKCON_DCLK0_CMP_SHIFT 8 -#define DCLKCON_DCLK1_DIV_SHIFT 20 -#define DCLKCON_DCLK1_CMP_SHIFT 24 - -static void s3c24xx_dclk_update_cmp(struct s3c24xx_dclk *s3c24xx_dclk, - int div_shift, int cmp_shift) -{ - unsigned long flags = 0; - u32 dclk_con, div, cmp; - - spin_lock_irqsave(&s3c24xx_dclk->dclk_lock, flags); - - dclk_con = readl_relaxed(s3c24xx_dclk->base); - - div = ((dclk_con >> div_shift) & DCLKCON_DCLK_DIV_MASK) + 1; - cmp = ((div + 1) / 2) - 1; - - dclk_con &= ~(DCLKCON_DCLK_DIV_MASK << cmp_shift); - dclk_con |= (cmp << cmp_shift); - - writel_relaxed(dclk_con, s3c24xx_dclk->base); - - spin_unlock_irqrestore(&s3c24xx_dclk->dclk_lock, flags); -} - -static int s3c24xx_dclk0_div_notify(struct notifier_block *nb, - unsigned long event, void *data) -{ - struct s3c24xx_dclk *s3c24xx_dclk = to_s3c24xx_dclk0(nb); - - if (event == POST_RATE_CHANGE) { - s3c24xx_dclk_update_cmp(s3c24xx_dclk, - DCLKCON_DCLK0_DIV_SHIFT, DCLKCON_DCLK0_CMP_SHIFT); - } - - return NOTIFY_DONE; -} - -static int s3c24xx_dclk1_div_notify(struct notifier_block *nb, - unsigned long event, void *data) -{ - struct s3c24xx_dclk *s3c24xx_dclk = to_s3c24xx_dclk1(nb); - - if (event == POST_RATE_CHANGE) { - s3c24xx_dclk_update_cmp(s3c24xx_dclk, - DCLKCON_DCLK1_DIV_SHIFT, DCLKCON_DCLK1_CMP_SHIFT); - } - - return NOTIFY_DONE; -} - -#ifdef CONFIG_PM_SLEEP -static int s3c24xx_dclk_suspend(struct device *dev) -{ - struct s3c24xx_dclk *s3c24xx_dclk = dev_get_drvdata(dev); - - s3c24xx_dclk->reg_save = readl_relaxed(s3c24xx_dclk->base); - return 0; -} - -static int s3c24xx_dclk_resume(struct device *dev) -{ - struct s3c24xx_dclk *s3c24xx_dclk = dev_get_drvdata(dev); - - writel_relaxed(s3c24xx_dclk->reg_save, s3c24xx_dclk->base); - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(s3c24xx_dclk_pm_ops, - s3c24xx_dclk_suspend, s3c24xx_dclk_resume); - -static int s3c24xx_dclk_probe(struct platform_device *pdev) -{ - struct s3c24xx_dclk *s3c24xx_dclk; - struct s3c24xx_dclk_drv_data *dclk_variant; - struct clk_hw **clk_table; - int ret, i; - - s3c24xx_dclk = devm_kzalloc(&pdev->dev, - struct_size(s3c24xx_dclk, clk_data.hws, - DCLK_MAX_CLKS), - GFP_KERNEL); - if (!s3c24xx_dclk) - return -ENOMEM; - - clk_table = s3c24xx_dclk->clk_data.hws; - - s3c24xx_dclk->dev = &pdev->dev; - s3c24xx_dclk->clk_data.num = DCLK_MAX_CLKS; - platform_set_drvdata(pdev, s3c24xx_dclk); - spin_lock_init(&s3c24xx_dclk->dclk_lock); - - s3c24xx_dclk->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(s3c24xx_dclk->base)) - return PTR_ERR(s3c24xx_dclk->base); - - dclk_variant = (struct s3c24xx_dclk_drv_data *) - platform_get_device_id(pdev)->driver_data; - - - clk_table[MUX_DCLK0] = clk_hw_register_mux(&pdev->dev, "mux_dclk0", - dclk_variant->mux_parent_names, - dclk_variant->mux_num_parents, 0, - s3c24xx_dclk->base, 1, 1, 0, - &s3c24xx_dclk->dclk_lock); - clk_table[MUX_DCLK1] = clk_hw_register_mux(&pdev->dev, "mux_dclk1", - dclk_variant->mux_parent_names, - dclk_variant->mux_num_parents, 0, - s3c24xx_dclk->base, 17, 1, 0, - &s3c24xx_dclk->dclk_lock); - - clk_table[DIV_DCLK0] = clk_hw_register_divider(&pdev->dev, "div_dclk0", - "mux_dclk0", 0, s3c24xx_dclk->base, - 4, 4, 0, &s3c24xx_dclk->dclk_lock); - clk_table[DIV_DCLK1] = clk_hw_register_divider(&pdev->dev, "div_dclk1", - "mux_dclk1", 0, s3c24xx_dclk->base, - 20, 4, 0, &s3c24xx_dclk->dclk_lock); - - clk_table[GATE_DCLK0] = clk_hw_register_gate(&pdev->dev, "gate_dclk0", - "div_dclk0", CLK_SET_RATE_PARENT, - s3c24xx_dclk->base, 0, 0, - &s3c24xx_dclk->dclk_lock); - clk_table[GATE_DCLK1] = clk_hw_register_gate(&pdev->dev, "gate_dclk1", - "div_dclk1", CLK_SET_RATE_PARENT, - s3c24xx_dclk->base, 16, 0, - &s3c24xx_dclk->dclk_lock); - - clk_table[MUX_CLKOUT0] = s3c24xx_register_clkout(&pdev->dev, - "clkout0", dclk_variant->clkout0_parent_names, - dclk_variant->clkout0_num_parents, 4, 7); - clk_table[MUX_CLKOUT1] = s3c24xx_register_clkout(&pdev->dev, - "clkout1", dclk_variant->clkout1_parent_names, - dclk_variant->clkout1_num_parents, 8, 7); - - for (i = 0; i < DCLK_MAX_CLKS; i++) - if (IS_ERR(clk_table[i])) { - dev_err(&pdev->dev, "clock %d failed to register\n", i); - ret = PTR_ERR(clk_table[i]); - goto err_clk_register; - } - - ret = clk_hw_register_clkdev(clk_table[MUX_DCLK0], "dclk0", NULL); - if (!ret) - ret = clk_hw_register_clkdev(clk_table[MUX_DCLK1], "dclk1", - NULL); - if (!ret) - ret = clk_hw_register_clkdev(clk_table[MUX_CLKOUT0], - "clkout0", NULL); - if (!ret) - ret = clk_hw_register_clkdev(clk_table[MUX_CLKOUT1], - "clkout1", NULL); - if (ret) { - dev_err(&pdev->dev, "failed to register aliases, %d\n", ret); - goto err_clk_register; - } - - s3c24xx_dclk->dclk0_div_change_nb.notifier_call = - s3c24xx_dclk0_div_notify; - - s3c24xx_dclk->dclk1_div_change_nb.notifier_call = - s3c24xx_dclk1_div_notify; - - ret = clk_notifier_register(clk_table[DIV_DCLK0]->clk, - &s3c24xx_dclk->dclk0_div_change_nb); - if (ret) - goto err_clk_register; - - ret = clk_notifier_register(clk_table[DIV_DCLK1]->clk, - &s3c24xx_dclk->dclk1_div_change_nb); - if (ret) - goto err_dclk_notify; - - return 0; - -err_dclk_notify: - clk_notifier_unregister(clk_table[DIV_DCLK0]->clk, - &s3c24xx_dclk->dclk0_div_change_nb); -err_clk_register: - for (i = 0; i < DCLK_MAX_CLKS; i++) - if (clk_table[i] && !IS_ERR(clk_table[i])) - clk_hw_unregister(clk_table[i]); - - return ret; -} - -static int s3c24xx_dclk_remove(struct platform_device *pdev) -{ - struct s3c24xx_dclk *s3c24xx_dclk = platform_get_drvdata(pdev); - struct clk_hw **clk_table = s3c24xx_dclk->clk_data.hws; - int i; - - clk_notifier_unregister(clk_table[DIV_DCLK1]->clk, - &s3c24xx_dclk->dclk1_div_change_nb); - clk_notifier_unregister(clk_table[DIV_DCLK0]->clk, - &s3c24xx_dclk->dclk0_div_change_nb); - - for (i = 0; i < DCLK_MAX_CLKS; i++) - clk_hw_unregister(clk_table[i]); - - return 0; -} - -static struct s3c24xx_dclk_drv_data dclk_variants[] = { - [S3C2410] = { - .clkout0_parent_names = clkout0_s3c2410_p, - .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2410_p), - .clkout1_parent_names = clkout1_s3c2410_p, - .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2410_p), - .mux_parent_names = dclk_s3c2410_p, - .mux_num_parents = ARRAY_SIZE(dclk_s3c2410_p), - }, - [S3C2412] = { - .clkout0_parent_names = clkout0_s3c2412_p, - .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2412_p), - .clkout1_parent_names = clkout1_s3c2412_p, - .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2412_p), - .mux_parent_names = dclk_s3c2410_p, - .mux_num_parents = ARRAY_SIZE(dclk_s3c2410_p), - }, - [S3C2440] = { - .clkout0_parent_names = clkout0_s3c2440_p, - .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2440_p), - .clkout1_parent_names = clkout1_s3c2440_p, - .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2440_p), - .mux_parent_names = dclk_s3c2410_p, - .mux_num_parents = ARRAY_SIZE(dclk_s3c2410_p), - }, - [S3C2443] = { - .clkout0_parent_names = clkout0_s3c2443_p, - .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2443_p), - .clkout1_parent_names = clkout1_s3c2443_p, - .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2443_p), - .mux_parent_names = dclk_s3c2443_p, - .mux_num_parents = ARRAY_SIZE(dclk_s3c2443_p), - }, -}; - -static const struct platform_device_id s3c24xx_dclk_driver_ids[] = { - { - .name = "s3c2410-dclk", - .driver_data = (kernel_ulong_t)&dclk_variants[S3C2410], - }, { - .name = "s3c2412-dclk", - .driver_data = (kernel_ulong_t)&dclk_variants[S3C2412], - }, { - .name = "s3c2440-dclk", - .driver_data = (kernel_ulong_t)&dclk_variants[S3C2440], - }, { - .name = "s3c2443-dclk", - .driver_data = (kernel_ulong_t)&dclk_variants[S3C2443], - }, - { } -}; - -MODULE_DEVICE_TABLE(platform, s3c24xx_dclk_driver_ids); - -static struct platform_driver s3c24xx_dclk_driver = { - .driver = { - .name = "s3c24xx-dclk", - .pm = &s3c24xx_dclk_pm_ops, - .suppress_bind_attrs = true, - }, - .probe = s3c24xx_dclk_probe, - .remove = s3c24xx_dclk_remove, - .id_table = s3c24xx_dclk_driver_ids, -}; -module_platform_driver(s3c24xx_dclk_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); -MODULE_DESCRIPTION("Driver for the S3C24XX external clock outputs"); diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c deleted file mode 100644 index 3d152a46169b..000000000000 --- a/drivers/clk/samsung/clk-s3c2410.c +++ /dev/null @@ -1,446 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de> - * - * Common Clock Framework support for S3C2410 and following SoCs. - */ - -#include <linux/clk-provider.h> -#include <linux/clk/samsung.h> -#include <linux/of.h> -#include <linux/of_address.h> - -#include <dt-bindings/clock/s3c2410.h> - -#include "clk.h" -#include "clk-pll.h" - -#define LOCKTIME 0x00 -#define MPLLCON 0x04 -#define UPLLCON 0x08 -#define CLKCON 0x0c -#define CLKSLOW 0x10 -#define CLKDIVN 0x14 -#define CAMDIVN 0x18 - -/* the soc types */ -enum supported_socs { - S3C2410, - S3C2440, - S3C2442, -}; - -/* list of PLLs to be registered */ -enum s3c2410_plls { - mpll, upll, -}; - -static void __iomem *reg_base; - -/* - * list of controller registers to be saved and restored during a - * suspend/resume cycle. - */ -static unsigned long s3c2410_clk_regs[] __initdata = { - LOCKTIME, - MPLLCON, - UPLLCON, - CLKCON, - CLKSLOW, - CLKDIVN, - CAMDIVN, -}; - -PNAME(fclk_p) = { "mpll", "div_slow" }; - -static struct samsung_mux_clock s3c2410_common_muxes[] __initdata = { - MUX(FCLK, "fclk", fclk_p, CLKSLOW, 4, 1), -}; - -static struct clk_div_table divslow_d[] = { - { .val = 0, .div = 1 }, - { .val = 1, .div = 2 }, - { .val = 2, .div = 4 }, - { .val = 3, .div = 6 }, - { .val = 4, .div = 8 }, - { .val = 5, .div = 10 }, - { .val = 6, .div = 12 }, - { .val = 7, .div = 14 }, - { /* sentinel */ }, -}; - -static struct samsung_div_clock s3c2410_common_dividers[] __initdata = { - DIV_T(0, "div_slow", "xti", CLKSLOW, 0, 3, divslow_d), - DIV(PCLK, "pclk", "hclk", CLKDIVN, 0, 1), -}; - -static struct samsung_gate_clock s3c2410_common_gates[] __initdata = { - GATE(PCLK_SPI, "spi", "pclk", CLKCON, 18, 0, 0), - GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 17, 0, 0), - GATE(PCLK_I2C, "i2c", "pclk", CLKCON, 16, 0, 0), - GATE(PCLK_ADC, "adc", "pclk", CLKCON, 15, 0, 0), - GATE(PCLK_RTC, "rtc", "pclk", CLKCON, 14, 0, 0), - GATE(PCLK_GPIO, "gpio", "pclk", CLKCON, 13, CLK_IGNORE_UNUSED, 0), - GATE(PCLK_UART2, "uart2", "pclk", CLKCON, 12, 0, 0), - GATE(PCLK_UART1, "uart1", "pclk", CLKCON, 11, 0, 0), - GATE(PCLK_UART0, "uart0", "pclk", CLKCON, 10, 0, 0), - GATE(PCLK_SDI, "sdi", "pclk", CLKCON, 9, 0, 0), - GATE(PCLK_PWM, "pwm", "pclk", CLKCON, 8, 0, 0), - GATE(HCLK_USBD, "usb-device", "hclk", CLKCON, 7, 0, 0), - GATE(HCLK_USBH, "usb-host", "hclk", CLKCON, 6, 0, 0), - GATE(HCLK_LCD, "lcd", "hclk", CLKCON, 5, 0, 0), - GATE(HCLK_NAND, "nand", "hclk", CLKCON, 4, 0, 0), -}; - -/* should be added _after_ the soc-specific clocks are created */ -static struct samsung_clock_alias s3c2410_common_aliases[] __initdata = { - ALIAS(PCLK_I2C, "s3c2410-i2c.0", "i2c"), - ALIAS(PCLK_ADC, NULL, "adc"), - ALIAS(PCLK_RTC, NULL, "rtc"), - ALIAS(PCLK_PWM, NULL, "timers"), - ALIAS(HCLK_LCD, NULL, "lcd"), - ALIAS(HCLK_USBD, NULL, "usb-device"), - ALIAS(HCLK_USBH, NULL, "usb-host"), - ALIAS(UCLK, NULL, "usb-bus-host"), - ALIAS(UCLK, NULL, "usb-bus-gadget"), - ALIAS(ARMCLK, NULL, "armclk"), - ALIAS(UCLK, NULL, "uclk"), - ALIAS(HCLK, NULL, "hclk"), - ALIAS(MPLL, NULL, "mpll"), - ALIAS(FCLK, NULL, "fclk"), - ALIAS(PCLK, NULL, "watchdog"), - ALIAS(PCLK_SDI, NULL, "sdi"), - ALIAS(HCLK_NAND, NULL, "nand"), - ALIAS(PCLK_I2S, NULL, "iis"), - ALIAS(PCLK_I2C, NULL, "i2c"), -}; - -/* S3C2410 specific clocks */ - -static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = { - /* sorted in descending order */ - /* 2410A extras */ - PLL_S3C2410_MPLL_RATE(12 * MHZ, 270000000, 127, 1, 1), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 268000000, 126, 1, 1), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 266000000, 125, 1, 1), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 226000000, 105, 1, 1), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 210000000, 132, 2, 1), - /* 2410 common */ - PLL_S3C2410_MPLL_RATE(12 * MHZ, 202800000, 161, 3, 1), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 192000000, 88, 1, 1), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 186000000, 85, 1, 1), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 180000000, 82, 1, 1), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 170000000, 77, 1, 1), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 158000000, 71, 1, 1), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 152000000, 68, 1, 1), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 147000000, 90, 2, 1), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 135000000, 82, 2, 1), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 124000000, 116, 1, 2), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 118500000, 150, 2, 2), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 113000000, 105, 1, 2), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 101250000, 127, 2, 2), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 90000000, 112, 2, 2), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 84750000, 105, 2, 2), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 79000000, 71, 1, 2), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 67500000, 82, 2, 2), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 56250000, 142, 2, 3), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 48000000, 120, 2, 3), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 50700000, 161, 3, 3), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 45000000, 82, 1, 3), - PLL_S3C2410_MPLL_RATE(12 * MHZ, 33750000, 82, 2, 3), - { /* sentinel */ }, -}; - -static struct samsung_pll_clock s3c2410_plls[] __initdata = { - [mpll] = PLL(pll_s3c2410_mpll, MPLL, "mpll", "xti", - LOCKTIME, MPLLCON, NULL), - [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "xti", - LOCKTIME, UPLLCON, NULL), -}; - -static struct samsung_div_clock s3c2410_dividers[] __initdata = { - DIV(HCLK, "hclk", "mpll", CLKDIVN, 1, 1), -}; - -static struct samsung_fixed_factor_clock s3c2410_ffactor[] __initdata = { - /* - * armclk is directly supplied by the fclk, without - * switching possibility like on the s3c244x below. - */ - FFACTOR(ARMCLK, "armclk", "fclk", 1, 1, 0), - - /* uclk is fed from the unmodified upll */ - FFACTOR(UCLK, "uclk", "upll", 1, 1, 0), -}; - -static struct samsung_clock_alias s3c2410_aliases[] __initdata = { - ALIAS(PCLK_UART0, "s3c2410-uart.0", "uart"), - ALIAS(PCLK_UART1, "s3c2410-uart.1", "uart"), - ALIAS(PCLK_UART2, "s3c2410-uart.2", "uart"), - ALIAS(PCLK_UART0, "s3c2410-uart.0", "clk_uart_baud0"), - ALIAS(PCLK_UART1, "s3c2410-uart.1", "clk_uart_baud0"), - ALIAS(PCLK_UART2, "s3c2410-uart.2", "clk_uart_baud0"), - ALIAS(UCLK, NULL, "clk_uart_baud1"), -}; - -/* S3C244x specific clocks */ - -static struct samsung_pll_rate_table pll_s3c244x_12mhz_tbl[] __initdata = { - /* sorted in descending order */ - PLL_S3C2440_MPLL_RATE(12 * MHZ, 400000000, 0x5c, 1, 1), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 390000000, 0x7a, 2, 1), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 380000000, 0x57, 1, 1), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 370000000, 0xb1, 4, 1), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 360000000, 0x70, 2, 1), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 350000000, 0xa7, 4, 1), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 340000000, 0x4d, 1, 1), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 330000000, 0x66, 2, 1), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 320000000, 0x98, 4, 1), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 310000000, 0x93, 4, 1), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 300000000, 0x75, 3, 1), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 240000000, 0x70, 1, 2), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 230000000, 0x6b, 1, 2), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 220000000, 0x66, 1, 2), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 210000000, 0x84, 2, 2), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 200000000, 0x5c, 1, 2), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 190000000, 0x57, 1, 2), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 180000000, 0x70, 2, 2), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 170000000, 0x4d, 1, 2), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 160000000, 0x98, 4, 2), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 150000000, 0x75, 3, 2), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 120000000, 0x70, 1, 3), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 110000000, 0x66, 1, 3), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 100000000, 0x5c, 1, 3), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 90000000, 0x70, 2, 3), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 80000000, 0x98, 4, 3), - PLL_S3C2440_MPLL_RATE(12 * MHZ, 75000000, 0x75, 3, 3), - { /* sentinel */ }, -}; - -static struct samsung_pll_clock s3c244x_common_plls[] __initdata = { - [mpll] = PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti", - LOCKTIME, MPLLCON, NULL), - [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "xti", - LOCKTIME, UPLLCON, NULL), -}; - -PNAME(hclk_p) = { "fclk", "div_hclk_2", "div_hclk_4", "div_hclk_3" }; -PNAME(armclk_p) = { "fclk", "hclk" }; - -static struct samsung_mux_clock s3c244x_common_muxes[] __initdata = { - MUX(HCLK, "hclk", hclk_p, CLKDIVN, 1, 2), - MUX(ARMCLK, "armclk", armclk_p, CAMDIVN, 12, 1), -}; - -static struct samsung_fixed_factor_clock s3c244x_common_ffactor[] __initdata = { - FFACTOR(0, "div_hclk_2", "fclk", 1, 2, 0), - FFACTOR(0, "ff_cam", "div_cam", 2, 1, CLK_SET_RATE_PARENT), -}; - -static struct clk_div_table div_hclk_4_d[] = { - { .val = 0, .div = 4 }, - { .val = 1, .div = 8 }, - { /* sentinel */ }, -}; - -static struct clk_div_table div_hclk_3_d[] = { - { .val = 0, .div = 3 }, - { .val = 1, .div = 6 }, - { /* sentinel */ }, -}; - -static struct samsung_div_clock s3c244x_common_dividers[] __initdata = { - DIV(UCLK, "uclk", "upll", CLKDIVN, 3, 1), - DIV(0, "div_hclk", "fclk", CLKDIVN, 1, 1), - DIV_T(0, "div_hclk_4", "fclk", CAMDIVN, 9, 1, div_hclk_4_d), - DIV_T(0, "div_hclk_3", "fclk", CAMDIVN, 8, 1, div_hclk_3_d), - DIV(0, "div_cam", "upll", CAMDIVN, 0, 3), -}; - -static struct samsung_gate_clock s3c244x_common_gates[] __initdata = { - GATE(HCLK_CAM, "cam", "hclk", CLKCON, 19, 0, 0), -}; - -static struct samsung_clock_alias s3c244x_common_aliases[] __initdata = { - ALIAS(PCLK_UART0, "s3c2440-uart.0", "uart"), - ALIAS(PCLK_UART1, "s3c2440-uart.1", "uart"), - ALIAS(PCLK_UART2, "s3c2440-uart.2", "uart"), - ALIAS(PCLK_UART0, "s3c2440-uart.0", "clk_uart_baud2"), - ALIAS(PCLK_UART1, "s3c2440-uart.1", "clk_uart_baud2"), - ALIAS(PCLK_UART2, "s3c2440-uart.2", "clk_uart_baud2"), - ALIAS(HCLK_CAM, NULL, "camif"), - ALIAS(CAMIF, NULL, "camif-upll"), -}; - -/* S3C2440 specific clocks */ - -PNAME(s3c2440_camif_p) = { "upll", "ff_cam" }; - -static struct samsung_mux_clock s3c2440_muxes[] __initdata = { - MUX(CAMIF, "camif", s3c2440_camif_p, CAMDIVN, 4, 1), -}; - -static struct samsung_gate_clock s3c2440_gates[] __initdata = { - GATE(PCLK_AC97, "ac97", "pclk", CLKCON, 20, 0, 0), -}; - -/* S3C2442 specific clocks */ - -static struct samsung_fixed_factor_clock s3c2442_ffactor[] __initdata = { - FFACTOR(0, "upll_3", "upll", 1, 3, 0), -}; - -PNAME(s3c2442_camif_p) = { "upll", "ff_cam", "upll", "upll_3" }; - -static struct samsung_mux_clock s3c2442_muxes[] __initdata = { - MUX(CAMIF, "camif", s3c2442_camif_p, CAMDIVN, 4, 2), -}; - -/* - * fixed rate clocks generated outside the soc - * Only necessary until the devicetree-move is complete - */ -#define XTI 1 -static struct samsung_fixed_rate_clock s3c2410_common_frate_clks[] __initdata = { - FRATE(XTI, "xti", NULL, 0, 0), -}; - -static void __init s3c2410_common_clk_register_fixed_ext( - struct samsung_clk_provider *ctx, - unsigned long xti_f) -{ - struct samsung_clock_alias xti_alias = ALIAS(XTI, NULL, "xtal"); - - s3c2410_common_frate_clks[0].fixed_rate = xti_f; - samsung_clk_register_fixed_rate(ctx, s3c2410_common_frate_clks, - ARRAY_SIZE(s3c2410_common_frate_clks)); - - samsung_clk_register_alias(ctx, &xti_alias, 1); -} - -void __init s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f, - int current_soc, - void __iomem *base) -{ - struct samsung_clk_provider *ctx; - struct clk_hw **hws; - reg_base = base; - - if (np) { - reg_base = of_iomap(np, 0); - if (!reg_base) - panic("%s: failed to map registers\n", __func__); - } - - ctx = samsung_clk_init(np, reg_base, NR_CLKS); - hws = ctx->clk_data.hws; - - /* Register external clocks only in non-dt cases */ - if (!np) - s3c2410_common_clk_register_fixed_ext(ctx, xti_f); - - if (current_soc == S3C2410) { - if (clk_hw_get_rate(hws[XTI]) == 12 * MHZ) { - s3c2410_plls[mpll].rate_table = pll_s3c2410_12mhz_tbl; - s3c2410_plls[upll].rate_table = pll_s3c2410_12mhz_tbl; - } - - /* Register PLLs. */ - samsung_clk_register_pll(ctx, s3c2410_plls, - ARRAY_SIZE(s3c2410_plls), reg_base); - - } else { /* S3C2440, S3C2442 */ - if (clk_hw_get_rate(hws[XTI]) == 12 * MHZ) { - /* - * plls follow different calculation schemes, with the - * upll following the same scheme as the s3c2410 plls - */ - s3c244x_common_plls[mpll].rate_table = - pll_s3c244x_12mhz_tbl; - s3c244x_common_plls[upll].rate_table = - pll_s3c2410_12mhz_tbl; - } - - /* Register PLLs. */ - samsung_clk_register_pll(ctx, s3c244x_common_plls, - ARRAY_SIZE(s3c244x_common_plls), reg_base); - } - - /* Register common internal clocks. */ - samsung_clk_register_mux(ctx, s3c2410_common_muxes, - ARRAY_SIZE(s3c2410_common_muxes)); - samsung_clk_register_div(ctx, s3c2410_common_dividers, - ARRAY_SIZE(s3c2410_common_dividers)); - samsung_clk_register_gate(ctx, s3c2410_common_gates, - ARRAY_SIZE(s3c2410_common_gates)); - - if (current_soc == S3C2440 || current_soc == S3C2442) { - samsung_clk_register_div(ctx, s3c244x_common_dividers, - ARRAY_SIZE(s3c244x_common_dividers)); - samsung_clk_register_gate(ctx, s3c244x_common_gates, - ARRAY_SIZE(s3c244x_common_gates)); - samsung_clk_register_mux(ctx, s3c244x_common_muxes, - ARRAY_SIZE(s3c244x_common_muxes)); - samsung_clk_register_fixed_factor(ctx, s3c244x_common_ffactor, - ARRAY_SIZE(s3c244x_common_ffactor)); - } - - /* Register SoC-specific clocks. */ - switch (current_soc) { - case S3C2410: - samsung_clk_register_div(ctx, s3c2410_dividers, - ARRAY_SIZE(s3c2410_dividers)); - samsung_clk_register_fixed_factor(ctx, s3c2410_ffactor, - ARRAY_SIZE(s3c2410_ffactor)); - samsung_clk_register_alias(ctx, s3c2410_aliases, - ARRAY_SIZE(s3c2410_aliases)); - break; - case S3C2440: - samsung_clk_register_mux(ctx, s3c2440_muxes, - ARRAY_SIZE(s3c2440_muxes)); - samsung_clk_register_gate(ctx, s3c2440_gates, - ARRAY_SIZE(s3c2440_gates)); - break; - case S3C2442: - samsung_clk_register_mux(ctx, s3c2442_muxes, - ARRAY_SIZE(s3c2442_muxes)); - samsung_clk_register_fixed_factor(ctx, s3c2442_ffactor, - ARRAY_SIZE(s3c2442_ffactor)); - break; - } - - /* - * Register common aliases at the end, as some of the aliased clocks - * are SoC specific. - */ - samsung_clk_register_alias(ctx, s3c2410_common_aliases, - ARRAY_SIZE(s3c2410_common_aliases)); - - if (current_soc == S3C2440 || current_soc == S3C2442) { - samsung_clk_register_alias(ctx, s3c244x_common_aliases, - ARRAY_SIZE(s3c244x_common_aliases)); - } - - samsung_clk_sleep_init(reg_base, s3c2410_clk_regs, - ARRAY_SIZE(s3c2410_clk_regs)); - - samsung_clk_of_add_provider(np, ctx); -} - -static void __init s3c2410_clk_init(struct device_node *np) -{ - s3c2410_common_clk_init(np, 0, S3C2410, NULL); -} -CLK_OF_DECLARE(s3c2410_clk, "samsung,s3c2410-clock", s3c2410_clk_init); - -static void __init s3c2440_clk_init(struct device_node *np) -{ - s3c2410_common_clk_init(np, 0, S3C2440, NULL); -} -CLK_OF_DECLARE(s3c2440_clk, "samsung,s3c2440-clock", s3c2440_clk_init); - -static void __init s3c2442_clk_init(struct device_node *np) -{ - s3c2410_common_clk_init(np, 0, S3C2442, NULL); -} -CLK_OF_DECLARE(s3c2442_clk, "samsung,s3c2442-clock", s3c2442_clk_init); diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c deleted file mode 100644 index 724ef642f048..000000000000 --- a/drivers/clk/samsung/clk-s3c2412.c +++ /dev/null @@ -1,254 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de> - * - * Common Clock Framework support for S3C2412 and S3C2413. - */ - -#include <linux/clk-provider.h> -#include <linux/clk/samsung.h> -#include <linux/io.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/reboot.h> - -#include <dt-bindings/clock/s3c2412.h> - -#include "clk.h" -#include "clk-pll.h" - -#define LOCKTIME 0x00 -#define MPLLCON 0x04 -#define UPLLCON 0x08 -#define CLKCON 0x0c -#define CLKDIVN 0x14 -#define CLKSRC 0x1c -#define SWRST 0x30 - -static void __iomem *reg_base; - -/* - * list of controller registers to be saved and restored during a - * suspend/resume cycle. - */ -static unsigned long s3c2412_clk_regs[] __initdata = { - LOCKTIME, - MPLLCON, - UPLLCON, - CLKCON, - CLKDIVN, - CLKSRC, -}; - -static struct clk_div_table divxti_d[] = { - { .val = 0, .div = 1 }, - { .val = 1, .div = 2 }, - { .val = 2, .div = 4 }, - { .val = 3, .div = 6 }, - { .val = 4, .div = 8 }, - { .val = 5, .div = 10 }, - { .val = 6, .div = 12 }, - { .val = 7, .div = 14 }, - { /* sentinel */ }, -}; - -static struct samsung_div_clock s3c2412_dividers[] __initdata = { - DIV_T(0, "div_xti", "xti", CLKSRC, 0, 3, divxti_d), - DIV(0, "div_cam", "mux_cam", CLKDIVN, 16, 4), - DIV(0, "div_i2s", "mux_i2s", CLKDIVN, 12, 4), - DIV(0, "div_uart", "mux_uart", CLKDIVN, 8, 4), - DIV(0, "div_usb", "mux_usb", CLKDIVN, 6, 1), - DIV(0, "div_hclk_half", "hclk", CLKDIVN, 5, 1), - DIV(ARMDIV, "armdiv", "msysclk", CLKDIVN, 3, 1), - DIV(PCLK, "pclk", "hclk", CLKDIVN, 2, 1), - DIV(HCLK, "hclk", "armdiv", CLKDIVN, 0, 2), -}; - -static struct samsung_fixed_factor_clock s3c2412_ffactor[] __initdata = { - FFACTOR(0, "ff_hclk", "hclk", 2, 1, CLK_SET_RATE_PARENT), -}; - -/* - * The first two use the OM[4] setting, which is not readable from - * software, so assume it is set to xti. - */ -PNAME(erefclk_p) = { "xti", "xti", "xti", "ext" }; -PNAME(urefclk_p) = { "xti", "xti", "xti", "ext" }; - -PNAME(camclk_p) = { "usysclk", "hclk" }; -PNAME(usbclk_p) = { "usysclk", "hclk" }; -PNAME(i2sclk_p) = { "erefclk", "mpll" }; -PNAME(uartclk_p) = { "erefclk", "mpll" }; -PNAME(usysclk_p) = { "urefclk", "upll" }; -PNAME(msysclk_p) = { "mdivclk", "mpll" }; -PNAME(mdivclk_p) = { "xti", "div_xti" }; -PNAME(armclk_p) = { "armdiv", "hclk" }; - -static struct samsung_mux_clock s3c2412_muxes[] __initdata = { - MUX(0, "erefclk", erefclk_p, CLKSRC, 14, 2), - MUX(0, "urefclk", urefclk_p, CLKSRC, 12, 2), - MUX(0, "mux_cam", camclk_p, CLKSRC, 11, 1), - MUX(0, "mux_usb", usbclk_p, CLKSRC, 10, 1), - MUX(0, "mux_i2s", i2sclk_p, CLKSRC, 9, 1), - MUX(0, "mux_uart", uartclk_p, CLKSRC, 8, 1), - MUX(USYSCLK, "usysclk", usysclk_p, CLKSRC, 5, 1), - MUX(MSYSCLK, "msysclk", msysclk_p, CLKSRC, 4, 1), - MUX(MDIVCLK, "mdivclk", mdivclk_p, CLKSRC, 3, 1), - MUX(ARMCLK, "armclk", armclk_p, CLKDIVN, 4, 1), -}; - -static struct samsung_pll_clock s3c2412_plls[] __initdata = { - PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti", LOCKTIME, MPLLCON, NULL), - PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk", LOCKTIME, UPLLCON, NULL), -}; - -static struct samsung_gate_clock s3c2412_gates[] __initdata = { - GATE(PCLK_WDT, "wdt", "pclk", CLKCON, 28, 0, 0), - GATE(PCLK_SPI, "spi", "pclk", CLKCON, 27, 0, 0), - GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 26, 0, 0), - GATE(PCLK_I2C, "i2c", "pclk", CLKCON, 25, 0, 0), - GATE(PCLK_ADC, "adc", "pclk", CLKCON, 24, 0, 0), - GATE(PCLK_RTC, "rtc", "pclk", CLKCON, 23, 0, 0), - GATE(PCLK_GPIO, "gpio", "pclk", CLKCON, 22, CLK_IGNORE_UNUSED, 0), - GATE(PCLK_UART2, "uart2", "pclk", CLKCON, 21, 0, 0), - GATE(PCLK_UART1, "uart1", "pclk", CLKCON, 20, 0, 0), - GATE(PCLK_UART0, "uart0", "pclk", CLKCON, 19, 0, 0), - GATE(PCLK_SDI, "sdi", "pclk", CLKCON, 18, 0, 0), - GATE(PCLK_PWM, "pwm", "pclk", CLKCON, 17, 0, 0), - GATE(PCLK_USBD, "usb-device", "pclk", CLKCON, 16, 0, 0), - GATE(SCLK_CAM, "sclk_cam", "div_cam", CLKCON, 15, 0, 0), - GATE(SCLK_UART, "sclk_uart", "div_uart", CLKCON, 14, 0, 0), - GATE(SCLK_I2S, "sclk_i2s", "div_i2s", CLKCON, 13, 0, 0), - GATE(SCLK_USBH, "sclk_usbh", "div_usb", CLKCON, 12, 0, 0), - GATE(SCLK_USBD, "sclk_usbd", "div_usb", CLKCON, 11, 0, 0), - GATE(HCLK_HALF, "hclk_half", "div_hclk_half", CLKCON, 10, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_X2, "hclkx2", "ff_hclk", CLKCON, 9, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_SDRAM, "sdram", "hclk", CLKCON, 8, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_USBH, "usb-host", "hclk", CLKCON, 6, 0, 0), - GATE(HCLK_LCD, "lcd", "hclk", CLKCON, 5, 0, 0), - GATE(HCLK_NAND, "nand", "hclk", CLKCON, 4, 0, 0), - GATE(HCLK_DMA3, "dma3", "hclk", CLKCON, 3, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_DMA2, "dma2", "hclk", CLKCON, 2, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_DMA1, "dma1", "hclk", CLKCON, 1, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_DMA0, "dma0", "hclk", CLKCON, 0, CLK_IGNORE_UNUSED, 0), -}; - -static struct samsung_clock_alias s3c2412_aliases[] __initdata = { - ALIAS(PCLK_UART0, "s3c2412-uart.0", "uart"), - ALIAS(PCLK_UART1, "s3c2412-uart.1", "uart"), - ALIAS(PCLK_UART2, "s3c2412-uart.2", "uart"), - ALIAS(PCLK_UART0, "s3c2412-uart.0", "clk_uart_baud2"), - ALIAS(PCLK_UART1, "s3c2412-uart.1", "clk_uart_baud2"), - ALIAS(PCLK_UART2, "s3c2412-uart.2", "clk_uart_baud2"), - ALIAS(SCLK_UART, NULL, "clk_uart_baud3"), - ALIAS(PCLK_I2C, "s3c2410-i2c.0", "i2c"), - ALIAS(PCLK_ADC, NULL, "adc"), - ALIAS(PCLK_RTC, NULL, "rtc"), - ALIAS(PCLK_PWM, NULL, "timers"), - ALIAS(HCLK_LCD, NULL, "lcd"), - ALIAS(PCLK_USBD, NULL, "usb-device"), - ALIAS(SCLK_USBD, NULL, "usb-bus-gadget"), - ALIAS(HCLK_USBH, NULL, "usb-host"), - ALIAS(SCLK_USBH, NULL, "usb-bus-host"), - ALIAS(ARMCLK, NULL, "armclk"), - ALIAS(HCLK, NULL, "hclk"), - ALIAS(MPLL, NULL, "mpll"), - ALIAS(MSYSCLK, NULL, "fclk"), -}; - -static int s3c2412_restart(struct notifier_block *this, - unsigned long mode, void *cmd) -{ - /* errata "Watch-dog/Software Reset Problem" specifies that - * this reset must be done with the SYSCLK sourced from - * EXTCLK instead of FOUT to avoid a glitch in the reset - * mechanism. - * - * See the watchdog section of the S3C2412 manual for more - * information on this fix. - */ - - __raw_writel(0x00, reg_base + CLKSRC); - __raw_writel(0x533C2412, reg_base + SWRST); - return NOTIFY_DONE; -} - -static struct notifier_block s3c2412_restart_handler = { - .notifier_call = s3c2412_restart, - .priority = 129, -}; - -/* - * fixed rate clocks generated outside the soc - * Only necessary until the devicetree-move is complete - */ -#define XTI 1 -static struct samsung_fixed_rate_clock s3c2412_common_frate_clks[] __initdata = { - FRATE(XTI, "xti", NULL, 0, 0), - FRATE(0, "ext", NULL, 0, 0), -}; - -static void __init s3c2412_common_clk_register_fixed_ext( - struct samsung_clk_provider *ctx, - unsigned long xti_f, unsigned long ext_f) -{ - /* xtal alias is necessary for the current cpufreq driver */ - struct samsung_clock_alias xti_alias = ALIAS(XTI, NULL, "xtal"); - - s3c2412_common_frate_clks[0].fixed_rate = xti_f; - s3c2412_common_frate_clks[1].fixed_rate = ext_f; - samsung_clk_register_fixed_rate(ctx, s3c2412_common_frate_clks, - ARRAY_SIZE(s3c2412_common_frate_clks)); - - samsung_clk_register_alias(ctx, &xti_alias, 1); -} - -void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f, - unsigned long ext_f, void __iomem *base) -{ - struct samsung_clk_provider *ctx; - int ret; - reg_base = base; - - if (np) { - reg_base = of_iomap(np, 0); - if (!reg_base) - panic("%s: failed to map registers\n", __func__); - } - - ctx = samsung_clk_init(np, reg_base, NR_CLKS); - - /* Register external clocks only in non-dt cases */ - if (!np) - s3c2412_common_clk_register_fixed_ext(ctx, xti_f, ext_f); - - /* Register PLLs. */ - samsung_clk_register_pll(ctx, s3c2412_plls, ARRAY_SIZE(s3c2412_plls), - reg_base); - - /* Register common internal clocks. */ - samsung_clk_register_mux(ctx, s3c2412_muxes, ARRAY_SIZE(s3c2412_muxes)); - samsung_clk_register_div(ctx, s3c2412_dividers, - ARRAY_SIZE(s3c2412_dividers)); - samsung_clk_register_gate(ctx, s3c2412_gates, - ARRAY_SIZE(s3c2412_gates)); - samsung_clk_register_fixed_factor(ctx, s3c2412_ffactor, - ARRAY_SIZE(s3c2412_ffactor)); - samsung_clk_register_alias(ctx, s3c2412_aliases, - ARRAY_SIZE(s3c2412_aliases)); - - samsung_clk_sleep_init(reg_base, s3c2412_clk_regs, - ARRAY_SIZE(s3c2412_clk_regs)); - - samsung_clk_of_add_provider(np, ctx); - - ret = register_restart_handler(&s3c2412_restart_handler); - if (ret) - pr_warn("cannot register restart handler, %d\n", ret); -} - -static void __init s3c2412_clk_init(struct device_node *np) -{ - s3c2412_common_clk_init(np, 0, 0, NULL); -} -CLK_OF_DECLARE(s3c2412_clk, "samsung,s3c2412-clock", s3c2412_clk_init); diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c deleted file mode 100644 index a827d63766d1..000000000000 --- a/drivers/clk/samsung/clk-s3c2443.c +++ /dev/null @@ -1,438 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de> - * - * Common Clock Framework support for S3C2443 and following SoCs. - */ - -#include <linux/clk-provider.h> -#include <linux/clk/samsung.h> -#include <linux/io.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/reboot.h> - -#include <dt-bindings/clock/s3c2443.h> - -#include "clk.h" -#include "clk-pll.h" - -/* S3C2416 clock controller register offsets */ -#define LOCKCON0 0x00 -#define LOCKCON1 0x04 -#define MPLLCON 0x10 -#define EPLLCON 0x18 -#define EPLLCON_K 0x1C -#define CLKSRC 0x20 -#define CLKDIV0 0x24 -#define CLKDIV1 0x28 -#define CLKDIV2 0x2C -#define HCLKCON 0x30 -#define PCLKCON 0x34 -#define SCLKCON 0x38 -#define SWRST 0x44 - -/* the soc types */ -enum supported_socs { - S3C2416, - S3C2443, - S3C2450, -}; - -static void __iomem *reg_base; - -/* - * list of controller registers to be saved and restored during a - * suspend/resume cycle. - */ -static unsigned long s3c2443_clk_regs[] __initdata = { - LOCKCON0, - LOCKCON1, - MPLLCON, - EPLLCON, - EPLLCON_K, - CLKSRC, - CLKDIV0, - CLKDIV1, - CLKDIV2, - PCLKCON, - HCLKCON, - SCLKCON, -}; - -PNAME(epllref_p) = { "mpllref", "mpllref", "xti", "ext" }; -PNAME(esysclk_p) = { "epllref", "epll" }; -PNAME(mpllref_p) = { "xti", "mdivclk" }; -PNAME(msysclk_p) = { "mpllref", "mpll" }; -PNAME(armclk_p) = { "armdiv" , "hclk" }; -PNAME(i2s0_p) = { "div_i2s0", "ext_i2s", "epllref", "epllref" }; - -static struct samsung_mux_clock s3c2443_common_muxes[] __initdata = { - MUX(0, "epllref", epllref_p, CLKSRC, 7, 2), - MUX(ESYSCLK, "esysclk", esysclk_p, CLKSRC, 6, 1), - MUX(0, "mpllref", mpllref_p, CLKSRC, 3, 1), - MUX(MSYSCLK, "msysclk", msysclk_p, CLKSRC, 4, 1), - MUX(ARMCLK, "armclk", armclk_p, CLKDIV0, 13, 1), - MUX(0, "mux_i2s0", i2s0_p, CLKSRC, 14, 2), -}; - -static struct clk_div_table hclk_d[] = { - { .val = 0, .div = 1 }, - { .val = 1, .div = 2 }, - { .val = 3, .div = 4 }, - { /* sentinel */ }, -}; - -static struct clk_div_table mdivclk_d[] = { - { .val = 0, .div = 1 }, - { .val = 1, .div = 3 }, - { .val = 2, .div = 5 }, - { .val = 3, .div = 7 }, - { .val = 4, .div = 9 }, - { .val = 5, .div = 11 }, - { .val = 6, .div = 13 }, - { .val = 7, .div = 15 }, - { /* sentinel */ }, -}; - -static struct samsung_div_clock s3c2443_common_dividers[] __initdata = { - DIV_T(0, "mdivclk", "xti", CLKDIV0, 6, 3, mdivclk_d), - DIV(0, "prediv", "msysclk", CLKDIV0, 4, 2), - DIV_T(HCLK, "hclk", "prediv", CLKDIV0, 0, 2, hclk_d), - DIV(PCLK, "pclk", "hclk", CLKDIV0, 2, 1), - DIV(0, "div_hsspi0_epll", "esysclk", CLKDIV1, 24, 2), - DIV(0, "div_fimd", "esysclk", CLKDIV1, 16, 8), - DIV(0, "div_i2s0", "esysclk", CLKDIV1, 12, 4), - DIV(0, "div_uart", "esysclk", CLKDIV1, 8, 4), - DIV(0, "div_hsmmc1", "esysclk", CLKDIV1, 6, 2), - DIV(0, "div_usbhost", "esysclk", CLKDIV1, 4, 2), -}; - -static struct samsung_gate_clock s3c2443_common_gates[] __initdata = { - GATE(SCLK_HSMMC_EXT, "sclk_hsmmcext", "ext", SCLKCON, 13, 0, 0), - GATE(SCLK_HSMMC1, "sclk_hsmmc1", "div_hsmmc1", SCLKCON, 12, 0, 0), - GATE(SCLK_FIMD, "sclk_fimd", "div_fimd", SCLKCON, 10, 0, 0), - GATE(SCLK_I2S0, "sclk_i2s0", "mux_i2s0", SCLKCON, 9, 0, 0), - GATE(SCLK_UART, "sclk_uart", "div_uart", SCLKCON, 8, 0, 0), - GATE(SCLK_USBH, "sclk_usbhost", "div_usbhost", SCLKCON, 1, 0, 0), - GATE(HCLK_DRAM, "dram", "hclk", HCLKCON, 19, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_SSMC, "ssmc", "hclk", HCLKCON, 18, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_HSMMC1, "hsmmc1", "hclk", HCLKCON, 16, 0, 0), - GATE(HCLK_USBD, "usb-device", "hclk", HCLKCON, 12, 0, 0), - GATE(HCLK_USBH, "usb-host", "hclk", HCLKCON, 11, 0, 0), - GATE(HCLK_LCD, "lcd", "hclk", HCLKCON, 9, 0, 0), - GATE(HCLK_DMA5, "dma5", "hclk", HCLKCON, 5, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_DMA4, "dma4", "hclk", HCLKCON, 4, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_DMA3, "dma3", "hclk", HCLKCON, 3, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_DMA2, "dma2", "hclk", HCLKCON, 2, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_DMA1, "dma1", "hclk", HCLKCON, 1, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_DMA0, "dma0", "hclk", HCLKCON, 0, CLK_IGNORE_UNUSED, 0), - GATE(PCLK_GPIO, "gpio", "pclk", PCLKCON, 13, CLK_IGNORE_UNUSED, 0), - GATE(PCLK_RTC, "rtc", "pclk", PCLKCON, 12, 0, 0), - GATE(PCLK_WDT, "wdt", "pclk", PCLKCON, 11, 0, 0), - GATE(PCLK_PWM, "pwm", "pclk", PCLKCON, 10, 0, 0), - GATE(PCLK_I2S0, "i2s0", "pclk", PCLKCON, 9, 0, 0), - GATE(PCLK_AC97, "ac97", "pclk", PCLKCON, 8, 0, 0), - GATE(PCLK_ADC, "adc", "pclk", PCLKCON, 7, 0, 0), - GATE(PCLK_SPI0, "spi0", "pclk", PCLKCON, 6, 0, 0), - GATE(PCLK_I2C0, "i2c0", "pclk", PCLKCON, 4, 0, 0), - GATE(PCLK_UART3, "uart3", "pclk", PCLKCON, 3, 0, 0), - GATE(PCLK_UART2, "uart2", "pclk", PCLKCON, 2, 0, 0), - GATE(PCLK_UART1, "uart1", "pclk", PCLKCON, 1, 0, 0), - GATE(PCLK_UART0, "uart0", "pclk", PCLKCON, 0, 0, 0), -}; - -static struct samsung_clock_alias s3c2443_common_aliases[] __initdata = { - ALIAS(MSYSCLK, NULL, "msysclk"), - ALIAS(ARMCLK, NULL, "armclk"), - ALIAS(MPLL, NULL, "mpll"), - ALIAS(EPLL, NULL, "epll"), - ALIAS(HCLK, NULL, "hclk"), - ALIAS(HCLK_SSMC, NULL, "nand"), - ALIAS(PCLK_UART0, "s3c2440-uart.0", "uart"), - ALIAS(PCLK_UART1, "s3c2440-uart.1", "uart"), - ALIAS(PCLK_UART2, "s3c2440-uart.2", "uart"), - ALIAS(PCLK_UART3, "s3c2440-uart.3", "uart"), - ALIAS(PCLK_UART0, "s3c2440-uart.0", "clk_uart_baud2"), - ALIAS(PCLK_UART1, "s3c2440-uart.1", "clk_uart_baud2"), - ALIAS(PCLK_UART2, "s3c2440-uart.2", "clk_uart_baud2"), - ALIAS(PCLK_UART3, "s3c2440-uart.3", "clk_uart_baud2"), - ALIAS(SCLK_UART, NULL, "clk_uart_baud3"), - ALIAS(PCLK_PWM, NULL, "timers"), - ALIAS(PCLK_RTC, NULL, "rtc"), - ALIAS(PCLK_WDT, NULL, "watchdog"), - ALIAS(PCLK_ADC, NULL, "adc"), - ALIAS(PCLK_I2C0, "s3c2410-i2c.0", "i2c"), - ALIAS(HCLK_USBD, NULL, "usb-device"), - ALIAS(HCLK_USBH, NULL, "usb-host"), - ALIAS(SCLK_USBH, NULL, "usb-bus-host"), - ALIAS(PCLK_SPI0, "s3c2443-spi.0", "spi"), - ALIAS(PCLK_SPI0, "s3c2443-spi.0", "spi_busclk0"), - ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "hsmmc"), - ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.0"), - ALIAS(PCLK_I2S0, "samsung-i2s.0", "iis"), - ALIAS(SCLK_I2S0, NULL, "i2s-if"), - ALIAS(HCLK_LCD, NULL, "lcd"), - ALIAS(SCLK_FIMD, NULL, "sclk_fimd"), -}; - -/* S3C2416 specific clocks */ - -static struct samsung_pll_clock s3c2416_pll_clks[] __initdata = { - PLL(pll_6552_s3c2416, MPLL, "mpll", "mpllref", LOCKCON0, MPLLCON, NULL), - PLL(pll_6553, EPLL, "epll", "epllref", LOCKCON1, EPLLCON, NULL), -}; - -PNAME(s3c2416_hsmmc0_p) = { "sclk_hsmmc0", "sclk_hsmmcext" }; -PNAME(s3c2416_hsmmc1_p) = { "sclk_hsmmc1", "sclk_hsmmcext" }; -PNAME(s3c2416_hsspi0_p) = { "hsspi0_epll", "hsspi0_mpll" }; - -static struct clk_div_table armdiv_s3c2416_d[] = { - { .val = 0, .div = 1 }, - { .val = 1, .div = 2 }, - { .val = 2, .div = 3 }, - { .val = 3, .div = 4 }, - { .val = 5, .div = 6 }, - { .val = 7, .div = 8 }, - { /* sentinel */ }, -}; - -static struct samsung_div_clock s3c2416_dividers[] __initdata = { - DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 3, armdiv_s3c2416_d), - DIV(0, "div_hsspi0_mpll", "msysclk", CLKDIV2, 0, 4), - DIV(0, "div_hsmmc0", "esysclk", CLKDIV2, 6, 2), -}; - -static struct samsung_mux_clock s3c2416_muxes[] __initdata = { - MUX(MUX_HSMMC0, "mux_hsmmc0", s3c2416_hsmmc0_p, CLKSRC, 16, 1), - MUX(MUX_HSMMC1, "mux_hsmmc1", s3c2416_hsmmc1_p, CLKSRC, 17, 1), - MUX(MUX_HSSPI0, "mux_hsspi0", s3c2416_hsspi0_p, CLKSRC, 18, 1), -}; - -static struct samsung_gate_clock s3c2416_gates[] __initdata = { - GATE(0, "hsspi0_mpll", "div_hsspi0_mpll", SCLKCON, 19, 0, 0), - GATE(0, "hsspi0_epll", "div_hsspi0_epll", SCLKCON, 14, 0, 0), - GATE(0, "sclk_hsmmc0", "div_hsmmc0", SCLKCON, 6, 0, 0), - GATE(HCLK_2D, "2d", "hclk", HCLKCON, 20, 0, 0), - GATE(HCLK_HSMMC0, "hsmmc0", "hclk", HCLKCON, 15, 0, 0), - GATE(HCLK_IROM, "irom", "hclk", HCLKCON, 13, CLK_IGNORE_UNUSED, 0), - GATE(PCLK_PCM, "pcm", "pclk", PCLKCON, 19, 0, 0), -}; - -static struct samsung_clock_alias s3c2416_aliases[] __initdata = { - ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"), - ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"), - ALIAS(MUX_HSMMC0, "s3c-sdhci.0", "mmc_busclk.2"), - ALIAS(MUX_HSMMC1, "s3c-sdhci.1", "mmc_busclk.2"), - ALIAS(MUX_HSSPI0, "s3c2443-spi.0", "spi_busclk2"), - ALIAS(ARMDIV, NULL, "armdiv"), -}; - -/* S3C2443 specific clocks */ - -static struct samsung_pll_clock s3c2443_pll_clks[] __initdata = { - PLL(pll_3000, MPLL, "mpll", "mpllref", LOCKCON0, MPLLCON, NULL), - PLL(pll_2126, EPLL, "epll", "epllref", LOCKCON1, EPLLCON, NULL), -}; - -static struct clk_div_table armdiv_s3c2443_d[] = { - { .val = 0, .div = 1 }, - { .val = 8, .div = 2 }, - { .val = 2, .div = 3 }, - { .val = 9, .div = 4 }, - { .val = 10, .div = 6 }, - { .val = 11, .div = 8 }, - { .val = 13, .div = 12 }, - { .val = 15, .div = 16 }, - { /* sentinel */ }, -}; - -static struct samsung_div_clock s3c2443_dividers[] __initdata = { - DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 4, armdiv_s3c2443_d), - DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4), -}; - -static struct samsung_gate_clock s3c2443_gates[] __initdata = { - GATE(SCLK_HSSPI0, "sclk_hsspi0", "div_hsspi0_epll", SCLKCON, 14, 0, 0), - GATE(SCLK_CAM, "sclk_cam", "div_cam", SCLKCON, 11, 0, 0), - GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_CAM, "cam", "hclk", HCLKCON, 8, 0, 0), - GATE(PCLK_SPI1, "spi1", "pclk", PCLKCON, 15, 0, 0), - GATE(PCLK_SDI, "sdi", "pclk", PCLKCON, 5, 0, 0), -}; - -static struct samsung_clock_alias s3c2443_aliases[] __initdata = { - ALIAS(SCLK_HSSPI0, "s3c2443-spi.0", "spi_busclk2"), - ALIAS(SCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.2"), - ALIAS(SCLK_CAM, NULL, "camif-upll"), - ALIAS(PCLK_SPI1, "s3c2410-spi.0", "spi"), - ALIAS(PCLK_SDI, NULL, "sdi"), - ALIAS(HCLK_CFC, NULL, "cfc"), - ALIAS(ARMDIV, NULL, "armdiv"), -}; - -/* S3C2450 specific clocks */ - -PNAME(s3c2450_cam_p) = { "div_cam", "hclk" }; -PNAME(s3c2450_hsspi1_p) = { "hsspi1_epll", "hsspi1_mpll" }; -PNAME(i2s1_p) = { "div_i2s1", "ext_i2s", "epllref", "epllref" }; - -static struct samsung_div_clock s3c2450_dividers[] __initdata = { - DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4), - DIV(0, "div_hsspi1_epll", "esysclk", CLKDIV2, 24, 2), - DIV(0, "div_hsspi1_mpll", "msysclk", CLKDIV2, 16, 4), - DIV(0, "div_i2s1", "esysclk", CLKDIV2, 12, 4), -}; - -static struct samsung_mux_clock s3c2450_muxes[] __initdata = { - MUX(0, "mux_cam", s3c2450_cam_p, CLKSRC, 20, 1), - MUX(MUX_HSSPI1, "mux_hsspi1", s3c2450_hsspi1_p, CLKSRC, 19, 1), - MUX(0, "mux_i2s1", i2s1_p, CLKSRC, 12, 2), -}; - -static struct samsung_gate_clock s3c2450_gates[] __initdata = { - GATE(SCLK_I2S1, "sclk_i2s1", "div_i2s1", SCLKCON, 5, 0, 0), - GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, 0, 0), - GATE(HCLK_CAM, "cam", "hclk", HCLKCON, 8, 0, 0), - GATE(HCLK_DMA7, "dma7", "hclk", HCLKCON, 7, CLK_IGNORE_UNUSED, 0), - GATE(HCLK_DMA6, "dma6", "hclk", HCLKCON, 6, CLK_IGNORE_UNUSED, 0), - GATE(PCLK_I2S1, "i2s1", "pclk", PCLKCON, 17, 0, 0), - GATE(PCLK_I2C1, "i2c1", "pclk", PCLKCON, 16, 0, 0), - GATE(PCLK_SPI1, "spi1", "pclk", PCLKCON, 14, 0, 0), -}; - -static struct samsung_clock_alias s3c2450_aliases[] __initdata = { - ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi"), - ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi_busclk0"), - ALIAS(MUX_HSSPI1, "s3c2443-spi.1", "spi_busclk2"), - ALIAS(PCLK_I2C1, "s3c2410-i2c.1", "i2c"), -}; - -static int s3c2443_restart(struct notifier_block *this, - unsigned long mode, void *cmd) -{ - __raw_writel(0x533c2443, reg_base + SWRST); - return NOTIFY_DONE; -} - -static struct notifier_block s3c2443_restart_handler = { - .notifier_call = s3c2443_restart, - .priority = 129, -}; - -/* - * fixed rate clocks generated outside the soc - * Only necessary until the devicetree-move is complete - */ -static struct samsung_fixed_rate_clock s3c2443_common_frate_clks[] __initdata = { - FRATE(0, "xti", NULL, 0, 0), - FRATE(0, "ext", NULL, 0, 0), - FRATE(0, "ext_i2s", NULL, 0, 0), - FRATE(0, "ext_uart", NULL, 0, 0), -}; - -static void __init s3c2443_common_clk_register_fixed_ext( - struct samsung_clk_provider *ctx, unsigned long xti_f) -{ - s3c2443_common_frate_clks[0].fixed_rate = xti_f; - samsung_clk_register_fixed_rate(ctx, s3c2443_common_frate_clks, - ARRAY_SIZE(s3c2443_common_frate_clks)); -} - -void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f, - int current_soc, - void __iomem *base) -{ - struct samsung_clk_provider *ctx; - int ret; - reg_base = base; - - if (np) { - reg_base = of_iomap(np, 0); - if (!reg_base) - panic("%s: failed to map registers\n", __func__); - } - - ctx = samsung_clk_init(np, reg_base, NR_CLKS); - - /* Register external clocks only in non-dt cases */ - if (!np) - s3c2443_common_clk_register_fixed_ext(ctx, xti_f); - - /* Register PLLs. */ - if (current_soc == S3C2416 || current_soc == S3C2450) - samsung_clk_register_pll(ctx, s3c2416_pll_clks, - ARRAY_SIZE(s3c2416_pll_clks), reg_base); - else - samsung_clk_register_pll(ctx, s3c2443_pll_clks, - ARRAY_SIZE(s3c2443_pll_clks), reg_base); - - /* Register common internal clocks. */ - samsung_clk_register_mux(ctx, s3c2443_common_muxes, - ARRAY_SIZE(s3c2443_common_muxes)); - samsung_clk_register_div(ctx, s3c2443_common_dividers, - ARRAY_SIZE(s3c2443_common_dividers)); - samsung_clk_register_gate(ctx, s3c2443_common_gates, - ARRAY_SIZE(s3c2443_common_gates)); - samsung_clk_register_alias(ctx, s3c2443_common_aliases, - ARRAY_SIZE(s3c2443_common_aliases)); - - /* Register SoC-specific clocks. */ - switch (current_soc) { - case S3C2450: - samsung_clk_register_div(ctx, s3c2450_dividers, - ARRAY_SIZE(s3c2450_dividers)); - samsung_clk_register_mux(ctx, s3c2450_muxes, - ARRAY_SIZE(s3c2450_muxes)); - samsung_clk_register_gate(ctx, s3c2450_gates, - ARRAY_SIZE(s3c2450_gates)); - samsung_clk_register_alias(ctx, s3c2450_aliases, - ARRAY_SIZE(s3c2450_aliases)); - fallthrough; /* as s3c2450 extends the s3c2416 clocks */ - case S3C2416: - samsung_clk_register_div(ctx, s3c2416_dividers, - ARRAY_SIZE(s3c2416_dividers)); - samsung_clk_register_mux(ctx, s3c2416_muxes, - ARRAY_SIZE(s3c2416_muxes)); - samsung_clk_register_gate(ctx, s3c2416_gates, - ARRAY_SIZE(s3c2416_gates)); - samsung_clk_register_alias(ctx, s3c2416_aliases, - ARRAY_SIZE(s3c2416_aliases)); - break; - case S3C2443: - samsung_clk_register_div(ctx, s3c2443_dividers, - ARRAY_SIZE(s3c2443_dividers)); - samsung_clk_register_gate(ctx, s3c2443_gates, - ARRAY_SIZE(s3c2443_gates)); - samsung_clk_register_alias(ctx, s3c2443_aliases, - ARRAY_SIZE(s3c2443_aliases)); - break; - } - - samsung_clk_sleep_init(reg_base, s3c2443_clk_regs, - ARRAY_SIZE(s3c2443_clk_regs)); - - samsung_clk_of_add_provider(np, ctx); - - ret = register_restart_handler(&s3c2443_restart_handler); - if (ret) - pr_warn("cannot register restart handler, %d\n", ret); -} - -static void __init s3c2416_clk_init(struct device_node *np) -{ - s3c2443_common_clk_init(np, 0, S3C2416, NULL); -} -CLK_OF_DECLARE(s3c2416_clk, "samsung,s3c2416-clock", s3c2416_clk_init); - -static void __init s3c2443_clk_init(struct device_node *np) -{ - s3c2443_common_clk_init(np, 0, S3C2443, NULL); -} -CLK_OF_DECLARE(s3c2443_clk, "samsung,s3c2443-clock", s3c2443_clk_init); - -static void __init s3c2450_clk_init(struct device_node *np) -{ - s3c2443_common_clk_init(np, 0, S3C2450, NULL); -} -CLK_OF_DECLARE(s3c2450_clk, "samsung,s3c2450-clock", s3c2450_clk_init); diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 4469e7f555e9..fc10ecc3602d 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -441,7 +441,7 @@ config CLKSRC_EXYNOS_MCT config CLKSRC_SAMSUNG_PWM bool "PWM timer driver for Samsung S3C, S5P" if COMPILE_TEST depends on HAS_IOMEM - depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210 || COMPILE_TEST + depends on ARCH_EXYNOS || ARCH_S3C64XX || ARCH_S5PV210 || COMPILE_TEST help This is a new clocksource driver for the PWM timer found in Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver diff --git a/drivers/comedi/drivers/adv_pci1760.c b/drivers/comedi/drivers/adv_pci1760.c index fcfc2e299110..27f3890f471d 100644 --- a/drivers/comedi/drivers/adv_pci1760.c +++ b/drivers/comedi/drivers/adv_pci1760.c @@ -58,7 +58,7 @@ #define PCI1760_CMD_CLR_IMB2 0x00 /* Clears IMB2 */ #define PCI1760_CMD_SET_DO 0x01 /* Set output state */ #define PCI1760_CMD_GET_DO 0x02 /* Read output status */ -#define PCI1760_CMD_GET_STATUS 0x03 /* Read current status */ +#define PCI1760_CMD_GET_STATUS 0x07 /* Read current status */ #define PCI1760_CMD_GET_FW_VER 0x0e /* Read firmware version */ #define PCI1760_CMD_GET_HW_VER 0x0f /* Read hardware version */ #define PCI1760_CMD_SET_PWM_HI(x) (0x10 + (x) * 2) /* Set "hi" period */ diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 2a84fc63371e..8466f78651fc 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -37,7 +37,7 @@ config CPU_FREQ_STAT choice prompt "Default CPUFreq governor" - default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ + default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1110_CPUFREQ default CPU_FREQ_DEFAULT_GOV_SCHEDUTIL if ARM64 || ARM default CPU_FREQ_DEFAULT_GOV_SCHEDUTIL if X86_INTEL_PSTATE && SMP default CPU_FREQ_DEFAULT_GOV_PERFORMANCE diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 0a0352d8fa45..97acaa2136fd 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -189,84 +189,6 @@ config ARM_RASPBERRYPI_CPUFREQ If in doubt, say N. -config ARM_S3C_CPUFREQ - bool - help - Internal configuration node for common cpufreq on Samsung SoC - -config ARM_S3C24XX_CPUFREQ - bool "CPUfreq driver for Samsung S3C24XX series CPUs (EXPERIMENTAL)" - depends on ARCH_S3C24XX - select ARM_S3C_CPUFREQ - help - This enables the CPUfreq driver for the Samsung S3C24XX family - of CPUs. - - For details, take a look at <file:Documentation/cpu-freq>. - - If in doubt, say N. - -config ARM_S3C24XX_CPUFREQ_DEBUG - bool "Debug CPUfreq Samsung driver core" - depends on ARM_S3C24XX_CPUFREQ - help - Enable s3c_freq_dbg for the Samsung S3C CPUfreq core - -config ARM_S3C24XX_CPUFREQ_IODEBUG - bool "Debug CPUfreq Samsung driver IO timing" - depends on ARM_S3C24XX_CPUFREQ - help - Enable s3c_freq_iodbg for the Samsung S3C CPUfreq core - -config ARM_S3C24XX_CPUFREQ_DEBUGFS - bool "Export debugfs for CPUFreq" - depends on ARM_S3C24XX_CPUFREQ && DEBUG_FS - help - Export status information via debugfs. - -config ARM_S3C2410_CPUFREQ - bool - depends on ARM_S3C24XX_CPUFREQ && CPU_S3C2410 - help - CPU Frequency scaling support for S3C2410 - -config ARM_S3C2412_CPUFREQ - bool - depends on ARM_S3C24XX_CPUFREQ && CPU_S3C2412 - default y - select S3C2412_IOTIMING - help - CPU Frequency scaling support for S3C2412 and S3C2413 SoC CPUs. - -config ARM_S3C2416_CPUFREQ - bool "S3C2416 CPU Frequency scaling support" - depends on CPU_S3C2416 - help - This adds the CPUFreq driver for the Samsung S3C2416 and - S3C2450 SoC. The S3C2416 supports changing the rate of the - armdiv clock source and also entering a so called dynamic - voltage scaling mode in which it is possible to reduce the - core voltage of the CPU. - - If in doubt, say N. - -config ARM_S3C2416_CPUFREQ_VCORESCALE - bool "Allow voltage scaling for S3C2416 arm core" - depends on ARM_S3C2416_CPUFREQ && REGULATOR - help - Enable CPU voltage scaling when entering the dvs mode. - It uses information gathered through existing hardware and - tests but not documented in any datasheet. - - If in doubt, say N. - -config ARM_S3C2440_CPUFREQ - bool "S3C2440/S3C2442 CPU Frequency scaling support" - depends on ARM_S3C24XX_CPUFREQ && (CPU_S3C2440 || CPU_S3C2442) - default y - help - CPU Frequency scaling support for S3C2440 and S3C2442 SoC CPUs. - config ARM_S3C64XX_CPUFREQ bool "Samsung S3C64XX" depends on CPU_S3C6410 @@ -286,9 +208,6 @@ config ARM_S5PV210_CPUFREQ If in doubt, say N. -config ARM_SA1100_CPUFREQ - bool - config ARM_SA1110_CPUFREQ bool diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 32a7029e25ed..a19842fbd521 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -71,15 +71,8 @@ obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o obj-$(CONFIG_ARM_QCOM_CPUFREQ_NVMEM) += qcom-cpufreq-nvmem.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 -obj-$(CONFIG_ARM_S3C2440_CPUFREQ) += s3c2440-cpufreq.o obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o -obj-$(CONFIG_ARM_S3C24XX_CPUFREQ) += s3c24xx-cpufreq.o -obj-$(CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS) += s3c24xx-cpufreq-debugfs.o obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o -obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o obj-$(CONFIG_ARM_SCMI_CPUFREQ) += scmi-cpufreq.o obj-$(CONFIG_ARM_SCPI_CPUFREQ) += scpi-cpufreq.o diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index 204e39006dda..c17bd845f5fc 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -307,6 +307,7 @@ static void amd_pstate_adjust_perf(unsigned int cpu, max_perf = min_perf; amd_pstate_update(cpudata, min_perf, des_perf, max_perf, true); + cpufreq_cpu_put(policy); } static int amd_get_min_freq(struct amd_cpudata *cpudata) diff --git a/drivers/cpufreq/apple-soc-cpufreq.c b/drivers/cpufreq/apple-soc-cpufreq.c index d1801281cdd9..c11d22fd84c3 100644 --- a/drivers/cpufreq/apple-soc-cpufreq.c +++ b/drivers/cpufreq/apple-soc-cpufreq.c @@ -280,6 +280,7 @@ static int apple_soc_cpufreq_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = transition_latency; policy->dvfs_possible_from_any_cpu = true; policy->fast_switch_possible = true; + policy->suspend_freq = freq_table[0].frequency; if (policy_has_boost_freq(policy)) { ret = cpufreq_enable_boost_support(); @@ -321,7 +322,6 @@ static struct cpufreq_driver apple_soc_cpufreq_driver = { .flags = CPUFREQ_HAVE_GOVERNOR_PER_POLICY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | CPUFREQ_IS_COOLING_DEV, .verify = cpufreq_generic_frequency_table_verify, - .attr = cpufreq_generic_attr, .get = apple_soc_cpufreq_get_rate, .init = apple_soc_cpufreq_init, .exit = apple_soc_cpufreq_exit, @@ -329,6 +329,7 @@ static struct cpufreq_driver apple_soc_cpufreq_driver = { .fast_switch = apple_soc_cpufreq_fast_switch, .register_em = cpufreq_register_em_with_opp, .attr = apple_soc_cpufreq_hw_attr, + .suspend = cpufreq_generic_suspend, }; static int __init apple_soc_cpufreq_module_init(void) diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c index c10fc33b29b1..b74289a95a17 100644 --- a/drivers/cpufreq/armada-37xx-cpufreq.c +++ b/drivers/cpufreq/armada-37xx-cpufreq.c @@ -445,7 +445,7 @@ static int __init armada37xx_cpufreq_driver_init(void) return -ENODEV; } - clk = clk_get(cpu_dev, 0); + clk = clk_get(cpu_dev, NULL); if (IS_ERR(clk)) { dev_err(cpu_dev, "Cannot get clock for CPU0\n"); return PTR_ERR(clk); diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 432dfb4e8027..022e3555407c 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -487,7 +487,8 @@ static unsigned int get_perf_level_count(struct cpufreq_policy *policy) cpu_data = policy->driver_data; perf_caps = &cpu_data->perf_caps; max_cap = arch_scale_cpu_capacity(cpu); - min_cap = div_u64(max_cap * perf_caps->lowest_perf, perf_caps->highest_perf); + min_cap = div_u64((u64)max_cap * perf_caps->lowest_perf, + perf_caps->highest_perf); if ((min_cap == 0) || (max_cap < min_cap)) return 0; return 1 + max_cap / CPPC_EM_CAP_STEP - min_cap / CPPC_EM_CAP_STEP; @@ -519,10 +520,10 @@ static int cppc_get_cpu_power(struct device *cpu_dev, cpu_data = policy->driver_data; perf_caps = &cpu_data->perf_caps; max_cap = arch_scale_cpu_capacity(cpu_dev->id); - min_cap = div_u64(max_cap * perf_caps->lowest_perf, - perf_caps->highest_perf); - - perf_step = CPPC_EM_CAP_STEP * perf_caps->highest_perf / max_cap; + min_cap = div_u64((u64)max_cap * perf_caps->lowest_perf, + perf_caps->highest_perf); + perf_step = div_u64((u64)CPPC_EM_CAP_STEP * perf_caps->highest_perf, + max_cap); min_step = min_cap / CPPC_EM_CAP_STEP; max_step = max_cap / CPPC_EM_CAP_STEP; diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index 8ab672883043..e85703651098 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -137,6 +137,7 @@ static const struct of_device_id blocklist[] __initconst = { { .compatible = "nvidia,tegra30", }, { .compatible = "nvidia,tegra124", }, { .compatible = "nvidia,tegra210", }, + { .compatible = "nvidia,tegra234", }, { .compatible = "qcom,apq8096", }, { .compatible = "qcom,msm8996", }, @@ -150,6 +151,7 @@ static const struct of_device_id blocklist[] __initconst = { { .compatible = "qcom,sdm845", }, { .compatible = "qcom,sm6115", }, { .compatible = "qcom,sm6350", }, + { .compatible = "qcom,sm6375", }, { .compatible = "qcom,sm8150", }, { .compatible = "qcom,sm8250", }, { .compatible = "qcom,sm8350", }, diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c index 340fed35e45d..d3f55ca06ed3 100644 --- a/drivers/cpufreq/qcom-cpufreq-hw.c +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -143,40 +143,42 @@ static unsigned long qcom_lmh_get_throttle_freq(struct qcom_cpufreq_data *data) return lval * xo_rate; } -/* Get the current frequency of the CPU (after throttling) */ -static unsigned int qcom_cpufreq_hw_get(unsigned int cpu) +/* Get the frequency requested by the cpufreq core for the CPU */ +static unsigned int qcom_cpufreq_get_freq(unsigned int cpu) { struct qcom_cpufreq_data *data; + const struct qcom_cpufreq_soc_data *soc_data; struct cpufreq_policy *policy; + unsigned int index; policy = cpufreq_cpu_get_raw(cpu); if (!policy) return 0; data = policy->driver_data; + soc_data = qcom_cpufreq.soc_data; - return qcom_lmh_get_throttle_freq(data) / HZ_PER_KHZ; + index = readl_relaxed(data->base + soc_data->reg_perf_state); + index = min(index, LUT_MAX_ENTRIES - 1); + + return policy->freq_table[index].frequency; } -/* Get the frequency requested by the cpufreq core for the CPU */ -static unsigned int qcom_cpufreq_get_freq(unsigned int cpu) +static unsigned int qcom_cpufreq_hw_get(unsigned int cpu) { struct qcom_cpufreq_data *data; - const struct qcom_cpufreq_soc_data *soc_data; struct cpufreq_policy *policy; - unsigned int index; policy = cpufreq_cpu_get_raw(cpu); if (!policy) return 0; data = policy->driver_data; - soc_data = qcom_cpufreq.soc_data; - index = readl_relaxed(data->base + soc_data->reg_perf_state); - index = min(index, LUT_MAX_ENTRIES - 1); + if (data->throttle_irq >= 0) + return qcom_lmh_get_throttle_freq(data) / HZ_PER_KHZ; - return policy->freq_table[index].frequency; + return qcom_cpufreq_get_freq(cpu); } static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, @@ -649,9 +651,10 @@ static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev) { struct clk_hw_onecell_data *clk_data; struct device *dev = &pdev->dev; + struct device_node *soc_node; struct device *cpu_dev; struct clk *clk; - int ret, i, num_domains; + int ret, i, num_domains, reg_sz; clk = clk_get(dev, "xo"); if (IS_ERR(clk)) @@ -679,7 +682,21 @@ static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev) return ret; /* Allocate qcom_cpufreq_data based on the available frequency domains in DT */ - num_domains = of_property_count_elems_of_size(dev->of_node, "reg", sizeof(u32) * 4); + soc_node = of_get_parent(dev->of_node); + if (!soc_node) + return -EINVAL; + + ret = of_property_read_u32(soc_node, "#address-cells", ®_sz); + if (ret) + goto of_exit; + + ret = of_property_read_u32(soc_node, "#size-cells", &i); + if (ret) + goto of_exit; + + reg_sz += i; + + num_domains = of_property_count_elems_of_size(dev->of_node, "reg", sizeof(u32) * reg_sz); if (num_domains <= 0) return num_domains; @@ -689,6 +706,8 @@ static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev) return -ENOMEM; qcom_cpufreq.soc_data = of_device_get_match_data(dev); + if (!qcom_cpufreq.soc_data) + return -ENODEV; clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, num_domains), GFP_KERNEL); if (!clk_data) @@ -743,6 +762,9 @@ static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev) else dev_dbg(dev, "QCOM CPUFreq HW driver initialized\n"); +of_exit: + of_node_put(soc_node); + return ret; } diff --git a/drivers/cpufreq/s3c2410-cpufreq.c b/drivers/cpufreq/s3c2410-cpufreq.c deleted file mode 100644 index 5dcfbf0bfb74..000000000000 --- a/drivers/cpufreq/s3c2410-cpufreq.c +++ /dev/null @@ -1,155 +0,0 @@ -// 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 -*/ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/cpufreq.h> -#include <linux/device.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/soc/samsung/s3c-cpufreq-core.h> -#include <linux/soc/samsung/s3c-pm.h> - -#include <asm/mach/arch.h> -#include <asm/mach/map.h> - -#define S3C2410_CLKDIVN_PDIVN (1<<0) -#define S3C2410_CLKDIVN_HDIVN (1<<1) - -/* Note, 2410A has an extra mode for 1:4:4 ratio, bit 2 of CLKDIV */ - -static void s3c2410_cpufreq_setdivs(struct s3c_cpufreq_config *cfg) -{ - u32 clkdiv = 0; - - if (cfg->divs.h_divisor == 2) - clkdiv |= S3C2410_CLKDIVN_HDIVN; - - if (cfg->divs.p_divisor != cfg->divs.h_divisor) - clkdiv |= S3C2410_CLKDIVN_PDIVN; - - s3c24xx_write_clkdivn(clkdiv); -} - -static int s3c2410_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg) -{ - unsigned long hclk, fclk, pclk; - unsigned int hdiv, pdiv; - unsigned long hclk_max; - - fclk = cfg->freq.fclk; - hclk_max = cfg->max.hclk; - - cfg->freq.armclk = fclk; - - s3c_freq_dbg("%s: fclk is %lu, max hclk %lu\n", - __func__, fclk, hclk_max); - - hdiv = (fclk > cfg->max.hclk) ? 2 : 1; - hclk = fclk / hdiv; - - if (hclk > cfg->max.hclk) { - s3c_freq_dbg("%s: hclk too big\n", __func__); - return -EINVAL; - } - - pdiv = (hclk > cfg->max.pclk) ? 2 : 1; - pclk = hclk / pdiv; - - if (pclk > cfg->max.pclk) { - s3c_freq_dbg("%s: pclk too big\n", __func__); - return -EINVAL; - } - - pdiv *= hdiv; - - /* record the result */ - cfg->divs.p_divisor = pdiv; - cfg->divs.h_divisor = hdiv; - - return 0; -} - -static struct s3c_cpufreq_info s3c2410_cpufreq_info = { - .max = { - .fclk = 200000000, - .hclk = 100000000, - .pclk = 50000000, - }, - - /* transition latency is about 5ms worst-case, so - * set 10ms to be sure */ - .latency = 10000000, - - .locktime_m = 150, - .locktime_u = 150, - .locktime_bits = 12, - - .need_pll = 1, - - .name = "s3c2410", - .calc_iotiming = s3c2410_iotiming_calc, - .set_iotiming = s3c2410_iotiming_set, - .get_iotiming = s3c2410_iotiming_get, - - .set_fvco = s3c2410_set_fvco, - .set_refresh = s3c2410_cpufreq_setrefresh, - .set_divs = s3c2410_cpufreq_setdivs, - .calc_divs = s3c2410_cpufreq_calcdivs, - - .debug_io_show = s3c_cpufreq_debugfs_call(s3c2410_iotiming_debugfs), -}; - -static int s3c2410_cpufreq_add(struct device *dev, - struct subsys_interface *sif) -{ - return s3c_cpufreq_register(&s3c2410_cpufreq_info); -} - -static struct subsys_interface s3c2410_cpufreq_interface = { - .name = "s3c2410_cpufreq", - .subsys = &s3c2410_subsys, - .add_dev = s3c2410_cpufreq_add, -}; - -static int __init s3c2410_cpufreq_init(void) -{ - return subsys_interface_register(&s3c2410_cpufreq_interface); -} -arch_initcall(s3c2410_cpufreq_init); - -static int s3c2410a_cpufreq_add(struct device *dev, - struct subsys_interface *sif) -{ - /* alter the maximum freq settings for S3C2410A. If a board knows - * it only has a maximum of 200, then it should register its own - * limits. */ - - s3c2410_cpufreq_info.max.fclk = 266000000; - s3c2410_cpufreq_info.max.hclk = 133000000; - s3c2410_cpufreq_info.max.pclk = 66500000; - s3c2410_cpufreq_info.name = "s3c2410a"; - - return s3c2410_cpufreq_add(dev, sif); -} - -static struct subsys_interface s3c2410a_cpufreq_interface = { - .name = "s3c2410a_cpufreq", - .subsys = &s3c2410a_subsys, - .add_dev = s3c2410a_cpufreq_add, -}; - -static int __init s3c2410a_cpufreq_init(void) -{ - return subsys_interface_register(&s3c2410a_cpufreq_interface); -} -arch_initcall(s3c2410a_cpufreq_init); diff --git a/drivers/cpufreq/s3c2412-cpufreq.c b/drivers/cpufreq/s3c2412-cpufreq.c deleted file mode 100644 index 5945945ead7c..000000000000 --- a/drivers/cpufreq/s3c2412-cpufreq.c +++ /dev/null @@ -1,240 +0,0 @@ -// 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 -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/cpufreq.h> -#include <linux/device.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/soc/samsung/s3c-cpufreq-core.h> -#include <linux/soc/samsung/s3c-pm.h> - -#include <asm/mach/arch.h> -#include <asm/mach/map.h> - -#define S3C2412_CLKDIVN_PDIVN (1<<2) -#define S3C2412_CLKDIVN_HDIVN_MASK (3<<0) -#define S3C2412_CLKDIVN_ARMDIVN (1<<3) -#define S3C2412_CLKDIVN_DVSEN (1<<4) -#define S3C2412_CLKDIVN_HALFHCLK (1<<5) -#define S3C2412_CLKDIVN_USB48DIV (1<<6) -#define S3C2412_CLKDIVN_UARTDIV_MASK (15<<8) -#define S3C2412_CLKDIVN_UARTDIV_SHIFT (8) -#define S3C2412_CLKDIVN_I2SDIV_MASK (15<<12) -#define S3C2412_CLKDIVN_I2SDIV_SHIFT (12) -#define S3C2412_CLKDIVN_CAMDIV_MASK (15<<16) -#define S3C2412_CLKDIVN_CAMDIV_SHIFT (16) - -/* our clock resources. */ -static struct clk *xtal; -static struct clk *fclk; -static struct clk *hclk; -static struct clk *armclk; - -/* HDIV: 1, 2, 3, 4, 6, 8 */ - -static int s3c2412_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg) -{ - unsigned int hdiv, pdiv, armdiv, dvs; - unsigned long hclk, fclk, armclk, armdiv_clk; - unsigned long hclk_max; - - fclk = cfg->freq.fclk; - armclk = cfg->freq.armclk; - hclk_max = cfg->max.hclk; - - /* We can't run hclk above armclk as at the best we have to - * have armclk and hclk in dvs mode. */ - - if (hclk_max > armclk) - hclk_max = armclk; - - s3c_freq_dbg("%s: fclk=%lu, armclk=%lu, hclk_max=%lu\n", - __func__, fclk, armclk, hclk_max); - s3c_freq_dbg("%s: want f=%lu, arm=%lu, h=%lu, p=%lu\n", - __func__, cfg->freq.fclk, cfg->freq.armclk, - cfg->freq.hclk, cfg->freq.pclk); - - armdiv = fclk / armclk; - - if (armdiv < 1) - armdiv = 1; - if (armdiv > 2) - armdiv = 2; - - cfg->divs.arm_divisor = armdiv; - armdiv_clk = fclk / armdiv; - - hdiv = armdiv_clk / hclk_max; - if (hdiv < 1) - hdiv = 1; - - cfg->freq.hclk = hclk = armdiv_clk / hdiv; - - /* set dvs depending on whether we reached armclk or not. */ - cfg->divs.dvs = dvs = armclk < armdiv_clk; - - /* update the actual armclk we achieved. */ - cfg->freq.armclk = dvs ? hclk : armdiv_clk; - - s3c_freq_dbg("%s: armclk %lu, hclk %lu, armdiv %d, hdiv %d, dvs %d\n", - __func__, armclk, hclk, armdiv, hdiv, cfg->divs.dvs); - - if (hdiv > 4) - goto invalid; - - pdiv = (hclk > cfg->max.pclk) ? 2 : 1; - - if ((hclk / pdiv) > cfg->max.pclk) - pdiv++; - - cfg->freq.pclk = hclk / pdiv; - - s3c_freq_dbg("%s: pdiv %d\n", __func__, pdiv); - - if (pdiv > 2) - goto invalid; - - pdiv *= hdiv; - - /* store the result, and then return */ - - cfg->divs.h_divisor = hdiv * armdiv; - cfg->divs.p_divisor = pdiv * armdiv; - - return 0; - -invalid: - return -EINVAL; -} - -static void s3c2412_cpufreq_setdivs(struct s3c_cpufreq_config *cfg) -{ - unsigned long clkdiv; - unsigned long olddiv; - - olddiv = clkdiv = s3c24xx_read_clkdivn(); - - /* clear off current clock info */ - - clkdiv &= ~S3C2412_CLKDIVN_ARMDIVN; - clkdiv &= ~S3C2412_CLKDIVN_HDIVN_MASK; - clkdiv &= ~S3C2412_CLKDIVN_PDIVN; - - if (cfg->divs.arm_divisor == 2) - clkdiv |= S3C2412_CLKDIVN_ARMDIVN; - - clkdiv |= ((cfg->divs.h_divisor / cfg->divs.arm_divisor) - 1); - - if (cfg->divs.p_divisor != cfg->divs.h_divisor) - clkdiv |= S3C2412_CLKDIVN_PDIVN; - - s3c_freq_dbg("%s: div %08lx => %08lx\n", __func__, olddiv, clkdiv); - s3c24xx_write_clkdivn(clkdiv); - - clk_set_parent(armclk, cfg->divs.dvs ? hclk : fclk); -} - -/* set the default cpu frequency information, based on an 200MHz part - * as we have no other way of detecting the speed rating in software. - */ - -static struct s3c_cpufreq_info s3c2412_cpufreq_info = { - .max = { - .fclk = 200000000, - .hclk = 100000000, - .pclk = 50000000, - }, - - .latency = 5000000, /* 5ms */ - - .locktime_m = 150, - .locktime_u = 150, - .locktime_bits = 16, - - .name = "s3c2412", - .set_refresh = s3c2412_cpufreq_setrefresh, - .set_divs = s3c2412_cpufreq_setdivs, - .calc_divs = s3c2412_cpufreq_calcdivs, - - .calc_iotiming = s3c2412_iotiming_calc, - .set_iotiming = s3c2412_iotiming_set, - .get_iotiming = s3c2412_iotiming_get, - - .debug_io_show = s3c_cpufreq_debugfs_call(s3c2412_iotiming_debugfs), -}; - -static int s3c2412_cpufreq_add(struct device *dev, - struct subsys_interface *sif) -{ - unsigned long fclk_rate; - - hclk = clk_get(NULL, "hclk"); - if (IS_ERR(hclk)) { - pr_err("cannot find hclk clock\n"); - return -ENOENT; - } - - fclk = clk_get(NULL, "fclk"); - if (IS_ERR(fclk)) { - pr_err("cannot find fclk clock\n"); - goto err_fclk; - } - - fclk_rate = clk_get_rate(fclk); - if (fclk_rate > 200000000) { - pr_info("fclk %ld MHz, assuming 266MHz capable part\n", - fclk_rate / 1000000); - s3c2412_cpufreq_info.max.fclk = 266000000; - s3c2412_cpufreq_info.max.hclk = 133000000; - s3c2412_cpufreq_info.max.pclk = 66000000; - } - - armclk = clk_get(NULL, "armclk"); - if (IS_ERR(armclk)) { - pr_err("cannot find arm clock\n"); - goto err_armclk; - } - - xtal = clk_get(NULL, "xtal"); - if (IS_ERR(xtal)) { - pr_err("cannot find xtal clock\n"); - goto err_xtal; - } - - return s3c_cpufreq_register(&s3c2412_cpufreq_info); - -err_xtal: - clk_put(armclk); -err_armclk: - clk_put(fclk); -err_fclk: - clk_put(hclk); - - return -ENOENT; -} - -static struct subsys_interface s3c2412_cpufreq_interface = { - .name = "s3c2412_cpufreq", - .subsys = &s3c2412_subsys, - .add_dev = s3c2412_cpufreq_add, -}; - -static int s3c2412_cpufreq_init(void) -{ - return subsys_interface_register(&s3c2412_cpufreq_interface); -} -arch_initcall(s3c2412_cpufreq_init); diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c deleted file mode 100644 index 5c221bc90210..000000000000 --- a/drivers/cpufreq/s3c2416-cpufreq.c +++ /dev/null @@ -1,492 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * S3C2416/2450 CPUfreq Support - * - * Copyright 2011 Heiko Stuebner <heiko@sntech.de> - * - * based on s3c64xx_cpufreq.c - * - * Copyright 2009 Wolfson Microelectronics plc - */ - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/cpufreq.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/regulator/consumer.h> -#include <linux/reboot.h> -#include <linux/module.h> - -static DEFINE_MUTEX(cpufreq_lock); - -struct s3c2416_data { - struct clk *armdiv; - struct clk *armclk; - struct clk *hclk; - - unsigned long regulator_latency; -#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE - struct regulator *vddarm; -#endif - - struct cpufreq_frequency_table *freq_table; - - bool is_dvs; - bool disable_dvs; -}; - -static struct s3c2416_data s3c2416_cpufreq; - -struct s3c2416_dvfs { - unsigned int vddarm_min; - unsigned int vddarm_max; -}; - -/* pseudo-frequency for dvs mode */ -#define FREQ_DVS 132333 - -/* frequency to sleep and reboot in - * it's essential to leave dvs, as some boards do not reconfigure the - * regulator on reboot - */ -#define FREQ_SLEEP 133333 - -/* Sources for the ARMCLK */ -#define SOURCE_HCLK 0 -#define SOURCE_ARMDIV 1 - -#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE -/* S3C2416 only supports changing the voltage in the dvs-mode. - * Voltages down to 1.0V seem to work, so we take what the regulator - * can get us. - */ -static struct s3c2416_dvfs s3c2416_dvfs_table[] = { - [SOURCE_HCLK] = { 950000, 1250000 }, - [SOURCE_ARMDIV] = { 1250000, 1350000 }, -}; -#endif - -static struct cpufreq_frequency_table s3c2416_freq_table[] = { - { 0, SOURCE_HCLK, FREQ_DVS }, - { 0, SOURCE_ARMDIV, 133333 }, - { 0, SOURCE_ARMDIV, 266666 }, - { 0, SOURCE_ARMDIV, 400000 }, - { 0, 0, CPUFREQ_TABLE_END }, -}; - -static struct cpufreq_frequency_table s3c2450_freq_table[] = { - { 0, SOURCE_HCLK, FREQ_DVS }, - { 0, SOURCE_ARMDIV, 133500 }, - { 0, SOURCE_ARMDIV, 267000 }, - { 0, SOURCE_ARMDIV, 534000 }, - { 0, 0, CPUFREQ_TABLE_END }, -}; - -static unsigned int s3c2416_cpufreq_get_speed(unsigned int cpu) -{ - struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; - - if (cpu != 0) - return 0; - - /* return our pseudo-frequency when in dvs mode */ - if (s3c_freq->is_dvs) - return FREQ_DVS; - - return clk_get_rate(s3c_freq->armclk) / 1000; -} - -static int s3c2416_cpufreq_set_armdiv(struct s3c2416_data *s3c_freq, - unsigned int freq) -{ - int ret; - - if (clk_get_rate(s3c_freq->armdiv) / 1000 != freq) { - ret = clk_set_rate(s3c_freq->armdiv, freq * 1000); - if (ret < 0) { - pr_err("cpufreq: Failed to set armdiv rate %dkHz: %d\n", - freq, ret); - return ret; - } - } - - return 0; -} - -static int s3c2416_cpufreq_enter_dvs(struct s3c2416_data *s3c_freq, int idx) -{ -#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE - struct s3c2416_dvfs *dvfs; -#endif - int ret; - - if (s3c_freq->is_dvs) { - pr_debug("cpufreq: already in dvs mode, nothing to do\n"); - return 0; - } - - pr_debug("cpufreq: switching armclk to hclk (%lukHz)\n", - clk_get_rate(s3c_freq->hclk) / 1000); - ret = clk_set_parent(s3c_freq->armclk, s3c_freq->hclk); - if (ret < 0) { - pr_err("cpufreq: Failed to switch armclk to hclk: %d\n", ret); - return ret; - } - -#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE - /* changing the core voltage is only allowed when in dvs mode */ - if (s3c_freq->vddarm) { - dvfs = &s3c2416_dvfs_table[idx]; - - pr_debug("cpufreq: setting regulator to %d-%d\n", - dvfs->vddarm_min, dvfs->vddarm_max); - ret = regulator_set_voltage(s3c_freq->vddarm, - dvfs->vddarm_min, - dvfs->vddarm_max); - - /* when lowering the voltage failed, there is nothing to do */ - if (ret != 0) - pr_err("cpufreq: Failed to set VDDARM: %d\n", ret); - } -#endif - - s3c_freq->is_dvs = 1; - - return 0; -} - -static int s3c2416_cpufreq_leave_dvs(struct s3c2416_data *s3c_freq, int idx) -{ -#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE - struct s3c2416_dvfs *dvfs; -#endif - int ret; - - if (!s3c_freq->is_dvs) { - pr_debug("cpufreq: not in dvs mode, so can't leave\n"); - return 0; - } - -#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE - if (s3c_freq->vddarm) { - dvfs = &s3c2416_dvfs_table[idx]; - - pr_debug("cpufreq: setting regulator to %d-%d\n", - dvfs->vddarm_min, dvfs->vddarm_max); - ret = regulator_set_voltage(s3c_freq->vddarm, - dvfs->vddarm_min, - dvfs->vddarm_max); - if (ret != 0) { - pr_err("cpufreq: Failed to set VDDARM: %d\n", ret); - return ret; - } - } -#endif - - /* force armdiv to hclk frequency for transition from dvs*/ - if (clk_get_rate(s3c_freq->armdiv) > clk_get_rate(s3c_freq->hclk)) { - pr_debug("cpufreq: force armdiv to hclk frequency (%lukHz)\n", - clk_get_rate(s3c_freq->hclk) / 1000); - ret = s3c2416_cpufreq_set_armdiv(s3c_freq, - clk_get_rate(s3c_freq->hclk) / 1000); - if (ret < 0) { - pr_err("cpufreq: Failed to set the armdiv to %lukHz: %d\n", - clk_get_rate(s3c_freq->hclk) / 1000, ret); - return ret; - } - } - - pr_debug("cpufreq: switching armclk parent to armdiv (%lukHz)\n", - clk_get_rate(s3c_freq->armdiv) / 1000); - - ret = clk_set_parent(s3c_freq->armclk, s3c_freq->armdiv); - if (ret < 0) { - pr_err("cpufreq: Failed to switch armclk clock parent to armdiv: %d\n", - ret); - return ret; - } - - s3c_freq->is_dvs = 0; - - return 0; -} - -static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, - unsigned int index) -{ - struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; - unsigned int new_freq; - int idx, ret, to_dvs = 0; - - mutex_lock(&cpufreq_lock); - - idx = s3c_freq->freq_table[index].driver_data; - - if (idx == SOURCE_HCLK) - to_dvs = 1; - - /* switching to dvs when it's not allowed */ - if (to_dvs && s3c_freq->disable_dvs) { - pr_debug("cpufreq: entering dvs mode not allowed\n"); - ret = -EINVAL; - goto out; - } - - /* When leavin dvs mode, always switch the armdiv to the hclk rate - * The S3C2416 has stability issues when switching directly to - * higher frequencies. - */ - new_freq = (s3c_freq->is_dvs && !to_dvs) - ? clk_get_rate(s3c_freq->hclk) / 1000 - : s3c_freq->freq_table[index].frequency; - - if (to_dvs) { - pr_debug("cpufreq: enter dvs\n"); - ret = s3c2416_cpufreq_enter_dvs(s3c_freq, idx); - } else if (s3c_freq->is_dvs) { - pr_debug("cpufreq: leave dvs\n"); - ret = s3c2416_cpufreq_leave_dvs(s3c_freq, idx); - } else { - pr_debug("cpufreq: change armdiv to %dkHz\n", new_freq); - ret = s3c2416_cpufreq_set_armdiv(s3c_freq, new_freq); - } - -out: - mutex_unlock(&cpufreq_lock); - - return ret; -} - -#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE -static void s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq) -{ - int count, v, i, found; - struct cpufreq_frequency_table *pos; - struct s3c2416_dvfs *dvfs; - - count = regulator_count_voltages(s3c_freq->vddarm); - if (count < 0) { - pr_err("cpufreq: Unable to check supported voltages\n"); - return; - } - - if (!count) - goto out; - - cpufreq_for_each_valid_entry(pos, s3c_freq->freq_table) { - dvfs = &s3c2416_dvfs_table[pos->driver_data]; - found = 0; - - /* Check only the min-voltage, more is always ok on S3C2416 */ - for (i = 0; i < count; i++) { - v = regulator_list_voltage(s3c_freq->vddarm, i); - if (v >= dvfs->vddarm_min) - found = 1; - } - - if (!found) { - pr_debug("cpufreq: %dkHz unsupported by regulator\n", - pos->frequency); - pos->frequency = CPUFREQ_ENTRY_INVALID; - } - } - -out: - /* Guessed */ - s3c_freq->regulator_latency = 1 * 1000 * 1000; -} -#endif - -static int s3c2416_cpufreq_reboot_notifier_evt(struct notifier_block *this, - unsigned long event, void *ptr) -{ - struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; - int ret; - struct cpufreq_policy *policy; - - mutex_lock(&cpufreq_lock); - - /* disable further changes */ - s3c_freq->disable_dvs = 1; - - mutex_unlock(&cpufreq_lock); - - /* some boards don't reconfigure the regulator on reboot, which - * could lead to undervolting the cpu when the clock is reset. - * Therefore we always leave the DVS mode on reboot. - */ - if (s3c_freq->is_dvs) { - pr_debug("cpufreq: leave dvs on reboot\n"); - - policy = cpufreq_cpu_get(0); - if (!policy) { - pr_debug("cpufreq: get no policy for cpu0\n"); - return NOTIFY_BAD; - } - - ret = cpufreq_driver_target(policy, FREQ_SLEEP, 0); - cpufreq_cpu_put(policy); - - if (ret < 0) - return NOTIFY_BAD; - } - - return NOTIFY_DONE; -} - -static struct notifier_block s3c2416_cpufreq_reboot_notifier = { - .notifier_call = s3c2416_cpufreq_reboot_notifier_evt, -}; - -static int s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy) -{ - struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; - struct cpufreq_frequency_table *pos; - struct clk *msysclk; - unsigned long rate; - int ret; - - if (policy->cpu != 0) - return -EINVAL; - - msysclk = clk_get(NULL, "msysclk"); - if (IS_ERR(msysclk)) { - ret = PTR_ERR(msysclk); - pr_err("cpufreq: Unable to obtain msysclk: %d\n", ret); - return ret; - } - - /* - * S3C2416 and S3C2450 share the same processor-ID and also provide no - * other means to distinguish them other than through the rate of - * msysclk. On S3C2416 msysclk runs at 800MHz and on S3C2450 at 533MHz. - */ - rate = clk_get_rate(msysclk); - if (rate == 800 * 1000 * 1000) { - pr_info("cpufreq: msysclk running at %lukHz, using S3C2416 frequency table\n", - rate / 1000); - s3c_freq->freq_table = s3c2416_freq_table; - policy->cpuinfo.max_freq = 400000; - } else if (rate / 1000 == 534000) { - pr_info("cpufreq: msysclk running at %lukHz, using S3C2450 frequency table\n", - rate / 1000); - s3c_freq->freq_table = s3c2450_freq_table; - policy->cpuinfo.max_freq = 534000; - } - - /* not needed anymore */ - clk_put(msysclk); - - if (s3c_freq->freq_table == NULL) { - pr_err("cpufreq: No frequency information for this CPU, msysclk at %lukHz\n", - rate / 1000); - return -ENODEV; - } - - s3c_freq->is_dvs = 0; - - s3c_freq->armdiv = clk_get(NULL, "armdiv"); - if (IS_ERR(s3c_freq->armdiv)) { - ret = PTR_ERR(s3c_freq->armdiv); - pr_err("cpufreq: Unable to obtain ARMDIV: %d\n", ret); - return ret; - } - - s3c_freq->hclk = clk_get(NULL, "hclk"); - if (IS_ERR(s3c_freq->hclk)) { - ret = PTR_ERR(s3c_freq->hclk); - pr_err("cpufreq: Unable to obtain HCLK: %d\n", ret); - goto err_hclk; - } - - /* chech hclk rate, we only support the common 133MHz for now - * hclk could also run at 66MHz, but this not often used - */ - rate = clk_get_rate(s3c_freq->hclk); - if (rate < 133 * 1000 * 1000) { - pr_err("cpufreq: HCLK not at 133MHz\n"); - ret = -EINVAL; - goto err_armclk; - } - - s3c_freq->armclk = clk_get(NULL, "armclk"); - if (IS_ERR(s3c_freq->armclk)) { - ret = PTR_ERR(s3c_freq->armclk); - pr_err("cpufreq: Unable to obtain ARMCLK: %d\n", ret); - goto err_armclk; - } - -#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE - s3c_freq->vddarm = regulator_get(NULL, "vddarm"); - if (IS_ERR(s3c_freq->vddarm)) { - ret = PTR_ERR(s3c_freq->vddarm); - pr_err("cpufreq: Failed to obtain VDDARM: %d\n", ret); - goto err_vddarm; - } - - s3c2416_cpufreq_cfg_regulator(s3c_freq); -#else - s3c_freq->regulator_latency = 0; -#endif - - cpufreq_for_each_entry(pos, s3c_freq->freq_table) { - /* special handling for dvs mode */ - if (pos->driver_data == 0) { - if (!s3c_freq->hclk) { - pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n", - pos->frequency); - pos->frequency = CPUFREQ_ENTRY_INVALID; - } else { - continue; - } - } - - /* Check for frequencies we can generate */ - rate = clk_round_rate(s3c_freq->armdiv, - pos->frequency * 1000); - rate /= 1000; - if (rate != pos->frequency) { - pr_debug("cpufreq: %dkHz unsupported by clock (clk_round_rate return %lu)\n", - pos->frequency, rate); - pos->frequency = CPUFREQ_ENTRY_INVALID; - } - } - - /* Datasheet says PLL stabalisation time must be at least 300us, - * so but add some fudge. (reference in LOCKCON0 register description) - */ - cpufreq_generic_init(policy, s3c_freq->freq_table, - (500 * 1000) + s3c_freq->regulator_latency); - register_reboot_notifier(&s3c2416_cpufreq_reboot_notifier); - - return 0; - -#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE -err_vddarm: - clk_put(s3c_freq->armclk); -#endif -err_armclk: - clk_put(s3c_freq->hclk); -err_hclk: - clk_put(s3c_freq->armdiv); - - return ret; -} - -static struct cpufreq_driver s3c2416_cpufreq_driver = { - .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, - .verify = cpufreq_generic_frequency_table_verify, - .target_index = s3c2416_cpufreq_set_target, - .get = s3c2416_cpufreq_get_speed, - .init = s3c2416_cpufreq_driver_init, - .name = "s3c2416", - .attr = cpufreq_generic_attr, -}; - -static int __init s3c2416_cpufreq_init(void) -{ - return cpufreq_register_driver(&s3c2416_cpufreq_driver); -} -module_init(s3c2416_cpufreq_init); diff --git a/drivers/cpufreq/s3c2440-cpufreq.c b/drivers/cpufreq/s3c2440-cpufreq.c deleted file mode 100644 index 2011fb9c03a4..000000000000 --- a/drivers/cpufreq/s3c2440-cpufreq.c +++ /dev/null @@ -1,321 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2006-2009 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks <ben@simtec.co.uk> - * Vincent Sanders <vince@simtec.co.uk> - * - * S3C2440/S3C2442 CPU Frequency scaling -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/cpufreq.h> -#include <linux/device.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/soc/samsung/s3c-cpufreq-core.h> -#include <linux/soc/samsung/s3c-pm.h> - -#include <asm/mach/arch.h> -#include <asm/mach/map.h> - -#define S3C2440_CLKDIVN_PDIVN (1<<0) -#define S3C2440_CLKDIVN_HDIVN_MASK (3<<1) -#define S3C2440_CLKDIVN_HDIVN_1 (0<<1) -#define S3C2440_CLKDIVN_HDIVN_2 (1<<1) -#define S3C2440_CLKDIVN_HDIVN_4_8 (2<<1) -#define S3C2440_CLKDIVN_HDIVN_3_6 (3<<1) -#define S3C2440_CLKDIVN_UCLK (1<<3) - -#define S3C2440_CAMDIVN_CAMCLK_MASK (0xf<<0) -#define S3C2440_CAMDIVN_CAMCLK_SEL (1<<4) -#define S3C2440_CAMDIVN_HCLK3_HALF (1<<8) -#define S3C2440_CAMDIVN_HCLK4_HALF (1<<9) -#define S3C2440_CAMDIVN_DVSEN (1<<12) - -#define S3C2442_CAMDIVN_CAMCLK_DIV3 (1<<5) - -static struct clk *xtal; -static struct clk *fclk; -static struct clk *hclk; -static struct clk *armclk; - -/* HDIV: 1, 2, 3, 4, 6, 8 */ - -static inline int within_khz(unsigned long a, unsigned long b) -{ - long diff = a - b; - - return (diff >= -1000 && diff <= 1000); -} - -/** - * s3c2440_cpufreq_calcdivs - calculate divider settings - * @cfg: The cpu frequency settings. - * - * Calcualte the divider values for the given frequency settings - * specified in @cfg. The values are stored in @cfg for later use - * by the relevant set routine if the request settings can be reached. - */ -static int s3c2440_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg) -{ - unsigned int hdiv, pdiv; - unsigned long hclk, fclk, armclk; - unsigned long hclk_max; - - fclk = cfg->freq.fclk; - armclk = cfg->freq.armclk; - hclk_max = cfg->max.hclk; - - s3c_freq_dbg("%s: fclk is %lu, armclk %lu, max hclk %lu\n", - __func__, fclk, armclk, hclk_max); - - if (armclk > fclk) { - pr_warn("%s: armclk > fclk\n", __func__); - armclk = fclk; - } - - /* if we are in DVS, we need HCLK to be <= ARMCLK */ - if (armclk < fclk && armclk < hclk_max) - hclk_max = armclk; - - for (hdiv = 1; hdiv < 9; hdiv++) { - if (hdiv == 5 || hdiv == 7) - hdiv++; - - hclk = (fclk / hdiv); - if (hclk <= hclk_max || within_khz(hclk, hclk_max)) - break; - } - - s3c_freq_dbg("%s: hclk %lu, div %d\n", __func__, hclk, hdiv); - - if (hdiv > 8) - goto invalid; - - pdiv = (hclk > cfg->max.pclk) ? 2 : 1; - - if ((hclk / pdiv) > cfg->max.pclk) - pdiv++; - - s3c_freq_dbg("%s: pdiv %d\n", __func__, pdiv); - - if (pdiv > 2) - goto invalid; - - pdiv *= hdiv; - - /* calculate a valid armclk */ - - if (armclk < hclk) - armclk = hclk; - - /* if we're running armclk lower than fclk, this really means - * that the system should go into dvs mode, which means that - * armclk is connected to hclk. */ - if (armclk < fclk) { - cfg->divs.dvs = 1; - armclk = hclk; - } else - cfg->divs.dvs = 0; - - cfg->freq.armclk = armclk; - - /* store the result, and then return */ - - cfg->divs.h_divisor = hdiv; - cfg->divs.p_divisor = pdiv; - - return 0; - - invalid: - return -EINVAL; -} - -#define CAMDIVN_HCLK_HALF (S3C2440_CAMDIVN_HCLK3_HALF | \ - S3C2440_CAMDIVN_HCLK4_HALF) - -/** - * s3c2440_cpufreq_setdivs - set the cpu frequency divider settings - * @cfg: The cpu frequency settings. - * - * Set the divisors from the settings in @cfg, which where generated - * during the calculation phase by s3c2440_cpufreq_calcdivs(). - */ -static void s3c2440_cpufreq_setdivs(struct s3c_cpufreq_config *cfg) -{ - unsigned long clkdiv, camdiv; - - s3c_freq_dbg("%s: divisors: h=%d, p=%d\n", __func__, - cfg->divs.h_divisor, cfg->divs.p_divisor); - - clkdiv = s3c24xx_read_clkdivn(); - camdiv = s3c2440_read_camdivn(); - - clkdiv &= ~(S3C2440_CLKDIVN_HDIVN_MASK | S3C2440_CLKDIVN_PDIVN); - camdiv &= ~CAMDIVN_HCLK_HALF; - - switch (cfg->divs.h_divisor) { - case 1: - clkdiv |= S3C2440_CLKDIVN_HDIVN_1; - break; - - case 2: - clkdiv |= S3C2440_CLKDIVN_HDIVN_2; - break; - - case 6: - camdiv |= S3C2440_CAMDIVN_HCLK3_HALF; - fallthrough; - case 3: - clkdiv |= S3C2440_CLKDIVN_HDIVN_3_6; - break; - - case 8: - camdiv |= S3C2440_CAMDIVN_HCLK4_HALF; - fallthrough; - case 4: - clkdiv |= S3C2440_CLKDIVN_HDIVN_4_8; - break; - - default: - BUG(); /* we don't expect to get here. */ - } - - if (cfg->divs.p_divisor != cfg->divs.h_divisor) - clkdiv |= S3C2440_CLKDIVN_PDIVN; - - /* todo - set pclk. */ - - /* Write the divisors first with hclk intentionally halved so that - * when we write clkdiv we will under-frequency instead of over. We - * then make a short delay and remove the hclk halving if necessary. - */ - - s3c2440_write_camdivn(camdiv | CAMDIVN_HCLK_HALF); - s3c24xx_write_clkdivn(clkdiv); - - ndelay(20); - s3c2440_write_camdivn(camdiv); - - clk_set_parent(armclk, cfg->divs.dvs ? hclk : fclk); -} - -static int run_freq_for(unsigned long max_hclk, unsigned long fclk, - int *divs, - struct cpufreq_frequency_table *table, - size_t table_size) -{ - unsigned long freq; - int index = 0; - int div; - - for (div = *divs; div > 0; div = *divs++) { - freq = fclk / div; - - if (freq > max_hclk && div != 1) - continue; - - freq /= 1000; /* table is in kHz */ - index = s3c_cpufreq_addfreq(table, index, table_size, freq); - if (index < 0) - break; - } - - return index; -} - -static int hclk_divs[] = { 1, 2, 3, 4, 6, 8, -1 }; - -static int s3c2440_cpufreq_calctable(struct s3c_cpufreq_config *cfg, - struct cpufreq_frequency_table *table, - size_t table_size) -{ - int ret; - - WARN_ON(cfg->info == NULL); - WARN_ON(cfg->board == NULL); - - ret = run_freq_for(cfg->info->max.hclk, - cfg->info->max.fclk, - hclk_divs, - table, table_size); - - s3c_freq_dbg("%s: returning %d\n", __func__, ret); - - return ret; -} - -static struct s3c_cpufreq_info s3c2440_cpufreq_info = { - .max = { - .fclk = 400000000, - .hclk = 133333333, - .pclk = 66666666, - }, - - .locktime_m = 300, - .locktime_u = 300, - .locktime_bits = 16, - - .name = "s3c244x", - .calc_iotiming = s3c2410_iotiming_calc, - .set_iotiming = s3c2410_iotiming_set, - .get_iotiming = s3c2410_iotiming_get, - .set_fvco = s3c2410_set_fvco, - - .set_refresh = s3c2410_cpufreq_setrefresh, - .set_divs = s3c2440_cpufreq_setdivs, - .calc_divs = s3c2440_cpufreq_calcdivs, - .calc_freqtable = s3c2440_cpufreq_calctable, - - .debug_io_show = s3c_cpufreq_debugfs_call(s3c2410_iotiming_debugfs), -}; - -static int s3c2440_cpufreq_add(struct device *dev, - struct subsys_interface *sif) -{ - xtal = s3c_cpufreq_clk_get(NULL, "xtal"); - hclk = s3c_cpufreq_clk_get(NULL, "hclk"); - fclk = s3c_cpufreq_clk_get(NULL, "fclk"); - armclk = s3c_cpufreq_clk_get(NULL, "armclk"); - - if (IS_ERR(xtal) || IS_ERR(hclk) || IS_ERR(fclk) || IS_ERR(armclk)) { - pr_err("%s: failed to get clocks\n", __func__); - return -ENOENT; - } - - return s3c_cpufreq_register(&s3c2440_cpufreq_info); -} - -static struct subsys_interface s3c2440_cpufreq_interface = { - .name = "s3c2440_cpufreq", - .subsys = &s3c2440_subsys, - .add_dev = s3c2440_cpufreq_add, -}; - -static int s3c2440_cpufreq_init(void) -{ - return subsys_interface_register(&s3c2440_cpufreq_interface); -} - -/* arch_initcall adds the clocks we need, so use subsys_initcall. */ -subsys_initcall(s3c2440_cpufreq_init); - -static struct subsys_interface s3c2442_cpufreq_interface = { - .name = "s3c2442_cpufreq", - .subsys = &s3c2442_subsys, - .add_dev = s3c2440_cpufreq_add, -}; - -static int s3c2442_cpufreq_init(void) -{ - return subsys_interface_register(&s3c2442_cpufreq_interface); -} -subsys_initcall(s3c2442_cpufreq_init); diff --git a/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c b/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c deleted file mode 100644 index 93971dfe7c75..000000000000 --- a/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c +++ /dev/null @@ -1,163 +0,0 @@ -// 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 -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/init.h> -#include <linux/export.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/cpufreq.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <linux/err.h> - -#include <linux/soc/samsung/s3c-cpufreq-core.h> - -static struct dentry *dbgfs_root; -static struct dentry *dbgfs_file_io; -static struct dentry *dbgfs_file_info; -static struct dentry *dbgfs_file_board; - -#define print_ns(x) ((x) / 10), ((x) % 10) - -static void show_max(struct seq_file *seq, struct s3c_freq *f) -{ - seq_printf(seq, "MAX: F=%lu, H=%lu, P=%lu, A=%lu\n", - f->fclk, f->hclk, f->pclk, f->armclk); -} - -static int board_show(struct seq_file *seq, void *p) -{ - struct s3c_cpufreq_config *cfg; - struct s3c_cpufreq_board *brd; - - cfg = s3c_cpufreq_getconfig(); - if (!cfg) { - seq_printf(seq, "no configuration registered\n"); - return 0; - } - - brd = cfg->board; - if (!brd) { - seq_printf(seq, "no board definition set?\n"); - return 0; - } - - seq_printf(seq, "SDRAM refresh %u ns\n", brd->refresh); - seq_printf(seq, "auto_io=%u\n", brd->auto_io); - seq_printf(seq, "need_io=%u\n", brd->need_io); - - show_max(seq, &brd->max); - - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(board); - -static int info_show(struct seq_file *seq, void *p) -{ - struct s3c_cpufreq_config *cfg; - - cfg = s3c_cpufreq_getconfig(); - if (!cfg) { - seq_printf(seq, "no configuration registered\n"); - return 0; - } - - seq_printf(seq, " FCLK %ld Hz\n", cfg->freq.fclk); - seq_printf(seq, " HCLK %ld Hz (%lu.%lu ns)\n", - cfg->freq.hclk, print_ns(cfg->freq.hclk_tns)); - seq_printf(seq, " PCLK %ld Hz\n", cfg->freq.hclk); - seq_printf(seq, "ARMCLK %ld Hz\n", cfg->freq.armclk); - seq_printf(seq, "\n"); - - show_max(seq, &cfg->max); - - seq_printf(seq, "Divisors: P=%d, H=%d, A=%d, dvs=%s\n", - cfg->divs.h_divisor, cfg->divs.p_divisor, - cfg->divs.arm_divisor, cfg->divs.dvs ? "on" : "off"); - seq_printf(seq, "\n"); - - seq_printf(seq, "lock_pll=%u\n", cfg->lock_pll); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(info); - -static int io_show(struct seq_file *seq, void *p) -{ - void (*show_bank)(struct seq_file *, struct s3c_cpufreq_config *, union s3c_iobank *); - struct s3c_cpufreq_config *cfg; - struct s3c_iotimings *iot; - union s3c_iobank *iob; - int bank; - - cfg = s3c_cpufreq_getconfig(); - if (!cfg) { - seq_printf(seq, "no configuration registered\n"); - return 0; - } - - show_bank = cfg->info->debug_io_show; - if (!show_bank) { - seq_printf(seq, "no code to show bank timing\n"); - return 0; - } - - iot = s3c_cpufreq_getiotimings(); - if (!iot) { - seq_printf(seq, "no io timings registered\n"); - return 0; - } - - seq_printf(seq, "hclk period is %lu.%lu ns\n", print_ns(cfg->freq.hclk_tns)); - - for (bank = 0; bank < MAX_BANKS; bank++) { - iob = &iot->bank[bank]; - - seq_printf(seq, "bank %d: ", bank); - - if (!iob->io_2410) { - seq_printf(seq, "nothing set\n"); - continue; - } - - show_bank(seq, cfg, iob); - } - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(io); - -static int __init s3c_freq_debugfs_init(void) -{ - dbgfs_root = debugfs_create_dir("s3c-cpufreq", NULL); - if (IS_ERR(dbgfs_root)) { - pr_err("%s: error creating debugfs root\n", __func__); - return PTR_ERR(dbgfs_root); - } - - dbgfs_file_io = debugfs_create_file("io-timing", S_IRUGO, dbgfs_root, - NULL, &io_fops); - - dbgfs_file_info = debugfs_create_file("info", S_IRUGO, dbgfs_root, - NULL, &info_fops); - - dbgfs_file_board = debugfs_create_file("board", S_IRUGO, dbgfs_root, - NULL, &board_fops); - - return 0; -} - -late_initcall(s3c_freq_debugfs_init); - diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c deleted file mode 100644 index 7380c32b238e..000000000000 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ /dev/null @@ -1,648 +0,0 @@ -// 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 -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/cpufreq.h> -#include <linux/cpu.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/device.h> -#include <linux/sysfs.h> -#include <linux/slab.h> -#include <linux/soc/samsung/s3c-cpufreq-core.h> -#include <linux/soc/samsung/s3c-pm.h> - -#include <asm/mach/arch.h> -#include <asm/mach/map.h> - -/* note, cpufreq support deals in kHz, no Hz */ -static struct cpufreq_driver s3c24xx_driver; -static struct s3c_cpufreq_config cpu_cur; -static struct s3c_iotimings s3c24xx_iotiming; -static struct cpufreq_frequency_table *pll_reg; -static unsigned int last_target = ~0; -static unsigned int ftab_size; -static struct cpufreq_frequency_table *ftab; - -static struct clk *_clk_mpll; -static struct clk *_clk_xtal; -static struct clk *clk_fclk; -static struct clk *clk_hclk; -static struct clk *clk_pclk; -static struct clk *clk_arm; - -#ifdef CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS -struct s3c_cpufreq_config *s3c_cpufreq_getconfig(void) -{ - return &cpu_cur; -} - -struct s3c_iotimings *s3c_cpufreq_getiotimings(void) -{ - return &s3c24xx_iotiming; -} -#endif /* CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS */ - -static void s3c_cpufreq_getcur(struct s3c_cpufreq_config *cfg) -{ - unsigned long fclk, pclk, hclk, armclk; - - cfg->freq.fclk = fclk = clk_get_rate(clk_fclk); - cfg->freq.hclk = hclk = clk_get_rate(clk_hclk); - cfg->freq.pclk = pclk = clk_get_rate(clk_pclk); - cfg->freq.armclk = armclk = clk_get_rate(clk_arm); - - cfg->pll.driver_data = s3c24xx_read_mpllcon(); - cfg->pll.frequency = fclk; - - cfg->freq.hclk_tns = 1000000000 / (cfg->freq.hclk / 10); - - cfg->divs.h_divisor = fclk / hclk; - cfg->divs.p_divisor = fclk / pclk; -} - -static inline void s3c_cpufreq_calc(struct s3c_cpufreq_config *cfg) -{ - unsigned long pll = cfg->pll.frequency; - - cfg->freq.fclk = pll; - cfg->freq.hclk = pll / cfg->divs.h_divisor; - cfg->freq.pclk = pll / cfg->divs.p_divisor; - - /* convert hclk into 10ths of nanoseconds for io calcs */ - cfg->freq.hclk_tns = 1000000000 / (cfg->freq.hclk / 10); -} - -static inline int closer(unsigned int target, unsigned int n, unsigned int c) -{ - int diff_cur = abs(target - c); - int diff_new = abs(target - n); - - return (diff_new < diff_cur); -} - -static void s3c_cpufreq_show(const char *pfx, - struct s3c_cpufreq_config *cfg) -{ - s3c_freq_dbg("%s: Fvco=%u, F=%lu, A=%lu, H=%lu (%u), P=%lu (%u)\n", - pfx, cfg->pll.frequency, cfg->freq.fclk, cfg->freq.armclk, - cfg->freq.hclk, cfg->divs.h_divisor, - cfg->freq.pclk, cfg->divs.p_divisor); -} - -/* functions to wrapper the driver info calls to do the cpu specific work */ - -static void s3c_cpufreq_setio(struct s3c_cpufreq_config *cfg) -{ - if (cfg->info->set_iotiming) - (cfg->info->set_iotiming)(cfg, &s3c24xx_iotiming); -} - -static int s3c_cpufreq_calcio(struct s3c_cpufreq_config *cfg) -{ - if (cfg->info->calc_iotiming) - return (cfg->info->calc_iotiming)(cfg, &s3c24xx_iotiming); - - return 0; -} - -static void s3c_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg) -{ - (cfg->info->set_refresh)(cfg); -} - -static void s3c_cpufreq_setdivs(struct s3c_cpufreq_config *cfg) -{ - (cfg->info->set_divs)(cfg); -} - -static int s3c_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg) -{ - return (cfg->info->calc_divs)(cfg); -} - -static void s3c_cpufreq_setfvco(struct s3c_cpufreq_config *cfg) -{ - cfg->mpll = _clk_mpll; - (cfg->info->set_fvco)(cfg); -} - -static inline void s3c_cpufreq_updateclk(struct clk *clk, - unsigned int freq) -{ - clk_set_rate(clk, freq); -} - -static int s3c_cpufreq_settarget(struct cpufreq_policy *policy, - unsigned int target_freq, - struct cpufreq_frequency_table *pll) -{ - struct s3c_cpufreq_freqs freqs; - struct s3c_cpufreq_config cpu_new; - unsigned long flags; - - cpu_new = cpu_cur; /* copy new from current */ - - s3c_cpufreq_show("cur", &cpu_cur); - - /* TODO - check for DMA currently outstanding */ - - cpu_new.pll = pll ? *pll : cpu_cur.pll; - - if (pll) - freqs.pll_changing = 1; - - /* update our frequencies */ - - cpu_new.freq.armclk = target_freq; - cpu_new.freq.fclk = cpu_new.pll.frequency; - - if (s3c_cpufreq_calcdivs(&cpu_new) < 0) { - pr_err("no divisors for %d\n", target_freq); - goto err_notpossible; - } - - s3c_freq_dbg("%s: got divs\n", __func__); - - s3c_cpufreq_calc(&cpu_new); - - s3c_freq_dbg("%s: calculated frequencies for new\n", __func__); - - if (cpu_new.freq.hclk != cpu_cur.freq.hclk) { - if (s3c_cpufreq_calcio(&cpu_new) < 0) { - pr_err("%s: no IO timings\n", __func__); - goto err_notpossible; - } - } - - s3c_cpufreq_show("new", &cpu_new); - - /* setup our cpufreq parameters */ - - freqs.old = cpu_cur.freq; - freqs.new = cpu_new.freq; - - freqs.freqs.old = cpu_cur.freq.armclk / 1000; - freqs.freqs.new = cpu_new.freq.armclk / 1000; - - /* update f/h/p clock settings before we issue the change - * notification, so that drivers do not need to do anything - * special if they want to recalculate on CPUFREQ_PRECHANGE. */ - - s3c_cpufreq_updateclk(_clk_mpll, cpu_new.pll.frequency); - s3c_cpufreq_updateclk(clk_fclk, cpu_new.freq.fclk); - s3c_cpufreq_updateclk(clk_hclk, cpu_new.freq.hclk); - s3c_cpufreq_updateclk(clk_pclk, cpu_new.freq.pclk); - - /* start the frequency change */ - cpufreq_freq_transition_begin(policy, &freqs.freqs); - - /* If hclk is staying the same, then we do not need to - * re-write the IO or the refresh timings whilst we are changing - * speed. */ - - local_irq_save(flags); - - /* is our memory clock slowing down? */ - if (cpu_new.freq.hclk < cpu_cur.freq.hclk) { - s3c_cpufreq_setrefresh(&cpu_new); - s3c_cpufreq_setio(&cpu_new); - } - - if (cpu_new.freq.fclk == cpu_cur.freq.fclk) { - /* not changing PLL, just set the divisors */ - - s3c_cpufreq_setdivs(&cpu_new); - } else { - if (cpu_new.freq.fclk < cpu_cur.freq.fclk) { - /* slow the cpu down, then set divisors */ - - s3c_cpufreq_setfvco(&cpu_new); - s3c_cpufreq_setdivs(&cpu_new); - } else { - /* set the divisors, then speed up */ - - s3c_cpufreq_setdivs(&cpu_new); - s3c_cpufreq_setfvco(&cpu_new); - } - } - - /* did our memory clock speed up */ - if (cpu_new.freq.hclk > cpu_cur.freq.hclk) { - s3c_cpufreq_setrefresh(&cpu_new); - s3c_cpufreq_setio(&cpu_new); - } - - /* update our current settings */ - cpu_cur = cpu_new; - - local_irq_restore(flags); - - /* notify everyone we've done this */ - cpufreq_freq_transition_end(policy, &freqs.freqs, 0); - - s3c_freq_dbg("%s: finished\n", __func__); - return 0; - - err_notpossible: - pr_err("no compatible settings for %d\n", target_freq); - return -EINVAL; -} - -/* s3c_cpufreq_target - * - * called by the cpufreq core to adjust the frequency that the CPU - * is currently running at. - */ - -static int s3c_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - struct cpufreq_frequency_table *pll; - unsigned int index; - - /* avoid repeated calls which cause a needless amout of duplicated - * logging output (and CPU time as the calculation process is - * done) */ - if (target_freq == last_target) - return 0; - - last_target = target_freq; - - s3c_freq_dbg("%s: policy %p, target %u, relation %u\n", - __func__, policy, target_freq, relation); - - if (ftab) { - index = cpufreq_frequency_table_target(policy, target_freq, - relation); - - s3c_freq_dbg("%s: adjust %d to entry %d (%u)\n", __func__, - target_freq, index, ftab[index].frequency); - target_freq = ftab[index].frequency; - } - - target_freq *= 1000; /* convert target to Hz */ - - /* find the settings for our new frequency */ - - if (!pll_reg || cpu_cur.lock_pll) { - /* either we've not got any PLL values, or we've locked - * to the current one. */ - pll = NULL; - } else { - struct cpufreq_policy tmp_policy; - - /* we keep the cpu pll table in Hz, to ensure we get an - * accurate value for the PLL output. */ - - tmp_policy.min = policy->min * 1000; - tmp_policy.max = policy->max * 1000; - tmp_policy.cpu = policy->cpu; - tmp_policy.freq_table = pll_reg; - - /* cpufreq_frequency_table_target returns the index - * of the table entry, not the value of - * the table entry's index field. */ - - index = cpufreq_frequency_table_target(&tmp_policy, target_freq, - relation); - pll = pll_reg + index; - - s3c_freq_dbg("%s: target %u => %u\n", - __func__, target_freq, pll->frequency); - - target_freq = pll->frequency; - } - - return s3c_cpufreq_settarget(policy, target_freq, pll); -} - -struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name) -{ - struct clk *clk; - - clk = clk_get(dev, name); - if (IS_ERR(clk)) - pr_err("failed to get clock '%s'\n", name); - - return clk; -} - -static int s3c_cpufreq_init(struct cpufreq_policy *policy) -{ - policy->clk = clk_arm; - policy->cpuinfo.transition_latency = cpu_cur.info->latency; - policy->freq_table = ftab; - - return 0; -} - -static int __init s3c_cpufreq_initclks(void) -{ - _clk_mpll = s3c_cpufreq_clk_get(NULL, "mpll"); - _clk_xtal = s3c_cpufreq_clk_get(NULL, "xtal"); - clk_fclk = s3c_cpufreq_clk_get(NULL, "fclk"); - clk_hclk = s3c_cpufreq_clk_get(NULL, "hclk"); - clk_pclk = s3c_cpufreq_clk_get(NULL, "pclk"); - clk_arm = s3c_cpufreq_clk_get(NULL, "armclk"); - - if (IS_ERR(clk_fclk) || IS_ERR(clk_hclk) || IS_ERR(clk_pclk) || - IS_ERR(_clk_mpll) || IS_ERR(clk_arm) || IS_ERR(_clk_xtal)) { - pr_err("%s: could not get clock(s)\n", __func__); - return -ENOENT; - } - - pr_info("%s: clocks f=%lu,h=%lu,p=%lu,a=%lu\n", - __func__, - clk_get_rate(clk_fclk) / 1000, - clk_get_rate(clk_hclk) / 1000, - clk_get_rate(clk_pclk) / 1000, - clk_get_rate(clk_arm) / 1000); - - return 0; -} - -#ifdef CONFIG_PM -static struct cpufreq_frequency_table suspend_pll; -static unsigned int suspend_freq; - -static int s3c_cpufreq_suspend(struct cpufreq_policy *policy) -{ - suspend_pll.frequency = clk_get_rate(_clk_mpll); - suspend_pll.driver_data = s3c24xx_read_mpllcon(); - suspend_freq = clk_get_rate(clk_arm); - - return 0; -} - -static int s3c_cpufreq_resume(struct cpufreq_policy *policy) -{ - int ret; - - s3c_freq_dbg("%s: resuming with policy %p\n", __func__, policy); - - last_target = ~0; /* invalidate last_target setting */ - - /* whilst we will be called later on, we try and re-set the - * cpu frequencies as soon as possible so that we do not end - * up resuming devices and then immediately having to re-set - * a number of settings once these devices have restarted. - * - * as a note, it is expected devices are not used until they - * have been un-suspended and at that time they should have - * used the updated clock settings. - */ - - ret = s3c_cpufreq_settarget(NULL, suspend_freq, &suspend_pll); - if (ret) { - pr_err("%s: failed to reset pll/freq\n", __func__); - return ret; - } - - return 0; -} -#else -#define s3c_cpufreq_resume NULL -#define s3c_cpufreq_suspend NULL -#endif - -static struct cpufreq_driver s3c24xx_driver = { - .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, - .target = s3c_cpufreq_target, - .get = cpufreq_generic_get, - .init = s3c_cpufreq_init, - .suspend = s3c_cpufreq_suspend, - .resume = s3c_cpufreq_resume, - .name = "s3c24xx", -}; - - -int s3c_cpufreq_register(struct s3c_cpufreq_info *info) -{ - if (!info || !info->name) { - pr_err("%s: failed to pass valid information\n", __func__); - return -EINVAL; - } - - pr_info("S3C24XX CPU Frequency driver, %s cpu support\n", - info->name); - - /* check our driver info has valid data */ - - BUG_ON(info->set_refresh == NULL); - BUG_ON(info->set_divs == NULL); - BUG_ON(info->calc_divs == NULL); - - /* info->set_fvco is optional, depending on whether there - * is a need to set the clock code. */ - - cpu_cur.info = info; - - /* Note, driver registering should probably update locktime */ - - return 0; -} - -int __init s3c_cpufreq_setboard(struct s3c_cpufreq_board *board) -{ - struct s3c_cpufreq_board *ours; - - if (!board) { - pr_info("%s: no board data\n", __func__); - return -EINVAL; - } - - /* Copy the board information so that each board can make this - * initdata. */ - - ours = kzalloc(sizeof(*ours), GFP_KERNEL); - if (!ours) - return -ENOMEM; - - *ours = *board; - cpu_cur.board = ours; - - return 0; -} - -static int __init s3c_cpufreq_auto_io(void) -{ - int ret; - - if (!cpu_cur.info->get_iotiming) { - pr_err("%s: get_iotiming undefined\n", __func__); - return -ENOENT; - } - - pr_info("%s: working out IO settings\n", __func__); - - ret = (cpu_cur.info->get_iotiming)(&cpu_cur, &s3c24xx_iotiming); - if (ret) - pr_err("%s: failed to get timings\n", __func__); - - return ret; -} - -/* if one or is zero, then return the other, otherwise return the min */ -#define do_min(_a, _b) ((_a) == 0 ? (_b) : (_b) == 0 ? (_a) : min(_a, _b)) - -/** - * s3c_cpufreq_freq_min - find the minimum settings for the given freq. - * @dst: The destination structure - * @a: One argument. - * @b: The other argument. - * - * Create a minimum of each frequency entry in the 'struct s3c_freq', - * unless the entry is zero when it is ignored and the non-zero argument - * used. - */ -static void s3c_cpufreq_freq_min(struct s3c_freq *dst, - struct s3c_freq *a, struct s3c_freq *b) -{ - dst->fclk = do_min(a->fclk, b->fclk); - dst->hclk = do_min(a->hclk, b->hclk); - dst->pclk = do_min(a->pclk, b->pclk); - dst->armclk = do_min(a->armclk, b->armclk); -} - -static inline u32 calc_locktime(u32 freq, u32 time_us) -{ - u32 result; - - result = freq * time_us; - result = DIV_ROUND_UP(result, 1000 * 1000); - - return result; -} - -static void s3c_cpufreq_update_loctkime(void) -{ - unsigned int bits = cpu_cur.info->locktime_bits; - u32 rate = (u32)clk_get_rate(_clk_xtal); - u32 val; - - if (bits == 0) { - WARN_ON(1); - return; - } - - val = calc_locktime(rate, cpu_cur.info->locktime_u) << bits; - val |= calc_locktime(rate, cpu_cur.info->locktime_m); - - pr_info("%s: new locktime is 0x%08x\n", __func__, val); - s3c24xx_write_locktime(val); -} - -static int s3c_cpufreq_build_freq(void) -{ - int size, ret; - - kfree(ftab); - - size = cpu_cur.info->calc_freqtable(&cpu_cur, NULL, 0); - size++; - - ftab = kcalloc(size, sizeof(*ftab), GFP_KERNEL); - if (!ftab) - return -ENOMEM; - - ftab_size = size; - - ret = cpu_cur.info->calc_freqtable(&cpu_cur, ftab, size); - s3c_cpufreq_addfreq(ftab, ret, size, CPUFREQ_TABLE_END); - - return 0; -} - -static int __init s3c_cpufreq_initcall(void) -{ - int ret = 0; - - if (cpu_cur.info && cpu_cur.board) { - ret = s3c_cpufreq_initclks(); - if (ret) - goto out; - - /* get current settings */ - s3c_cpufreq_getcur(&cpu_cur); - s3c_cpufreq_show("cur", &cpu_cur); - - if (cpu_cur.board->auto_io) { - ret = s3c_cpufreq_auto_io(); - if (ret) { - pr_err("%s: failed to get io timing\n", - __func__); - goto out; - } - } - - if (cpu_cur.board->need_io && !cpu_cur.info->set_iotiming) { - pr_err("%s: no IO support registered\n", __func__); - ret = -EINVAL; - goto out; - } - - if (!cpu_cur.info->need_pll) - cpu_cur.lock_pll = 1; - - s3c_cpufreq_update_loctkime(); - - s3c_cpufreq_freq_min(&cpu_cur.max, &cpu_cur.board->max, - &cpu_cur.info->max); - - if (cpu_cur.info->calc_freqtable) - s3c_cpufreq_build_freq(); - - ret = cpufreq_register_driver(&s3c24xx_driver); - } - - out: - return ret; -} - -late_initcall(s3c_cpufreq_initcall); - -/** - * s3c_plltab_register - register CPU PLL table. - * @plls: The list of PLL entries. - * @plls_no: The size of the PLL entries @plls. - * - * Register the given set of PLLs with the system. - */ -int s3c_plltab_register(struct cpufreq_frequency_table *plls, - unsigned int plls_no) -{ - struct cpufreq_frequency_table *vals; - unsigned int size; - - size = sizeof(*vals) * (plls_no + 1); - - vals = kzalloc(size, GFP_KERNEL); - if (vals) { - memcpy(vals, plls, size); - pll_reg = vals; - - /* write a terminating entry, we don't store it in the - * table that is stored in the kernel */ - vals += plls_no; - vals->frequency = CPUFREQ_TABLE_END; - - pr_info("%d PLL entries\n", plls_no); - } else - pr_err("no memory for PLL tables\n"); - - return vals ? 0 : -ENOMEM; -} diff --git a/drivers/cpufreq/sa1100-cpufreq.c b/drivers/cpufreq/sa1100-cpufreq.c deleted file mode 100644 index 252b9fc26124..000000000000 --- a/drivers/cpufreq/sa1100-cpufreq.c +++ /dev/null @@ -1,206 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * cpu-sa1100.c: clock scaling for the SA1100 - * - * Copyright (C) 2000 2001, The Delft University of Technology - * - * Authors: - * - Johan Pouwelse (J.A.Pouwelse@its.tudelft.nl): initial version - * - Erik Mouw (J.A.K.Mouw@its.tudelft.nl): - * - major rewrite for linux-2.3.99 - * - rewritten for the more generic power management scheme in - * linux-2.4.5-rmk1 - * - * This software has been developed while working on the LART - * computing board (http://www.lartmaker.nl/), which is - * sponsored by the Mobile Multi-media Communications - * (http://www.mobimedia.org/) and Ubiquitous Communications - * (http://www.ubicom.tudelft.nl/) projects. - * - * The authors can be reached at: - * - * Erik Mouw - * Information and Communication Theory Group - * Faculty of Information Technology and Systems - * Delft University of Technology - * P.O. Box 5031 - * 2600 GA Delft - * The Netherlands - * - * Theory of operations - * ==================== - * - * Clock scaling can be used to lower the power consumption of the CPU - * core. This will give you a somewhat longer running time. - * - * The SA-1100 has a single register to change the core clock speed: - * - * PPCR 0x90020014 PLL config - * - * However, the DRAM timings are closely related to the core clock - * speed, so we need to change these, too. The used registers are: - * - * MDCNFG 0xA0000000 DRAM config - * MDCAS0 0xA0000004 Access waveform - * MDCAS1 0xA0000008 Access waveform - * MDCAS2 0xA000000C Access waveform - * - * Care must be taken to change the DRAM parameters the correct way, - * because otherwise the DRAM becomes unusable and the kernel will - * crash. - * - * The simple solution to avoid a kernel crash is to put the actual - * clock change in ROM and jump to that code from the kernel. The main - * disadvantage is that the ROM has to be modified, which is not - * possible on all SA-1100 platforms. Another disadvantage is that - * jumping to ROM makes clock switching unnecessary complicated. - * - * The idea behind this driver is that the memory configuration can be - * changed while running from DRAM (even with interrupts turned on!) - * as long as all re-configuration steps yield a valid DRAM - * configuration. The advantages are clear: it will run on all SA-1100 - * platforms, and the code is very simple. - * - * If you really want to understand what is going on in - * sa1100_update_dram_timings(), you'll have to read sections 8.2, - * 9.5.7.3, and 10.2 from the "Intel StrongARM SA-1100 Microprocessor - * Developers Manual" (available for free from Intel). - */ - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/cpufreq.h> -#include <linux/io.h> - -#include <asm/cputype.h> - -#include <mach/generic.h> -#include <mach/hardware.h> - -struct sa1100_dram_regs { - int speed; - u32 mdcnfg; - u32 mdcas0; - u32 mdcas1; - u32 mdcas2; -}; - - -static struct cpufreq_driver sa1100_driver; - -static struct sa1100_dram_regs sa1100_dram_settings[] = { - /*speed, mdcnfg, mdcas0, mdcas1, mdcas2, clock freq */ - { 59000, 0x00dc88a3, 0xcccccccf, 0xfffffffc, 0xffffffff},/* 59.0 MHz */ - { 73700, 0x011490a3, 0xcccccccf, 0xfffffffc, 0xffffffff},/* 73.7 MHz */ - { 88500, 0x014e90a3, 0xcccccccf, 0xfffffffc, 0xffffffff},/* 88.5 MHz */ - {103200, 0x01889923, 0xcccccccf, 0xfffffffc, 0xffffffff},/* 103.2 MHz */ - {118000, 0x01c29923, 0x9999998f, 0xfffffff9, 0xffffffff},/* 118.0 MHz */ - {132700, 0x01fb2123, 0x9999998f, 0xfffffff9, 0xffffffff},/* 132.7 MHz */ - {147500, 0x02352123, 0x3333330f, 0xfffffff3, 0xffffffff},/* 147.5 MHz */ - {162200, 0x026b29a3, 0x38e38e1f, 0xfff8e38e, 0xffffffff},/* 162.2 MHz */ - {176900, 0x02a329a3, 0x71c71c1f, 0xfff1c71c, 0xffffffff},/* 176.9 MHz */ - {191700, 0x02dd31a3, 0xe38e383f, 0xffe38e38, 0xffffffff},/* 191.7 MHz */ - {206400, 0x03153223, 0xc71c703f, 0xffc71c71, 0xffffffff},/* 206.4 MHz */ - {221200, 0x034fba23, 0xc71c703f, 0xffc71c71, 0xffffffff},/* 221.2 MHz */ - {235900, 0x03853a23, 0xe1e1e07f, 0xe1e1e1e1, 0xffffffe1},/* 235.9 MHz */ - {250700, 0x03bf3aa3, 0xc3c3c07f, 0xc3c3c3c3, 0xffffffc3},/* 250.7 MHz */ - {265400, 0x03f7c2a3, 0xc3c3c07f, 0xc3c3c3c3, 0xffffffc3},/* 265.4 MHz */ - {280200, 0x0431c2a3, 0x878780ff, 0x87878787, 0xffffff87},/* 280.2 MHz */ - { 0, 0, 0, 0, 0 } /* last entry */ -}; - -static void sa1100_update_dram_timings(int current_speed, int new_speed) -{ - struct sa1100_dram_regs *settings = sa1100_dram_settings; - - /* find speed */ - while (settings->speed != 0) { - if (new_speed == settings->speed) - break; - - settings++; - } - - if (settings->speed == 0) { - panic("%s: couldn't find dram setting for speed %d\n", - __func__, new_speed); - } - - /* No risk, no fun: run with interrupts on! */ - if (new_speed > current_speed) { - /* We're going FASTER, so first relax the memory - * timings before changing the core frequency - */ - - /* Half the memory access clock */ - MDCNFG |= MDCNFG_CDB2; - - /* The order of these statements IS important, keep 8 - * pulses!! - */ - MDCAS2 = settings->mdcas2; - MDCAS1 = settings->mdcas1; - MDCAS0 = settings->mdcas0; - MDCNFG = settings->mdcnfg; - } else { - /* We're going SLOWER: first decrease the core - * frequency and then tighten the memory settings. - */ - - /* Half the memory access clock */ - MDCNFG |= MDCNFG_CDB2; - - /* The order of these statements IS important, keep 8 - * pulses!! - */ - MDCAS0 = settings->mdcas0; - MDCAS1 = settings->mdcas1; - MDCAS2 = settings->mdcas2; - MDCNFG = settings->mdcnfg; - } -} - -static int sa1100_target(struct cpufreq_policy *policy, unsigned int ppcr) -{ - unsigned int cur = sa11x0_getspeed(0); - unsigned int new_freq; - - new_freq = sa11x0_freq_table[ppcr].frequency; - - if (new_freq > cur) - sa1100_update_dram_timings(cur, new_freq); - - PPCR = ppcr; - - if (new_freq < cur) - sa1100_update_dram_timings(cur, new_freq); - - return 0; -} - -static int __init sa1100_cpu_init(struct cpufreq_policy *policy) -{ - cpufreq_generic_init(policy, sa11x0_freq_table, 0); - return 0; -} - -static struct cpufreq_driver sa1100_driver __refdata = { - .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK | - CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING, - .verify = cpufreq_generic_frequency_table_verify, - .target_index = sa1100_target, - .get = sa11x0_getspeed, - .init = sa1100_cpu_init, - .name = "sa1100", -}; - -static int __init sa1100_dram_init(void) -{ - if (cpu_is_sa1100()) - return cpufreq_register_driver(&sa1100_driver); - else - return -ENODEV; -} - -arch_initcall(sa1100_dram_init); diff --git a/drivers/cpufreq/sa1110-cpufreq.c b/drivers/cpufreq/sa1110-cpufreq.c index 1a83c8678a63..bb7f591a8b05 100644 --- a/drivers/cpufreq/sa1110-cpufreq.c +++ b/drivers/cpufreq/sa1110-cpufreq.c @@ -344,14 +344,8 @@ static int __init sa1110_clk_init(void) if (!name[0]) { if (machine_is_assabet()) name = "TC59SM716-CL3"; - if (machine_is_pt_system3()) - name = "K4S641632D"; - if (machine_is_h3100()) - name = "KM416S4030CT"; if (machine_is_jornada720() || machine_is_h3600()) name = "K4S281632B-1H"; - if (machine_is_nanoengine()) - name = "MT48LC8M16A2TG-75"; } sdram = sa1110_find_sdram(name); diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c index 8c758920d699..7cfb980a357d 100644 --- a/drivers/cpuidle/cpuidle-arm.c +++ b/drivers/cpuidle/cpuidle-arm.c @@ -31,8 +31,8 @@ * Called from the CPUidle framework to program the device to the * specified target state selected by the governor. */ -static int arm_enter_idle_state(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int idx) +static __cpuidle int arm_enter_idle_state(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int idx) { /* * Pass idle state index to arm_cpuidle_suspend which in turn diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c index abe51185f243..74972deda0ea 100644 --- a/drivers/cpuidle/cpuidle-big_little.c +++ b/drivers/cpuidle/cpuidle-big_little.c @@ -64,7 +64,8 @@ static struct cpuidle_driver bl_idle_little_driver = { .enter = bl_enter_powerdown, .exit_latency = 700, .target_residency = 2500, - .flags = CPUIDLE_FLAG_TIMER_STOP, + .flags = CPUIDLE_FLAG_TIMER_STOP | + CPUIDLE_FLAG_RCU_IDLE, .name = "C1", .desc = "ARM little-cluster power down", }, @@ -85,7 +86,8 @@ static struct cpuidle_driver bl_idle_big_driver = { .enter = bl_enter_powerdown, .exit_latency = 500, .target_residency = 2000, - .flags = CPUIDLE_FLAG_TIMER_STOP, + .flags = CPUIDLE_FLAG_TIMER_STOP | + CPUIDLE_FLAG_RCU_IDLE, .name = "C1", .desc = "ARM big-cluster power down", }, @@ -120,15 +122,17 @@ static int notrace bl_powerdown_finisher(unsigned long arg) * Called from the CPUidle framework to program the device to the * specified target state selected by the governor. */ -static int bl_enter_powerdown(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int idx) +static __cpuidle int bl_enter_powerdown(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int idx) { cpu_pm_enter(); + ct_cpuidle_enter(); cpu_suspend(0, bl_powerdown_finisher); /* signals the MCPM core that CPU is out of low power state */ mcpm_cpu_powered_up(); + ct_cpuidle_exit(); cpu_pm_exit(); diff --git a/drivers/cpuidle/cpuidle-mvebu-v7.c b/drivers/cpuidle/cpuidle-mvebu-v7.c index 01a856971f05..563dba609b98 100644 --- a/drivers/cpuidle/cpuidle-mvebu-v7.c +++ b/drivers/cpuidle/cpuidle-mvebu-v7.c @@ -25,9 +25,9 @@ static int (*mvebu_v7_cpu_suspend)(int); -static int mvebu_v7_enter_idle(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) +static __cpuidle int mvebu_v7_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) { int ret; bool deepidle = false; @@ -36,7 +36,10 @@ static int mvebu_v7_enter_idle(struct cpuidle_device *dev, if (drv->states[index].flags & MVEBU_V7_FLAG_DEEP_IDLE) deepidle = true; + ct_cpuidle_enter(); ret = mvebu_v7_cpu_suspend(deepidle); + ct_cpuidle_exit(); + cpu_pm_exit(); if (ret) @@ -53,6 +56,7 @@ static struct cpuidle_driver armadaxp_idle_driver = { .exit_latency = 100, .power_usage = 50, .target_residency = 1000, + .flags = CPUIDLE_FLAG_RCU_IDLE, .name = "MV CPU IDLE", .desc = "CPU power down", }, @@ -61,7 +65,7 @@ static struct cpuidle_driver armadaxp_idle_driver = { .exit_latency = 1000, .power_usage = 5, .target_residency = 10000, - .flags = MVEBU_V7_FLAG_DEEP_IDLE, + .flags = MVEBU_V7_FLAG_DEEP_IDLE | CPUIDLE_FLAG_RCU_IDLE, .name = "MV CPU DEEP IDLE", .desc = "CPU and L2 Fabric power down", }, @@ -76,7 +80,7 @@ static struct cpuidle_driver armada370_idle_driver = { .exit_latency = 100, .power_usage = 5, .target_residency = 1000, - .flags = MVEBU_V7_FLAG_DEEP_IDLE, + .flags = MVEBU_V7_FLAG_DEEP_IDLE | CPUIDLE_FLAG_RCU_IDLE, .name = "Deep Idle", .desc = "CPU and L2 Fabric power down", }, @@ -91,6 +95,7 @@ static struct cpuidle_driver armada38x_idle_driver = { .exit_latency = 10, .power_usage = 5, .target_residency = 100, + .flags = CPUIDLE_FLAG_RCU_IDLE, .name = "Idle", .desc = "CPU and SCU power down", }, diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c index 57bc3e3ae391..312a34ef28dc 100644 --- a/drivers/cpuidle/cpuidle-psci.c +++ b/drivers/cpuidle/cpuidle-psci.c @@ -49,14 +49,9 @@ static inline u32 psci_get_domain_state(void) return __this_cpu_read(domain_state); } -static inline int psci_enter_state(int idx, u32 state) -{ - return CPU_PM_CPU_IDLE_ENTER_PARAM(psci_cpu_suspend_enter, idx, state); -} - -static int __psci_enter_domain_idle_state(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int idx, - bool s2idle) +static __cpuidle int __psci_enter_domain_idle_state(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int idx, + bool s2idle) { struct psci_cpuidle_data *data = this_cpu_ptr(&psci_cpuidle_data); u32 *states = data->psci_states; @@ -69,12 +64,10 @@ static int __psci_enter_domain_idle_state(struct cpuidle_device *dev, return -1; /* Do runtime PM to manage a hierarchical CPU toplogy. */ - ct_irq_enter_irqson(); if (s2idle) dev_pm_genpd_suspend(pd_dev); else pm_runtime_put_sync_suspend(pd_dev); - ct_irq_exit_irqson(); state = psci_get_domain_state(); if (!state) @@ -82,12 +75,10 @@ static int __psci_enter_domain_idle_state(struct cpuidle_device *dev, ret = psci_cpu_suspend_enter(state) ? -1 : idx; - ct_irq_enter_irqson(); if (s2idle) dev_pm_genpd_resume(pd_dev); else pm_runtime_get_sync(pd_dev); - ct_irq_exit_irqson(); cpu_pm_exit(); @@ -192,12 +183,12 @@ static void psci_idle_init_cpuhp(void) pr_warn("Failed %d while setup cpuhp state\n", err); } -static int psci_enter_idle_state(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int idx) +static __cpuidle int psci_enter_idle_state(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int idx) { u32 *state = __this_cpu_read(psci_cpuidle_data.psci_states); - return psci_enter_state(idx, state[idx]); + return CPU_PM_CPU_IDLE_ENTER_PARAM_RCU(psci_cpu_suspend_enter, idx, state[idx]); } static const struct of_device_id psci_idle_state_match[] = { @@ -240,6 +231,7 @@ static int psci_dt_cpu_init_topology(struct cpuidle_driver *drv, * of a shared state for the domain, assumes the domain states are all * deeper states. */ + drv->states[state_count - 1].flags |= CPUIDLE_FLAG_RCU_IDLE; drv->states[state_count - 1].enter = psci_enter_domain_idle_state; drv->states[state_count - 1].enter_s2idle = psci_enter_s2idle_domain_idle_state; psci_cpuidle_use_cpuhp = true; diff --git a/drivers/cpuidle/cpuidle-qcom-spm.c b/drivers/cpuidle/cpuidle-qcom-spm.c index beedf22cbe78..326bca154ac7 100644 --- a/drivers/cpuidle/cpuidle-qcom-spm.c +++ b/drivers/cpuidle/cpuidle-qcom-spm.c @@ -58,8 +58,8 @@ static int qcom_cpu_spc(struct spm_driver_data *drv) return ret; } -static int spm_enter_idle_state(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int idx) +static __cpuidle int spm_enter_idle_state(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int idx) { struct cpuidle_qcom_spm_data *data = container_of(drv, struct cpuidle_qcom_spm_data, cpuidle_driver); diff --git a/drivers/cpuidle/cpuidle-riscv-sbi.c b/drivers/cpuidle/cpuidle-riscv-sbi.c index 05fe2902df9a..be383f4b6855 100644 --- a/drivers/cpuidle/cpuidle-riscv-sbi.c +++ b/drivers/cpuidle/cpuidle-riscv-sbi.c @@ -93,8 +93,8 @@ static int sbi_suspend(u32 state) return sbi_suspend_finisher(state, 0, 0); } -static int sbi_cpuidle_enter_state(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int idx) +static __cpuidle int sbi_cpuidle_enter_state(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int idx) { u32 *states = __this_cpu_read(sbi_cpuidle_data.states); u32 state = states[idx]; @@ -106,9 +106,9 @@ static int sbi_cpuidle_enter_state(struct cpuidle_device *dev, idx, state); } -static int __sbi_enter_domain_idle_state(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int idx, - bool s2idle) +static __cpuidle int __sbi_enter_domain_idle_state(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int idx, + bool s2idle) { struct sbi_cpuidle_data *data = this_cpu_ptr(&sbi_cpuidle_data); u32 *states = data->states; @@ -121,12 +121,12 @@ static int __sbi_enter_domain_idle_state(struct cpuidle_device *dev, return -1; /* Do runtime PM to manage a hierarchical CPU toplogy. */ - ct_irq_enter_irqson(); if (s2idle) dev_pm_genpd_suspend(pd_dev); else pm_runtime_put_sync_suspend(pd_dev); - ct_irq_exit_irqson(); + + ct_cpuidle_enter(); if (sbi_is_domain_state_available()) state = sbi_get_domain_state(); @@ -135,12 +135,12 @@ static int __sbi_enter_domain_idle_state(struct cpuidle_device *dev, ret = sbi_suspend(state) ? -1 : idx; - ct_irq_enter_irqson(); + ct_cpuidle_exit(); + if (s2idle) dev_pm_genpd_resume(pd_dev); else pm_runtime_get_sync(pd_dev); - ct_irq_exit_irqson(); cpu_pm_exit(); @@ -251,6 +251,7 @@ static int sbi_dt_cpu_init_topology(struct cpuidle_driver *drv, * of a shared state for the domain, assumes the domain states are all * deeper states. */ + drv->states[state_count - 1].flags |= CPUIDLE_FLAG_RCU_IDLE; drv->states[state_count - 1].enter = sbi_enter_domain_idle_state; drv->states[state_count - 1].enter_s2idle = sbi_enter_s2idle_domain_idle_state; diff --git a/drivers/cpuidle/cpuidle-tegra.c b/drivers/cpuidle/cpuidle-tegra.c index 9845629aeb6d..b203a93deac5 100644 --- a/drivers/cpuidle/cpuidle-tegra.c +++ b/drivers/cpuidle/cpuidle-tegra.c @@ -160,8 +160,8 @@ static int tegra_cpuidle_coupled_barrier(struct cpuidle_device *dev) return 0; } -static int tegra_cpuidle_state_enter(struct cpuidle_device *dev, - int index, unsigned int cpu) +static __cpuidle int tegra_cpuidle_state_enter(struct cpuidle_device *dev, + int index, unsigned int cpu) { int err; @@ -180,9 +180,11 @@ static int tegra_cpuidle_state_enter(struct cpuidle_device *dev, } local_fiq_disable(); - RCU_NONIDLE(tegra_pm_set_cpu_in_lp2()); + tegra_pm_set_cpu_in_lp2(); cpu_pm_enter(); + ct_cpuidle_enter(); + switch (index) { case TEGRA_C7: err = tegra_cpuidle_c7_enter(); @@ -197,8 +199,10 @@ static int tegra_cpuidle_state_enter(struct cpuidle_device *dev, break; } + ct_cpuidle_exit(); + cpu_pm_exit(); - RCU_NONIDLE(tegra_pm_clear_cpu_in_lp2()); + tegra_pm_clear_cpu_in_lp2(); local_fiq_enable(); return err ?: index; @@ -222,10 +226,11 @@ static int tegra_cpuidle_adjust_state_index(int index, unsigned int cpu) return index; } -static int tegra_cpuidle_enter(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) +static __cpuidle int tegra_cpuidle_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) { + bool do_rcu = drv->states[index].flags & CPUIDLE_FLAG_RCU_IDLE; unsigned int cpu = cpu_logical_map(dev->cpu); int ret; @@ -233,9 +238,13 @@ static int tegra_cpuidle_enter(struct cpuidle_device *dev, if (dev->states_usage[index].disable) return -1; - if (index == TEGRA_C1) + if (index == TEGRA_C1) { + if (do_rcu) + ct_cpuidle_enter(); ret = arm_cpuidle_simple_enter(dev, drv, index); - else + if (do_rcu) + ct_cpuidle_exit(); + } else ret = tegra_cpuidle_state_enter(dev, index, cpu); if (ret < 0) { @@ -285,7 +294,8 @@ static struct cpuidle_driver tegra_idle_driver = { .exit_latency = 2000, .target_residency = 2200, .power_usage = 100, - .flags = CPUIDLE_FLAG_TIMER_STOP, + .flags = CPUIDLE_FLAG_TIMER_STOP | + CPUIDLE_FLAG_RCU_IDLE, .name = "C7", .desc = "CPU core powered off", }, @@ -295,6 +305,7 @@ static struct cpuidle_driver tegra_idle_driver = { .target_residency = 10000, .power_usage = 0, .flags = CPUIDLE_FLAG_TIMER_STOP | + CPUIDLE_FLAG_RCU_IDLE | CPUIDLE_FLAG_COUPLED, .name = "CC6", .desc = "CPU cluster powered off", diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 6eceb1988243..0b00f21cefe3 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -14,6 +14,7 @@ #include <linux/mutex.h> #include <linux/sched.h> #include <linux/sched/clock.h> +#include <linux/sched/idle.h> #include <linux/notifier.h> #include <linux/pm_qos.h> #include <linux/cpu.h> @@ -136,11 +137,13 @@ int cpuidle_find_deepest_state(struct cpuidle_driver *drv, } #ifdef CONFIG_SUSPEND -static void enter_s2idle_proper(struct cpuidle_driver *drv, - struct cpuidle_device *dev, int index) +static noinstr void enter_s2idle_proper(struct cpuidle_driver *drv, + struct cpuidle_device *dev, int index) { - ktime_t time_start, time_end; struct cpuidle_state *target_state = &drv->states[index]; + ktime_t time_start, time_end; + + instrumentation_begin(); time_start = ns_to_ktime(local_clock()); @@ -151,13 +154,18 @@ static void enter_s2idle_proper(struct cpuidle_driver *drv, * suspended is generally unsafe. */ stop_critical_timings(); - if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE)) - ct_idle_enter(); + if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE)) { + ct_cpuidle_enter(); + /* Annotate away the indirect call */ + instrumentation_begin(); + } target_state->enter_s2idle(dev, drv, index); if (WARN_ON_ONCE(!irqs_disabled())) - local_irq_disable(); - if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE)) - ct_idle_exit(); + raw_local_irq_disable(); + if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE)) { + instrumentation_end(); + ct_cpuidle_exit(); + } tick_unfreeze(); start_critical_timings(); @@ -165,6 +173,7 @@ static void enter_s2idle_proper(struct cpuidle_driver *drv, dev->states_usage[index].s2idle_time += ktime_us_delta(time_end, time_start); dev->states_usage[index].s2idle_usage++; + instrumentation_end(); } /** @@ -199,8 +208,9 @@ int cpuidle_enter_s2idle(struct cpuidle_driver *drv, struct cpuidle_device *dev) * @drv: cpuidle driver for this cpu * @index: index into the states table in @drv of the state to enter */ -int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, - int index) +noinstr int cpuidle_enter_state(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) { int entered_state; @@ -208,6 +218,8 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, bool broadcast = !!(target_state->flags & CPUIDLE_FLAG_TIMER_STOP); ktime_t time_start, time_end; + instrumentation_begin(); + /* * Tell the time framework to switch to a broadcast timer because our * local timer will be shut down. If a local timer is used from another @@ -234,11 +246,33 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, time_start = ns_to_ktime(local_clock()); stop_critical_timings(); - if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE)) - ct_idle_enter(); + if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE)) { + ct_cpuidle_enter(); + /* Annotate away the indirect call */ + instrumentation_begin(); + } + + /* + * NOTE!! + * + * For cpuidle_state::enter() methods that do *NOT* set + * CPUIDLE_FLAG_RCU_IDLE RCU will be disabled here and these functions + * must be marked either noinstr or __cpuidle. + * + * For cpuidle_state::enter() methods that *DO* set + * CPUIDLE_FLAG_RCU_IDLE this isn't required, but they must mark the + * function calling ct_cpuidle_enter() as noinstr/__cpuidle and all + * functions called within the RCU-idle region. + */ entered_state = target_state->enter(dev, drv, index); - if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE)) - ct_idle_exit(); + + if (WARN_ONCE(!irqs_disabled(), "%ps leaked IRQ state", target_state->enter)) + raw_local_irq_disable(); + + if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE)) { + instrumentation_end(); + ct_cpuidle_exit(); + } start_critical_timings(); sched_clock_idle_wakeup_event(); @@ -248,12 +282,8 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, /* The cpu is no longer idle or about to enter idle. */ sched_idle_set_state(NULL); - if (broadcast) { - if (WARN_ON_ONCE(!irqs_disabled())) - local_irq_disable(); - + if (broadcast) tick_broadcast_exit(); - } if (!cpuidle_state_is_coupled(drv, index)) local_irq_enable(); @@ -305,6 +335,8 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, dev->states_usage[index].rejected++; } + instrumentation_end(); + return entered_state; } @@ -394,7 +426,7 @@ void cpuidle_reflect(struct cpuidle_device *dev, int index) * @dev: the cpuidle device * */ -u64 cpuidle_poll_time(struct cpuidle_driver *drv, +__cpuidle u64 cpuidle_poll_time(struct cpuidle_driver *drv, struct cpuidle_device *dev) { int i; diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c index 7ca3d7d9b5ea..02aa0b39af9d 100644 --- a/drivers/cpuidle/dt_idle_states.c +++ b/drivers/cpuidle/dt_idle_states.c @@ -77,7 +77,7 @@ static int init_state_node(struct cpuidle_state *idle_state, if (err) desc = state_node->name; - idle_state->flags = 0; + idle_state->flags = CPUIDLE_FLAG_RCU_IDLE; if (of_property_read_bool(state_node, "local-timer-stop")) idle_state->flags |= CPUIDLE_FLAG_TIMER_STOP; /* diff --git a/drivers/cpuidle/poll_state.c b/drivers/cpuidle/poll_state.c index f7e83613ae94..bdcfeaecd228 100644 --- a/drivers/cpuidle/poll_state.c +++ b/drivers/cpuidle/poll_state.c @@ -13,11 +13,13 @@ static int __cpuidle poll_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - u64 time_start = local_clock(); + u64 time_start; + + time_start = local_clock(); dev->poll_time_limit = false; - local_irq_enable(); + raw_local_irq_enable(); if (!current_set_polling_and_test()) { unsigned int loop_count = 0; u64 limit; @@ -36,6 +38,8 @@ static int __cpuidle poll_idle(struct cpuidle_device *dev, } } } + raw_local_irq_disable(); + current_clr_polling(); return index; diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c index 53100fb9b07b..12205e2b53b4 100644 --- a/drivers/crypto/atmel-ecc.c +++ b/drivers/crypto/atmel-ecc.c @@ -3,7 +3,7 @@ * Microchip / Atmel ECC (I2C) driver. * * Copyright (c) 2017, Microchip Technology Inc. - * Author: Tudor Ambarus <tudor.ambarus@microchip.com> + * Author: Tudor Ambarus */ #include <linux/delay.h> @@ -411,6 +411,6 @@ static void __exit atmel_ecc_exit(void) module_init(atmel_ecc_init); module_exit(atmel_ecc_exit); -MODULE_AUTHOR("Tudor Ambarus <tudor.ambarus@microchip.com>"); +MODULE_AUTHOR("Tudor Ambarus"); MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c index 81ce09bedda8..55bff1e13142 100644 --- a/drivers/crypto/atmel-i2c.c +++ b/drivers/crypto/atmel-i2c.c @@ -3,7 +3,7 @@ * Microchip / Atmel ECC (I2C) driver. * * Copyright (c) 2017, Microchip Technology Inc. - * Author: Tudor Ambarus <tudor.ambarus@microchip.com> + * Author: Tudor Ambarus */ #include <linux/bitrev.h> @@ -390,6 +390,6 @@ static void __exit atmel_i2c_exit(void) module_init(atmel_i2c_init); module_exit(atmel_i2c_exit); -MODULE_AUTHOR("Tudor Ambarus <tudor.ambarus@microchip.com>"); +MODULE_AUTHOR("Tudor Ambarus"); 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 index 48929efe2a5b..35f7857a7f7c 100644 --- a/drivers/crypto/atmel-i2c.h +++ b/drivers/crypto/atmel-i2c.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2017, Microchip Technology Inc. - * Author: Tudor Ambarus <tudor.ambarus@microchip.com> + * Author: Tudor Ambarus */ #ifndef __ATMEL_I2C_H__ diff --git a/drivers/crypto/caam/blob_gen.c b/drivers/crypto/caam/blob_gen.c index 1f65df489847..f46b161d2cda 100644 --- a/drivers/crypto/caam/blob_gen.c +++ b/drivers/crypto/caam/blob_gen.c @@ -104,7 +104,7 @@ int caam_process_blob(struct caam_blob_priv *priv, } ctrlpriv = dev_get_drvdata(jrdev->parent); - moo = FIELD_GET(CSTA_MOO, ioread32(&ctrlpriv->ctrl->perfmon.status)); + moo = FIELD_GET(CSTA_MOO, rd_reg32(&ctrlpriv->ctrl->perfmon.status)); if (moo != CSTA_MOO_SECURE && moo != CSTA_MOO_TRUSTED) dev_warn(jrdev, "using insecure test key, enable HAB to use unique device key!\n"); diff --git a/drivers/crypto/virtio/virtio_crypto_skcipher_algs.c b/drivers/crypto/virtio/virtio_crypto_skcipher_algs.c index e553ccadbcbc..e5876286828b 100644 --- a/drivers/crypto/virtio/virtio_crypto_skcipher_algs.c +++ b/drivers/crypto/virtio/virtio_crypto_skcipher_algs.c @@ -239,7 +239,8 @@ static int virtio_crypto_alg_skcipher_close_session( pr_err("virtio_crypto: Close session failed status: %u, session_id: 0x%llx\n", ctrl_status->status, destroy_session->session_id); - return -EINVAL; + err = -EINVAL; + goto out; } err = 0; diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index ad0849af42d7..13cde44c6086 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -736,4 +736,3 @@ module_exit(cxl_acpi_exit); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS(CXL); MODULE_IMPORT_NS(ACPI); -MODULE_SOFTDEP("pre: cxl_pmem"); diff --git a/drivers/cxl/core/pmem.c b/drivers/cxl/core/pmem.c index f3d2169b6731..c2e4b1093788 100644 --- a/drivers/cxl/core/pmem.c +++ b/drivers/cxl/core/pmem.c @@ -227,34 +227,16 @@ static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_nvdimm_bridge *cxl_nvb, return cxl_nvd; } -static void cxl_nvd_unregister(void *_cxl_nvd) +static void cxlmd_release_nvdimm(void *_cxlmd) { - struct cxl_nvdimm *cxl_nvd = _cxl_nvd; - struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; + struct cxl_memdev *cxlmd = _cxlmd; + struct cxl_nvdimm *cxl_nvd = cxlmd->cxl_nvd; struct cxl_nvdimm_bridge *cxl_nvb = cxlmd->cxl_nvb; - /* - * Either the bridge is in ->remove() context under the device_lock(), - * or cxlmd_release_nvdimm() is cancelling the bridge's release action - * for @cxl_nvd and doing it itself (while manually holding the bridge - * lock). - */ - device_lock_assert(&cxl_nvb->dev); cxl_nvd->cxlmd = NULL; cxlmd->cxl_nvd = NULL; + cxlmd->cxl_nvb = NULL; device_unregister(&cxl_nvd->dev); -} - -static void cxlmd_release_nvdimm(void *_cxlmd) -{ - struct cxl_memdev *cxlmd = _cxlmd; - struct cxl_nvdimm_bridge *cxl_nvb = cxlmd->cxl_nvb; - - device_lock(&cxl_nvb->dev); - if (cxlmd->cxl_nvd) - devm_release_action(&cxl_nvb->dev, cxl_nvd_unregister, - cxlmd->cxl_nvd); - device_unlock(&cxl_nvb->dev); put_device(&cxl_nvb->dev); } @@ -293,22 +275,6 @@ int devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd) dev_dbg(&cxlmd->dev, "register %s\n", dev_name(dev)); - /* - * The two actions below arrange for @cxl_nvd to be deleted when either - * the top-level PMEM bridge goes down, or the endpoint device goes - * through ->remove(). - */ - device_lock(&cxl_nvb->dev); - if (cxl_nvb->dev.driver) - rc = devm_add_action_or_reset(&cxl_nvb->dev, cxl_nvd_unregister, - cxl_nvd); - else - rc = -ENXIO; - device_unlock(&cxl_nvb->dev); - - if (rc) - goto err_alloc; - /* @cxlmd carries a reference on @cxl_nvb until cxlmd_release_nvdimm */ return devm_add_action_or_reset(&cxlmd->dev, cxlmd_release_nvdimm, cxlmd); diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 02f28da519e3..940f805b1534 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -131,7 +131,7 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count) struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); struct cxl_port *iter = cxled_to_port(cxled); struct cxl_ep *ep; - int rc; + int rc = 0; while (!is_cxl_root(to_cxl_port(iter->dev.parent))) iter = to_cxl_port(iter->dev.parent); @@ -143,7 +143,8 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count) cxl_rr = cxl_rr_load(iter, cxlr); cxld = cxl_rr->decoder; - rc = cxld->reset(cxld); + if (cxld->reset) + rc = cxld->reset(cxld); if (rc) return rc; } @@ -186,7 +187,8 @@ static int cxl_region_decode_commit(struct cxl_region *cxlr) iter = ep->next, ep = cxl_ep_load(iter, cxlmd)) { cxl_rr = cxl_rr_load(iter, cxlr); cxld = cxl_rr->decoder; - cxld->reset(cxld); + if (cxld->reset) + cxld->reset(cxld); } cxled->cxld.reset(&cxled->cxld); @@ -991,10 +993,10 @@ static int cxl_port_setup_targets(struct cxl_port *port, int i, distance; /* - * Passthrough ports impose no distance requirements between + * Passthrough decoders impose no distance requirements between * peers */ - if (port->nr_dports == 1) + if (cxl_rr->nr_targets == 1) distance = 0; else distance = p->nr_targets / cxl_rr->nr_targets; diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 33083a522fd1..258004f34281 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -554,8 +554,11 @@ static bool cxl_report_and_clear(struct cxl_dev_state *cxlds) /* If multiple errors, log header points to first error from ctrl reg */ if (hweight32(status) > 1) { - addr = cxlds->regs.ras + CXL_RAS_CAP_CONTROL_OFFSET; - fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK, readl(addr))); + void __iomem *rcc_addr = + cxlds->regs.ras + CXL_RAS_CAP_CONTROL_OFFSET; + + fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK, + readl(rcc_addr))); } else { fe = status; } diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c index eedefebc4283..08bbbac9a6d0 100644 --- a/drivers/cxl/pmem.c +++ b/drivers/cxl/pmem.c @@ -225,11 +225,35 @@ static int cxl_pmem_ctl(struct nvdimm_bus_descriptor *nd_desc, return cxl_pmem_nvdimm_ctl(nvdimm, cmd, buf, buf_len); } +static int detach_nvdimm(struct device *dev, void *data) +{ + struct cxl_nvdimm *cxl_nvd; + bool release = false; + + if (!is_cxl_nvdimm(dev)) + return 0; + + device_lock(dev); + if (!dev->driver) + goto out; + + cxl_nvd = to_cxl_nvdimm(dev); + if (cxl_nvd->cxlmd && cxl_nvd->cxlmd->cxl_nvb == data) + release = true; +out: + device_unlock(dev); + if (release) + device_release_driver(dev); + return 0; +} + static void unregister_nvdimm_bus(void *_cxl_nvb) { struct cxl_nvdimm_bridge *cxl_nvb = _cxl_nvb; struct nvdimm_bus *nvdimm_bus = cxl_nvb->nvdimm_bus; + bus_for_each_dev(&cxl_bus_type, NULL, cxl_nvb, detach_nvdimm); + cxl_nvb->nvdimm_bus = NULL; nvdimm_bus_unregister(nvdimm_bus); } diff --git a/drivers/dax/super.c b/drivers/dax/super.c index da4438f3188c..c4c4728a36e4 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -475,7 +475,7 @@ EXPORT_SYMBOL_GPL(put_dax); /** * dax_holder() - obtain the holder of a dax device * @dax_dev: a dax_device instance - + * * Return: the holder's data which represents the holder if registered, * otherwize NULL. */ diff --git a/drivers/dma-buf/dma-buf-sysfs-stats.c b/drivers/dma-buf/dma-buf-sysfs-stats.c index f69d68122b9b..fbf725fae7c1 100644 --- a/drivers/dma-buf/dma-buf-sysfs-stats.c +++ b/drivers/dma-buf/dma-buf-sysfs-stats.c @@ -168,14 +168,11 @@ void dma_buf_uninit_sysfs_statistics(void) kset_unregister(dma_buf_stats_kset); } -int dma_buf_stats_setup(struct dma_buf *dmabuf) +int dma_buf_stats_setup(struct dma_buf *dmabuf, struct file *file) { struct dma_buf_sysfs_entry *sysfs_entry; int ret; - if (!dmabuf || !dmabuf->file) - return -EINVAL; - if (!dmabuf->exp_name) { pr_err("exporter name must not be empty if stats needed\n"); return -EINVAL; @@ -192,7 +189,7 @@ int dma_buf_stats_setup(struct dma_buf *dmabuf) /* create the directory for buffer stats */ ret = kobject_init_and_add(&sysfs_entry->kobj, &dma_buf_ktype, NULL, - "%lu", file_inode(dmabuf->file)->i_ino); + "%lu", file_inode(file)->i_ino); if (ret) goto err_sysfs_dmabuf; diff --git a/drivers/dma-buf/dma-buf-sysfs-stats.h b/drivers/dma-buf/dma-buf-sysfs-stats.h index a49c6e2650cc..7a8a995b75ba 100644 --- a/drivers/dma-buf/dma-buf-sysfs-stats.h +++ b/drivers/dma-buf/dma-buf-sysfs-stats.h @@ -13,7 +13,7 @@ int dma_buf_init_sysfs_statistics(void); void dma_buf_uninit_sysfs_statistics(void); -int dma_buf_stats_setup(struct dma_buf *dmabuf); +int dma_buf_stats_setup(struct dma_buf *dmabuf, struct file *file); void dma_buf_stats_teardown(struct dma_buf *dmabuf); #else @@ -25,7 +25,7 @@ static inline int dma_buf_init_sysfs_statistics(void) static inline void dma_buf_uninit_sysfs_statistics(void) {} -static inline int dma_buf_stats_setup(struct dma_buf *dmabuf) +static inline int dma_buf_stats_setup(struct dma_buf *dmabuf, struct file *file) { return 0; } diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index b6c36914e7c6..e6528767efc7 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -95,10 +95,11 @@ static int dma_buf_file_release(struct inode *inode, struct file *file) return -EINVAL; dmabuf = file->private_data; - - mutex_lock(&db_list.lock); - list_del(&dmabuf->list_node); - mutex_unlock(&db_list.lock); + if (dmabuf) { + mutex_lock(&db_list.lock); + list_del(&dmabuf->list_node); + mutex_unlock(&db_list.lock); + } return 0; } @@ -528,17 +529,17 @@ static inline int is_dma_buf_file(struct file *file) return file->f_op == &dma_buf_fops; } -static struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags) +static struct file *dma_buf_getfile(size_t size, int flags) { static atomic64_t dmabuf_inode = ATOMIC64_INIT(0); - struct file *file; struct inode *inode = alloc_anon_inode(dma_buf_mnt->mnt_sb); + struct file *file; if (IS_ERR(inode)) return ERR_CAST(inode); - inode->i_size = dmabuf->size; - inode_set_bytes(inode, dmabuf->size); + inode->i_size = size; + inode_set_bytes(inode, size); /* * The ->i_ino acquired from get_next_ino() is not unique thus @@ -552,8 +553,6 @@ static struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags) flags, &dma_buf_fops); if (IS_ERR(file)) goto err_alloc_file; - file->private_data = dmabuf; - file->f_path.dentry->d_fsdata = dmabuf; return file; @@ -619,19 +618,11 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) size_t alloc_size = sizeof(struct dma_buf); int ret; - if (!exp_info->resv) - alloc_size += sizeof(struct dma_resv); - else - /* prevent &dma_buf[1] == dma_buf->resv */ - alloc_size += 1; - - if (WARN_ON(!exp_info->priv - || !exp_info->ops - || !exp_info->ops->map_dma_buf - || !exp_info->ops->unmap_dma_buf - || !exp_info->ops->release)) { + if (WARN_ON(!exp_info->priv || !exp_info->ops + || !exp_info->ops->map_dma_buf + || !exp_info->ops->unmap_dma_buf + || !exp_info->ops->release)) return ERR_PTR(-EINVAL); - } if (WARN_ON(exp_info->ops->cache_sgt_mapping && (exp_info->ops->pin || exp_info->ops->unpin))) @@ -643,10 +634,21 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) if (!try_module_get(exp_info->owner)) return ERR_PTR(-ENOENT); + file = dma_buf_getfile(exp_info->size, exp_info->flags); + if (IS_ERR(file)) { + ret = PTR_ERR(file); + goto err_module; + } + + if (!exp_info->resv) + alloc_size += sizeof(struct dma_resv); + else + /* prevent &dma_buf[1] == dma_buf->resv */ + alloc_size += 1; dmabuf = kzalloc(alloc_size, GFP_KERNEL); if (!dmabuf) { ret = -ENOMEM; - goto err_module; + goto err_file; } dmabuf->priv = exp_info->priv; @@ -658,43 +660,35 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) init_waitqueue_head(&dmabuf->poll); dmabuf->cb_in.poll = dmabuf->cb_out.poll = &dmabuf->poll; dmabuf->cb_in.active = dmabuf->cb_out.active = 0; + INIT_LIST_HEAD(&dmabuf->attachments); if (!resv) { - resv = (struct dma_resv *)&dmabuf[1]; - dma_resv_init(resv); + dmabuf->resv = (struct dma_resv *)&dmabuf[1]; + dma_resv_init(dmabuf->resv); + } else { + dmabuf->resv = resv; } - dmabuf->resv = resv; - file = dma_buf_getfile(dmabuf, exp_info->flags); - if (IS_ERR(file)) { - ret = PTR_ERR(file); + ret = dma_buf_stats_setup(dmabuf, file); + if (ret) goto err_dmabuf; - } + file->private_data = dmabuf; + file->f_path.dentry->d_fsdata = dmabuf; dmabuf->file = file; - INIT_LIST_HEAD(&dmabuf->attachments); - mutex_lock(&db_list.lock); list_add(&dmabuf->list_node, &db_list.head); mutex_unlock(&db_list.lock); - ret = dma_buf_stats_setup(dmabuf); - if (ret) - goto err_sysfs; - return dmabuf; -err_sysfs: - /* - * Set file->f_path.dentry->d_fsdata to NULL so that when - * dma_buf_release() gets invoked by dentry_ops, it exits - * early before calling the release() dma_buf op. - */ - file->f_path.dentry->d_fsdata = NULL; - fput(file); err_dmabuf: + if (!resv) + dma_resv_fini(dmabuf->resv); kfree(dmabuf); +err_file: + fput(file); err_module: module_put(exp_info->owner); return ERR_PTR(ret); diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 406b4e26f538..0de0482cd36e 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -167,7 +167,7 @@ struct dma_fence *dma_fence_allocate_private_stub(void) 0, 0); set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, - &dma_fence_stub.flags); + &fence->flags); dma_fence_signal(fence); diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index b6d48d54f42f..2f2a2dd0b95d 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -610,18 +610,6 @@ config SPRD_DMA help Enable support for the on-chip DMA controller on Spreadtrum platform. -config S3C24XX_DMAC - bool "Samsung S3C24XX DMA support" - depends on ARCH_S3C24XX || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Support for the Samsung S3C24XX DMA controller driver. The - DMA controller is having multiple DMA channels which can be - configured for different peripherals like audio, UART, SPI. - The DMA controller can transfer data from memory to peripheral, - periphal to memory, periphal to periphal and memory to memory. - config TXX9_DMAC tristate "Toshiba TXx9 SoC DMA support" depends on MACH_TX49XX diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 5b55ada052a7..a4fd1ce29510 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -70,7 +70,6 @@ obj-$(CONFIG_STM32_DMA) += stm32-dma.o obj-$(CONFIG_STM32_DMAMUX) += stm32-dmamux.o obj-$(CONFIG_STM32_MDMA) += stm32-mdma.o obj-$(CONFIG_SPRD_DMA) += sprd-dma.o -obj-$(CONFIG_S3C24XX_DMAC) += s3c24xx-dma.o obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o obj-$(CONFIG_TEGRA186_GPC_DMA) += tegra186-gpc-dma.o obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index c741b6431958..8a6e6b60d66f 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -451,7 +451,8 @@ static int dma_chan_get(struct dma_chan *chan) /* The channel is already in use, update client count */ if (chan->client_count) { __module_get(owner); - goto out; + chan->client_count++; + return 0; } if (!try_module_get(owner)) @@ -470,11 +471,11 @@ static int dma_chan_get(struct dma_chan *chan) goto err_out; } + chan->client_count++; + if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask)) balance_ref_count(chan); -out: - chan->client_count++; return 0; err_out: diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index a183d93bd7e2..bf85aa0979ec 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -1018,6 +1018,11 @@ static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status) /* The bad descriptor currently is in the head of vc list */ vd = vchan_next_desc(&chan->vc); + if (!vd) { + dev_err(chan2dev(chan), "BUG: %s, IRQ with no descriptors\n", + axi_chan_name(chan)); + goto out; + } /* Remove the completed descriptor from issued list */ list_del(&vd->node); @@ -1032,6 +1037,7 @@ static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status) /* Try to restart the controller */ axi_chan_start_first_queued(chan); +out: spin_unlock_irqrestore(&chan->vc.lock, flags); } diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 06f5d3783d77..29dbb0f52e18 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -1172,8 +1172,19 @@ static void idxd_flush_pending_descs(struct idxd_irq_entry *ie) spin_unlock(&ie->list_lock); list_for_each_entry_safe(desc, itr, &flist, list) { + struct dma_async_tx_descriptor *tx; + list_del(&desc->list); ctype = desc->completion->status ? IDXD_COMPLETE_NORMAL : IDXD_COMPLETE_ABORT; + /* + * wq is being disabled. Any remaining descriptors are + * likely to be stuck and can be dropped. callback could + * point to code that is no longer accessible, for example + * if dmatest module has been unloaded. + */ + tx = &desc->txd; + tx->callback = NULL; + tx->callback_result = NULL; idxd_dma_complete_txd(desc, ctype, true); } } @@ -1390,8 +1401,7 @@ err_res_alloc: err_irq: idxd_wq_unmap_portal(wq); err_map_portal: - rc = idxd_wq_disable(wq, false); - if (rc < 0) + if (idxd_wq_disable(wq, false)) dev_dbg(dev, "wq %s disable failed\n", dev_name(wq_confdev(wq))); err: return rc; @@ -1408,11 +1418,11 @@ void drv_disable_wq(struct idxd_wq *wq) dev_warn(dev, "Clients has claim on wq %d: %d\n", wq->id, idxd_wq_refcount(wq)); - idxd_wq_free_resources(wq); idxd_wq_unmap_portal(wq); idxd_wq_drain(wq); idxd_wq_free_irq(wq); idxd_wq_reset(wq); + idxd_wq_free_resources(wq); percpu_ref_exit(&wq->wq_active); wq->type = IDXD_WQT_NONE; wq->client_count = 0; diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index fbea5f62dd98..b926abe4fa43 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1521,10 +1521,12 @@ static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac, sdma_config_ownership(sdmac, false, true, false); if (sdma_load_context(sdmac)) - goto err_desc_out; + goto err_bd_out; return desc; +err_bd_out: + sdma_free_bd(desc); err_desc_out: kfree(desc); err_out: diff --git a/drivers/dma/lgm/lgm-dma.c b/drivers/dma/lgm/lgm-dma.c index 9b9184f964be..1709d159af7e 100644 --- a/drivers/dma/lgm/lgm-dma.c +++ b/drivers/dma/lgm/lgm-dma.c @@ -914,7 +914,7 @@ static void ldma_dev_init(struct ldma_dev *d) } } -static int ldma_cfg_init(struct ldma_dev *d) +static int ldma_parse_dt(struct ldma_dev *d) { struct fwnode_handle *fwnode = dev_fwnode(d->dev); struct ldma_port *p; @@ -1661,10 +1661,6 @@ static int intel_ldma_probe(struct platform_device *pdev) p->ldev = d; } - ret = ldma_cfg_init(d); - if (ret) - return ret; - dma_dev->dev = &pdev->dev; ch_mask = (unsigned long)d->channels_mask; @@ -1675,6 +1671,10 @@ static int intel_ldma_probe(struct platform_device *pdev) ldma_dma_init_v3X(j, d); } + ret = ldma_parse_dt(d); + if (ret) + return ret; + dma_dev->device_alloc_chan_resources = ldma_alloc_chan_resources; dma_dev->device_free_chan_resources = ldma_free_chan_resources; dma_dev->device_terminate_all = ldma_terminate_all; diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index a262e0eb4cc9..d83e608dca05 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -15,7 +15,7 @@ #include <linux/dmaengine.h> #include <linux/platform_device.h> #include <linux/device.h> -#include <linux/platform_data/dma-mmp_tdma.h> +#include <linux/genalloc.h> #include <linux/of_device.h> #include <linux/of_dma.h> @@ -670,10 +670,7 @@ static int mmp_tdma_probe(struct platform_device *pdev) INIT_LIST_HEAD(&tdev->device.channels); - if (pdev->dev.of_node) - pool = of_gen_pool_get(pdev->dev.of_node, "asram", 0); - else - pool = sram_get_gpool("asram"); + pool = of_gen_pool_get(pdev->dev.of_node, "asram", 0); if (!pool) { dev_err(&pdev->dev, "asram pool not available\n"); return -ENOMEM; diff --git a/drivers/dma/ptdma/ptdma-dev.c b/drivers/dma/ptdma/ptdma-dev.c index 377da23012ac..a2bf13ff18b6 100644 --- a/drivers/dma/ptdma/ptdma-dev.c +++ b/drivers/dma/ptdma/ptdma-dev.c @@ -71,12 +71,13 @@ static int pt_core_execute_cmd(struct ptdma_desc *desc, struct pt_cmd_queue *cmd bool soc = FIELD_GET(DWORD0_SOC, desc->dw0); u8 *q_desc = (u8 *)&cmd_q->qbase[cmd_q->qidx]; u32 tail; + unsigned long flags; if (soc) { desc->dw0 |= FIELD_PREP(DWORD0_IOC, desc->dw0); desc->dw0 &= ~DWORD0_SOC; } - mutex_lock(&cmd_q->q_mutex); + spin_lock_irqsave(&cmd_q->q_lock, flags); /* Copy 32-byte command descriptor to hw queue. */ memcpy(q_desc, desc, 32); @@ -91,7 +92,7 @@ static int pt_core_execute_cmd(struct ptdma_desc *desc, struct pt_cmd_queue *cmd /* Turn the queue back on using our cached control register */ pt_start_queue(cmd_q); - mutex_unlock(&cmd_q->q_mutex); + spin_unlock_irqrestore(&cmd_q->q_lock, flags); return 0; } @@ -199,7 +200,7 @@ int pt_core_init(struct pt_device *pt) cmd_q->pt = pt; cmd_q->dma_pool = dma_pool; - mutex_init(&cmd_q->q_mutex); + spin_lock_init(&cmd_q->q_lock); /* Page alignment satisfies our needs for N <= 128 */ cmd_q->qsize = Q_SIZE(Q_DESC_SIZE); diff --git a/drivers/dma/ptdma/ptdma.h b/drivers/dma/ptdma/ptdma.h index d093c43b7d13..21b4bf895200 100644 --- a/drivers/dma/ptdma/ptdma.h +++ b/drivers/dma/ptdma/ptdma.h @@ -196,7 +196,7 @@ struct pt_cmd_queue { struct ptdma_desc *qbase; /* Aligned queue start address (per requirement) */ - struct mutex q_mutex ____cacheline_aligned; + spinlock_t q_lock ____cacheline_aligned; unsigned int qidx; unsigned int qsize; diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index 061add832295..59a36cbf9b5f 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -1756,6 +1756,7 @@ static int gpi_create_spi_tre(struct gchan *chan, struct gpi_desc *desc, tre->dword[3] = u32_encode_bits(TRE_TYPE_GO, TRE_FLAGS_TYPE); if (spi->cmd == SPI_RX) { tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_IEOB); + tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_LINK); } else if (spi->cmd == SPI_TX) { tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_CHAIN); } else { /* SPI_DUPLEX */ diff --git a/drivers/dma/s3c24xx-dma.c b/drivers/dma/s3c24xx-dma.c deleted file mode 100644 index a09eeb545f7d..000000000000 --- a/drivers/dma/s3c24xx-dma.c +++ /dev/null @@ -1,1428 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * S3C24XX DMA handling - * - * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de> - * - * based on amba-pl08x.c - * - * Copyright (c) 2006 ARM Ltd. - * Copyright (c) 2010 ST-Ericsson SA - * - * Author: Peter Pearse <peter.pearse@arm.com> - * Author: Linus Walleij <linus.walleij@stericsson.com> - * - * The DMA controllers in S3C24XX SoCs have a varying number of DMA signals - * that can be routed to any of the 4 to 8 hardware-channels. - * - * Therefore on these DMA controllers the number of channels - * and the number of incoming DMA signals are two totally different things. - * It is usually not possible to theoretically handle all physical signals, - * so a multiplexing scheme with possible denial of use is necessary. - * - * Open items: - * - bursts - */ - -#include <linux/platform_device.h> -#include <linux/types.h> -#include <linux/dmaengine.h> -#include <linux/dma-mapping.h> -#include <linux/interrupt.h> -#include <linux/clk.h> -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/slab.h> -#include <linux/platform_data/dma-s3c24xx.h> - -#include "dmaengine.h" -#include "virt-dma.h" - -#define MAX_DMA_CHANNELS 8 - -#define S3C24XX_DISRC 0x00 -#define S3C24XX_DISRCC 0x04 -#define S3C24XX_DISRCC_INC_INCREMENT 0 -#define S3C24XX_DISRCC_INC_FIXED BIT(0) -#define S3C24XX_DISRCC_LOC_AHB 0 -#define S3C24XX_DISRCC_LOC_APB BIT(1) - -#define S3C24XX_DIDST 0x08 -#define S3C24XX_DIDSTC 0x0c -#define S3C24XX_DIDSTC_INC_INCREMENT 0 -#define S3C24XX_DIDSTC_INC_FIXED BIT(0) -#define S3C24XX_DIDSTC_LOC_AHB 0 -#define S3C24XX_DIDSTC_LOC_APB BIT(1) -#define S3C24XX_DIDSTC_INT_TC0 0 -#define S3C24XX_DIDSTC_INT_RELOAD BIT(2) - -#define S3C24XX_DCON 0x10 - -#define S3C24XX_DCON_TC_MASK 0xfffff -#define S3C24XX_DCON_DSZ_BYTE (0 << 20) -#define S3C24XX_DCON_DSZ_HALFWORD (1 << 20) -#define S3C24XX_DCON_DSZ_WORD (2 << 20) -#define S3C24XX_DCON_DSZ_MASK (3 << 20) -#define S3C24XX_DCON_DSZ_SHIFT 20 -#define S3C24XX_DCON_AUTORELOAD 0 -#define S3C24XX_DCON_NORELOAD BIT(22) -#define S3C24XX_DCON_HWTRIG BIT(23) -#define S3C24XX_DCON_HWSRC_SHIFT 24 -#define S3C24XX_DCON_SERV_SINGLE 0 -#define S3C24XX_DCON_SERV_WHOLE BIT(27) -#define S3C24XX_DCON_TSZ_UNIT 0 -#define S3C24XX_DCON_TSZ_BURST4 BIT(28) -#define S3C24XX_DCON_INT BIT(29) -#define S3C24XX_DCON_SYNC_PCLK 0 -#define S3C24XX_DCON_SYNC_HCLK BIT(30) -#define S3C24XX_DCON_DEMAND 0 -#define S3C24XX_DCON_HANDSHAKE BIT(31) - -#define S3C24XX_DSTAT 0x14 -#define S3C24XX_DSTAT_STAT_BUSY BIT(20) -#define S3C24XX_DSTAT_CURRTC_MASK 0xfffff - -#define S3C24XX_DMASKTRIG 0x20 -#define S3C24XX_DMASKTRIG_SWTRIG BIT(0) -#define S3C24XX_DMASKTRIG_ON BIT(1) -#define S3C24XX_DMASKTRIG_STOP BIT(2) - -#define S3C24XX_DMAREQSEL 0x24 -#define S3C24XX_DMAREQSEL_HW BIT(0) - -/* - * S3C2410, S3C2440 and S3C2442 SoCs cannot select any physical channel - * for a DMA source. Instead only specific channels are valid. - * All of these SoCs have 4 physical channels and the number of request - * source bits is 3. Additionally we also need 1 bit to mark the channel - * as valid. - * Therefore we separate the chansel element of the channel data into 4 - * parts of 4 bits each, to hold the information if the channel is valid - * and the hw request source to use. - * - * Example: - * SDI is valid on channels 0, 2 and 3 - with varying hw request sources. - * For it the chansel field would look like - * - * ((BIT(3) | 1) << 3 * 4) | // channel 3, with request source 1 - * ((BIT(3) | 2) << 2 * 4) | // channel 2, with request source 2 - * ((BIT(3) | 2) << 0 * 4) // channel 0, with request source 2 - */ -#define S3C24XX_CHANSEL_WIDTH 4 -#define S3C24XX_CHANSEL_VALID BIT(3) -#define S3C24XX_CHANSEL_REQ_MASK 7 - -/* - * struct soc_data - vendor-specific config parameters for individual SoCs - * @stride: spacing between the registers of each channel - * @has_reqsel: does the controller use the newer requestselection mechanism - * @has_clocks: are controllable dma-clocks present - */ -struct soc_data { - int stride; - bool has_reqsel; - bool has_clocks; -}; - -/* - * enum s3c24xx_dma_chan_state - holds the virtual channel states - * @S3C24XX_DMA_CHAN_IDLE: the channel is idle - * @S3C24XX_DMA_CHAN_RUNNING: the channel has allocated a physical transport - * channel and is running a transfer on it - * @S3C24XX_DMA_CHAN_WAITING: the channel is waiting for a physical transport - * channel to become available (only pertains to memcpy channels) - */ -enum s3c24xx_dma_chan_state { - S3C24XX_DMA_CHAN_IDLE, - S3C24XX_DMA_CHAN_RUNNING, - S3C24XX_DMA_CHAN_WAITING, -}; - -/* - * struct s3c24xx_sg - structure containing data per sg - * @src_addr: src address of sg - * @dst_addr: dst address of sg - * @len: transfer len in bytes - * @node: node for txd's dsg_list - */ -struct s3c24xx_sg { - dma_addr_t src_addr; - dma_addr_t dst_addr; - size_t len; - struct list_head node; -}; - -/* - * struct s3c24xx_txd - wrapper for struct dma_async_tx_descriptor - * @vd: virtual DMA descriptor - * @dsg_list: list of children sg's - * @at: sg currently being transfered - * @width: transfer width - * @disrcc: value for source control register - * @didstc: value for destination control register - * @dcon: base value for dcon register - * @cyclic: indicate cyclic transfer - */ -struct s3c24xx_txd { - struct virt_dma_desc vd; - struct list_head dsg_list; - struct list_head *at; - u8 width; - u32 disrcc; - u32 didstc; - u32 dcon; - bool cyclic; -}; - -struct s3c24xx_dma_chan; - -/* - * struct s3c24xx_dma_phy - holder for the physical channels - * @id: physical index to this channel - * @valid: does the channel have all required elements - * @base: virtual memory base (remapped) for the this channel - * @irq: interrupt for this channel - * @clk: clock for this channel - * @lock: a lock to use when altering an instance of this struct - * @serving: virtual channel currently being served by this physicalchannel - * @host: a pointer to the host (internal use) - */ -struct s3c24xx_dma_phy { - unsigned int id; - bool valid; - void __iomem *base; - int irq; - struct clk *clk; - spinlock_t lock; - struct s3c24xx_dma_chan *serving; - struct s3c24xx_dma_engine *host; -}; - -/* - * struct s3c24xx_dma_chan - this structure wraps a DMA ENGINE channel - * @id: the id of the channel - * @name: name of the channel - * @vc: wrapped virtual channel - * @phy: the physical channel utilized by this channel, if there is one - * @runtime_addr: address for RX/TX according to the runtime config - * @at: active transaction on this channel - * @lock: a lock for this channel data - * @host: a pointer to the host (internal use) - * @state: whether the channel is idle, running etc - * @slave: whether this channel is a device (slave) or for memcpy - */ -struct s3c24xx_dma_chan { - int id; - const char *name; - struct virt_dma_chan vc; - struct s3c24xx_dma_phy *phy; - struct dma_slave_config cfg; - struct s3c24xx_txd *at; - struct s3c24xx_dma_engine *host; - enum s3c24xx_dma_chan_state state; - bool slave; -}; - -/* - * struct s3c24xx_dma_engine - the local state holder for the S3C24XX - * @pdev: the corresponding platform device - * @pdata: platform data passed in from the platform/machine - * @base: virtual memory base (remapped) - * @slave: slave engine for this instance - * @memcpy: memcpy engine for this instance - * @phy_chans: array of data for the physical channels - */ -struct s3c24xx_dma_engine { - struct platform_device *pdev; - const struct s3c24xx_dma_platdata *pdata; - struct soc_data *sdata; - void __iomem *base; - struct dma_device slave; - struct dma_device memcpy; - struct s3c24xx_dma_phy *phy_chans; -}; - -/* - * Physical channel handling - */ - -/* - * Check whether a certain channel is busy or not. - */ -static int s3c24xx_dma_phy_busy(struct s3c24xx_dma_phy *phy) -{ - unsigned int val = readl(phy->base + S3C24XX_DSTAT); - return val & S3C24XX_DSTAT_STAT_BUSY; -} - -static bool s3c24xx_dma_phy_valid(struct s3c24xx_dma_chan *s3cchan, - struct s3c24xx_dma_phy *phy) -{ - struct s3c24xx_dma_engine *s3cdma = s3cchan->host; - const struct s3c24xx_dma_platdata *pdata = s3cdma->pdata; - struct s3c24xx_dma_channel *cdata = &pdata->channels[s3cchan->id]; - int phyvalid; - - /* every phy is valid for memcopy channels */ - if (!s3cchan->slave) - return true; - - /* On newer variants all phys can be used for all virtual channels */ - if (s3cdma->sdata->has_reqsel) - return true; - - phyvalid = (cdata->chansel >> (phy->id * S3C24XX_CHANSEL_WIDTH)); - return (phyvalid & S3C24XX_CHANSEL_VALID) ? true : false; -} - -/* - * Allocate a physical channel for a virtual channel - * - * Try to locate a physical channel to be used for this transfer. If all - * are taken return NULL and the requester will have to cope by using - * some fallback PIO mode or retrying later. - */ -static -struct s3c24xx_dma_phy *s3c24xx_dma_get_phy(struct s3c24xx_dma_chan *s3cchan) -{ - struct s3c24xx_dma_engine *s3cdma = s3cchan->host; - struct s3c24xx_dma_phy *phy = NULL; - unsigned long flags; - int i; - int ret; - - for (i = 0; i < s3cdma->pdata->num_phy_channels; i++) { - phy = &s3cdma->phy_chans[i]; - - if (!phy->valid) - continue; - - if (!s3c24xx_dma_phy_valid(s3cchan, phy)) - continue; - - spin_lock_irqsave(&phy->lock, flags); - - if (!phy->serving) { - phy->serving = s3cchan; - spin_unlock_irqrestore(&phy->lock, flags); - break; - } - - spin_unlock_irqrestore(&phy->lock, flags); - } - - /* No physical channel available, cope with it */ - if (i == s3cdma->pdata->num_phy_channels) { - dev_warn(&s3cdma->pdev->dev, "no phy channel available\n"); - return NULL; - } - - /* start the phy clock */ - if (s3cdma->sdata->has_clocks) { - ret = clk_enable(phy->clk); - if (ret) { - dev_err(&s3cdma->pdev->dev, "could not enable clock for channel %d, err %d\n", - phy->id, ret); - phy->serving = NULL; - return NULL; - } - } - - return phy; -} - -/* - * Mark the physical channel as free. - * - * This drops the link between the physical and virtual channel. - */ -static inline void s3c24xx_dma_put_phy(struct s3c24xx_dma_phy *phy) -{ - struct s3c24xx_dma_engine *s3cdma = phy->host; - - if (s3cdma->sdata->has_clocks) - clk_disable(phy->clk); - - phy->serving = NULL; -} - -/* - * Stops the channel by writing the stop bit. - * This should not be used for an on-going transfer, but as a method of - * shutting down a channel (eg, when it's no longer used) or terminating a - * transfer. - */ -static void s3c24xx_dma_terminate_phy(struct s3c24xx_dma_phy *phy) -{ - writel(S3C24XX_DMASKTRIG_STOP, phy->base + S3C24XX_DMASKTRIG); -} - -/* - * Virtual channel handling - */ - -static inline -struct s3c24xx_dma_chan *to_s3c24xx_dma_chan(struct dma_chan *chan) -{ - return container_of(chan, struct s3c24xx_dma_chan, vc.chan); -} - -static u32 s3c24xx_dma_getbytes_chan(struct s3c24xx_dma_chan *s3cchan) -{ - struct s3c24xx_dma_phy *phy = s3cchan->phy; - struct s3c24xx_txd *txd = s3cchan->at; - u32 tc = readl(phy->base + S3C24XX_DSTAT) & S3C24XX_DSTAT_CURRTC_MASK; - - return tc * txd->width; -} - -static int s3c24xx_dma_set_runtime_config(struct dma_chan *chan, - struct dma_slave_config *config) -{ - struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(chan); - unsigned long flags; - int ret = 0; - - /* Reject definitely invalid configurations */ - if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES || - config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) - return -EINVAL; - - spin_lock_irqsave(&s3cchan->vc.lock, flags); - - if (!s3cchan->slave) { - ret = -EINVAL; - goto out; - } - - s3cchan->cfg = *config; - -out: - spin_unlock_irqrestore(&s3cchan->vc.lock, flags); - return ret; -} - -/* - * Transfer handling - */ - -static inline -struct s3c24xx_txd *to_s3c24xx_txd(struct dma_async_tx_descriptor *tx) -{ - return container_of(tx, struct s3c24xx_txd, vd.tx); -} - -static struct s3c24xx_txd *s3c24xx_dma_get_txd(void) -{ - struct s3c24xx_txd *txd = kzalloc(sizeof(*txd), GFP_NOWAIT); - - if (txd) { - INIT_LIST_HEAD(&txd->dsg_list); - txd->dcon = S3C24XX_DCON_INT | S3C24XX_DCON_NORELOAD; - } - - return txd; -} - -static void s3c24xx_dma_free_txd(struct s3c24xx_txd *txd) -{ - struct s3c24xx_sg *dsg, *_dsg; - - list_for_each_entry_safe(dsg, _dsg, &txd->dsg_list, node) { - list_del(&dsg->node); - kfree(dsg); - } - - kfree(txd); -} - -static void s3c24xx_dma_start_next_sg(struct s3c24xx_dma_chan *s3cchan, - struct s3c24xx_txd *txd) -{ - struct s3c24xx_dma_engine *s3cdma = s3cchan->host; - struct s3c24xx_dma_phy *phy = s3cchan->phy; - const struct s3c24xx_dma_platdata *pdata = s3cdma->pdata; - struct s3c24xx_sg *dsg = list_entry(txd->at, struct s3c24xx_sg, node); - u32 dcon = txd->dcon; - u32 val; - - /* transfer-size and -count from len and width */ - switch (txd->width) { - case 1: - dcon |= S3C24XX_DCON_DSZ_BYTE | dsg->len; - break; - case 2: - dcon |= S3C24XX_DCON_DSZ_HALFWORD | (dsg->len / 2); - break; - case 4: - dcon |= S3C24XX_DCON_DSZ_WORD | (dsg->len / 4); - break; - } - - if (s3cchan->slave) { - struct s3c24xx_dma_channel *cdata = - &pdata->channels[s3cchan->id]; - - if (s3cdma->sdata->has_reqsel) { - writel_relaxed((cdata->chansel << 1) | - S3C24XX_DMAREQSEL_HW, - phy->base + S3C24XX_DMAREQSEL); - } else { - int csel = cdata->chansel >> (phy->id * - S3C24XX_CHANSEL_WIDTH); - - csel &= S3C24XX_CHANSEL_REQ_MASK; - dcon |= csel << S3C24XX_DCON_HWSRC_SHIFT; - dcon |= S3C24XX_DCON_HWTRIG; - } - } else { - if (s3cdma->sdata->has_reqsel) - writel_relaxed(0, phy->base + S3C24XX_DMAREQSEL); - } - - writel_relaxed(dsg->src_addr, phy->base + S3C24XX_DISRC); - writel_relaxed(txd->disrcc, phy->base + S3C24XX_DISRCC); - writel_relaxed(dsg->dst_addr, phy->base + S3C24XX_DIDST); - writel_relaxed(txd->didstc, phy->base + S3C24XX_DIDSTC); - writel_relaxed(dcon, phy->base + S3C24XX_DCON); - - val = readl_relaxed(phy->base + S3C24XX_DMASKTRIG); - val &= ~S3C24XX_DMASKTRIG_STOP; - val |= S3C24XX_DMASKTRIG_ON; - - /* trigger the dma operation for memcpy transfers */ - if (!s3cchan->slave) - val |= S3C24XX_DMASKTRIG_SWTRIG; - - writel(val, phy->base + S3C24XX_DMASKTRIG); -} - -/* - * Set the initial DMA register values and start first sg. - */ -static void s3c24xx_dma_start_next_txd(struct s3c24xx_dma_chan *s3cchan) -{ - struct s3c24xx_dma_phy *phy = s3cchan->phy; - struct virt_dma_desc *vd = vchan_next_desc(&s3cchan->vc); - struct s3c24xx_txd *txd = to_s3c24xx_txd(&vd->tx); - - list_del(&txd->vd.node); - - s3cchan->at = txd; - - /* Wait for channel inactive */ - while (s3c24xx_dma_phy_busy(phy)) - cpu_relax(); - - /* point to the first element of the sg list */ - txd->at = txd->dsg_list.next; - s3c24xx_dma_start_next_sg(s3cchan, txd); -} - -/* - * Try to allocate a physical channel. When successful, assign it to - * this virtual channel, and initiate the next descriptor. The - * virtual channel lock must be held at this point. - */ -static void s3c24xx_dma_phy_alloc_and_start(struct s3c24xx_dma_chan *s3cchan) -{ - struct s3c24xx_dma_engine *s3cdma = s3cchan->host; - struct s3c24xx_dma_phy *phy; - - phy = s3c24xx_dma_get_phy(s3cchan); - if (!phy) { - dev_dbg(&s3cdma->pdev->dev, "no physical channel available for xfer on %s\n", - s3cchan->name); - s3cchan->state = S3C24XX_DMA_CHAN_WAITING; - return; - } - - dev_dbg(&s3cdma->pdev->dev, "allocated physical channel %d for xfer on %s\n", - phy->id, s3cchan->name); - - s3cchan->phy = phy; - s3cchan->state = S3C24XX_DMA_CHAN_RUNNING; - - s3c24xx_dma_start_next_txd(s3cchan); -} - -static void s3c24xx_dma_phy_reassign_start(struct s3c24xx_dma_phy *phy, - struct s3c24xx_dma_chan *s3cchan) -{ - struct s3c24xx_dma_engine *s3cdma = s3cchan->host; - - dev_dbg(&s3cdma->pdev->dev, "reassigned physical channel %d for xfer on %s\n", - phy->id, s3cchan->name); - - /* - * We do this without taking the lock; we're really only concerned - * about whether this pointer is NULL or not, and we're guaranteed - * that this will only be called when it _already_ is non-NULL. - */ - phy->serving = s3cchan; - s3cchan->phy = phy; - s3cchan->state = S3C24XX_DMA_CHAN_RUNNING; - s3c24xx_dma_start_next_txd(s3cchan); -} - -/* - * Free a physical DMA channel, potentially reallocating it to another - * virtual channel if we have any pending. - */ -static void s3c24xx_dma_phy_free(struct s3c24xx_dma_chan *s3cchan) -{ - struct s3c24xx_dma_engine *s3cdma = s3cchan->host; - struct s3c24xx_dma_chan *p, *next; - -retry: - next = NULL; - - /* Find a waiting virtual channel for the next transfer. */ - list_for_each_entry(p, &s3cdma->memcpy.channels, vc.chan.device_node) - if (p->state == S3C24XX_DMA_CHAN_WAITING) { - next = p; - break; - } - - if (!next) { - list_for_each_entry(p, &s3cdma->slave.channels, - vc.chan.device_node) - if (p->state == S3C24XX_DMA_CHAN_WAITING && - s3c24xx_dma_phy_valid(p, s3cchan->phy)) { - next = p; - break; - } - } - - /* Ensure that the physical channel is stopped */ - s3c24xx_dma_terminate_phy(s3cchan->phy); - - if (next) { - bool success; - - /* - * Eww. We know this isn't going to deadlock - * but lockdep probably doesn't. - */ - spin_lock(&next->vc.lock); - /* Re-check the state now that we have the lock */ - success = next->state == S3C24XX_DMA_CHAN_WAITING; - if (success) - s3c24xx_dma_phy_reassign_start(s3cchan->phy, next); - spin_unlock(&next->vc.lock); - - /* If the state changed, try to find another channel */ - if (!success) - goto retry; - } else { - /* No more jobs, so free up the physical channel */ - s3c24xx_dma_put_phy(s3cchan->phy); - } - - s3cchan->phy = NULL; - s3cchan->state = S3C24XX_DMA_CHAN_IDLE; -} - -static void s3c24xx_dma_desc_free(struct virt_dma_desc *vd) -{ - struct s3c24xx_txd *txd = to_s3c24xx_txd(&vd->tx); - struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(vd->tx.chan); - - if (!s3cchan->slave) - dma_descriptor_unmap(&vd->tx); - - s3c24xx_dma_free_txd(txd); -} - -static irqreturn_t s3c24xx_dma_irq(int irq, void *data) -{ - struct s3c24xx_dma_phy *phy = data; - struct s3c24xx_dma_chan *s3cchan = phy->serving; - struct s3c24xx_txd *txd; - - dev_dbg(&phy->host->pdev->dev, "interrupt on channel %d\n", phy->id); - - /* - * Interrupts happen to notify the completion of a transfer and the - * channel should have moved into its stop state already on its own. - * Therefore interrupts on channels not bound to a virtual channel - * should never happen. Nevertheless send a terminate command to the - * channel if the unlikely case happens. - */ - if (unlikely(!s3cchan)) { - dev_err(&phy->host->pdev->dev, "interrupt on unused channel %d\n", - phy->id); - - s3c24xx_dma_terminate_phy(phy); - - return IRQ_HANDLED; - } - - spin_lock(&s3cchan->vc.lock); - txd = s3cchan->at; - if (txd) { - /* when more sg's are in this txd, start the next one */ - if (!list_is_last(txd->at, &txd->dsg_list)) { - txd->at = txd->at->next; - if (txd->cyclic) - vchan_cyclic_callback(&txd->vd); - s3c24xx_dma_start_next_sg(s3cchan, txd); - } else if (!txd->cyclic) { - s3cchan->at = NULL; - vchan_cookie_complete(&txd->vd); - - /* - * And start the next descriptor (if any), - * otherwise free this channel. - */ - if (vchan_next_desc(&s3cchan->vc)) - s3c24xx_dma_start_next_txd(s3cchan); - else - s3c24xx_dma_phy_free(s3cchan); - } else { - vchan_cyclic_callback(&txd->vd); - - /* Cyclic: reset at beginning */ - txd->at = txd->dsg_list.next; - s3c24xx_dma_start_next_sg(s3cchan, txd); - } - } - spin_unlock(&s3cchan->vc.lock); - - return IRQ_HANDLED; -} - -/* - * The DMA ENGINE API - */ - -static int s3c24xx_dma_terminate_all(struct dma_chan *chan) -{ - struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(chan); - struct s3c24xx_dma_engine *s3cdma = s3cchan->host; - LIST_HEAD(head); - unsigned long flags; - int ret; - - spin_lock_irqsave(&s3cchan->vc.lock, flags); - - if (!s3cchan->phy && !s3cchan->at) { - dev_err(&s3cdma->pdev->dev, "trying to terminate already stopped channel %d\n", - s3cchan->id); - ret = -EINVAL; - goto unlock; - } - - s3cchan->state = S3C24XX_DMA_CHAN_IDLE; - - /* Mark physical channel as free */ - if (s3cchan->phy) - s3c24xx_dma_phy_free(s3cchan); - - /* Dequeue current job */ - if (s3cchan->at) { - vchan_terminate_vdesc(&s3cchan->at->vd); - s3cchan->at = NULL; - } - - /* Dequeue jobs not yet fired as well */ - - vchan_get_all_descriptors(&s3cchan->vc, &head); - - spin_unlock_irqrestore(&s3cchan->vc.lock, flags); - - vchan_dma_desc_free_list(&s3cchan->vc, &head); - - return 0; - -unlock: - spin_unlock_irqrestore(&s3cchan->vc.lock, flags); - - return ret; -} - -static void s3c24xx_dma_synchronize(struct dma_chan *chan) -{ - struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(chan); - - vchan_synchronize(&s3cchan->vc); -} - -static void s3c24xx_dma_free_chan_resources(struct dma_chan *chan) -{ - /* Ensure all queued descriptors are freed */ - vchan_free_chan_resources(to_virt_chan(chan)); -} - -static enum dma_status s3c24xx_dma_tx_status(struct dma_chan *chan, - dma_cookie_t cookie, struct dma_tx_state *txstate) -{ - struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(chan); - struct s3c24xx_txd *txd; - struct s3c24xx_sg *dsg; - struct virt_dma_desc *vd; - unsigned long flags; - enum dma_status ret; - size_t bytes = 0; - - spin_lock_irqsave(&s3cchan->vc.lock, flags); - ret = dma_cookie_status(chan, cookie, txstate); - - /* - * There's no point calculating the residue if there's - * no txstate to store the value. - */ - if (ret == DMA_COMPLETE || !txstate) { - spin_unlock_irqrestore(&s3cchan->vc.lock, flags); - return ret; - } - - vd = vchan_find_desc(&s3cchan->vc, cookie); - if (vd) { - /* On the issued list, so hasn't been processed yet */ - txd = to_s3c24xx_txd(&vd->tx); - - list_for_each_entry(dsg, &txd->dsg_list, node) - bytes += dsg->len; - } else { - /* - * Currently running, so sum over the pending sg's and - * the currently active one. - */ - txd = s3cchan->at; - - dsg = list_entry(txd->at, struct s3c24xx_sg, node); - list_for_each_entry_from(dsg, &txd->dsg_list, node) - bytes += dsg->len; - - bytes += s3c24xx_dma_getbytes_chan(s3cchan); - } - spin_unlock_irqrestore(&s3cchan->vc.lock, flags); - - /* - * This cookie not complete yet - * Get number of bytes left in the active transactions and queue - */ - dma_set_residue(txstate, bytes); - - /* Whether waiting or running, we're in progress */ - return ret; -} - -/* - * Initialize a descriptor to be used by memcpy submit - */ -static struct dma_async_tx_descriptor *s3c24xx_dma_prep_memcpy( - struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, - size_t len, unsigned long flags) -{ - struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(chan); - struct s3c24xx_dma_engine *s3cdma = s3cchan->host; - struct s3c24xx_txd *txd; - struct s3c24xx_sg *dsg; - int src_mod, dest_mod; - - dev_dbg(&s3cdma->pdev->dev, "prepare memcpy of %zu bytes from %s\n", - len, s3cchan->name); - - if ((len & S3C24XX_DCON_TC_MASK) != len) { - dev_err(&s3cdma->pdev->dev, "memcpy size %zu to large\n", len); - return NULL; - } - - txd = s3c24xx_dma_get_txd(); - if (!txd) - return NULL; - - dsg = kzalloc(sizeof(*dsg), GFP_NOWAIT); - if (!dsg) { - s3c24xx_dma_free_txd(txd); - return NULL; - } - list_add_tail(&dsg->node, &txd->dsg_list); - - dsg->src_addr = src; - dsg->dst_addr = dest; - dsg->len = len; - - /* - * Determine a suitable transfer width. - * The DMA controller cannot fetch/store information which is not - * naturally aligned on the bus, i.e., a 4 byte fetch must start at - * an address divisible by 4 - more generally addr % width must be 0. - */ - src_mod = src % 4; - dest_mod = dest % 4; - switch (len % 4) { - case 0: - txd->width = (src_mod == 0 && dest_mod == 0) ? 4 : 1; - break; - case 2: - txd->width = ((src_mod == 2 || src_mod == 0) && - (dest_mod == 2 || dest_mod == 0)) ? 2 : 1; - break; - default: - txd->width = 1; - break; - } - - txd->disrcc = S3C24XX_DISRCC_LOC_AHB | S3C24XX_DISRCC_INC_INCREMENT; - txd->didstc = S3C24XX_DIDSTC_LOC_AHB | S3C24XX_DIDSTC_INC_INCREMENT; - txd->dcon |= S3C24XX_DCON_DEMAND | S3C24XX_DCON_SYNC_HCLK | - S3C24XX_DCON_SERV_WHOLE; - - return vchan_tx_prep(&s3cchan->vc, &txd->vd, flags); -} - -static struct dma_async_tx_descriptor *s3c24xx_dma_prep_dma_cyclic( - struct dma_chan *chan, dma_addr_t addr, size_t size, size_t period, - enum dma_transfer_direction direction, unsigned long flags) -{ - struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(chan); - struct s3c24xx_dma_engine *s3cdma = s3cchan->host; - const struct s3c24xx_dma_platdata *pdata = s3cdma->pdata; - struct s3c24xx_dma_channel *cdata = &pdata->channels[s3cchan->id]; - struct s3c24xx_txd *txd; - struct s3c24xx_sg *dsg; - unsigned sg_len; - dma_addr_t slave_addr; - u32 hwcfg = 0; - int i; - - dev_dbg(&s3cdma->pdev->dev, - "prepare cyclic transaction of %zu bytes with period %zu from %s\n", - size, period, s3cchan->name); - - if (!is_slave_direction(direction)) { - dev_err(&s3cdma->pdev->dev, - "direction %d unsupported\n", direction); - return NULL; - } - - txd = s3c24xx_dma_get_txd(); - if (!txd) - return NULL; - - txd->cyclic = 1; - - if (cdata->handshake) - txd->dcon |= S3C24XX_DCON_HANDSHAKE; - - switch (cdata->bus) { - case S3C24XX_DMA_APB: - txd->dcon |= S3C24XX_DCON_SYNC_PCLK; - hwcfg |= S3C24XX_DISRCC_LOC_APB; - break; - case S3C24XX_DMA_AHB: - txd->dcon |= S3C24XX_DCON_SYNC_HCLK; - hwcfg |= S3C24XX_DISRCC_LOC_AHB; - break; - } - - /* - * Always assume our peripheral desintation is a fixed - * address in memory. - */ - hwcfg |= S3C24XX_DISRCC_INC_FIXED; - - /* - * Individual dma operations are requested by the slave, - * so serve only single atomic operations (S3C24XX_DCON_SERV_SINGLE). - */ - txd->dcon |= S3C24XX_DCON_SERV_SINGLE; - - if (direction == DMA_MEM_TO_DEV) { - txd->disrcc = S3C24XX_DISRCC_LOC_AHB | - S3C24XX_DISRCC_INC_INCREMENT; - txd->didstc = hwcfg; - slave_addr = s3cchan->cfg.dst_addr; - txd->width = s3cchan->cfg.dst_addr_width; - } else { - txd->disrcc = hwcfg; - txd->didstc = S3C24XX_DIDSTC_LOC_AHB | - S3C24XX_DIDSTC_INC_INCREMENT; - slave_addr = s3cchan->cfg.src_addr; - txd->width = s3cchan->cfg.src_addr_width; - } - - sg_len = size / period; - - for (i = 0; i < sg_len; i++) { - dsg = kzalloc(sizeof(*dsg), GFP_NOWAIT); - if (!dsg) { - s3c24xx_dma_free_txd(txd); - return NULL; - } - list_add_tail(&dsg->node, &txd->dsg_list); - - dsg->len = period; - /* Check last period length */ - if (i == sg_len - 1) - dsg->len = size - period * i; - if (direction == DMA_MEM_TO_DEV) { - dsg->src_addr = addr + period * i; - dsg->dst_addr = slave_addr; - } else { /* DMA_DEV_TO_MEM */ - dsg->src_addr = slave_addr; - dsg->dst_addr = addr + period * i; - } - } - - return vchan_tx_prep(&s3cchan->vc, &txd->vd, flags); -} - -static struct dma_async_tx_descriptor *s3c24xx_dma_prep_slave_sg( - struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_transfer_direction direction, - unsigned long flags, void *context) -{ - struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(chan); - struct s3c24xx_dma_engine *s3cdma = s3cchan->host; - const struct s3c24xx_dma_platdata *pdata = s3cdma->pdata; - struct s3c24xx_dma_channel *cdata = &pdata->channels[s3cchan->id]; - struct s3c24xx_txd *txd; - struct s3c24xx_sg *dsg; - struct scatterlist *sg; - dma_addr_t slave_addr; - u32 hwcfg = 0; - int tmp; - - dev_dbg(&s3cdma->pdev->dev, "prepare transaction of %d bytes from %s\n", - sg_dma_len(sgl), s3cchan->name); - - txd = s3c24xx_dma_get_txd(); - if (!txd) - return NULL; - - if (cdata->handshake) - txd->dcon |= S3C24XX_DCON_HANDSHAKE; - - switch (cdata->bus) { - case S3C24XX_DMA_APB: - txd->dcon |= S3C24XX_DCON_SYNC_PCLK; - hwcfg |= S3C24XX_DISRCC_LOC_APB; - break; - case S3C24XX_DMA_AHB: - txd->dcon |= S3C24XX_DCON_SYNC_HCLK; - hwcfg |= S3C24XX_DISRCC_LOC_AHB; - break; - } - - /* - * Always assume our peripheral desintation is a fixed - * address in memory. - */ - hwcfg |= S3C24XX_DISRCC_INC_FIXED; - - /* - * Individual dma operations are requested by the slave, - * so serve only single atomic operations (S3C24XX_DCON_SERV_SINGLE). - */ - txd->dcon |= S3C24XX_DCON_SERV_SINGLE; - - if (direction == DMA_MEM_TO_DEV) { - txd->disrcc = S3C24XX_DISRCC_LOC_AHB | - S3C24XX_DISRCC_INC_INCREMENT; - txd->didstc = hwcfg; - slave_addr = s3cchan->cfg.dst_addr; - txd->width = s3cchan->cfg.dst_addr_width; - } else if (direction == DMA_DEV_TO_MEM) { - txd->disrcc = hwcfg; - txd->didstc = S3C24XX_DIDSTC_LOC_AHB | - S3C24XX_DIDSTC_INC_INCREMENT; - slave_addr = s3cchan->cfg.src_addr; - txd->width = s3cchan->cfg.src_addr_width; - } else { - s3c24xx_dma_free_txd(txd); - dev_err(&s3cdma->pdev->dev, - "direction %d unsupported\n", direction); - return NULL; - } - - for_each_sg(sgl, sg, sg_len, tmp) { - dsg = kzalloc(sizeof(*dsg), GFP_NOWAIT); - if (!dsg) { - s3c24xx_dma_free_txd(txd); - return NULL; - } - list_add_tail(&dsg->node, &txd->dsg_list); - - dsg->len = sg_dma_len(sg); - if (direction == DMA_MEM_TO_DEV) { - dsg->src_addr = sg_dma_address(sg); - dsg->dst_addr = slave_addr; - } else { /* DMA_DEV_TO_MEM */ - dsg->src_addr = slave_addr; - dsg->dst_addr = sg_dma_address(sg); - } - } - - return vchan_tx_prep(&s3cchan->vc, &txd->vd, flags); -} - -/* - * Slave transactions callback to the slave device to allow - * synchronization of slave DMA signals with the DMAC enable - */ -static void s3c24xx_dma_issue_pending(struct dma_chan *chan) -{ - struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(chan); - unsigned long flags; - - spin_lock_irqsave(&s3cchan->vc.lock, flags); - if (vchan_issue_pending(&s3cchan->vc)) { - if (!s3cchan->phy && s3cchan->state != S3C24XX_DMA_CHAN_WAITING) - s3c24xx_dma_phy_alloc_and_start(s3cchan); - } - spin_unlock_irqrestore(&s3cchan->vc.lock, flags); -} - -/* - * Bringup and teardown - */ - -/* - * Initialise the DMAC memcpy/slave channels. - * Make a local wrapper to hold required data - */ -static int s3c24xx_dma_init_virtual_channels(struct s3c24xx_dma_engine *s3cdma, - struct dma_device *dmadev, unsigned int channels, bool slave) -{ - struct s3c24xx_dma_chan *chan; - int i; - - INIT_LIST_HEAD(&dmadev->channels); - - /* - * Register as many memcpy as we have physical channels, - * we won't always be able to use all but the code will have - * to cope with that situation. - */ - for (i = 0; i < channels; i++) { - chan = devm_kzalloc(dmadev->dev, sizeof(*chan), GFP_KERNEL); - if (!chan) - return -ENOMEM; - - chan->id = i; - chan->host = s3cdma; - chan->state = S3C24XX_DMA_CHAN_IDLE; - - if (slave) { - chan->slave = true; - chan->name = kasprintf(GFP_KERNEL, "slave%d", i); - if (!chan->name) - return -ENOMEM; - } else { - chan->name = kasprintf(GFP_KERNEL, "memcpy%d", i); - if (!chan->name) - return -ENOMEM; - } - dev_dbg(dmadev->dev, - "initialize virtual channel \"%s\"\n", - chan->name); - - chan->vc.desc_free = s3c24xx_dma_desc_free; - vchan_init(&chan->vc, dmadev); - } - dev_info(dmadev->dev, "initialized %d virtual %s channels\n", - i, slave ? "slave" : "memcpy"); - return i; -} - -static void s3c24xx_dma_free_virtual_channels(struct dma_device *dmadev) -{ - struct s3c24xx_dma_chan *chan = NULL; - struct s3c24xx_dma_chan *next; - - list_for_each_entry_safe(chan, - next, &dmadev->channels, vc.chan.device_node) { - list_del(&chan->vc.chan.device_node); - tasklet_kill(&chan->vc.task); - } -} - -/* s3c2410, s3c2440 and s3c2442 have a 0x40 stride without separate clocks */ -static struct soc_data soc_s3c2410 = { - .stride = 0x40, - .has_reqsel = false, - .has_clocks = false, -}; - -/* s3c2412 and s3c2413 have a 0x40 stride and dmareqsel mechanism */ -static struct soc_data soc_s3c2412 = { - .stride = 0x40, - .has_reqsel = true, - .has_clocks = true, -}; - -/* s3c2443 and following have a 0x100 stride and dmareqsel mechanism */ -static struct soc_data soc_s3c2443 = { - .stride = 0x100, - .has_reqsel = true, - .has_clocks = true, -}; - -static const struct platform_device_id s3c24xx_dma_driver_ids[] = { - { - .name = "s3c2410-dma", - .driver_data = (kernel_ulong_t)&soc_s3c2410, - }, { - .name = "s3c2412-dma", - .driver_data = (kernel_ulong_t)&soc_s3c2412, - }, { - .name = "s3c2443-dma", - .driver_data = (kernel_ulong_t)&soc_s3c2443, - }, - { }, -}; - -static struct soc_data *s3c24xx_dma_get_soc_data(struct platform_device *pdev) -{ - return (struct soc_data *) - platform_get_device_id(pdev)->driver_data; -} - -static int s3c24xx_dma_probe(struct platform_device *pdev) -{ - const struct s3c24xx_dma_platdata *pdata = dev_get_platdata(&pdev->dev); - struct s3c24xx_dma_engine *s3cdma; - struct soc_data *sdata; - struct resource *res; - int ret; - int i; - - if (!pdata) { - dev_err(&pdev->dev, "platform data missing\n"); - return -ENODEV; - } - - /* Basic sanity check */ - if (pdata->num_phy_channels > MAX_DMA_CHANNELS) { - dev_err(&pdev->dev, "too many dma channels %d, max %d\n", - pdata->num_phy_channels, MAX_DMA_CHANNELS); - return -EINVAL; - } - - sdata = s3c24xx_dma_get_soc_data(pdev); - if (!sdata) - return -EINVAL; - - s3cdma = devm_kzalloc(&pdev->dev, sizeof(*s3cdma), GFP_KERNEL); - if (!s3cdma) - return -ENOMEM; - - s3cdma->pdev = pdev; - s3cdma->pdata = pdata; - s3cdma->sdata = sdata; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - s3cdma->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(s3cdma->base)) - return PTR_ERR(s3cdma->base); - - s3cdma->phy_chans = devm_kcalloc(&pdev->dev, - pdata->num_phy_channels, - sizeof(struct s3c24xx_dma_phy), - GFP_KERNEL); - if (!s3cdma->phy_chans) - return -ENOMEM; - - /* acquire irqs and clocks for all physical channels */ - for (i = 0; i < pdata->num_phy_channels; i++) { - struct s3c24xx_dma_phy *phy = &s3cdma->phy_chans[i]; - char clk_name[6]; - - phy->id = i; - phy->base = s3cdma->base + (i * sdata->stride); - phy->host = s3cdma; - - phy->irq = platform_get_irq(pdev, i); - if (phy->irq < 0) - continue; - - ret = devm_request_irq(&pdev->dev, phy->irq, s3c24xx_dma_irq, - 0, pdev->name, phy); - if (ret) { - dev_err(&pdev->dev, "Unable to request irq for channel %d, error %d\n", - i, ret); - continue; - } - - if (sdata->has_clocks) { - sprintf(clk_name, "dma.%d", i); - phy->clk = devm_clk_get(&pdev->dev, clk_name); - if (IS_ERR(phy->clk) && sdata->has_clocks) { - dev_err(&pdev->dev, "unable to acquire clock for channel %d, error %lu\n", - i, PTR_ERR(phy->clk)); - continue; - } - - ret = clk_prepare(phy->clk); - if (ret) { - dev_err(&pdev->dev, "clock for phy %d failed, error %d\n", - i, ret); - continue; - } - } - - spin_lock_init(&phy->lock); - phy->valid = true; - - dev_dbg(&pdev->dev, "physical channel %d is %s\n", - i, s3c24xx_dma_phy_busy(phy) ? "BUSY" : "FREE"); - } - - /* Initialize memcpy engine */ - dma_cap_set(DMA_MEMCPY, s3cdma->memcpy.cap_mask); - dma_cap_set(DMA_PRIVATE, s3cdma->memcpy.cap_mask); - s3cdma->memcpy.dev = &pdev->dev; - s3cdma->memcpy.device_free_chan_resources = - s3c24xx_dma_free_chan_resources; - s3cdma->memcpy.device_prep_dma_memcpy = s3c24xx_dma_prep_memcpy; - s3cdma->memcpy.device_tx_status = s3c24xx_dma_tx_status; - s3cdma->memcpy.device_issue_pending = s3c24xx_dma_issue_pending; - s3cdma->memcpy.device_config = s3c24xx_dma_set_runtime_config; - s3cdma->memcpy.device_terminate_all = s3c24xx_dma_terminate_all; - s3cdma->memcpy.device_synchronize = s3c24xx_dma_synchronize; - - /* Initialize slave engine for SoC internal dedicated peripherals */ - dma_cap_set(DMA_SLAVE, s3cdma->slave.cap_mask); - dma_cap_set(DMA_CYCLIC, s3cdma->slave.cap_mask); - dma_cap_set(DMA_PRIVATE, s3cdma->slave.cap_mask); - s3cdma->slave.dev = &pdev->dev; - s3cdma->slave.device_free_chan_resources = - s3c24xx_dma_free_chan_resources; - s3cdma->slave.device_tx_status = s3c24xx_dma_tx_status; - s3cdma->slave.device_issue_pending = s3c24xx_dma_issue_pending; - s3cdma->slave.device_prep_slave_sg = s3c24xx_dma_prep_slave_sg; - s3cdma->slave.device_prep_dma_cyclic = s3c24xx_dma_prep_dma_cyclic; - s3cdma->slave.device_config = s3c24xx_dma_set_runtime_config; - s3cdma->slave.device_terminate_all = s3c24xx_dma_terminate_all; - s3cdma->slave.device_synchronize = s3c24xx_dma_synchronize; - s3cdma->slave.filter.map = pdata->slave_map; - s3cdma->slave.filter.mapcnt = pdata->slavecnt; - s3cdma->slave.filter.fn = s3c24xx_dma_filter; - - /* Register as many memcpy channels as there are physical channels */ - ret = s3c24xx_dma_init_virtual_channels(s3cdma, &s3cdma->memcpy, - pdata->num_phy_channels, false); - if (ret <= 0) { - dev_warn(&pdev->dev, - "%s failed to enumerate memcpy channels - %d\n", - __func__, ret); - goto err_memcpy; - } - - /* Register slave channels */ - ret = s3c24xx_dma_init_virtual_channels(s3cdma, &s3cdma->slave, - pdata->num_channels, true); - if (ret <= 0) { - dev_warn(&pdev->dev, - "%s failed to enumerate slave channels - %d\n", - __func__, ret); - goto err_slave; - } - - ret = dma_async_device_register(&s3cdma->memcpy); - if (ret) { - dev_warn(&pdev->dev, - "%s failed to register memcpy as an async device - %d\n", - __func__, ret); - goto err_memcpy_reg; - } - - ret = dma_async_device_register(&s3cdma->slave); - if (ret) { - dev_warn(&pdev->dev, - "%s failed to register slave as an async device - %d\n", - __func__, ret); - goto err_slave_reg; - } - - platform_set_drvdata(pdev, s3cdma); - dev_info(&pdev->dev, "Loaded dma driver with %d physical channels\n", - pdata->num_phy_channels); - - return 0; - -err_slave_reg: - dma_async_device_unregister(&s3cdma->memcpy); -err_memcpy_reg: - s3c24xx_dma_free_virtual_channels(&s3cdma->slave); -err_slave: - s3c24xx_dma_free_virtual_channels(&s3cdma->memcpy); -err_memcpy: - if (sdata->has_clocks) - for (i = 0; i < pdata->num_phy_channels; i++) { - struct s3c24xx_dma_phy *phy = &s3cdma->phy_chans[i]; - if (phy->valid) - clk_unprepare(phy->clk); - } - - return ret; -} - -static void s3c24xx_dma_free_irq(struct platform_device *pdev, - struct s3c24xx_dma_engine *s3cdma) -{ - int i; - - for (i = 0; i < s3cdma->pdata->num_phy_channels; i++) { - struct s3c24xx_dma_phy *phy = &s3cdma->phy_chans[i]; - - devm_free_irq(&pdev->dev, phy->irq, phy); - } -} - -static int s3c24xx_dma_remove(struct platform_device *pdev) -{ - const struct s3c24xx_dma_platdata *pdata = dev_get_platdata(&pdev->dev); - struct s3c24xx_dma_engine *s3cdma = platform_get_drvdata(pdev); - struct soc_data *sdata = s3c24xx_dma_get_soc_data(pdev); - int i; - - dma_async_device_unregister(&s3cdma->slave); - dma_async_device_unregister(&s3cdma->memcpy); - - s3c24xx_dma_free_irq(pdev, s3cdma); - - s3c24xx_dma_free_virtual_channels(&s3cdma->slave); - s3c24xx_dma_free_virtual_channels(&s3cdma->memcpy); - - if (sdata->has_clocks) - for (i = 0; i < pdata->num_phy_channels; i++) { - struct s3c24xx_dma_phy *phy = &s3cdma->phy_chans[i]; - if (phy->valid) - clk_unprepare(phy->clk); - } - - return 0; -} - -static struct platform_driver s3c24xx_dma_driver = { - .driver = { - .name = "s3c24xx-dma", - }, - .id_table = s3c24xx_dma_driver_ids, - .probe = s3c24xx_dma_probe, - .remove = s3c24xx_dma_remove, -}; - -module_platform_driver(s3c24xx_dma_driver); - -bool s3c24xx_dma_filter(struct dma_chan *chan, void *param) -{ - struct s3c24xx_dma_chan *s3cchan; - - if (chan->device->dev->driver != &s3c24xx_dma_driver.driver) - return false; - - s3cchan = to_s3c24xx_dma_chan(chan); - - return s3cchan->id == (uintptr_t)param; -} -EXPORT_SYMBOL(s3c24xx_dma_filter); - -MODULE_DESCRIPTION("S3C24XX DMA Driver"); -MODULE_AUTHOR("Heiko Stuebner"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c index 1d1180db6d4e..8f67f453a492 100644 --- a/drivers/dma/tegra186-gpc-dma.c +++ b/drivers/dma/tegra186-gpc-dma.c @@ -711,6 +711,7 @@ static int tegra_dma_terminate_all(struct dma_chan *dc) return err; } + vchan_terminate_vdesc(&tdc->dma_desc->vd); tegra_dma_disable(tdc); tdc->dma_desc = NULL; } diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index ae39b52012b2..79da93cc77b6 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -221,7 +221,7 @@ static int tegra_adma_init(struct tegra_adma *tdma) int ret; /* Clear any interrupts */ - tdma_write(tdma, tdma->cdata->global_int_clear, 0x1); + tdma_write(tdma, tdma->cdata->ch_base_offset + tdma->cdata->global_int_clear, 0x1); /* Assert soft reset */ tdma_write(tdma, ADMA_GLOBAL_SOFT_RESET, 0x1); diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index ce8b80bb34d7..4c62274e0b33 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -762,11 +762,12 @@ static void udma_decrement_byte_counters(struct udma_chan *uc, u32 val) if (uc->desc->dir == DMA_DEV_TO_MEM) { udma_rchanrt_write(uc, UDMA_CHAN_RT_BCNT_REG, val); udma_rchanrt_write(uc, UDMA_CHAN_RT_SBCNT_REG, val); - udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val); + if (uc->config.ep_type != PSIL_EP_NATIVE) + udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val); } else { udma_tchanrt_write(uc, UDMA_CHAN_RT_BCNT_REG, val); udma_tchanrt_write(uc, UDMA_CHAN_RT_SBCNT_REG, val); - if (!uc->bchan) + if (!uc->bchan && uc->config.ep_type != PSIL_EP_NATIVE) udma_tchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val); } } diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index a8d23cdf883e..ac09f0e5f58d 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -3143,8 +3143,10 @@ static int xilinx_dma_probe(struct platform_device *pdev) /* Initialize the channels */ for_each_child_of_node(node, child) { err = xilinx_dma_child_probe(xdev, child); - if (err < 0) + if (err < 0) { + of_node_put(child); goto error; + } } if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) { diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 19522c568aa5..0689e1510721 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -34,6 +34,9 @@ static DEFINE_MUTEX(device_ctls_mutex); static LIST_HEAD(edac_device_list); +/* Default workqueue processing interval on this instance, in msecs */ +#define DEFAULT_POLL_INTERVAL 1000 + #ifdef CONFIG_EDAC_DEBUG static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev) { @@ -336,7 +339,7 @@ static void edac_device_workq_function(struct work_struct *work_req) * whole one second to save timers firing all over the period * between integral seconds */ - if (edac_dev->poll_msec == 1000) + if (edac_dev->poll_msec == DEFAULT_POLL_INTERVAL) edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay)); else edac_queue_work(&edac_dev->work, edac_dev->delay); @@ -366,7 +369,7 @@ static void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, * timers firing on sub-second basis, while they are happy * to fire together on the 1 second exactly */ - if (edac_dev->poll_msec == 1000) + if (edac_dev->poll_msec == DEFAULT_POLL_INTERVAL) edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay)); else edac_queue_work(&edac_dev->work, edac_dev->delay); @@ -394,17 +397,16 @@ static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev) * Then restart the workq on the new delay */ void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev, - unsigned long value) + unsigned long msec) { - unsigned long jiffs = msecs_to_jiffies(value); - - if (value == 1000) - jiffs = round_jiffies_relative(value); - - edac_dev->poll_msec = value; - edac_dev->delay = jiffs; + edac_dev->poll_msec = msec; + edac_dev->delay = msecs_to_jiffies(msec); - edac_mod_work(&edac_dev->work, jiffs); + /* See comment in edac_device_workq_setup() above */ + if (edac_dev->poll_msec == DEFAULT_POLL_INTERVAL) + edac_mod_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay)); + else + edac_mod_work(&edac_dev->work, edac_dev->delay); } int edac_device_alloc_index(void) @@ -443,11 +445,7 @@ int edac_device_add_device(struct edac_device_ctl_info *edac_dev) /* This instance is NOW RUNNING */ edac_dev->op_state = OP_RUNNING_POLL; - /* - * enable workq processing on this instance, - * default = 1000 msec - */ - edac_device_workq_setup(edac_dev, 1000); + edac_device_workq_setup(edac_dev, edac_dev->poll_msec ?: DEFAULT_POLL_INTERVAL); } else { edac_dev->op_state = OP_RUNNING_INTERRUPT; } diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index 763c076d96f2..47593afdc234 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h @@ -53,7 +53,7 @@ bool edac_stop_work(struct delayed_work *work); bool edac_mod_work(struct delayed_work *work, unsigned long delay); extern void edac_device_reset_delay_period(struct edac_device_ctl_info - *edac_dev, unsigned long value); + *edac_dev, unsigned long msec); extern void edac_mc_reset_delay_period(unsigned long value); /* diff --git a/drivers/edac/highbank_mc_edac.c b/drivers/edac/highbank_mc_edac.c index 61b76ec226af..19fba258ae10 100644 --- a/drivers/edac/highbank_mc_edac.c +++ b/drivers/edac/highbank_mc_edac.c @@ -174,8 +174,10 @@ static int highbank_mc_probe(struct platform_device *pdev) drvdata = mci->pvt_info; platform_set_drvdata(pdev, mci); - if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) - return -ENOMEM; + if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) { + res = -ENOMEM; + goto free; + } r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { @@ -243,6 +245,7 @@ err2: edac_mc_del_mc(&pdev->dev); err: devres_release_group(&pdev->dev, NULL); +free: edac_mc_free(mci); return res; } diff --git a/drivers/edac/qcom_edac.c b/drivers/edac/qcom_edac.c index 97a27e42dd61..c45519f59dc1 100644 --- a/drivers/edac/qcom_edac.c +++ b/drivers/edac/qcom_edac.c @@ -252,7 +252,7 @@ clear: static int dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, u32 bank) { - struct llcc_drv_data *drv = edev_ctl->pvt_info; + struct llcc_drv_data *drv = edev_ctl->dev->platform_data; int ret; ret = dump_syn_reg_values(drv, bank, err_type); @@ -289,7 +289,7 @@ static irqreturn_t llcc_ecc_irq_handler(int irq, void *edev_ctl) { struct edac_device_ctl_info *edac_dev_ctl = edev_ctl; - struct llcc_drv_data *drv = edac_dev_ctl->pvt_info; + struct llcc_drv_data *drv = edac_dev_ctl->dev->platform_data; irqreturn_t irq_rc = IRQ_NONE; u32 drp_error, trp_error, i; int ret; @@ -358,7 +358,6 @@ static int qcom_llcc_edac_probe(struct platform_device *pdev) edev_ctl->dev_name = dev_name(dev); edev_ctl->ctl_name = "llcc"; edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE; - edev_ctl->pvt_info = llcc_driv_data; rc = edac_device_add_device(edev_ctl); if (rc) diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 9c89f7d53e99..958aa4662ccb 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -819,8 +819,10 @@ static int ioctl_send_response(struct client *client, union ioctl_arg *arg) r = container_of(resource, struct inbound_transaction_resource, resource); - if (is_fcp_request(r->request)) + if (is_fcp_request(r->request)) { + kfree(r->data); goto out; + } if (a->length != fw_get_response_length(r->request)) { ret = -EINVAL; diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index f818d00bb2c6..ffdad59ec81f 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -910,6 +910,8 @@ static int do_xfer(const struct scmi_protocol_handle *ph, xfer->hdr.protocol_id, xfer->hdr.seq, xfer->hdr.poll_completion); + /* Clear any stale status */ + xfer->hdr.status = SCMI_SUCCESS; xfer->state = SCMI_XFER_SENT_OK; /* * Even though spinlocking is not needed here since no race is possible diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c index 1dfe534b8518..87b4f4d35f06 100644 --- a/drivers/firmware/arm_scmi/shmem.c +++ b/drivers/firmware/arm_scmi/shmem.c @@ -81,10 +81,11 @@ u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem) void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, struct scmi_xfer *xfer) { + size_t len = ioread32(&shmem->length); + xfer->hdr.status = ioread32(shmem->msg_payload); /* Skip the length of header and status in shmem area i.e 8 bytes */ - xfer->rx.len = min_t(size_t, xfer->rx.len, - ioread32(&shmem->length) - 8); + xfer->rx.len = min_t(size_t, xfer->rx.len, len > 8 ? len - 8 : 0); /* Take a copy to the rx buffer.. */ memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len); @@ -93,8 +94,10 @@ void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, size_t max_len, struct scmi_xfer *xfer) { + size_t len = ioread32(&shmem->length); + /* Skip only the length of header in shmem area i.e 4 bytes */ - xfer->rx.len = min_t(size_t, max_len, ioread32(&shmem->length) - 4); + xfer->rx.len = min_t(size_t, max_len, len > 4 ? len - 4 : 0); /* Take a copy to the rx buffer.. */ memcpy_fromio(xfer->rx.buf, shmem->msg_payload, xfer->rx.len); diff --git a/drivers/firmware/arm_scmi/virtio.c b/drivers/firmware/arm_scmi/virtio.c index 33c9b81a55cd..1db975c08896 100644 --- a/drivers/firmware/arm_scmi/virtio.c +++ b/drivers/firmware/arm_scmi/virtio.c @@ -160,7 +160,6 @@ static void scmi_vio_channel_cleanup_sync(struct scmi_vio_channel *vioch) } vioch->shutdown_done = &vioch_shutdown_done; - virtio_break_device(vioch->vqueue->vdev); if (!vioch->is_rx && vioch->deferred_tx_wq) /* Cannot be kicked anymore after this...*/ vioch->deferred_tx_wq = NULL; @@ -482,6 +481,12 @@ static int virtio_chan_free(int id, void *p, void *data) struct scmi_chan_info *cinfo = p; struct scmi_vio_channel *vioch = cinfo->transport_info; + /* + * Break device to inhibit further traffic flowing while shutting down + * the channels: doing it later holding vioch->lock creates unsafe + * locking dependency chains as reported by LOCKDEP. + */ + virtio_break_device(vioch->vqueue->vdev); scmi_vio_channel_cleanup_sync(vioch); scmi_free_channel(cinfo, data, id); diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 09716eebe8ac..1e0b016fdc2b 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -394,8 +394,8 @@ static int __init efisubsys_init(void) efi_kobj = kobject_create_and_add("efi", firmware_kobj); if (!efi_kobj) { pr_err("efi: Firmware registration failed.\n"); - destroy_workqueue(efi_rts_wq); - return -ENOMEM; + error = -ENOMEM; + goto err_destroy_wq; } if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE | @@ -443,7 +443,10 @@ err_unregister: err_put: kobject_put(efi_kobj); efi_kobj = NULL; - destroy_workqueue(efi_rts_wq); +err_destroy_wq: + if (efi_rts_wq) + destroy_workqueue(efi_rts_wq); + return error; } @@ -1004,6 +1007,8 @@ 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; ) { rsv = memremap(prsv, sizeof(*rsv), MEMREMAP_WB); + if (!rsv) + return -ENOMEM; index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size); if (index < rsv->size) { rsv->entry[index].base = addr; diff --git a/drivers/firmware/efi/libstub/arm64.c b/drivers/firmware/efi/libstub/arm64.c index ff2d18c42ee7..4501652e11ab 100644 --- a/drivers/firmware/efi/libstub/arm64.c +++ b/drivers/firmware/efi/libstub/arm64.c @@ -19,10 +19,13 @@ static bool system_needs_vamap(void) const u8 *type1_family = efi_get_smbios_string(1, family); /* - * Ampere Altra machines crash in SetTime() if SetVirtualAddressMap() - * has not been called prior. + * Ampere eMAG, Altra, and Altra Max machines crash in SetTime() if + * SetVirtualAddressMap() has not been called prior. */ - if (!type1_family || strcmp(type1_family, "Altra")) + if (!type1_family || ( + strcmp(type1_family, "eMAG") && + strcmp(type1_family, "Altra") && + strcmp(type1_family, "Altra Max"))) return false; efi_warn("Working around broken SetVirtualAddressMap()\n"); diff --git a/drivers/firmware/efi/memattr.c b/drivers/firmware/efi/memattr.c index 0a9aba5f9cef..f178b2984dfb 100644 --- a/drivers/firmware/efi/memattr.c +++ b/drivers/firmware/efi/memattr.c @@ -33,7 +33,7 @@ int __init efi_memattr_init(void) return -ENOMEM; } - if (tbl->version > 1) { + if (tbl->version > 2) { pr_warn("Unexpected EFI Memory Attributes table version %d\n", tbl->version); goto unmap; diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index 7feee3d9c2bf..1fba4e09cdcf 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c @@ -62,6 +62,7 @@ struct efi_runtime_work efi_rts_work; \ if (!efi_enabled(EFI_RUNTIME_SERVICES)) { \ pr_warn_once("EFI Runtime Services are disabled!\n"); \ + efi_rts_work.status = EFI_DEVICE_ERROR; \ goto exit; \ } \ \ diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index 2652c396c423..33ae94745aef 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -93,14 +93,19 @@ static int coreboot_table_populate(struct device *dev, void *ptr) for (i = 0; i < header->table_entries; i++) { entry = ptr_entry; - device = kzalloc(sizeof(struct device) + entry->size, GFP_KERNEL); + if (entry->size < sizeof(*entry)) { + dev_warn(dev, "coreboot table entry too small!\n"); + return -EINVAL; + } + + device = kzalloc(sizeof(device->dev) + entry->size, GFP_KERNEL); if (!device) return -ENOMEM; device->dev.parent = dev; device->dev.bus = &coreboot_bus_type; device->dev.release = coreboot_device_release; - memcpy(&device->entry, ptr_entry, entry->size); + memcpy(device->raw, ptr_entry, entry->size); switch (device->entry.tag) { case LB_TAG_CBMEM_ENTRY: diff --git a/drivers/firmware/google/coreboot_table.h b/drivers/firmware/google/coreboot_table.h index 37f4d335a606..d814dca33a08 100644 --- a/drivers/firmware/google/coreboot_table.h +++ b/drivers/firmware/google/coreboot_table.h @@ -79,6 +79,7 @@ struct coreboot_device { struct lb_cbmem_ref cbmem_ref; struct lb_cbmem_entry cbmem_entry; struct lb_framebuffer framebuffer; + DECLARE_FLEX_ARRAY(u8, raw); }; }; diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index 4e2575dfeb90..871bedf533a8 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -361,9 +361,10 @@ static efi_status_t gsmi_get_variable(efi_char16_t *name, memcpy(data, gsmi_dev.data_buf->start, *data_size); /* All variables are have the following attributes */ - *attr = EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS; + if (attr) + *attr = EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; } spin_unlock_irqrestore(&gsmi_dev.lock, flags); diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c index e7bcfca4159f..29619f49873a 100644 --- a/drivers/firmware/psci/psci.c +++ b/drivers/firmware/psci/psci.c @@ -108,9 +108,10 @@ bool psci_power_state_is_valid(u32 state) return !(state & ~valid_mask); } -static unsigned long __invoke_psci_fn_hvc(unsigned long function_id, - unsigned long arg0, unsigned long arg1, - unsigned long arg2) +static __always_inline unsigned long +__invoke_psci_fn_hvc(unsigned long function_id, + unsigned long arg0, unsigned long arg1, + unsigned long arg2) { struct arm_smccc_res res; @@ -118,9 +119,10 @@ static unsigned long __invoke_psci_fn_hvc(unsigned long function_id, return res.a0; } -static unsigned long __invoke_psci_fn_smc(unsigned long function_id, - unsigned long arg0, unsigned long arg1, - unsigned long arg2) +static __always_inline unsigned long +__invoke_psci_fn_smc(unsigned long function_id, + unsigned long arg0, unsigned long arg1, + unsigned long arg2) { struct arm_smccc_res res; @@ -128,7 +130,7 @@ static unsigned long __invoke_psci_fn_smc(unsigned long function_id, return res.a0; } -static int psci_to_linux_errno(int errno) +static __always_inline int psci_to_linux_errno(int errno) { switch (errno) { case PSCI_RET_SUCCESS: @@ -169,7 +171,8 @@ int psci_set_osi_mode(bool enable) return psci_to_linux_errno(err); } -static int __psci_cpu_suspend(u32 fn, u32 state, unsigned long entry_point) +static __always_inline int +__psci_cpu_suspend(u32 fn, u32 state, unsigned long entry_point) { int err; @@ -177,13 +180,15 @@ static int __psci_cpu_suspend(u32 fn, u32 state, unsigned long entry_point) return psci_to_linux_errno(err); } -static int psci_0_1_cpu_suspend(u32 state, unsigned long entry_point) +static __always_inline int +psci_0_1_cpu_suspend(u32 state, unsigned long entry_point) { return __psci_cpu_suspend(psci_0_1_function_ids.cpu_suspend, state, entry_point); } -static int psci_0_2_cpu_suspend(u32 state, unsigned long entry_point) +static __always_inline int +psci_0_2_cpu_suspend(u32 state, unsigned long entry_point) { return __psci_cpu_suspend(PSCI_FN_NATIVE(0_2, CPU_SUSPEND), state, entry_point); @@ -440,6 +445,9 @@ static const struct file_operations psci_debugfs_ops = { static int __init psci_debugfs_init(void) { + if (!invoke_psci_fn || !psci_ops.get_version) + return 0; + return PTR_ERR_OR_ZERO(debugfs_create_file("psci", 0444, NULL, NULL, &psci_debugfs_ops)); } @@ -447,10 +455,12 @@ late_initcall(psci_debugfs_init) #endif #ifdef CONFIG_CPU_IDLE -static int psci_suspend_finisher(unsigned long state) +static noinstr int psci_suspend_finisher(unsigned long state) { u32 power_state = state; - phys_addr_t pa_cpu_resume = __pa_symbol(cpu_resume); + phys_addr_t pa_cpu_resume; + + pa_cpu_resume = __pa_symbol_nodebug((unsigned long)cpu_resume); return psci_ops.cpu_suspend(power_state, pa_cpu_resume); } @@ -462,11 +472,22 @@ int psci_cpu_suspend_enter(u32 state) if (!psci_power_state_loses_context(state)) { struct arm_cpuidle_irq_context context; + ct_cpuidle_enter(); arm_cpuidle_save_irq_context(&context); ret = psci_ops.cpu_suspend(state, 0); arm_cpuidle_restore_irq_context(&context); + ct_cpuidle_exit(); } else { + /* + * ARM64 cpu_suspend() wants to do ct_cpuidle_*() itself. + */ + if (!IS_ENABLED(CONFIG_ARM64)) + ct_cpuidle_enter(); + ret = cpu_suspend(state, psci_suspend_finisher); + + if (!IS_ENABLED(CONFIG_ARM64)) + ct_cpuidle_exit(); } return ret; diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c index 79d48852825e..03f1bd81c434 100644 --- a/drivers/fpga/intel-m10-bmc-sec-update.c +++ b/drivers/fpga/intel-m10-bmc-sec-update.c @@ -574,20 +574,27 @@ static int m10bmc_sec_probe(struct platform_device *pdev) len = scnprintf(buf, SEC_UPDATE_LEN_MAX, "secure-update%d", sec->fw_name_id); sec->fw_name = kmemdup_nul(buf, len, GFP_KERNEL); - if (!sec->fw_name) - return -ENOMEM; + if (!sec->fw_name) { + ret = -ENOMEM; + goto fw_name_fail; + } fwl = firmware_upload_register(THIS_MODULE, sec->dev, sec->fw_name, &m10bmc_ops, sec); if (IS_ERR(fwl)) { dev_err(sec->dev, "Firmware Upload driver failed to start\n"); - kfree(sec->fw_name); - xa_erase(&fw_upload_xa, sec->fw_name_id); - return PTR_ERR(fwl); + ret = PTR_ERR(fwl); + goto fw_uploader_fail; } sec->fwl = fwl; return 0; + +fw_uploader_fail: + kfree(sec->fw_name); +fw_name_fail: + xa_erase(&fw_upload_xa, sec->fw_name_id); + return ret; } static int m10bmc_sec_remove(struct platform_device *pdev) diff --git a/drivers/fpga/stratix10-soc.c b/drivers/fpga/stratix10-soc.c index 357cea58ec98..f7f01982a512 100644 --- a/drivers/fpga/stratix10-soc.c +++ b/drivers/fpga/stratix10-soc.c @@ -213,9 +213,9 @@ static int s10_ops_write_init(struct fpga_manager *mgr, /* Allocate buffers from the service layer's pool. */ for (i = 0; i < NUM_SVC_BUFS; i++) { kbuf = stratix10_svc_allocate_memory(priv->chan, SVC_BUF_SIZE); - if (!kbuf) { + if (IS_ERR(kbuf)) { s10_free_buffers(mgr); - ret = -ENOMEM; + ret = PTR_ERR(kbuf); goto init_done; } diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ec7cfd4f52b1..c85726a6831f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -354,16 +354,6 @@ config GPIO_IMX_SCU def_bool y depends on IMX_SCU -config GPIO_IOP - tristate "Intel IOP GPIO" - depends on ARCH_IOP32X || COMPILE_TEST - select GPIO_GENERIC - help - Say yes here to support the GPIO functionality of a number of Intel - IOP32X or IOP33X series of chips. - - If unsure, say N. - config GPIO_IXP4XX bool "Intel IXP4xx GPIO" depends on ARCH_IXP4XX @@ -1438,13 +1428,6 @@ config GPIO_TWL6040 Say yes here to access the GPO signals of twl6040 audio chip from Texas Instruments. -config GPIO_UCB1400 - tristate "Philips UCB1400 GPIO" - depends on UCB1400_CORE - help - This enables support for the Philips UCB1400 GPIO pins. - The UCB1400 is an AC97 audio codec. - config GPIO_WHISKEY_COVE tristate "GPIO support for Whiskey Cove PMIC" depends on (X86 || COMPILE_TEST) && INTEL_SOC_PMIC_BXTWC @@ -1531,6 +1514,7 @@ config GPIO_MLXBF2 tristate "Mellanox BlueField 2 SoC GPIO" depends on (MELLANOX_PLATFORM && ARM64 && ACPI) || (64BIT && COMPILE_TEST) select GPIO_GENERIC + select GPIOLIB_IRQCHIP help Say Y here if you want GPIO support on Mellanox BlueField 2 SoC. diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 010587025fc8..c048ba003367 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -72,7 +72,6 @@ obj-$(CONFIG_GPIO_ICH) += gpio-ich.o obj-$(CONFIG_GPIO_IDIO_16) += gpio-idio-16.o obj-$(CONFIG_GPIO_IDT3243X) += gpio-idt3243x.o obj-$(CONFIG_GPIO_IMX_SCU) += gpio-imx-scu.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 @@ -166,7 +165,6 @@ 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 diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c index 8d722e026e9c..84352a6f4973 100644 --- a/drivers/gpio/gpio-eic-sprd.c +++ b/drivers/gpio/gpio-eic-sprd.c @@ -91,7 +91,6 @@ enum sprd_eic_type { struct sprd_eic { struct gpio_chip chip; - struct irq_chip intc; void __iomem *base[SPRD_EIC_MAX_BANK]; enum sprd_eic_type type; spinlock_t lock; @@ -255,6 +254,8 @@ static void sprd_eic_irq_mask(struct irq_data *data) default: dev_err(chip->parent, "Unsupported EIC type.\n"); } + + gpiochip_disable_irq(chip, offset); } static void sprd_eic_irq_unmask(struct irq_data *data) @@ -263,6 +264,8 @@ static void sprd_eic_irq_unmask(struct irq_data *data) struct sprd_eic *sprd_eic = gpiochip_get_data(chip); u32 offset = irqd_to_hwirq(data); + gpiochip_enable_irq(chip, offset); + switch (sprd_eic->type) { case SPRD_EIC_DEBOUNCE: sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IE, 1); @@ -564,6 +567,15 @@ static void sprd_eic_irq_handler(struct irq_desc *desc) chained_irq_exit(ic, desc); } +static const struct irq_chip sprd_eic_irq = { + .name = "sprd-eic", + .irq_ack = sprd_eic_irq_ack, + .irq_mask = sprd_eic_irq_mask, + .irq_unmask = sprd_eic_irq_unmask, + .irq_set_type = sprd_eic_irq_set_type, + .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; static int sprd_eic_probe(struct platform_device *pdev) { const struct sprd_eic_variant_data *pdata; @@ -626,15 +638,8 @@ static int sprd_eic_probe(struct platform_device *pdev) break; } - sprd_eic->intc.name = dev_name(&pdev->dev); - sprd_eic->intc.irq_ack = sprd_eic_irq_ack; - sprd_eic->intc.irq_mask = sprd_eic_irq_mask; - sprd_eic->intc.irq_unmask = sprd_eic_irq_unmask; - sprd_eic->intc.irq_set_type = sprd_eic_irq_set_type; - sprd_eic->intc.flags = IRQCHIP_SKIP_SET_WAKE; - irq = &sprd_eic->chip.irq; - irq->chip = &sprd_eic->intc; + gpio_irq_chip_set_chip(irq, &sprd_eic_irq); irq->handler = handle_bad_irq; irq->default_type = IRQ_TYPE_NONE; irq->parent_handler = sprd_eic_irq_handler; diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 2e1779709113..6cedf46efec6 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/gpio/driver.h> #include <linux/bitops.h> +#include <linux/seq_file.h> #define EP93XX_GPIO_F_INT_STATUS 0x5c #define EP93XX_GPIO_A_INT_STATUS 0xa0 @@ -40,7 +41,6 @@ #define EP93XX_GPIO_F_IRQ_BASE 80 struct ep93xx_gpio_irq_chip { - struct irq_chip ic; u8 irq_offset; u8 int_unmasked; u8 int_enabled; @@ -148,7 +148,7 @@ static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc) */ struct irq_chip *irqchip = irq_desc_get_chip(desc); unsigned int irq = irq_desc_get_irq(desc); - int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */ + int port_f_idx = (irq & 7) ^ 4; /* {20..23,48..51} -> {0..7} */ int gpio_irq = EP93XX_GPIO_F_IRQ_BASE + port_f_idx; chained_irq_enter(irqchip, desc); @@ -185,6 +185,7 @@ static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) ep93xx_gpio_update_int_params(epg, eic); writeb(port_mask, epg->base + eic->irq_offset + EP93XX_INT_EOI_OFFSET); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } static void ep93xx_gpio_irq_mask(struct irq_data *d) @@ -195,6 +196,7 @@ static void ep93xx_gpio_irq_mask(struct irq_data *d) eic->int_unmasked &= ~BIT(d->irq & 7); ep93xx_gpio_update_int_params(epg, eic); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } static void ep93xx_gpio_irq_unmask(struct irq_data *d) @@ -203,6 +205,7 @@ static void ep93xx_gpio_irq_unmask(struct irq_data *d) struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); struct ep93xx_gpio *epg = gpiochip_get_data(gc); + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); eic->int_unmasked |= BIT(d->irq & 7); ep93xx_gpio_update_int_params(epg, eic); } @@ -320,15 +323,25 @@ static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset, return 0; } -static void ep93xx_init_irq_chip(struct device *dev, struct irq_chip *ic) +static void ep93xx_irq_print_chip(struct irq_data *data, struct seq_file *p) { - ic->irq_ack = ep93xx_gpio_irq_ack; - ic->irq_mask_ack = ep93xx_gpio_irq_mask_ack; - ic->irq_mask = ep93xx_gpio_irq_mask; - ic->irq_unmask = ep93xx_gpio_irq_unmask; - ic->irq_set_type = ep93xx_gpio_irq_type; + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + + seq_printf(p, dev_name(gc->parent)); } +static const struct irq_chip gpio_eic_irq_chip = { + .name = "ep93xx-gpio-eic", + .irq_ack = ep93xx_gpio_irq_ack, + .irq_mask = ep93xx_gpio_irq_mask, + .irq_unmask = ep93xx_gpio_irq_unmask, + .irq_mask_ack = ep93xx_gpio_irq_mask_ack, + .irq_set_type = ep93xx_gpio_irq_type, + .irq_print_chip = ep93xx_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, struct platform_device *pdev, struct ep93xx_gpio *epg, @@ -350,8 +363,6 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, girq = &gc->irq; if (bank->has_irq || bank->has_hierarchical_irq) { - struct irq_chip *ic; - gc->set_config = ep93xx_gpio_set_config; egc->eic = devm_kcalloc(dev, 1, sizeof(*egc->eic), @@ -359,12 +370,7 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, if (!egc->eic) return -ENOMEM; egc->eic->irq_offset = bank->irq; - ic = &egc->eic->ic; - ic->name = devm_kasprintf(dev, GFP_KERNEL, "gpio-irq-%s", bank->label); - if (!ic->name) - return -ENOMEM; - ep93xx_init_irq_chip(dev, ic); - girq->chip = ic; + gpio_irq_chip_set_chip(girq, &gpio_eic_irq_chip); } if (bank->has_irq) { diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c deleted file mode 100644 index 7390b5ca09e3..000000000000 --- a/drivers/gpio/gpio-iop.c +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * arch/arm/plat-iop/gpio.c - * GPIO handling for Intel IOP3xx processors. - * - * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> - */ - -#include <linux/err.h> -#include <linux/module.h> -#include <linux/gpio/driver.h> -#include <linux/platform_device.h> - -#define IOP3XX_GPOE 0x0000 -#define IOP3XX_GPID 0x0004 -#define IOP3XX_GPOD 0x0008 - -static int iop3xx_gpio_probe(struct platform_device *pdev) -{ - struct gpio_chip *gc; - void __iomem *base; - int err; - - gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); - if (!gc) - return -ENOMEM; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); - - err = bgpio_init(gc, &pdev->dev, 1, base + IOP3XX_GPID, - base + IOP3XX_GPOD, NULL, NULL, base + IOP3XX_GPOE, 0); - if (err) - return err; - - gc->base = 0; - gc->owner = THIS_MODULE; - gc->label = "gpio-iop"; - - return devm_gpiochip_add_data(&pdev->dev, gc, NULL); -} - -static struct platform_driver iop3xx_gpio_driver = { - .driver = { - .name = "gpio-iop", - }, - .probe = iop3xx_gpio_probe, -}; - -static int __init iop3xx_gpio_init(void) -{ - return platform_driver_register(&iop3xx_gpio_driver); -} -arch_initcall(iop3xx_gpio_init); - -MODULE_DESCRIPTION("GPIO handling for Intel IOP3xx processors"); -MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index d5626c572d24..9d0cec4b82a3 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -18,6 +18,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/spinlock.h> #include <linux/syscore_ops.h> #include <linux/gpio/driver.h> #include <linux/of.h> @@ -159,6 +160,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct mxc_gpio_port *port = gc->private; + unsigned long flags; u32 bit, val; u32 gpio_idx = d->hwirq; int edge; @@ -197,6 +199,8 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) return -EINVAL; } + raw_spin_lock_irqsave(&port->gc.bgpio_lock, flags); + if (GPIO_EDGE_SEL >= 0) { val = readl(port->base + GPIO_EDGE_SEL); if (edge == GPIO_INT_BOTH_EDGES) @@ -217,15 +221,20 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) writel(1 << gpio_idx, port->base + GPIO_ISR); port->pad_type[gpio_idx] = type; - return 0; + raw_spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); + + return port->gc.direction_input(&port->gc, gpio_idx); } static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) { void __iomem *reg = port->base; + unsigned long flags; u32 bit, val; int edge; + raw_spin_lock_irqsave(&port->gc.bgpio_lock, flags); + reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ bit = gpio & 0xf; val = readl(reg); @@ -240,9 +249,12 @@ static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) } else { pr_err("mxc: invalid configuration for GPIO %d: %x\n", gpio, edge); - return; + goto unlock; } writel(val | (edge << (bit << 1)), reg); + +unlock: + raw_spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); } /* handle 32 interrupts in one status register */ diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index a59d61cd44b2..5299e5bb76d6 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -474,6 +474,9 @@ static u8 pcal6534_recalc_addr(struct pca953x_chip *chip, int reg, int off) case PCAL6524_DEBOUNCE: pinctrl = ((reg & PCAL_PINCTRL_MASK) >> 1) + 0x1c; break; + default: + pinctrl = 0; + break; } return pinctrl + addr + (off / BANK_SZ); diff --git a/drivers/gpio/gpio-pmic-eic-sprd.c b/drivers/gpio/gpio-pmic-eic-sprd.c index e518490c4b68..c3e4d90f6b18 100644 --- a/drivers/gpio/gpio-pmic-eic-sprd.c +++ b/drivers/gpio/gpio-pmic-eic-sprd.c @@ -47,7 +47,6 @@ enum { /** * struct sprd_pmic_eic - PMIC EIC controller * @chip: the gpio_chip structure. - * @intc: the irq_chip structure. * @map: the regmap from the parent device. * @offset: the EIC controller's offset address of the PMIC. * @reg: the array to cache the EIC registers. @@ -56,7 +55,6 @@ enum { */ struct sprd_pmic_eic { struct gpio_chip chip; - struct irq_chip intc; struct regmap *map; u32 offset; u8 reg[CACHE_NR_REGS]; @@ -151,15 +149,21 @@ static void sprd_pmic_eic_irq_mask(struct irq_data *data) { struct gpio_chip *chip = irq_data_get_irq_chip_data(data); struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip); + u32 offset = irqd_to_hwirq(data); pmic_eic->reg[REG_IE] = 0; pmic_eic->reg[REG_TRIG] = 0; + + gpiochip_disable_irq(chip, offset); } static void sprd_pmic_eic_irq_unmask(struct irq_data *data) { struct gpio_chip *chip = irq_data_get_irq_chip_data(data); struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip); + u32 offset = irqd_to_hwirq(data); + + gpiochip_enable_irq(chip, offset); pmic_eic->reg[REG_IE] = 1; pmic_eic->reg[REG_TRIG] = 1; @@ -292,6 +296,17 @@ static irqreturn_t sprd_pmic_eic_irq_handler(int irq, void *data) return IRQ_HANDLED; } +static const struct irq_chip pmic_eic_irq_chip = { + .name = "sprd-pmic-eic", + .irq_mask = sprd_pmic_eic_irq_mask, + .irq_unmask = sprd_pmic_eic_irq_unmask, + .irq_set_type = sprd_pmic_eic_irq_set_type, + .irq_bus_lock = sprd_pmic_eic_bus_lock, + .irq_bus_sync_unlock = sprd_pmic_eic_bus_sync_unlock, + .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int sprd_pmic_eic_probe(struct platform_device *pdev) { struct gpio_irq_chip *irq; @@ -338,16 +353,8 @@ static int sprd_pmic_eic_probe(struct platform_device *pdev) pmic_eic->chip.set = sprd_pmic_eic_set; pmic_eic->chip.get = sprd_pmic_eic_get; - pmic_eic->intc.name = dev_name(&pdev->dev); - pmic_eic->intc.irq_mask = sprd_pmic_eic_irq_mask; - pmic_eic->intc.irq_unmask = sprd_pmic_eic_irq_unmask; - pmic_eic->intc.irq_set_type = sprd_pmic_eic_irq_set_type; - pmic_eic->intc.irq_bus_lock = sprd_pmic_eic_bus_lock; - pmic_eic->intc.irq_bus_sync_unlock = sprd_pmic_eic_bus_sync_unlock; - pmic_eic->intc.flags = IRQCHIP_SKIP_SET_WAKE; - irq = &pmic_eic->chip.irq; - irq->chip = &pmic_eic->intc; + gpio_irq_chip_set_chip(irq, &pmic_eic_irq_chip); irq->threaded = true; ret = devm_gpiochip_add_data(&pdev->dev, &pmic_eic->chip, pmic_eic); diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c index 238f3210970c..bc5660f61c57 100644 --- a/drivers/gpio/gpio-sifive.c +++ b/drivers/gpio/gpio-sifive.c @@ -215,6 +215,7 @@ static int sifive_gpio_probe(struct platform_device *pdev) return -ENODEV; } parent = irq_find_host(irq_parent); + of_node_put(irq_parent); if (!parent) { dev_err(dev, "no IRQ parent domain\n"); return -ENODEV; diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index 60514bc5454f..9e3893b19e4f 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -736,7 +736,7 @@ static void gpio_sim_remove_hogs(struct gpio_sim_device *dev) gpiod_remove_hogs(dev->hogs); - for (hog = dev->hogs; !hog->chip_label; hog++) { + for (hog = dev->hogs; hog->chip_label; hog++) { kfree(hog->chip_label); kfree(hog->line_name); } diff --git a/drivers/gpio/gpio-sprd.c b/drivers/gpio/gpio-sprd.c index 9bff63990eee..072b4e653216 100644 --- a/drivers/gpio/gpio-sprd.c +++ b/drivers/gpio/gpio-sprd.c @@ -120,6 +120,7 @@ static void sprd_gpio_irq_mask(struct irq_data *data) u32 offset = irqd_to_hwirq(data); sprd_gpio_update(chip, offset, SPRD_GPIO_IE, 0); + gpiochip_disable_irq(chip, offset); } static void sprd_gpio_irq_ack(struct irq_data *data) @@ -136,6 +137,7 @@ static void sprd_gpio_irq_unmask(struct irq_data *data) u32 offset = irqd_to_hwirq(data); sprd_gpio_update(chip, offset, SPRD_GPIO_IE, 1); + gpiochip_enable_irq(chip, offset); } static int sprd_gpio_irq_set_type(struct irq_data *data, @@ -205,13 +207,14 @@ static void sprd_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(ic, desc); } -static struct irq_chip sprd_gpio_irqchip = { +static const struct irq_chip sprd_gpio_irqchip = { .name = "sprd-gpio", .irq_ack = sprd_gpio_irq_ack, .irq_mask = sprd_gpio_irq_mask, .irq_unmask = sprd_gpio_irq_unmask, .irq_set_type = sprd_gpio_irq_set_type, - .flags = IRQCHIP_SKIP_SET_WAKE, + .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; static int sprd_gpio_probe(struct platform_device *pdev) @@ -245,7 +248,7 @@ static int sprd_gpio_probe(struct platform_device *pdev) sprd_gpio->chip.direction_output = sprd_gpio_direction_output; irq = &sprd_gpio->chip.irq; - irq->chip = &sprd_gpio_irqchip; + gpio_irq_chip_set_chip(irq, &sprd_gpio_irqchip); irq->handler = handle_bad_irq; irq->default_type = IRQ_TYPE_NONE; irq->parent_handler = sprd_gpio_irq_handler; diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c deleted file mode 100644 index 676adf1f198a..000000000000 --- a/drivers/gpio/gpio-ucb1400.c +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Philips UCB1400 GPIO driver - * - * Author: Marek Vasut <marek.vasut@gmail.com> - */ - -#include <linux/module.h> -#include <linux/ucb1400.h> -#include <linux/gpio/driver.h> - -static int ucb1400_gpio_dir_in(struct gpio_chip *gc, unsigned off) -{ - struct ucb1400_gpio *gpio; - gpio = gpiochip_get_data(gc); - ucb1400_gpio_set_direction(gpio->ac97, off, 0); - return 0; -} - -static int ucb1400_gpio_dir_out(struct gpio_chip *gc, unsigned off, int val) -{ - struct ucb1400_gpio *gpio; - gpio = gpiochip_get_data(gc); - ucb1400_gpio_set_direction(gpio->ac97, off, 1); - ucb1400_gpio_set_value(gpio->ac97, off, val); - return 0; -} - -static int ucb1400_gpio_get(struct gpio_chip *gc, unsigned off) -{ - struct ucb1400_gpio *gpio; - - gpio = gpiochip_get_data(gc); - return !!ucb1400_gpio_get_value(gpio->ac97, off); -} - -static void ucb1400_gpio_set(struct gpio_chip *gc, unsigned off, int val) -{ - struct ucb1400_gpio *gpio; - gpio = gpiochip_get_data(gc); - ucb1400_gpio_set_value(gpio->ac97, off, val); -} - -static int ucb1400_gpio_probe(struct platform_device *dev) -{ - struct ucb1400_gpio *ucb = dev_get_platdata(&dev->dev); - int err = 0; - - if (!(ucb && ucb->gpio_offset)) { - err = -EINVAL; - goto err; - } - - platform_set_drvdata(dev, ucb); - - ucb->gc.label = "ucb1400_gpio"; - ucb->gc.base = ucb->gpio_offset; - ucb->gc.ngpio = 10; - ucb->gc.owner = THIS_MODULE; - - ucb->gc.direction_input = ucb1400_gpio_dir_in; - ucb->gc.direction_output = ucb1400_gpio_dir_out; - ucb->gc.get = ucb1400_gpio_get; - ucb->gc.set = ucb1400_gpio_set; - ucb->gc.can_sleep = true; - - err = devm_gpiochip_add_data(&dev->dev, &ucb->gc, ucb); - -err: - return err; - -} - -static struct platform_driver ucb1400_gpio_driver = { - .probe = ucb1400_gpio_probe, - .driver = { - .name = "ucb1400_gpio" - }, -}; - -module_platform_driver(ucb1400_gpio_driver); - -MODULE_DESCRIPTION("Philips UCB1400 GPIO driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:ucb1400_gpio"); diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 9db42f6a2043..9033db00c360 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -30,7 +30,6 @@ struct fsl_gpio_soc_data { struct vf610_gpio_port { struct gpio_chip gc; - struct irq_chip ic; void __iomem *base; void __iomem *gpio_base; const struct fsl_gpio_soc_data *sdata; @@ -207,20 +206,24 @@ static int vf610_gpio_irq_set_type(struct irq_data *d, u32 type) static void vf610_gpio_irq_mask(struct irq_data *d) { - struct vf610_gpio_port *port = - gpiochip_get_data(irq_data_get_irq_chip_data(d)); - void __iomem *pcr_base = port->base + PORT_PCR(d->hwirq); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct vf610_gpio_port *port = gpiochip_get_data(gc); + irq_hw_number_t gpio_num = irqd_to_hwirq(d); + void __iomem *pcr_base = port->base + PORT_PCR(gpio_num); vf610_gpio_writel(0, pcr_base); + gpiochip_disable_irq(gc, gpio_num); } static void vf610_gpio_irq_unmask(struct irq_data *d) { - struct vf610_gpio_port *port = - gpiochip_get_data(irq_data_get_irq_chip_data(d)); - void __iomem *pcr_base = port->base + PORT_PCR(d->hwirq); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct vf610_gpio_port *port = gpiochip_get_data(gc); + irq_hw_number_t gpio_num = irqd_to_hwirq(d); + void __iomem *pcr_base = port->base + PORT_PCR(gpio_num); - vf610_gpio_writel(port->irqc[d->hwirq] << PORT_PCR_IRQC_OFFSET, + gpiochip_enable_irq(gc, gpio_num); + vf610_gpio_writel(port->irqc[gpio_num] << PORT_PCR_IRQC_OFFSET, pcr_base); } @@ -237,6 +240,17 @@ static int vf610_gpio_irq_set_wake(struct irq_data *d, u32 enable) return 0; } +static const struct irq_chip vf610_irqchip = { + .name = "gpio-vf610", + .irq_ack = vf610_gpio_irq_ack, + .irq_mask = vf610_gpio_irq_mask, + .irq_unmask = vf610_gpio_irq_unmask, + .irq_set_type = vf610_gpio_irq_set_type, + .irq_set_wake = vf610_gpio_irq_set_wake, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static void vf610_gpio_disable_clk(void *data) { clk_disable_unprepare(data); @@ -249,7 +263,6 @@ static int vf610_gpio_probe(struct platform_device *pdev) struct vf610_gpio_port *port; struct gpio_chip *gc; struct gpio_irq_chip *girq; - struct irq_chip *ic; int i; int ret; @@ -315,14 +328,6 @@ static int vf610_gpio_probe(struct platform_device *pdev) gc->direction_output = vf610_gpio_direction_output; gc->set = vf610_gpio_set; - ic = &port->ic; - ic->name = "gpio-vf610"; - ic->irq_ack = vf610_gpio_irq_ack; - ic->irq_mask = vf610_gpio_irq_mask; - ic->irq_unmask = vf610_gpio_irq_unmask; - ic->irq_set_type = vf610_gpio_irq_set_type; - ic->irq_set_wake = vf610_gpio_irq_set_wake; - /* Mask all GPIO interrupts */ for (i = 0; i < gc->ngpio; i++) vf610_gpio_writel(0, port->base + PORT_PCR(i)); @@ -331,7 +336,7 @@ static int vf610_gpio_probe(struct platform_device *pdev) vf610_gpio_writel(~0, port->base + PORT_ISFR); girq = &gc->irq; - girq->chip = ic; + gpio_irq_chip_set_chip(girq, &vf610_irqchip); girq->parent_handler = vf610_gpio_irq_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(&pdev->dev, 1, diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index bed0380c5136..34ff048e70d0 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -385,7 +385,7 @@ err: } static bool acpi_gpio_irq_is_wake(struct device *parent, - struct acpi_resource_gpio *agpio) + const struct acpi_resource_gpio *agpio) { unsigned int pin = agpio->pin_table[0]; @@ -778,7 +778,7 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data) lookup->info.pin_config = agpio->pin_config; lookup->info.debounce = agpio->debounce_timeout; lookup->info.gpioint = gpioint; - lookup->info.wake_capable = agpio->wake_capable == ACPI_WAKE_CAPABLE; + lookup->info.wake_capable = acpi_gpio_irq_is_wake(&lookup->info.adev->dev, agpio); /* * Polarity and triggering are only specified for GpioInt @@ -1104,7 +1104,8 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, in dev_dbg(&adev->dev, "IRQ %d already in use\n", irq); } - if (wake_capable) + /* avoid suspend issues with GPIOs when systems are using S3 */ + if (wake_capable && acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) *wake_capable = info.wake_capable; return irq; @@ -1623,6 +1624,31 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = { .ignore_interrupt = "AMDI0030:00@18", }, }, + { + /* + * Spurious wakeups from TP_ATTN# pin + * Found in BIOS 1.7.8 + * https://gitlab.freedesktop.org/drm/amd/-/issues/1722#note_1720627 + */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"), + }, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_wake = "ELAN0415:00@9", + }, + }, + { + /* + * Spurious wakeups from TP_ATTN# pin + * Found in BIOS 1.7.7 + */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "NH5xAx"), + }, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_wake = "SYNA1202:00@16", + }, + }, {} /* Terminating entry */ }; diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h index 9475f99a9694..5a08693b8fb1 100644 --- a/drivers/gpio/gpiolib-acpi.h +++ b/drivers/gpio/gpiolib-acpi.h @@ -14,7 +14,6 @@ #include <linux/gpio/consumer.h> -struct acpi_device; struct device; struct fwnode_handle; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5a66d9616d7c..939c776b9488 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3905,8 +3905,8 @@ static struct gpio_desc *gpiod_find_and_request(struct device *consumer, const char *label, bool platform_lookup_allowed) { + unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT; struct gpio_desc *desc = ERR_PTR(-ENOENT); - unsigned long lookupflags; int ret; if (!IS_ERR_OR_NULL(fwnode)) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 315cbdf61979..9abfb482b615 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -53,7 +53,8 @@ config DRM_DEBUG_MM config DRM_USE_DYNAMIC_DEBUG bool "use dynamic debug to implement drm.debug" - default y + default n + depends on BROKEN depends on DRM depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE depends on JUMP_LABEL diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 6b74df446694..d148a1bd85e6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -195,6 +195,7 @@ extern int amdgpu_emu_mode; extern uint amdgpu_smu_memory_pool_size; extern int amdgpu_smu_pptable_id; extern uint amdgpu_dc_feature_mask; +extern uint amdgpu_freesync_vid_mode; extern uint amdgpu_dc_debug_mask; extern uint amdgpu_dc_visual_confirm; extern uint amdgpu_dm_abm_level; @@ -242,6 +243,7 @@ extern int amdgpu_num_kcq; #define AMDGPU_VCNFW_LOG_SIZE (32 * 1024) extern int amdgpu_vcnfw_log; +extern int amdgpu_sg_display; #define AMDGPU_VM_MAX_NUM_CTX 4096 #define AMDGPU_SG_THRESHOLD (256*1024*1024) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index b15091d8310d..3b5c53712d31 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -2099,7 +2099,7 @@ int amdgpu_amdkfd_map_gtt_bo_to_gart(struct amdgpu_device *adev, struct amdgpu_b } amdgpu_amdkfd_remove_eviction_fence( - bo, bo->kfd_bo->process_info->eviction_fence); + bo, bo->vm_bo->vm->process_info->eviction_fence); amdgpu_bo_unreserve(bo); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 8516c814bc9b..7af3041ccd0e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -61,6 +61,8 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, amdgpu_ctx_put(p->ctx); return -ECANCELED; } + + amdgpu_sync_create(&p->sync); return 0; } @@ -452,18 +454,6 @@ static int amdgpu_syncobj_lookup_and_add(struct amdgpu_cs_parser *p, } r = amdgpu_sync_fence(&p->sync, fence); - if (r) - goto error; - - /* - * When we have an explicit dependency it might be necessary to insert a - * pipeline sync to make sure that all caches etc are flushed and the - * next job actually sees the results from the previous one. - */ - if (fence->context == p->gang_leader->base.entity->fence_context) - r = amdgpu_sync_fence(&p->gang_leader->explicit_sync, fence); - -error: dma_fence_put(fence); return r; } @@ -1188,10 +1178,19 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p) { struct amdgpu_fpriv *fpriv = p->filp->driver_priv; + struct drm_gpu_scheduler *sched; struct amdgpu_bo_list_entry *e; + struct dma_fence *fence; unsigned int i; int r; + r = amdgpu_ctx_wait_prev_fence(p->ctx, p->entities[p->gang_leader_idx]); + if (r) { + if (r != -ERESTARTSYS) + DRM_ERROR("amdgpu_ctx_wait_prev_fence failed.\n"); + return r; + } + list_for_each_entry(e, &p->validated, tv.head) { struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); struct dma_resv *resv = bo->tbo.base.resv; @@ -1211,10 +1210,27 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p) return r; } - r = amdgpu_ctx_wait_prev_fence(p->ctx, p->entities[p->gang_leader_idx]); - if (r && r != -ERESTARTSYS) - DRM_ERROR("amdgpu_ctx_wait_prev_fence failed.\n"); - return r; + sched = p->gang_leader->base.entity->rq->sched; + while ((fence = amdgpu_sync_get_fence(&p->sync))) { + struct drm_sched_fence *s_fence = to_drm_sched_fence(fence); + + /* + * When we have an dependency it might be necessary to insert a + * pipeline sync to make sure that all caches etc are flushed and the + * next job actually sees the results from the previous one + * before we start executing on the same scheduler ring. + */ + if (!s_fence || s_fence->sched != sched) { + dma_fence_put(fence); + continue; + } + + r = amdgpu_sync_fence(&p->gang_leader->explicit_sync, fence); + dma_fence_put(fence); + if (r) + return r; + } + return 0; } static void amdgpu_cs_post_dependencies(struct amdgpu_cs_parser *p) @@ -1254,9 +1270,12 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, continue; fence = &p->jobs[i]->base.s_fence->scheduled; + dma_fence_get(fence); r = drm_sched_job_add_dependency(&leader->base, fence); - if (r) + if (r) { + dma_fence_put(fence); goto error_cleanup; + } } if (p->gang_size > 1) { @@ -1344,6 +1363,7 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser) { unsigned i; + amdgpu_sync_free(&parser->sync); for (i = 0; i < parser->num_post_deps; i++) { drm_syncobj_put(parser->post_deps[i].syncobj); kfree(parser->post_deps[i].chain); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index afe6af9c0138..fbf2f24169eb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -36,6 +36,7 @@ #include <generated/utsrelease.h> #include <linux/pci-p2pdma.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_probe_helper.h> @@ -90,6 +91,8 @@ MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin"); #define AMDGPU_MAX_RETRY_LIMIT 2 #define AMDGPU_RETRY_SRIOV_RESET(r) ((r) == -EBUSY || (r) == -ETIMEDOUT || (r) == -EINVAL) +static const struct drm_driver amdgpu_kms_driver; + const char *amdgpu_asic_name[] = { "TAHITI", "PITCAIRN", @@ -3687,6 +3690,11 @@ int amdgpu_device_init(struct amdgpu_device *adev, if (r) return r; + /* Get rid of things like offb */ + r = drm_aperture_remove_conflicting_pci_framebuffers(adev->pdev, &amdgpu_kms_driver); + if (r) + return r; + /* Enable TMZ based on IP_VERSION */ amdgpu_gmc_tmz_set(adev); @@ -4260,6 +4268,9 @@ exit: } adev->in_suspend = false; + if (adev->enable_mes) + amdgpu_mes_self_test(adev); + if (amdgpu_acpi_smart_shift_update(dev, AMDGPU_SS_DEV_D0)) DRM_WARN("smart shift update failed\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index b4f2d61ea0d5..3fe277bc233f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -23,7 +23,6 @@ */ #include <drm/amdgpu_drm.h> -#include <drm/drm_aperture.h> #include <drm/drm_drv.h> #include <drm/drm_fbdev_generic.h> #include <drm/drm_gem.h> @@ -181,11 +180,13 @@ int amdgpu_mes_kiq; int amdgpu_noretry = -1; int amdgpu_force_asic_type = -1; int amdgpu_tmz = -1; /* auto */ +uint amdgpu_freesync_vid_mode; int amdgpu_reset_method = -1; /* auto */ int amdgpu_num_kcq = -1; int amdgpu_smartshift_bias; int amdgpu_use_xgmi_p2p = 1; int amdgpu_vcnfw_log; +int amdgpu_sg_display = -1; /* auto */ static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work); @@ -880,6 +881,32 @@ MODULE_PARM_DESC(tmz, "Enable TMZ feature (-1 = auto (default), 0 = off, 1 = on) module_param_named(tmz, amdgpu_tmz, int, 0444); /** + * DOC: freesync_video (uint) + * Enable the optimization to adjust front porch timing to achieve seamless + * mode change experience when setting a freesync supported mode for which full + * modeset is not needed. + * + * The Display Core will add a set of modes derived from the base FreeSync + * video mode into the corresponding connector's mode list based on commonly + * used refresh rates and VRR range of the connected display, when users enable + * this feature. From the userspace perspective, they can see a seamless mode + * change experience when the change between different refresh rates under the + * same resolution. Additionally, userspace applications such as Video playback + * can read this modeset list and change the refresh rate based on the video + * frame rate. Finally, the userspace can also derive an appropriate mode for a + * particular refresh rate based on the FreeSync Mode and add it to the + * connector's mode list. + * + * Note: This is an experimental feature. + * + * The default value: 0 (off). + */ +MODULE_PARM_DESC( + freesync_video, + "Enable freesync modesetting optimization feature (0 = off (default), 1 = on)"); +module_param_named(freesync_video, amdgpu_freesync_vid_mode, uint, 0444); + +/** * DOC: reset_method (int) * GPU reset method (-1 = auto (default), 0 = legacy, 1 = mode0, 2 = mode1, 3 = mode2, 4 = baco) */ @@ -906,6 +933,16 @@ MODULE_PARM_DESC(vcnfw_log, "Enable vcnfw log(0 = disable (default value), 1 = e module_param_named(vcnfw_log, amdgpu_vcnfw_log, int, 0444); /** + * DOC: sg_display (int) + * Disable S/G (scatter/gather) display (i.e., display from system memory). + * This option is only relevant on APUs. Set this option to 0 to disable + * S/G display if you experience flickering or other issues under memory + * pressure and report the issue. + */ +MODULE_PARM_DESC(sg_display, "S/G Display (-1 = auto (default), 0 = disable)"); +module_param_named(sg_display, amdgpu_sg_display, int, 0444); + +/** * DOC: smu_pptable_id (int) * Used to override pptable id. id = 0 use VBIOS pptable. * id > 0 use the soft pptable with specicfied id. @@ -2095,11 +2132,6 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, } #endif - /* Get rid of things like offb */ - ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &amdgpu_kms_driver); - if (ret) - return ret; - adev = devm_drm_dev_alloc(&pdev->dev, &amdgpu_kms_driver, typeof(*adev), ddev); if (IS_ERR(adev)) return PTR_ERR(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 00444203220d..faff4a3f96e6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -618,7 +618,13 @@ void amdgpu_fence_driver_sw_fini(struct amdgpu_device *adev) if (!ring || !ring->fence_drv.initialized) continue; - if (!ring->no_scheduler) + /* + * Notice we check for sched.ops since there's some + * override on the meaning of sched.ready by amdgpu. + * The natural check would be sched.ready, which is + * set as drm_sched_init() finishes... + */ + if (ring->sched.ops) drm_sched_fini(&ring->sched); for (j = 0; j <= ring->fence_drv.num_fences_mask; ++j) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index 23692e5d4d13..3380daf42da8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -156,6 +156,9 @@ static bool amdgpu_gfx_is_compute_multipipe_capable(struct amdgpu_device *adev) return amdgpu_compute_multipipe == 1; } + if (adev->ip_versions[GC_HWIP][0] > IP_VERSION(9, 0, 0)) + return true; + /* FIXME: spreading the queues across pipes causes perf regressions * on POLARIS11 compute workloads */ if (adev->asic_type == CHIP_POLARIS11) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index fcb711a11a5b..3f07b1a2ce47 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -497,6 +497,7 @@ void amdgpu_vmid_free_reserved(struct amdgpu_device *adev, !--id_mgr->reserved_use_count) { /* give the reserved ID back to normal round robin */ list_add(&id_mgr->reserved->list, &id_mgr->ids_lru); + id_mgr->reserved = NULL; } vm->reserved_vmid[vmhub] = false; mutex_unlock(&id_mgr->lock); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 9e549923622b..c3d9d75143f4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -161,8 +161,14 @@ void amdgpu_job_free_resources(struct amdgpu_job *job) struct dma_fence *f; unsigned i; - /* use sched fence if available */ - f = job->base.s_fence ? &job->base.s_fence->finished : &job->hw_fence; + /* Check if any fences where initialized */ + if (job->base.s_fence && job->base.s_fence->finished.ops) + f = &job->base.s_fence->finished; + else if (job->hw_fence.ops) + f = &job->hw_fence; + else + f = NULL; + for (i = 0; i < job->num_ibs; ++i) amdgpu_ib_free(ring->adev, &job->ibs[i], f); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 4e684c2afc70..25a68d8888e0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -470,8 +470,9 @@ static bool amdgpu_bo_validate_size(struct amdgpu_device *adev, return true; fail: - DRM_DEBUG("BO size %lu > total memory in domain: %llu\n", size, - man->size); + if (man) + DRM_DEBUG("BO size %lu > total memory in domain: %llu\n", size, + man->size); return false; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index f752c7ae7f60..3989e755a5b4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -295,7 +295,7 @@ struct amdgpu_ring { #define amdgpu_ring_parse_cs(r, p, job, ib) ((r)->funcs->parse_cs((p), (job), (ib))) #define amdgpu_ring_patch_cs_in_place(r, p, job, ib) ((r)->funcs->patch_cs_in_place((p), (job), (ib))) #define amdgpu_ring_test_ring(r) (r)->funcs->test_ring((r)) -#define amdgpu_ring_test_ib(r, t) (r)->funcs->test_ib((r), (t)) +#define amdgpu_ring_test_ib(r, t) ((r)->funcs->test_ib ? (r)->funcs->test_ib((r), (t)) : 0) #define amdgpu_ring_get_rptr(r) (r)->funcs->get_rptr((r)) #define amdgpu_ring_get_wptr(r) (r)->funcs->get_wptr((r)) #define amdgpu_ring_set_wptr(r) (r)->funcs->set_wptr((r)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index bac7976975bd..dcd8c066bc1f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -391,8 +391,10 @@ int amdgpu_sync_push_to_job(struct amdgpu_sync *sync, struct amdgpu_job *job) dma_fence_get(f); r = drm_sched_job_add_dependency(&job->base, f); - if (r) + if (r) { + dma_fence_put(f); return r; + } } return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c index b5f3bba851db..01e42bdd8e4e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c @@ -974,7 +974,7 @@ int amdgpu_vm_ptes_update(struct amdgpu_vm_update_params *params, trace_amdgpu_vm_update_ptes(params, frag_start, upd_end, min(nptes, 32u), dst, incr, upd_flags, - vm->task_info.pid, + vm->task_info.tgid, vm->immediate.fence_context); amdgpu_vm_pte_update_flags(params, to_amdgpu_bo_vm(pt), cursor.level, pe_start, dst, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index faa12146635c..9fa1d814508a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -882,7 +882,7 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev) kfree(rsv); list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, blocks) { - drm_buddy_free_list(&mgr->mm, &rsv->blocks); + drm_buddy_free_list(&mgr->mm, &rsv->allocated); kfree(rsv); } drm_buddy_fini(&mgr->mm); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index a56c6e106d00..66eb102cd88f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -790,8 +790,8 @@ static void gfx_v11_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, * zero here */ WARN_ON(simd != 0); - /* type 2 wave data */ - dst[(*no_fields)++] = 2; + /* type 3 wave data */ + dst[(*no_fields)++] = 3; dst[(*no_fields)++] = wave_read_ind(adev, wave, ixSQ_WAVE_STATUS); dst[(*no_fields)++] = wave_read_ind(adev, wave, ixSQ_WAVE_PC_LO); dst[(*no_fields)++] = wave_read_ind(adev, wave, ixSQ_WAVE_PC_HI); @@ -1287,10 +1287,8 @@ static int gfx_v11_0_sw_init(void *handle) switch (adev->ip_versions[GC_HWIP][0]) { case IP_VERSION(11, 0, 0): - case IP_VERSION(11, 0, 1): case IP_VERSION(11, 0, 2): case IP_VERSION(11, 0, 3): - case IP_VERSION(11, 0, 4): adev->gfx.me.num_me = 1; adev->gfx.me.num_pipe_per_me = 1; adev->gfx.me.num_queue_per_pipe = 1; @@ -1298,6 +1296,15 @@ static int gfx_v11_0_sw_init(void *handle) adev->gfx.mec.num_pipe_per_mec = 4; adev->gfx.mec.num_queue_per_pipe = 4; break; + case IP_VERSION(11, 0, 1): + case IP_VERSION(11, 0, 4): + adev->gfx.me.num_me = 1; + adev->gfx.me.num_pipe_per_me = 1; + adev->gfx.me.num_queue_per_pipe = 1; + adev->gfx.mec.num_mec = 1; + adev->gfx.mec.num_pipe_per_mec = 4; + adev->gfx.mec.num_queue_per_pipe = 4; + break; default: adev->gfx.me.num_me = 1; adev->gfx.me.num_pipe_per_me = 1; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index f202b45c413c..5dde6f82a1ca 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -6877,7 +6877,6 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_gfx = { .emit_gds_switch = gfx_v9_0_ring_emit_gds_switch, .emit_hdp_flush = gfx_v9_0_ring_emit_hdp_flush, .test_ring = gfx_v9_0_ring_test_ring, - .test_ib = gfx_v9_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, .pad_ib = amdgpu_ring_generic_pad_ib, .emit_switch_buffer = gfx_v9_ring_emit_sb, diff --git a/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c b/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c index 95548c512f4f..077c53c6cc08 100644 --- a/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c @@ -35,6 +35,7 @@ MODULE_FIRMWARE("amdgpu/gc_11_0_0_imu.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_1_imu.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_2_imu.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_3_imu.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_0_4_imu.bin"); static int imu_v11_0_init_microcode(struct amdgpu_device *adev) { diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index 970b066b37bb..1c4787000a5f 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -40,6 +40,8 @@ MODULE_FIRMWARE("amdgpu/gc_11_0_2_mes.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_2_mes1.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_3_mes.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_3_mes1.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_0_4_mes.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_0_4_mes1.bin"); static int mes_v11_0_hw_fini(void *handle); static int mes_v11_0_kiq_hw_init(struct amdgpu_device *adev); @@ -196,7 +198,6 @@ static int mes_v11_0_add_hw_queue(struct amdgpu_mes *mes, mes_add_queue_pkt.trap_handler_addr = input->tba_addr; mes_add_queue_pkt.tma_addr = input->tma_addr; mes_add_queue_pkt.is_kfd_process = input->is_kfd_process; - mes_add_queue_pkt.trap_en = 1; /* For KFD, gds_size is re-used for queue size (needed in MES for AQL queues) */ mes_add_queue_pkt.is_aql_queue = input->is_aql_queue; @@ -1343,7 +1344,7 @@ static int mes_v11_0_late_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; /* it's only intended for use in mes_self_test case, not for s0ix and reset */ - if (!amdgpu_in_reset(adev) && !adev->in_s0ix && + if (!amdgpu_in_reset(adev) && !adev->in_s0ix && !adev->in_suspend && (adev->ip_versions[GC_HWIP][0] != IP_VERSION(11, 0, 3))) amdgpu_mes_self_test(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v4_3.c b/drivers/gpu/drm/amd/amdgpu/nbio_v4_3.c index 15eb3658d70e..09fdcd20cb91 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v4_3.c @@ -337,7 +337,13 @@ const struct nbio_hdp_flush_reg nbio_v4_3_hdp_flush_reg = { static void nbio_v4_3_init_registers(struct amdgpu_device *adev) { - return; + if (adev->ip_versions[NBIO_HWIP][0] == IP_VERSION(4, 3, 0)) { + uint32_t data; + + data = RREG32_SOC15(NBIO, 0, regRCC_DEV0_EPF2_STRAP2); + data &= ~RCC_DEV0_EPF2_STRAP2__STRAP_NO_SOFT_RESET_DEV0_F2_MASK; + WREG32_SOC15(NBIO, 0, regRCC_DEV0_EPF2_STRAP2, data); + } } static u32 nbio_v4_3_get_rom_offset(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c index 5562670b7b52..7050238c4c48 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc21.c +++ b/drivers/gpu/drm/amd/amdgpu/soc21.c @@ -640,7 +640,10 @@ static int soc21_common_early_init(void *handle) AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_CGLS | AMD_CG_SUPPORT_REPEATER_FGCG | - AMD_CG_SUPPORT_GFX_MGCG; + AMD_CG_SUPPORT_GFX_MGCG | + AMD_CG_SUPPORT_HDP_SD | + AMD_CG_SUPPORT_ATHUB_MGCG | + AMD_CG_SUPPORT_ATHUB_LS; adev->pg_flags = AMD_PG_SUPPORT_VCN | AMD_PG_SUPPORT_VCN_DPG | AMD_PG_SUPPORT_JPEG; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index ecb4c3abc629..c06ada0844ba 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -200,7 +200,7 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q, queue_input.wptr_addr = (uint64_t)q->properties.write_ptr; if (q->wptr_bo) { - wptr_addr_off = (uint64_t)q->properties.write_ptr - (uint64_t)q->wptr_bo->kfd_bo->va; + wptr_addr_off = (uint64_t)q->properties.write_ptr & (PAGE_SIZE - 1); queue_input.wptr_mc_addr = ((uint64_t)q->wptr_bo->tbo.resource->start << PAGE_SHIFT) + wptr_addr_off; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 814f99888ab1..b94d2c1422ad 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -570,6 +570,15 @@ svm_range_vram_node_new(struct amdgpu_device *adev, struct svm_range *prange, goto reserve_bo_failed; } + if (clear) { + r = amdgpu_bo_sync_wait(bo, AMDGPU_FENCE_OWNER_KFD, false); + if (r) { + pr_debug("failed %d to sync bo\n", r); + amdgpu_bo_unreserve(bo); + goto reserve_bo_failed; + } + } + r = dma_resv_reserve_fences(bo->tbo.base.resv, 1); if (r) { pr_debug("failed %d to reserve bo\n", r); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index bceb1a5b2518..3fdaba56be6f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -801,7 +801,7 @@ static int kfd_build_sysfs_node_entry(struct kfd_topology_device *dev, p2plink->attr.name = "properties"; p2plink->attr.mode = KFD_SYSFS_FILE_MODE; - sysfs_attr_init(&iolink->attr); + sysfs_attr_init(&p2plink->attr); ret = sysfs_create_file(p2plink->kobj, &p2plink->attr); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 50c783e19f5a..9c7b69d377bd 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1184,24 +1184,38 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_ memset(pa_config, 0, sizeof(*pa_config)); - logical_addr_low = min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18; - pt_base = amdgpu_gmc_pd_addr(adev->gart.bo); - - if (adev->apu_flags & AMD_APU_IS_RAVEN2) - /* - * Raven2 has a HW issue that it is unable to use the vram which - * is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. So here is the - * workaround that increase system aperture high address (add 1) - * to get rid of the VM fault and hardware hang. - */ - logical_addr_high = max((adev->gmc.fb_end >> 18) + 0x1, adev->gmc.agp_end >> 18); - else - logical_addr_high = max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18; - agp_base = 0; agp_bot = adev->gmc.agp_start >> 24; agp_top = adev->gmc.agp_end >> 24; + /* AGP aperture is disabled */ + if (agp_bot == agp_top) { + logical_addr_low = adev->gmc.vram_start >> 18; + if (adev->apu_flags & AMD_APU_IS_RAVEN2) + /* + * Raven2 has a HW issue that it is unable to use the vram which + * is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. So here is the + * workaround that increase system aperture high address (add 1) + * to get rid of the VM fault and hardware hang. + */ + logical_addr_high = (adev->gmc.fb_end >> 18) + 0x1; + else + logical_addr_high = adev->gmc.vram_end >> 18; + } else { + logical_addr_low = min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18; + if (adev->apu_flags & AMD_APU_IS_RAVEN2) + /* + * Raven2 has a HW issue that it is unable to use the vram which + * is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. So here is the + * workaround that increase system aperture high address (add 1) + * to get rid of the VM fault and hardware hang. + */ + logical_addr_high = max((adev->gmc.fb_end >> 18) + 0x1, adev->gmc.agp_end >> 18); + else + logical_addr_high = max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18; + } + + pt_base = amdgpu_gmc_pd_addr(adev->gart.bo); page_table_start.high_part = (u32)(adev->gmc.gart_start >> 44) & 0xF; page_table_start.low_part = (u32)(adev->gmc.gart_start >> 12); @@ -1513,6 +1527,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) } break; } + if (init_data.flags.gpu_vm_support && + (amdgpu_sg_display == 0)) + init_data.flags.gpu_vm_support = false; if (init_data.flags.gpu_vm_support) adev->mode_info.gpu_vm_support = true; @@ -1730,10 +1747,6 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) adev->dm.vblank_control_workqueue = NULL; } - for (i = 0; i < adev->dm.display_indexes_num; i++) { - drm_encoder_cleanup(&adev->dm.mst_encoders[i].base); - } - amdgpu_dm_destroy_drm_device(&adev->dm); #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) @@ -4361,6 +4374,10 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) amdgpu_set_panel_orientation(&aconnector->base); } + /* If we didn't find a panel, notify the acpi video detection */ + if (dm->adev->flags & AMD_IS_APU && dm->num_of_edps == 0) + acpi_video_report_nolcd(); + /* Software is initialized. Now we can register interrupt handlers. */ switch (adev->asic_type) { #if defined(CONFIG_DRM_AMD_DC_SI) @@ -4503,6 +4520,17 @@ DEVICE_ATTR_WO(s3_debug); static int dm_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_mode_info *mode_info = &adev->mode_info; + struct atom_context *ctx = mode_info->atom_context; + int index = GetIndexIntoMasterTable(DATA, Object_Header); + u16 data_offset; + + /* if there is no object header, skip DM */ + if (!amdgpu_atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) { + adev->harvest_ip_mask |= AMD_HARVEST_IP_DMU_MASK; + dev_info(adev->dev, "No object header, skipping DM\n"); + return -ENOENT; + } switch (adev->asic_type) { #if defined(CONFIG_DRM_AMD_DC_SI) @@ -5307,8 +5335,6 @@ static void fill_stream_properties_from_drm_display_mode( timing_out->aspect_ratio = get_aspect_ratio(mode_in); - stream->output_color_space = get_output_color_space(timing_out); - stream->out_transfer_func->type = TF_TYPE_PREDEFINED; stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB; if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) { @@ -5319,6 +5345,8 @@ static void fill_stream_properties_from_drm_display_mode( adjust_colour_depth_from_display_info(timing_out, info); } } + + stream->output_color_space = get_output_color_space(timing_out); } static void fill_audio_info(struct audio_info *audio_info, @@ -5831,7 +5859,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, */ DRM_DEBUG_DRIVER("No preferred mode found\n"); } else { - recalculate_timing = is_freesync_video_mode(&mode, aconnector); + recalculate_timing = amdgpu_freesync_vid_mode && + is_freesync_video_mode(&mode, aconnector); if (recalculate_timing) { freesync_mode = get_highest_refresh_rate_mode(aconnector, false); drm_mode_copy(&saved_mode, &mode); @@ -6982,7 +7011,7 @@ static void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connect struct amdgpu_dm_connector *amdgpu_dm_connector = to_amdgpu_dm_connector(connector); - if (!edid) + if (!(amdgpu_freesync_vid_mode && edid)) return; if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) @@ -8846,7 +8875,8 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, * TODO: Refactor this function to allow this check to work * in all conditions. */ - if (dm_new_crtc_state->stream && + if (amdgpu_freesync_vid_mode && + dm_new_crtc_state->stream && is_timing_unchanged_for_freesync(new_crtc_state, old_crtc_state)) goto skip_modeset; @@ -8881,7 +8911,14 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, if (!dm_old_crtc_state->stream) goto skip_modeset; - if (dm_new_crtc_state->stream && + /* Unset freesync video if it was active before */ + if (dm_old_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED) { + dm_new_crtc_state->freesync_config.state = VRR_STATE_INACTIVE; + dm_new_crtc_state->freesync_config.fixed_refresh_in_uhz = 0; + } + + /* Now check if we should set freesync video mode */ + if (amdgpu_freesync_vid_mode && dm_new_crtc_state->stream && is_timing_unchanged_for_freesync(new_crtc_state, old_crtc_state)) { new_crtc_state->mode_changed = false; @@ -8893,7 +8930,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, set_freesync_fixed_config(dm_new_crtc_state); goto skip_modeset; - } else if (aconnector && + } else if (amdgpu_freesync_vid_mode && aconnector && is_freesync_video_mode(&new_crtc_state->mode, aconnector)) { struct drm_display_mode *high_mode; @@ -9497,6 +9534,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, bool lock_and_validation_needed = false; struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state; #if defined(CONFIG_DRM_AMD_DC_DCN) + struct drm_dp_mst_topology_mgr *mgr; + struct drm_dp_mst_topology_state *mst_state; struct dsc_mst_fairness_vars vars[MAX_PIPES]; #endif @@ -9524,8 +9563,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, goto fail; } - if (dm_old_con_state->abm_level != - dm_new_con_state->abm_level) + if (dm_old_con_state->abm_level != dm_new_con_state->abm_level || + dm_old_con_state->scaling != dm_new_con_state->scaling) new_crtc_state->connectors_changed = true; } @@ -9619,7 +9658,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, * `dcn10_can_pipe_disable_cursor`). By now, all modified planes are in * atomic state, so call drm helper to normalize zpos. */ - drm_atomic_normalize_zpos(dev, state); + ret = drm_atomic_normalize_zpos(dev, state); + if (ret) { + drm_dbg(dev, "drm_atomic_normalize_zpos() failed\n"); + goto fail; + } /* Remove exiting planes if they are modified */ for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { @@ -9745,6 +9788,28 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, lock_and_validation_needed = true; } +#if defined(CONFIG_DRM_AMD_DC_DCN) + /* set the slot info for each mst_state based on the link encoding format */ + for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { + struct amdgpu_dm_connector *aconnector; + struct drm_connector *connector; + struct drm_connector_list_iter iter; + u8 link_coding_cap; + + drm_connector_list_iter_begin(dev, &iter); + drm_for_each_connector_iter(connector, &iter) { + if (connector->index == mst_state->mgr->conn_base_id) { + aconnector = to_amdgpu_dm_connector(connector); + link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(aconnector->dc_link); + drm_dp_mst_update_slots(mst_state, link_coding_cap); + + break; + } + } + drm_connector_list_iter_end(&iter); + } +#endif + /** * Streams and planes are reset when there are changes that affect * bandwidth. Anything that affects bandwidth needs to go through diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 6994c9a1ed85..5cff56bb8f56 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -120,23 +120,50 @@ enum dc_edid_status dm_helpers_parse_edid_caps( } static void -fill_dc_mst_payload_table_from_drm(struct drm_dp_mst_topology_state *mst_state, - struct amdgpu_dm_connector *aconnector, +fill_dc_mst_payload_table_from_drm(struct dc_link *link, + bool enable, + struct drm_dp_mst_atomic_payload *target_payload, struct dc_dp_mst_stream_allocation_table *table) { struct dc_dp_mst_stream_allocation_table new_table = { 0 }; struct dc_dp_mst_stream_allocation *sa; - struct drm_dp_mst_atomic_payload *payload; + struct link_mst_stream_allocation_table copy_of_link_table = + link->mst_stream_alloc_table; + + int i; + int current_hw_table_stream_cnt = copy_of_link_table.stream_count; + struct link_mst_stream_allocation *dc_alloc; + + /* TODO: refactor to set link->mst_stream_alloc_table directly if possible.*/ + if (enable) { + dc_alloc = + ©_of_link_table.stream_allocations[current_hw_table_stream_cnt]; + dc_alloc->vcp_id = target_payload->vcpi; + dc_alloc->slot_count = target_payload->time_slots; + } else { + for (i = 0; i < copy_of_link_table.stream_count; i++) { + dc_alloc = + ©_of_link_table.stream_allocations[i]; + + if (dc_alloc->vcp_id == target_payload->vcpi) { + dc_alloc->vcp_id = 0; + dc_alloc->slot_count = 0; + break; + } + } + ASSERT(i != copy_of_link_table.stream_count); + } /* Fill payload info*/ - list_for_each_entry(payload, &mst_state->payloads, next) { - if (payload->delete) - continue; - - sa = &new_table.stream_allocations[new_table.stream_count]; - sa->slot_count = payload->time_slots; - sa->vcp_id = payload->vcpi; - new_table.stream_count++; + for (i = 0; i < MAX_CONTROLLER_NUM; i++) { + dc_alloc = + ©_of_link_table.stream_allocations[i]; + if (dc_alloc->vcp_id > 0 && dc_alloc->slot_count > 0) { + sa = &new_table.stream_allocations[new_table.stream_count]; + sa->slot_count = dc_alloc->slot_count; + sa->vcp_id = dc_alloc->vcp_id; + new_table.stream_count++; + } } /* Overwrite the old table */ @@ -185,7 +212,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( * AUX message. The sequence is slot 1-63 allocated sequence for each * stream. AMD ASIC stream slot allocation should follow the same * sequence. copy DRM MST allocation to dc */ - fill_dc_mst_payload_table_from_drm(mst_state, aconnector, proposed_table); + fill_dc_mst_payload_table_from_drm(stream->link, enable, payload, proposed_table); return true; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 1edf7385f8d8..abdbd4352f6f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -468,7 +468,6 @@ static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder) { drm_encoder_cleanup(encoder); - kfree(encoder); } static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = { @@ -904,11 +903,6 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, if (IS_ERR(mst_state)) return PTR_ERR(mst_state); - mst_state->pbn_div = dm_mst_get_pbn_divider(dc_link); -#if defined(CONFIG_DRM_AMD_DC_DCN) - drm_dp_mst_update_slots(mst_state, dc_link_dp_mst_decide_link_encoding_format(dc_link)); -#endif - /* Set up params */ for (i = 0; i < dc_state->stream_count; i++) { struct dc_dsc_policy dsc_policy = {0}; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c index 471078fc3900..652270a0b498 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c @@ -90,8 +90,8 @@ static const struct out_csc_color_matrix_type output_csc_matrix[] = { { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3, 0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }, { COLOR_SPACE_YCBCR2020_TYPE, - { 0x1000, 0xF149, 0xFEB7, 0x0000, 0x0868, 0x15B2, - 0x01E6, 0x0000, 0xFB88, 0xF478, 0x1000, 0x0000} }, + { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2, + 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} }, { COLOR_SPACE_YCBCR709_BLACK_TYPE, { 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0000, 0x0000, 0x0000, 0x1000} }, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 342e906ae26e..c88f044666fe 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -3995,10 +3995,13 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) struct fixed31_32 avg_time_slots_per_mtp = dc_fixpt_from_int(0); int i; bool mst_mode = (link->type == dc_connection_mst_branch); + /* adjust for drm changes*/ + bool update_drm_mst_state = true; const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); const struct dc_link_settings empty_link_settings = {0}; DC_LOGGER_INIT(link->ctx->logger); + /* deallocate_mst_payload is called before disable link. When mode or * disable/enable monitor, new stream is created which is not in link * stream[] yet. For this, payload is not allocated yet, so de-alloc @@ -4014,7 +4017,7 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) &empty_link_settings, avg_time_slots_per_mtp); - if (mst_mode) { + if (mst_mode || update_drm_mst_state) { /* when link is in mst mode, reply on mst manager to remove * payload */ @@ -4077,11 +4080,18 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) stream->ctx, stream); + if (!update_drm_mst_state) + dm_helpers_dp_mst_send_payload_allocation( + stream->ctx, + stream, + false); + } + + if (update_drm_mst_state) dm_helpers_dp_mst_send_payload_allocation( stream->ctx, stream, false); - } return DC_OK; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index fe2023f18b7d..8f894c1d1d1e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -3626,7 +3626,7 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) (int)hubp->curs_attr.width || pos_cpy.x <= (int)hubp->curs_attr.width + pipe_ctx->plane_state->src_rect.x) { - pos_cpy.x = temp_x + viewport_width; + pos_cpy.x = 2 * viewport_width - temp_x; } } } else { diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c index f9ea1e86707f..79850a68f62a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c @@ -874,8 +874,9 @@ static const struct dc_plane_cap plane_cap = { }, // 6:1 downscaling ratio: 1000/6 = 166.666 + // 4:1 downscaling ratio for ARGB888 to prevent underflow during P010 playback: 1000/4 = 250 .max_downscale_factor = { - .argb8888 = 167, + .argb8888 = 250, .nv12 = 167, .fp16 = 167 }, @@ -1763,7 +1764,7 @@ static bool dcn314_resource_construct( pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; pool->base.pipe_count = pool->base.res_cap->num_timing_generator; pool->base.mpcc_count = pool->base.res_cap->num_timing_generator; - dc->caps.max_downscale_ratio = 600; + dc->caps.max_downscale_ratio = 400; dc->caps.i2c_speed_in_khz = 100; dc->caps.i2c_speed_in_khz_hdcp = 100; dc->caps.max_cursor_size = 256; diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c index dc4649458567..a4e9fd5307c6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c @@ -94,7 +94,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = { .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, .calc_vupdate_position = dcn10_calc_vupdate_position, .apply_idle_power_optimizations = dcn32_apply_idle_power_optimizations, - .does_plane_fit_in_mall = dcn30_does_plane_fit_in_mall, + .does_plane_fit_in_mall = NULL, .set_backlight_level = dcn21_set_backlight_level, .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, .hardware_release = dcn30_hardware_release, diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c index 950669f2c10d..cb7c0c878423 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c @@ -3183,7 +3183,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman } else { v->MIN_DST_Y_NEXT_START[k] = v->VTotal[k] - v->VFrontPorch[k] + v->VTotal[k] - v->VActive[k] - v->VStartup[k]; } - v->MIN_DST_Y_NEXT_START[k] += dml_floor(4.0 * v->TSetup[k] / (double)v->HTotal[k] / v->PixelClock[k], 1.0) / 4.0; + v->MIN_DST_Y_NEXT_START[k] += dml_floor(4.0 * v->TSetup[k] / ((double)v->HTotal[k] / v->PixelClock[k]), 1.0) / 4.0; if (((v->VUpdateOffsetPix[k] + v->VUpdateWidthPix[k] + v->VReadyOffsetPix[k]) / v->HTotal[k]) <= (isInterlaceTiming ? dml_floor((v->VTotal[k] - v->VActive[k] - v->VFrontPorch[k] - v->VStartup[k]) / 2.0, 1.0) : diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c index 5af601cff1a0..b53feeaf5cf1 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c @@ -6257,12 +6257,12 @@ bool dml32_CalculateDETSwathFillLatencyHiding(unsigned int NumberOfActiveSurface double SwathSizePerSurfaceC[DC__NUM_DPP__MAX]; bool NotEnoughDETSwathFillLatencyHiding = false; - /* calculate sum of single swath size for all pipes in bytes*/ + /* calculate sum of single swath size for all pipes in bytes */ for (k = 0; k < NumberOfActiveSurfaces; k++) { - SwathSizePerSurfaceY[k] += SwathHeightY[k] * SwathWidthY[k] * BytePerPixelInDETY[k] * NumOfDPP[k]; + SwathSizePerSurfaceY[k] = SwathHeightY[k] * SwathWidthY[k] * BytePerPixelInDETY[k] * NumOfDPP[k]; if (SwathHeightC[k] != 0) - SwathSizePerSurfaceC[k] += SwathHeightC[k] * SwathWidthC[k] * BytePerPixelInDETC[k] * NumOfDPP[k]; + SwathSizePerSurfaceC[k] = SwathHeightC[k] * SwathWidthC[k] * BytePerPixelInDETC[k] * NumOfDPP[k]; else SwathSizePerSurfaceC[k] = 0; diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c index 4a122925c3ae..92c18bfb98b3 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -532,6 +532,9 @@ enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub, if (dmub->hw_funcs.reset) dmub->hw_funcs.reset(dmub); + /* reset the cache of the last wptr as well now that hw is reset */ + dmub->inbox1_last_wptr = 0; + cw0.offset.quad_part = inst_fb->gpu_addr; cw0.region.base = DMUB_CW0_BASE; cw0.region.top = cw0.region.base + inst_fb->size - 1; @@ -649,6 +652,15 @@ enum dmub_status dmub_srv_hw_reset(struct dmub_srv *dmub) if (dmub->hw_funcs.reset) dmub->hw_funcs.reset(dmub); + /* mailboxes have been reset in hw, so reset the sw state as well */ + dmub->inbox1_last_wptr = 0; + dmub->inbox1_rb.wrpt = 0; + dmub->inbox1_rb.rptr = 0; + dmub->outbox0_rb.wrpt = 0; + dmub->outbox0_rb.rptr = 0; + dmub->outbox1_rb.wrpt = 0; + dmub->outbox1_rb.rptr = 0; + dmub->hw_init = false; return DMUB_STATUS_OK; diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 236657eece47..2f3e239e623d 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -1991,6 +1991,8 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ case IP_VERSION(9, 4, 2): case IP_VERSION(10, 3, 0): case IP_VERSION(11, 0, 0): + case IP_VERSION(11, 0, 1): + case IP_VERSION(11, 0, 2): *states = ATTR_STATE_SUPPORTED; break; default: @@ -2007,14 +2009,16 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ gc_ver == IP_VERSION(10, 3, 0) || gc_ver == IP_VERSION(10, 1, 2) || gc_ver == IP_VERSION(11, 0, 0) || - gc_ver == IP_VERSION(11, 0, 2))) + gc_ver == IP_VERSION(11, 0, 2) || + gc_ver == IP_VERSION(11, 0, 3))) *states = ATTR_STATE_UNSUPPORTED; } else if (DEVICE_ATTR_IS(pp_dpm_dclk)) { if (!(gc_ver == IP_VERSION(10, 3, 1) || gc_ver == IP_VERSION(10, 3, 0) || gc_ver == IP_VERSION(10, 1, 2) || gc_ver == IP_VERSION(11, 0, 0) || - gc_ver == IP_VERSION(11, 0, 2))) + gc_ver == IP_VERSION(11, 0, 2) || + gc_ver == IP_VERSION(11, 0, 3))) *states = ATTR_STATE_UNSUPPORTED; } else if (DEVICE_ATTR_IS(pp_power_profile_mode)) { if (amdgpu_dpm_get_power_profile_mode(adev, NULL) == -EOPNOTSUPP) diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index ca3beb5d8f27..6ab155023592 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1500,6 +1500,20 @@ static int smu_disable_dpms(struct smu_context *smu) } /* + * For SMU 13.0.4/11, PMFW will handle the features disablement properly + * for gpu reset case. Driver involvement is unnecessary. + */ + if (amdgpu_in_reset(adev)) { + switch (adev->ip_versions[MP1_HWIP][0]) { + case IP_VERSION(13, 0, 4): + case IP_VERSION(13, 0, 11): + return 0; + default: + break; + } + } + + /* * For gpu reset, runpm and hibernation through BACO, * BACO feature has to be kept enabled. */ diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h index d6b964cf73bd..4bc7aee4d44f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h @@ -123,7 +123,8 @@ (1 << FEATURE_DS_FCLK_BIT) | \ (1 << FEATURE_DS_LCLK_BIT) | \ (1 << FEATURE_DS_DCFCLK_BIT) | \ - (1 << FEATURE_DS_UCLK_BIT)) + (1 << FEATURE_DS_UCLK_BIT) | \ + (1ULL << FEATURE_DS_VCN_BIT)) //For use with feature control messages typedef enum { @@ -522,9 +523,9 @@ typedef enum { TEMP_HOTSPOT_M, TEMP_MEM, TEMP_VR_GFX, - TEMP_VR_SOC, TEMP_VR_MEM0, TEMP_VR_MEM1, + TEMP_VR_SOC, TEMP_VR_U, TEMP_LIQUID0, TEMP_LIQUID1, diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h index d6b13933a98f..48a3a3952ceb 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h @@ -113,20 +113,21 @@ #define NUM_FEATURES 64 #define ALLOWED_FEATURE_CTRL_DEFAULT 0xFFFFFFFFFFFFFFFFULL -#define ALLOWED_FEATURE_CTRL_SCPM (1 << FEATURE_DPM_GFXCLK_BIT) | \ - (1 << FEATURE_DPM_GFX_POWER_OPTIMIZER_BIT) | \ - (1 << FEATURE_DPM_UCLK_BIT) | \ - (1 << FEATURE_DPM_FCLK_BIT) | \ - (1 << FEATURE_DPM_SOCCLK_BIT) | \ - (1 << FEATURE_DPM_MP0CLK_BIT) | \ - (1 << FEATURE_DPM_LINK_BIT) | \ - (1 << FEATURE_DPM_DCN_BIT) | \ - (1 << FEATURE_DS_GFXCLK_BIT) | \ - (1 << FEATURE_DS_SOCCLK_BIT) | \ - (1 << FEATURE_DS_FCLK_BIT) | \ - (1 << FEATURE_DS_LCLK_BIT) | \ - (1 << FEATURE_DS_DCFCLK_BIT) | \ - (1 << FEATURE_DS_UCLK_BIT) +#define ALLOWED_FEATURE_CTRL_SCPM ((1 << FEATURE_DPM_GFXCLK_BIT) | \ + (1 << FEATURE_DPM_GFX_POWER_OPTIMIZER_BIT) | \ + (1 << FEATURE_DPM_UCLK_BIT) | \ + (1 << FEATURE_DPM_FCLK_BIT) | \ + (1 << FEATURE_DPM_SOCCLK_BIT) | \ + (1 << FEATURE_DPM_MP0CLK_BIT) | \ + (1 << FEATURE_DPM_LINK_BIT) | \ + (1 << FEATURE_DPM_DCN_BIT) | \ + (1 << FEATURE_DS_GFXCLK_BIT) | \ + (1 << FEATURE_DS_SOCCLK_BIT) | \ + (1 << FEATURE_DS_FCLK_BIT) | \ + (1 << FEATURE_DS_LCLK_BIT) | \ + (1 << FEATURE_DS_DCFCLK_BIT) | \ + (1 << FEATURE_DS_UCLK_BIT) | \ + (1ULL << FEATURE_DS_VCN_BIT)) //For use with feature control messages typedef enum { diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index e8c6febb8b64..992163e66f7b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -28,11 +28,11 @@ #define SMU13_DRIVER_IF_VERSION_INV 0xFFFFFFFF #define SMU13_DRIVER_IF_VERSION_YELLOW_CARP 0x04 #define SMU13_DRIVER_IF_VERSION_ALDE 0x08 -#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_0_0 0x34 +#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_0_0 0x37 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_4 0x07 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_5 0x04 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_0_10 0x32 -#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_7 0x35 +#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_7 0x37 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_10 0x1D #define SMU13_MODE1_RESET_WAIT_TIME_IN_MS 500 //500ms diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c index 85e22210963f..5cdc07165480 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -1171,6 +1171,7 @@ static int renoir_get_smu_metrics_data(struct smu_context *smu, int ret = 0; uint32_t apu_percent = 0; uint32_t dgpu_percent = 0; + struct amdgpu_device *adev = smu->adev; ret = smu_cmn_get_metrics_table(smu, @@ -1196,7 +1197,11 @@ static int renoir_get_smu_metrics_data(struct smu_context *smu, *value = metrics->AverageUvdActivity / 100; break; case METRICS_AVERAGE_SOCKETPOWER: - *value = (metrics->CurrentSocketPower << 8) / 1000; + if (((adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 1)) && (adev->pm.fw_version >= 0x40000f)) || + ((adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 0)) && (adev->pm.fw_version >= 0x373200))) + *value = metrics->CurrentSocketPower << 8; + else + *value = (metrics->CurrentSocketPower << 8) / 1000; break; case METRICS_TEMPERATURE_EDGE: *value = (metrics->GfxTemperature / 100) * diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index e54b760b875b..b4373b6568ae 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -1261,7 +1261,8 @@ int smu_v13_0_set_fan_speed_rpm(struct smu_context *smu, uint32_t speed) { struct amdgpu_device *adev = smu->adev; - uint32_t tach_period, crystal_clock_freq; + uint32_t crystal_clock_freq = 2500; + uint32_t tach_period; int ret; if (!speed) @@ -1271,7 +1272,6 @@ int smu_v13_0_set_fan_speed_rpm(struct smu_context *smu, if (ret) return ret; - crystal_clock_freq = amdgpu_asic_get_xclk(adev); tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed); WREG32_SOC15(THM, 0, regCG_TACH_CTRL, REG_SET_FIELD(RREG32_SOC15(THM, 0, regCG_TACH_CTRL), @@ -2298,6 +2298,10 @@ bool smu_v13_0_baco_is_support(struct smu_context *smu) !smu_baco->platform_support) return false; + /* return true if ASIC is in BACO state already */ + if (smu_v13_0_baco_get_state(smu) == SMU_BACO_STATE_ENTER) + return true; + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_BACO_BIT) && !smu_cmn_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT)) return false; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index 9643b21c636a..508e392547d7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -145,6 +145,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(SetBadMemoryPagesRetiredFlagsPerChannel, PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel, 0), MSG_MAP(AllowGpo, PPSMC_MSG_SetGpoAllow, 0), + MSG_MAP(AllowIHHostInterrupt, PPSMC_MSG_AllowIHHostInterrupt, 0), }; static struct cmn2asic_mapping smu_v13_0_0_clk_map[SMU_CLK_COUNT] = { @@ -213,6 +214,7 @@ static struct cmn2asic_mapping smu_v13_0_0_feature_mask_map[SMU_FEATURE_COUNT] = FEA_MAP(SOC_PCC), [SMU_FEATURE_DPM_VCLK_BIT] = {1, FEATURE_MM_DPM_BIT}, [SMU_FEATURE_DPM_DCLK_BIT] = {1, FEATURE_MM_DPM_BIT}, + [SMU_FEATURE_PPT_BIT] = {1, FEATURE_THROTTLERS_BIT}, }; static struct cmn2asic_mapping smu_v13_0_0_table_map[SMU_TABLE_COUNT] = { @@ -405,6 +407,9 @@ static int smu_v13_0_0_setup_pptable(struct smu_context *smu) struct amdgpu_device *adev = smu->adev; int ret = 0; + if (amdgpu_sriov_vf(smu->adev)) + return 0; + ret = smu_v13_0_0_get_pptable_from_pmfw(smu, &smu_table->power_play_table, &smu_table->power_play_table_size); @@ -1255,6 +1260,9 @@ static int smu_v13_0_0_get_thermal_temperature_range(struct smu_context *smu, table_context->power_play_table; PPTable_t *pptable = smu->smu_table.driver_pptable; + if (amdgpu_sriov_vf(smu->adev)) + return 0; + if (!range) return -EINVAL; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index 5c6c6ad011ca..9e1967d8049e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -124,6 +124,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_7_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(DFCstateControl, PPSMC_MSG_SetExternalClientDfCstateAllow, 0), MSG_MAP(ArmD3, PPSMC_MSG_ArmD3, 0), MSG_MAP(AllowGpo, PPSMC_MSG_SetGpoAllow, 0), + MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 0), }; static struct cmn2asic_mapping smu_v13_0_7_clk_map[SMU_CLK_COUNT] = { @@ -192,6 +193,7 @@ static struct cmn2asic_mapping smu_v13_0_7_feature_mask_map[SMU_FEATURE_COUNT] = FEA_MAP(SOC_PCC), [SMU_FEATURE_DPM_VCLK_BIT] = {1, FEATURE_MM_DPM_BIT}, [SMU_FEATURE_DPM_DCLK_BIT] = {1, FEATURE_MM_DPM_BIT}, + [SMU_FEATURE_PPT_BIT] = {1, FEATURE_THROTTLERS_BIT}, }; static struct cmn2asic_mapping smu_v13_0_7_table_map[SMU_TABLE_COUNT] = { diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index c7443317c747..66a4a41c3fe9 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -714,7 +714,7 @@ static int ast_primary_plane_init(struct ast_private *ast) struct ast_plane *ast_primary_plane = &ast->primary_plane; struct drm_plane *primary_plane = &ast_primary_plane->base; void __iomem *vaddr = ast->vram; - u64 offset = ast->vram_base; + u64 offset = 0; /* with shmem, the primary plane is always at offset 0 */ unsigned long cursor_size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE); unsigned long size = ast->vram_fb_available - cursor_size; int ret; @@ -972,7 +972,7 @@ static int ast_cursor_plane_init(struct ast_private *ast) return -ENOMEM; vaddr = ast->vram + ast->vram_fb_available - size; - offset = ast->vram_base + ast->vram_fb_available - size; + offset = ast->vram_fb_available - size; ret = ast_plane_init(dev, ast_cursor_plane, vaddr, offset, size, 0x01, &ast_cursor_plane_funcs, diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c index a2f0860b20bb..d751820c6da6 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c @@ -193,6 +193,7 @@ static int snd_dw_hdmi_probe(struct platform_device *pdev) struct hdmi_codec_pdata pdata; struct platform_device *platform; + memset(&pdata, 0, sizeof(pdata)); pdata.ops = &dw_hdmi_i2s_ops; pdata.i2s = 1; pdata.max_i2s_channels = 8; diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 51a46689cda7..4ca37261584a 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -3372,6 +3372,9 @@ void drm_dp_remove_payload(struct drm_dp_mst_topology_mgr *mgr, mgr->payload_count--; mgr->next_start_slot -= payload->time_slots; + + if (payload->delete) + drm_dp_mst_put_port_malloc(payload->port); } EXPORT_SYMBOL(drm_dp_remove_payload); @@ -4327,7 +4330,6 @@ int drm_dp_atomic_release_time_slots(struct drm_atomic_state *state, drm_dbg_atomic(mgr->dev, "[MST PORT:%p] TU %d -> 0\n", port, payload->time_slots); if (!payload->delete) { - drm_dp_mst_put_port_malloc(port); payload->pbn = 0; payload->delete = true; topology_state->payload_mask &= ~BIT(payload->vcpi - 1); diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index 11bb59399471..3d1f50f481cf 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -38,6 +38,25 @@ static void drm_block_free(struct drm_buddy *mm, kmem_cache_free(slab_blocks, block); } +static void list_insert_sorted(struct drm_buddy *mm, + struct drm_buddy_block *block) +{ + struct drm_buddy_block *node; + struct list_head *head; + + head = &mm->free_list[drm_buddy_block_order(block)]; + if (list_empty(head)) { + list_add(&block->link, head); + return; + } + + list_for_each_entry(node, head, link) + if (drm_buddy_block_offset(block) < drm_buddy_block_offset(node)) + break; + + __list_add(&block->link, node->link.prev, &node->link); +} + static void mark_allocated(struct drm_buddy_block *block) { block->header &= ~DRM_BUDDY_HEADER_STATE; @@ -52,8 +71,7 @@ static void mark_free(struct drm_buddy *mm, block->header &= ~DRM_BUDDY_HEADER_STATE; block->header |= DRM_BUDDY_FREE; - list_add(&block->link, - &mm->free_list[drm_buddy_block_order(block)]); + list_insert_sorted(mm, block); } static void mark_split(struct drm_buddy_block *block) @@ -387,20 +405,26 @@ err_undo: } static struct drm_buddy_block * -get_maxblock(struct list_head *head) +get_maxblock(struct drm_buddy *mm, unsigned int order) { struct drm_buddy_block *max_block = NULL, *node; + unsigned int i; - max_block = list_first_entry_or_null(head, - struct drm_buddy_block, - link); - if (!max_block) - return NULL; + for (i = order; i <= mm->max_order; ++i) { + if (!list_empty(&mm->free_list[i])) { + node = list_last_entry(&mm->free_list[i], + struct drm_buddy_block, + link); + if (!max_block) { + max_block = node; + continue; + } - list_for_each_entry(node, head, link) { - if (drm_buddy_block_offset(node) > - drm_buddy_block_offset(max_block)) - max_block = node; + if (drm_buddy_block_offset(node) > + drm_buddy_block_offset(max_block)) { + max_block = node; + } + } } return max_block; @@ -412,20 +436,23 @@ alloc_from_freelist(struct drm_buddy *mm, unsigned long flags) { struct drm_buddy_block *block = NULL; - unsigned int i; + unsigned int tmp; int err; - for (i = order; i <= mm->max_order; ++i) { - if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) { - block = get_maxblock(&mm->free_list[i]); - if (block) - break; - } else { - block = list_first_entry_or_null(&mm->free_list[i], - struct drm_buddy_block, - link); - if (block) - break; + if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) { + block = get_maxblock(mm, order); + if (block) + /* Store the obtained block order */ + tmp = drm_buddy_block_order(block); + } else { + for (tmp = order; tmp <= mm->max_order; ++tmp) { + if (!list_empty(&mm->free_list[tmp])) { + block = list_last_entry(&mm->free_list[tmp], + struct drm_buddy_block, + link); + if (block) + break; + } } } @@ -434,18 +461,18 @@ alloc_from_freelist(struct drm_buddy *mm, BUG_ON(!drm_buddy_block_is_free(block)); - while (i != order) { + while (tmp != order) { err = split_block(mm, block); if (unlikely(err)) goto err_undo; block = block->right; - i--; + tmp--; } return block; err_undo: - if (i != order) + if (tmp != order) __drm_buddy_free(mm, block); return ERR_PTR(err); } diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index fd67efe37c63..056ab9d5f313 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -233,21 +233,17 @@ void drm_client_dev_restore(struct drm_device *dev) static void drm_client_buffer_delete(struct drm_client_buffer *buffer) { - struct drm_device *dev = buffer->client->dev; - if (buffer->gem) { drm_gem_vunmap_unlocked(buffer->gem, &buffer->map); drm_gem_object_put(buffer->gem); } - if (buffer->handle) - drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file); - kfree(buffer); } static struct drm_client_buffer * -drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format) +drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, + u32 format, u32 *handle) { const struct drm_format_info *info = drm_format_info(format); struct drm_mode_create_dumb dumb_args = { }; @@ -269,16 +265,15 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u if (ret) goto err_delete; - buffer->handle = dumb_args.handle; - buffer->pitch = dumb_args.pitch; - obj = drm_gem_object_lookup(client->file, dumb_args.handle); if (!obj) { ret = -ENOENT; goto err_delete; } + buffer->pitch = dumb_args.pitch; buffer->gem = obj; + *handle = dumb_args.handle; return buffer; @@ -365,7 +360,8 @@ static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer) } static int drm_client_buffer_addfb(struct drm_client_buffer *buffer, - u32 width, u32 height, u32 format) + u32 width, u32 height, u32 format, + u32 handle) { struct drm_client_dev *client = buffer->client; struct drm_mode_fb_cmd fb_req = { }; @@ -377,7 +373,7 @@ static int drm_client_buffer_addfb(struct drm_client_buffer *buffer, fb_req.depth = info->depth; fb_req.width = width; fb_req.height = height; - fb_req.handle = buffer->handle; + fb_req.handle = handle; fb_req.pitch = buffer->pitch; ret = drm_mode_addfb(client->dev, &fb_req, client->file); @@ -414,13 +410,24 @@ struct drm_client_buffer * drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format) { struct drm_client_buffer *buffer; + u32 handle; int ret; - buffer = drm_client_buffer_create(client, width, height, format); + buffer = drm_client_buffer_create(client, width, height, format, + &handle); if (IS_ERR(buffer)) return buffer; - ret = drm_client_buffer_addfb(buffer, width, height, format); + ret = drm_client_buffer_addfb(buffer, width, height, format, handle); + + /* + * The handle is only needed for creating the framebuffer, destroy it + * again to solve a circular dependency should anybody export the GEM + * object as DMA-buf. The framebuffer and our buffer structure are still + * holding references to the GEM object to prevent its destruction. + */ + drm_mode_destroy_dumb(client->dev, handle, client->file); + if (ret) { drm_client_buffer_delete(buffer); return ERR_PTR(ret); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index b3a731b9170a..0d0c26ebab90 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -30,7 +30,9 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/console.h> +#include <linux/pci.h> #include <linux/sysrq.h> +#include <linux/vga_switcheroo.h> #include <drm/drm_atomic.h> #include <drm/drm_drv.h> @@ -1909,6 +1911,11 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, return ret; strcpy(fb_helper->fb->comm, "[fbcon]"); + + /* Set the fb info for vgaswitcheroo clients. Does nothing otherwise. */ + if (dev_is_pci(dev->dev)) + vga_switcheroo_client_fb_set(to_pci_dev(dev->dev), fb_helper->info); + return 0; } diff --git a/drivers/gpu/drm/drm_fbdev_generic.c b/drivers/gpu/drm/drm_fbdev_generic.c index ab8695669279..593aa3283792 100644 --- a/drivers/gpu/drm/drm_fbdev_generic.c +++ b/drivers/gpu/drm/drm_fbdev_generic.c @@ -171,11 +171,6 @@ static const struct fb_ops drm_fbdev_fb_ops = { .fb_imageblit = drm_fbdev_fb_imageblit, }; -static struct fb_deferred_io drm_fbdev_defio = { - .delay = HZ / 20, - .deferred_io = drm_fb_helper_deferred_io, -}; - /* * This function uses the client API to create a framebuffer backed by a dumb buffer. */ @@ -222,8 +217,14 @@ static int drm_fbdev_fb_probe(struct drm_fb_helper *fb_helper, return -ENOMEM; fbi->flags |= FBINFO_VIRTFB | FBINFO_READS_FAST; - fbi->fbdefio = &drm_fbdev_defio; - fb_deferred_io_init(fbi); + /* Set a default deferred I/O handler */ + fb_helper->fbdefio.delay = HZ / 20; + fb_helper->fbdefio.deferred_io = drm_fb_helper_deferred_io; + + fbi->fbdefio = &fb_helper->fbdefio; + ret = fb_deferred_io_init(fbi); + if (ret) + return ret; } else { /* buffer is mapped for HW framebuffer */ ret = drm_client_buffer_vmap(fb_helper->buffer, &map); diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index 52d8800a8ab8..3659f0465a72 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -304,6 +304,12 @@ static const struct dmi_system_id orientation_data[] = { DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGM"), }, .driver_data = (void *)&lcd1200x1920_rightside_up, + }, { /* Lenovo Ideapad D330-10IGL (HD) */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGL"), + }, + .driver_data = (void *)&lcd800x1280_rightside_up, }, { /* Lenovo Yoga Book X90F / X91F / X91L */ .matches = { /* Non exact match to match all versions */ diff --git a/drivers/gpu/drm/drm_vma_manager.c b/drivers/gpu/drm/drm_vma_manager.c index 7de37f8c68fd..83229a031af0 100644 --- a/drivers/gpu/drm/drm_vma_manager.c +++ b/drivers/gpu/drm/drm_vma_manager.c @@ -240,27 +240,8 @@ void drm_vma_offset_remove(struct drm_vma_offset_manager *mgr, } EXPORT_SYMBOL(drm_vma_offset_remove); -/** - * drm_vma_node_allow - Add open-file to list of allowed users - * @node: Node to modify - * @tag: Tag of file to remove - * - * Add @tag to the list of allowed open-files for this node. If @tag is - * already on this list, the ref-count is incremented. - * - * The list of allowed-users is preserved across drm_vma_offset_add() and - * drm_vma_offset_remove() calls. You may even call it if the node is currently - * not added to any offset-manager. - * - * You must remove all open-files the same number of times as you added them - * before destroying the node. Otherwise, you will leak memory. - * - * This is locked against concurrent access internally. - * - * RETURNS: - * 0 on success, negative error code on internal failure (out-of-mem) - */ -int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag) +static int vma_node_allow(struct drm_vma_offset_node *node, + struct drm_file *tag, bool ref_counted) { struct rb_node **iter; struct rb_node *parent = NULL; @@ -282,7 +263,8 @@ int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag) entry = rb_entry(*iter, struct drm_vma_offset_file, vm_rb); if (tag == entry->vm_tag) { - entry->vm_count++; + if (ref_counted) + entry->vm_count++; goto unlock; } else if (tag > entry->vm_tag) { iter = &(*iter)->rb_right; @@ -307,9 +289,59 @@ unlock: kfree(new); return ret; } + +/** + * drm_vma_node_allow - Add open-file to list of allowed users + * @node: Node to modify + * @tag: Tag of file to remove + * + * Add @tag to the list of allowed open-files for this node. If @tag is + * already on this list, the ref-count is incremented. + * + * The list of allowed-users is preserved across drm_vma_offset_add() and + * drm_vma_offset_remove() calls. You may even call it if the node is currently + * not added to any offset-manager. + * + * You must remove all open-files the same number of times as you added them + * before destroying the node. Otherwise, you will leak memory. + * + * This is locked against concurrent access internally. + * + * RETURNS: + * 0 on success, negative error code on internal failure (out-of-mem) + */ +int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag) +{ + return vma_node_allow(node, tag, true); +} EXPORT_SYMBOL(drm_vma_node_allow); /** + * drm_vma_node_allow_once - Add open-file to list of allowed users + * @node: Node to modify + * @tag: Tag of file to remove + * + * Add @tag to the list of allowed open-files for this node. + * + * The list of allowed-users is preserved across drm_vma_offset_add() and + * drm_vma_offset_remove() calls. You may even call it if the node is currently + * not added to any offset-manager. + * + * This is not ref-counted unlike drm_vma_node_allow() hence drm_vma_node_revoke() + * should only be called once after this. + * + * This is locked against concurrent access internally. + * + * RETURNS: + * 0 on success, negative error code on internal failure (out-of-mem) + */ +int drm_vma_node_allow_once(struct drm_vma_offset_node *node, struct drm_file *tag) +{ + return vma_node_allow(node, tag, false); +} +EXPORT_SYMBOL(drm_vma_node_allow_once); + +/** * drm_vma_node_revoke - Remove open-file from list of allowed users * @node: Node to modify * @tag: Tag of file to remove diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 572a4e3769f3..a491e6c38875 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -2466,6 +2466,22 @@ static enum port dvo_port_to_port(struct drm_i915_private *i915, dvo_port); } +static enum port +dsi_dvo_port_to_port(struct drm_i915_private *i915, u8 dvo_port) +{ + switch (dvo_port) { + case DVO_PORT_MIPIA: + return PORT_A; + case DVO_PORT_MIPIC: + if (DISPLAY_VER(i915) >= 11) + return PORT_B; + else + return PORT_C; + default: + return PORT_NONE; + } +} + static int parse_bdb_230_dp_max_link_rate(const int vbt_max_link_rate) { switch (vbt_max_link_rate) { @@ -3414,19 +3430,16 @@ bool intel_bios_is_dsi_present(struct drm_i915_private *i915, dvo_port = child->dvo_port; - if (dvo_port == DVO_PORT_MIPIA || - (dvo_port == DVO_PORT_MIPIB && DISPLAY_VER(i915) >= 11) || - (dvo_port == DVO_PORT_MIPIC && DISPLAY_VER(i915) < 11)) { - if (port) - *port = dvo_port - DVO_PORT_MIPIA; - return true; - } else if (dvo_port == DVO_PORT_MIPIB || - dvo_port == DVO_PORT_MIPIC || - dvo_port == DVO_PORT_MIPID) { + if (dsi_dvo_port_to_port(i915, dvo_port) == PORT_NONE) { drm_dbg_kms(&i915->drm, "VBT has unsupported DSI port %c\n", port_name(dvo_port - DVO_PORT_MIPIA)); + continue; } + + if (port) + *port = dsi_dvo_port_to_port(i915, dvo_port); + return true; } return false; @@ -3511,7 +3524,7 @@ bool intel_bios_get_dsc_params(struct intel_encoder *encoder, if (!(child->device_type & DEVICE_TYPE_MIPI_OUTPUT)) continue; - if (child->dvo_port - DVO_PORT_MIPIA == encoder->port) { + if (dsi_dvo_port_to_port(i915, child->dvo_port) == encoder->port) { if (!devdata->dsc) return false; diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index b74e36d76013..407a477939e5 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -1319,7 +1319,7 @@ static const struct intel_cdclk_vals adlp_cdclk_table[] = { { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 }, { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 }, { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 }, - { .refclk = 24400, .cdclk = 648000, .divider = 2, .ratio = 54 }, + { .refclk = 24000, .cdclk = 648000, .divider = 2, .ratio = 54 }, { .refclk = 38400, .cdclk = 179200, .divider = 3, .ratio = 14 }, { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 }, diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index fce69fa446d5..2cbc1292ab38 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -41,9 +41,11 @@ #include "i915_drv.h" #include "i915_reg.h" +#include "intel_de.h" #include "intel_display_types.h" #include "intel_dsi.h" #include "intel_dsi_vbt.h" +#include "intel_gmbus_regs.h" #include "vlv_dsi.h" #include "vlv_dsi_regs.h" #include "vlv_sideband.h" @@ -377,6 +379,85 @@ static void icl_exec_gpio(struct intel_connector *connector, drm_dbg_kms(&dev_priv->drm, "Skipping ICL GPIO element execution\n"); } +enum { + MIPI_RESET_1 = 0, + MIPI_AVDD_EN_1, + MIPI_BKLT_EN_1, + MIPI_AVEE_EN_1, + MIPI_VIO_EN_1, + MIPI_RESET_2, + MIPI_AVDD_EN_2, + MIPI_BKLT_EN_2, + MIPI_AVEE_EN_2, + MIPI_VIO_EN_2, +}; + +static void icl_native_gpio_set_value(struct drm_i915_private *dev_priv, + int gpio, bool value) +{ + int index; + + if (drm_WARN_ON(&dev_priv->drm, DISPLAY_VER(dev_priv) == 11 && gpio >= MIPI_RESET_2)) + return; + + switch (gpio) { + case MIPI_RESET_1: + case MIPI_RESET_2: + index = gpio == MIPI_RESET_1 ? HPD_PORT_A : HPD_PORT_B; + + /* + * Disable HPD to set the pin to output, and set output + * value. The HPD pin should not be enabled for DSI anyway, + * assuming the board design and VBT are sane, and the pin isn't + * used by a non-DSI encoder. + * + * The locking protects against concurrent SHOTPLUG_CTL_DDI + * modifications in irq setup and handling. + */ + spin_lock_irq(&dev_priv->irq_lock); + intel_de_rmw(dev_priv, SHOTPLUG_CTL_DDI, + SHOTPLUG_CTL_DDI_HPD_ENABLE(index) | + SHOTPLUG_CTL_DDI_HPD_OUTPUT_DATA(index), + value ? SHOTPLUG_CTL_DDI_HPD_OUTPUT_DATA(index) : 0); + spin_unlock_irq(&dev_priv->irq_lock); + break; + case MIPI_AVDD_EN_1: + case MIPI_AVDD_EN_2: + index = gpio == MIPI_AVDD_EN_1 ? 0 : 1; + + intel_de_rmw(dev_priv, PP_CONTROL(index), PANEL_POWER_ON, + value ? PANEL_POWER_ON : 0); + break; + case MIPI_BKLT_EN_1: + case MIPI_BKLT_EN_2: + index = gpio == MIPI_BKLT_EN_1 ? 0 : 1; + + intel_de_rmw(dev_priv, PP_CONTROL(index), EDP_BLC_ENABLE, + value ? EDP_BLC_ENABLE : 0); + break; + case MIPI_AVEE_EN_1: + case MIPI_AVEE_EN_2: + index = gpio == MIPI_AVEE_EN_1 ? 1 : 2; + + intel_de_rmw(dev_priv, GPIO(dev_priv, index), + GPIO_CLOCK_VAL_OUT, + GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_DIR_OUT | + GPIO_CLOCK_VAL_MASK | (value ? GPIO_CLOCK_VAL_OUT : 0)); + break; + case MIPI_VIO_EN_1: + case MIPI_VIO_EN_2: + index = gpio == MIPI_VIO_EN_1 ? 1 : 2; + + intel_de_rmw(dev_priv, GPIO(dev_priv, index), + GPIO_DATA_VAL_OUT, + GPIO_DATA_DIR_MASK | GPIO_DATA_DIR_OUT | + GPIO_DATA_VAL_MASK | (value ? GPIO_DATA_VAL_OUT : 0)); + break; + default: + MISSING_CASE(gpio); + } +} + static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) { struct drm_device *dev = intel_dsi->base.base.dev; @@ -384,8 +465,7 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) struct intel_connector *connector = intel_dsi->attached_connector; u8 gpio_source, gpio_index = 0, gpio_number; bool value; - - drm_dbg_kms(&dev_priv->drm, "\n"); + bool native = DISPLAY_VER(dev_priv) >= 11; if (connector->panel.vbt.dsi.seq_version >= 3) gpio_index = *data++; @@ -398,10 +478,18 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) else gpio_source = 0; + if (connector->panel.vbt.dsi.seq_version >= 4 && *data & BIT(1)) + native = false; + /* pull up/down */ value = *data++ & 1; - if (DISPLAY_VER(dev_priv) >= 11) + drm_dbg_kms(&dev_priv->drm, "GPIO index %u, number %u, source %u, native %s, set to %s\n", + gpio_index, gpio_number, gpio_source, str_yes_no(native), str_on_off(value)); + + if (native) + icl_native_gpio_set_value(dev_priv, gpio_number, value); + else if (DISPLAY_VER(dev_priv) >= 11) icl_exec_gpio(connector, gpio_source, gpio_index, value); else if (IS_VALLEYVIEW(dev_priv)) vlv_exec_gpio(connector, gpio_source, gpio_number, value); diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 5575d7abdc09..f76c06b7f1d4 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -328,8 +328,20 @@ out_unlock: return ret; } +static int intelfb_dirty(struct drm_fb_helper *helper, struct drm_clip_rect *clip) +{ + if (!(clip->x1 < clip->x2 && clip->y1 < clip->y2)) + return 0; + + if (helper->fb->funcs->dirty) + return helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, clip, 1); + + return 0; +} + static const struct drm_fb_helper_funcs intel_fb_helper_funcs = { .fb_probe = intelfb_create, + .fb_dirty = intelfb_dirty, }; static void intel_fbdev_destroy(struct intel_fbdev *ifbdev) diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 76490cc59d8f..7d07fa3123ec 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -1627,7 +1627,7 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state) u32 offset; int ret; - if (w > max_width || w < min_width || h > max_height) { + if (w > max_width || w < min_width || h > max_height || h < 1) { drm_dbg_kms(&dev_priv->drm, "requested Y/RGB source size %dx%d outside limits (min: %dx1 max: %dx%d)\n", w, h, min_width, max_width, max_height); diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index e0766d1be966..11554645e6ee 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -1587,7 +1587,8 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, skl_check_wm_level(&wm->wm[level], ddb); if (icl_need_wm1_wa(i915, plane_id) && - level == 1 && wm->wm[0].enable) { + level == 1 && !wm->wm[level].enable && + wm->wm[0].enable) { wm->wm[level].blocks = wm->wm[0].blocks; wm->wm[level].lines = wm->wm[0].lines; wm->wm[level].ignore_lines = wm->wm[0].ignore_lines; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index 7f2831efc798..e4b78ab4773b 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -1688,6 +1688,10 @@ void i915_gem_init__contexts(struct drm_i915_private *i915) init_contexts(&i915->gem.contexts); } +/* + * Note that this implicitly consumes the ctx reference, by placing + * the ctx in the context_xa. + */ static void gem_context_register(struct i915_gem_context *ctx, struct drm_i915_file_private *fpriv, u32 id) @@ -1703,10 +1707,6 @@ static void gem_context_register(struct i915_gem_context *ctx, snprintf(ctx->name, sizeof(ctx->name), "%s[%d]", current->comm, pid_nr(ctx->pid)); - /* And finally expose ourselves to userspace via the idr */ - old = xa_store(&fpriv->context_xa, id, ctx, GFP_KERNEL); - WARN_ON(old); - spin_lock(&ctx->client->ctx_lock); list_add_tail_rcu(&ctx->client_link, &ctx->client->ctx_list); spin_unlock(&ctx->client->ctx_lock); @@ -1714,6 +1714,10 @@ static void gem_context_register(struct i915_gem_context *ctx, spin_lock(&i915->gem.contexts.lock); list_add_tail(&ctx->link, &i915->gem.contexts.list); spin_unlock(&i915->gem.contexts.lock); + + /* And finally expose ourselves to userspace via the idr */ + old = xa_store(&fpriv->context_xa, id, ctx, GFP_KERNEL); + WARN_ON(old); } int i915_gem_context_open(struct drm_i915_private *i915, @@ -1857,11 +1861,19 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv, vm = ctx->vm; GEM_BUG_ON(!vm); + /* + * Get a reference for the allocated handle. Once the handle is + * visible in the vm_xa table, userspace could try to close it + * from under our feet, so we need to hold the extra reference + * first. + */ + i915_vm_get(vm); + err = xa_alloc(&file_priv->vm_xa, &id, vm, xa_limit_32b, GFP_KERNEL); - if (err) + if (err) { + i915_vm_put(vm); return err; - - i915_vm_get(vm); + } GEM_BUG_ON(id == 0); /* reserved for invalid/unassigned ppgtt */ args->value = id; @@ -2199,14 +2211,22 @@ finalize_create_context_locked(struct drm_i915_file_private *file_priv, if (IS_ERR(ctx)) return ctx; + /* + * One for the xarray and one for the caller. We need to grab + * the reference *prior* to making the ctx visble to userspace + * in gem_context_register(), as at any point after that + * userspace can try to race us with another thread destroying + * the context under our feet. + */ + i915_gem_context_get(ctx); + gem_context_register(ctx, file_priv, id); old = xa_erase(&file_priv->proto_context_xa, id); GEM_BUG_ON(old != pc); proto_context_close(file_priv->dev_priv, pc); - /* One for the xarray and one for the caller */ - return i915_gem_context_get(ctx); + return ctx; } struct i915_gem_context * diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index da09767fda07..0f2e056c02dd 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -730,37 +730,74 @@ static int eb_reserve(struct i915_execbuffer *eb) bool unpinned; /* - * Attempt to pin all of the buffers into the GTT. - * This is done in 2 phases: + * We have one more buffers that we couldn't bind, which could be due to + * various reasons. To resolve this we have 4 passes, with every next + * level turning the screws tighter: * - * 1. Unbind all objects that do not match the GTT constraints for - * the execbuffer (fenceable, mappable, alignment etc). - * 2. Bind new objects. + * 0. Unbind all objects that do not match the GTT constraints for the + * execbuffer (fenceable, mappable, alignment etc). Bind all new + * objects. This avoids unnecessary unbinding of later objects in order + * to make room for the earlier objects *unless* we need to defragment. * - * This avoid unnecessary unbinding of later objects in order to make - * room for the earlier objects *unless* we need to defragment. + * 1. Reorder the buffers, where objects with the most restrictive + * placement requirements go first (ignoring fixed location buffers for + * now). For example, objects needing the mappable aperture (the first + * 256M of GTT), should go first vs objects that can be placed just + * about anywhere. Repeat the previous pass. * - * Defragmenting is skipped if all objects are pinned at a fixed location. + * 2. Consider buffers that are pinned at a fixed location. Also try to + * evict the entire VM this time, leaving only objects that we were + * unable to lock. Try again to bind the buffers. (still using the new + * buffer order). + * + * 3. We likely have object lock contention for one or more stubborn + * objects in the VM, for which we need to evict to make forward + * progress (perhaps we are fighting the shrinker?). When evicting the + * VM this time around, anything that we can't lock we now track using + * the busy_bo, using the full lock (after dropping the vm->mutex to + * prevent deadlocks), instead of trylock. We then continue to evict the + * VM, this time with the stubborn object locked, which we can now + * hopefully unbind (if still bound in the VM). Repeat until the VM is + * evicted. Finally we should be able bind everything. */ - for (pass = 0; pass <= 2; pass++) { + for (pass = 0; pass <= 3; pass++) { int pin_flags = PIN_USER | PIN_VALIDATE; if (pass == 0) pin_flags |= PIN_NONBLOCK; if (pass >= 1) - unpinned = eb_unbind(eb, pass == 2); + unpinned = eb_unbind(eb, pass >= 2); if (pass == 2) { err = mutex_lock_interruptible(&eb->context->vm->mutex); if (!err) { - err = i915_gem_evict_vm(eb->context->vm, &eb->ww); + err = i915_gem_evict_vm(eb->context->vm, &eb->ww, NULL); mutex_unlock(&eb->context->vm->mutex); } if (err) return err; } + if (pass == 3) { +retry: + err = mutex_lock_interruptible(&eb->context->vm->mutex); + if (!err) { + struct drm_i915_gem_object *busy_bo = NULL; + + err = i915_gem_evict_vm(eb->context->vm, &eb->ww, &busy_bo); + mutex_unlock(&eb->context->vm->mutex); + if (err && busy_bo) { + err = i915_gem_object_lock(busy_bo, &eb->ww); + i915_gem_object_put(busy_bo); + if (!err) + goto retry; + } + } + if (err) + return err; + } + list_for_each_entry(ev, &eb->unbound, bind_link) { err = eb_reserve_vma(eb, ev, pin_flags); if (err) @@ -3446,6 +3483,13 @@ err_request: eb.composite_fence : &eb.requests[0]->fence); + if (unlikely(eb.gem_context->syncobj)) { + drm_syncobj_replace_fence(eb.gem_context->syncobj, + eb.composite_fence ? + eb.composite_fence : + &eb.requests[0]->fence); + } + if (out_fence) { if (err == 0) { fd_install(out_fence_fd, out_fence->file); @@ -3457,13 +3501,6 @@ err_request: } } - if (unlikely(eb.gem_context->syncobj)) { - drm_syncobj_replace_fence(eb.gem_context->syncobj, - eb.composite_fence ? - eb.composite_fence : - &eb.requests[0]->fence); - } - if (!out_fence && eb.composite_fence) dma_fence_put(eb.composite_fence); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c index c29efdef8313..c7c252d4d366 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c @@ -369,7 +369,7 @@ retry: if (vma == ERR_PTR(-ENOSPC)) { ret = mutex_lock_interruptible(&ggtt->vm.mutex); if (!ret) { - ret = i915_gem_evict_vm(&ggtt->vm, &ww); + ret = i915_gem_evict_vm(&ggtt->vm, &ww, NULL); mutex_unlock(&ggtt->vm.mutex); } if (ret) @@ -697,7 +697,7 @@ insert: GEM_BUG_ON(lookup_mmo(obj, mmap_type) != mmo); out: if (file) - drm_vma_node_allow(&mmo->vma_node, file); + drm_vma_node_allow_once(&mmo->vma_node, file); return mmo; err: diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c index 9c759df700ca..937728840428 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -579,7 +579,7 @@ static int shmem_object_init(struct intel_memory_region *mem, mapping_set_gfp_mask(mapping, mask); GEM_BUG_ON(!(mapping_gfp_mask(mapping) & __GFP_RECLAIM)); - i915_gem_object_init(obj, &i915_gem_shmem_ops, &lock_class, 0); + i915_gem_object_init(obj, &i915_gem_shmem_ops, &lock_class, flags); obj->mem_flags |= I915_BO_FLAG_STRUCT_PAGE; obj->write_domain = I915_GEM_DOMAIN_CPU; obj->read_domains = I915_GEM_DOMAIN_CPU; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_tiling.c b/drivers/gpu/drm/i915/gem/i915_gem_tiling.c index fd42b89b7162..bc21b1c2350a 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_tiling.c @@ -305,10 +305,6 @@ i915_gem_object_set_tiling(struct drm_i915_gem_object *obj, spin_unlock(&obj->vma.lock); obj->tiling_and_stride = tiling | stride; - i915_gem_object_unlock(obj); - - /* Force the fence to be reacquired for GTT access */ - i915_gem_object_release_mmap_gtt(obj); /* Try to preallocate memory required to save swizzling on put-pages */ if (i915_gem_object_needs_bit17_swizzle(obj)) { @@ -321,6 +317,11 @@ i915_gem_object_set_tiling(struct drm_i915_gem_object *obj, obj->bit_17 = NULL; } + i915_gem_object_unlock(obj); + + /* Force the fence to be reacquired for GTT access */ + i915_gem_object_release_mmap_gtt(obj); + return 0; } diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c index beaf27e09e8a..977dead10ab5 100644 --- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c @@ -1847,7 +1847,7 @@ static int igt_shrink_thp(void *arg) I915_SHRINK_ACTIVE); i915_vma_unpin(vma); if (err) - goto out_put; + goto out_wf; /* * Now that the pages are *unpinned* shrinking should invoke @@ -1863,19 +1863,19 @@ static int igt_shrink_thp(void *arg) pr_err("unexpected pages mismatch, should_swap=%s\n", str_yes_no(should_swap)); err = -EINVAL; - goto out_put; + goto out_wf; } if (should_swap == (obj->mm.page_sizes.sg || obj->mm.page_sizes.phys)) { pr_err("unexpected residual page-size bits, should_swap=%s\n", str_yes_no(should_swap)); err = -EINVAL; - goto out_put; + goto out_wf; } err = i915_vma_pin(vma, 0, 0, flags); if (err) - goto out_put; + goto out_wf; while (n--) { err = cpu_check(obj, n, 0xdeadbeaf); diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c index e94365b08f1e..2aa63ec521b8 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.c +++ b/drivers/gpu/drm/i915/gt/intel_context.c @@ -528,7 +528,7 @@ retry: return rq; } -struct i915_request *intel_context_find_active_request(struct intel_context *ce) +struct i915_request *intel_context_get_active_request(struct intel_context *ce) { struct intel_context *parent = intel_context_to_parent(ce); struct i915_request *rq, *active = NULL; @@ -552,6 +552,8 @@ struct i915_request *intel_context_find_active_request(struct intel_context *ce) active = rq; } + if (active) + active = i915_request_get_rcu(active); spin_unlock_irqrestore(&parent->guc_state.lock, flags); return active; diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h index fb62b7b8cbcd..0a8d553da3f4 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.h +++ b/drivers/gpu/drm/i915/gt/intel_context.h @@ -268,8 +268,7 @@ int intel_context_prepare_remote_request(struct intel_context *ce, struct i915_request *intel_context_create_request(struct intel_context *ce); -struct i915_request * -intel_context_find_active_request(struct intel_context *ce); +struct i915_request *intel_context_get_active_request(struct intel_context *ce); static inline bool intel_context_is_barrier(const struct intel_context *ce) { diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h index cbc8b857d5f7..7a4504ea35c3 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine.h +++ b/drivers/gpu/drm/i915/gt/intel_engine.h @@ -248,8 +248,8 @@ void intel_engine_dump_active_requests(struct list_head *requests, ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine, ktime_t *now); -struct i915_request * -intel_engine_execlist_find_hung_request(struct intel_engine_cs *engine); +void intel_engine_get_hung_entity(struct intel_engine_cs *engine, + struct intel_context **ce, struct i915_request **rq); u32 intel_engine_context_size(struct intel_gt *gt, u8 class); struct intel_context * diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index c33e0d72d670..d37931e16fd9 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -2094,17 +2094,6 @@ static void print_request_ring(struct drm_printer *m, struct i915_request *rq) } } -static unsigned long list_count(struct list_head *list) -{ - struct list_head *pos; - unsigned long count = 0; - - list_for_each(pos, list) - count++; - - return count; -} - static unsigned long read_ul(void *p, size_t x) { return *(unsigned long *)(p + x); @@ -2196,11 +2185,11 @@ void intel_engine_dump_active_requests(struct list_head *requests, } } -static void engine_dump_active_requests(struct intel_engine_cs *engine, struct drm_printer *m) +static void engine_dump_active_requests(struct intel_engine_cs *engine, + struct drm_printer *m) { + struct intel_context *hung_ce = NULL; struct i915_request *hung_rq = NULL; - struct intel_context *ce; - bool guc; /* * No need for an engine->irq_seqno_barrier() before the seqno reads. @@ -2209,27 +2198,22 @@ static void engine_dump_active_requests(struct intel_engine_cs *engine, struct d * But the intention here is just to report an instantaneous snapshot * so that's fine. */ - lockdep_assert_held(&engine->sched_engine->lock); + intel_engine_get_hung_entity(engine, &hung_ce, &hung_rq); drm_printf(m, "\tRequests:\n"); - guc = intel_uc_uses_guc_submission(&engine->gt->uc); - if (guc) { - ce = intel_engine_get_hung_context(engine); - if (ce) - hung_rq = intel_context_find_active_request(ce); - } else { - hung_rq = intel_engine_execlist_find_hung_request(engine); - } - if (hung_rq) engine_dump_request(hung_rq, m, "\t\thung"); + else if (hung_ce) + drm_printf(m, "\t\tGot hung ce but no hung rq!\n"); - if (guc) + if (intel_uc_uses_guc_submission(&engine->gt->uc)) intel_guc_dump_active_requests(engine, hung_rq, m); else - intel_engine_dump_active_requests(&engine->sched_engine->requests, - hung_rq, m); + intel_execlists_dump_active_requests(engine, hung_rq, m); + + if (hung_rq) + i915_request_put(hung_rq); } void intel_engine_dump(struct intel_engine_cs *engine, @@ -2239,7 +2223,6 @@ void intel_engine_dump(struct intel_engine_cs *engine, struct i915_gpu_error * const error = &engine->i915->gpu_error; struct i915_request *rq; intel_wakeref_t wakeref; - unsigned long flags; ktime_t dummy; if (header) { @@ -2276,13 +2259,8 @@ void intel_engine_dump(struct intel_engine_cs *engine, i915_reset_count(error)); print_properties(engine, m); - spin_lock_irqsave(&engine->sched_engine->lock, flags); engine_dump_active_requests(engine, m); - drm_printf(m, "\tOn hold?: %lu\n", - list_count(&engine->sched_engine->hold)); - spin_unlock_irqrestore(&engine->sched_engine->lock, flags); - drm_printf(m, "\tMMIO base: 0x%08x\n", engine->mmio_base); wakeref = intel_runtime_pm_get_if_in_use(engine->uncore->rpm); if (wakeref) { @@ -2328,8 +2306,7 @@ intel_engine_create_virtual(struct intel_engine_cs **siblings, return siblings[0]->cops->create_virtual(siblings, count, flags); } -struct i915_request * -intel_engine_execlist_find_hung_request(struct intel_engine_cs *engine) +static struct i915_request *engine_execlist_find_hung_request(struct intel_engine_cs *engine) { struct i915_request *request, *active = NULL; @@ -2381,6 +2358,33 @@ intel_engine_execlist_find_hung_request(struct intel_engine_cs *engine) return active; } +void intel_engine_get_hung_entity(struct intel_engine_cs *engine, + struct intel_context **ce, struct i915_request **rq) +{ + unsigned long flags; + + *ce = intel_engine_get_hung_context(engine); + if (*ce) { + intel_engine_clear_hung_context(engine); + + *rq = intel_context_get_active_request(*ce); + return; + } + + /* + * Getting here with GuC enabled means it is a forced error capture + * with no actual hang. So, no need to attempt the execlist search. + */ + if (intel_uc_uses_guc_submission(&engine->gt->uc)) + return; + + spin_lock_irqsave(&engine->sched_engine->lock, flags); + *rq = engine_execlist_find_hung_request(engine); + if (*rq) + *rq = i915_request_get_rcu(*rq); + spin_unlock_irqrestore(&engine->sched_engine->lock, flags); +} + void xehp_enable_ccs_engines(struct intel_engine_cs *engine) { /* diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index 2daffa7c7dfd..21cb5b69d82e 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -4148,6 +4148,33 @@ void intel_execlists_show_requests(struct intel_engine_cs *engine, spin_unlock_irqrestore(&sched_engine->lock, flags); } +static unsigned long list_count(struct list_head *list) +{ + struct list_head *pos; + unsigned long count = 0; + + list_for_each(pos, list) + count++; + + return count; +} + +void intel_execlists_dump_active_requests(struct intel_engine_cs *engine, + struct i915_request *hung_rq, + struct drm_printer *m) +{ + unsigned long flags; + + spin_lock_irqsave(&engine->sched_engine->lock, flags); + + intel_engine_dump_active_requests(&engine->sched_engine->requests, hung_rq, m); + + drm_printf(m, "\tOn hold?: %lu\n", + list_count(&engine->sched_engine->hold)); + + spin_unlock_irqrestore(&engine->sched_engine->lock, flags); +} + #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #include "selftest_execlists.c" #endif diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h index a1aa92c983a5..d2c7d45ea062 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h @@ -32,6 +32,10 @@ void intel_execlists_show_requests(struct intel_engine_cs *engine, int indent), unsigned int max); +void intel_execlists_dump_active_requests(struct intel_engine_cs *engine, + struct i915_request *hung_rq, + struct drm_printer *m); + bool intel_engine_in_execlists_submission_mode(const struct intel_engine_cs *engine); diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 767e329e1cc5..9c18b5f2e789 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -1109,9 +1109,15 @@ static void mmio_invalidate_full(struct intel_gt *gt) continue; if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { + u32 val = BIT(engine->instance); + + if (engine->class == VIDEO_DECODE_CLASS || + engine->class == VIDEO_ENHANCEMENT_CLASS || + engine->class == COMPUTE_CLASS) + val = _MASKED_BIT_ENABLE(val); intel_gt_mcr_multicast_write_fw(gt, xehp_regs[engine->class], - BIT(engine->instance)); + val); } else { rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num); if (!i915_mmio_reg_offset(rb.reg)) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index c3cd92691795..a5454af2a9cf 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -406,10 +406,10 @@ #define GEN9_WM_CHICKEN3 _MMIO(0x5588) #define GEN9_FACTOR_IN_CLR_VAL_HIZ (1 << 9) -#define CHICKEN_RASTER_1 _MMIO(0x6204) +#define CHICKEN_RASTER_1 MCR_REG(0x6204) #define DIS_SF_ROUND_NEAREST_EVEN REG_BIT(8) -#define CHICKEN_RASTER_2 _MMIO(0x6208) +#define CHICKEN_RASTER_2 MCR_REG(0x6208) #define TBIMR_FAST_CLIP REG_BIT(5) #define VFLSKPD MCR_REG(0x62a8) @@ -429,9 +429,10 @@ #define RC_OP_FLUSH_ENABLE (1 << 0) #define HIZ_RAW_STALL_OPT_DISABLE (1 << 2) #define CACHE_MODE_1 _MMIO(0x7004) /* IVB+ */ -#define PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1 << 6) -#define GEN8_4x4_STC_OPTIMIZATION_DISABLE (1 << 6) -#define GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE (1 << 1) +#define MSAA_OPTIMIZATION_REDUC_DISABLE REG_BIT(11) +#define PIXEL_SUBSPAN_COLLECT_OPT_DISABLE REG_BIT(6) +#define GEN8_4x4_STC_OPTIMIZATION_DISABLE REG_BIT(6) +#define GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE REG_BIT(1) #define GEN7_GT_MODE _MMIO(0x7008) #define GEN9_IZ_HASHING_MASK(slice) (0x3 << ((slice) * 2)) @@ -457,6 +458,9 @@ #define GEN8_L3CNTLREG _MMIO(0x7034) #define GEN8_ERRDETBCTRL (1 << 9) +#define PSS_MODE2 _MMIO(0x703c) +#define SCOREBOARD_STALL_FLUSH_CONTROL REG_BIT(5) + #define GEN7_SC_INSTDONE _MMIO(0x7100) #define GEN12_SC_INSTDONE_EXTRA _MMIO(0x7104) #define GEN12_SC_INSTDONE_EXTRA2 _MMIO(0x7108) diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index 7771a19008c6..bbeeb6dde7ae 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -288,39 +288,6 @@ static const u8 dg2_xcs_offsets[] = { END }; -static const u8 mtl_xcs_offsets[] = { - NOP(1), - LRI(13, POSTED), - REG16(0x244), - REG(0x034), - REG(0x030), - REG(0x038), - REG(0x03c), - REG(0x168), - REG(0x140), - REG(0x110), - REG(0x1c0), - REG(0x1c4), - REG(0x1c8), - REG(0x180), - REG16(0x2b4), - NOP(4), - - NOP(1), - LRI(9, POSTED), - REG16(0x3a8), - REG16(0x28c), - REG16(0x288), - REG16(0x284), - REG16(0x280), - REG16(0x27c), - REG16(0x278), - REG16(0x274), - REG16(0x270), - - END -}; - static const u8 gen8_rcs_offsets[] = { NOP(1), LRI(14, POSTED), @@ -739,9 +706,7 @@ static const u8 *reg_offsets(const struct intel_engine_cs *engine) else return gen8_rcs_offsets; } else { - if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 70)) - return mtl_xcs_offsets; - else if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 55)) + if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 55)) return dg2_xcs_offsets; else if (GRAPHICS_VER(engine->i915) >= 12) return gen12_xcs_offsets; diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c index 24736ebee17c..78dc5e493c62 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.c +++ b/drivers/gpu/drm/i915/gt/intel_reset.c @@ -278,6 +278,7 @@ out: static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask) { struct intel_uncore *uncore = gt->uncore; + int loops = 2; int err; /* @@ -285,18 +286,39 @@ static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask) * for fifo space for the write or forcewake the chip for * the read */ - intel_uncore_write_fw(uncore, GEN6_GDRST, hw_domain_mask); + do { + intel_uncore_write_fw(uncore, GEN6_GDRST, hw_domain_mask); - /* Wait for the device to ack the reset requests */ - err = __intel_wait_for_register_fw(uncore, - GEN6_GDRST, hw_domain_mask, 0, - 500, 0, - NULL); + /* + * Wait for the device to ack the reset requests. + * + * On some platforms, e.g. Jasperlake, we see that the + * engine register state is not cleared until shortly after + * GDRST reports completion, causing a failure as we try + * to immediately resume while the internal state is still + * in flux. If we immediately repeat the reset, the second + * reset appears to serialise with the first, and since + * it is a no-op, the registers should retain their reset + * value. However, there is still a concern that upon + * leaving the second reset, the internal engine state + * is still in flux and not ready for resuming. + */ + err = __intel_wait_for_register_fw(uncore, GEN6_GDRST, + hw_domain_mask, 0, + 2000, 0, + NULL); + } while (err == 0 && --loops); if (err) GT_TRACE(gt, "Wait for 0x%08x engines reset failed\n", hw_domain_mask); + /* + * As we have observed that the engine state is still volatile + * after GDRST is acked, impose a small delay to let everything settle. + */ + udelay(50); + return err; } diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 2afb4f80a954..a0740308555d 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -645,7 +645,7 @@ static void icl_ctx_workarounds_init(struct intel_engine_cs *engine, static void dg2_ctx_gt_tuning_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { - wa_masked_en(wal, CHICKEN_RASTER_2, TBIMR_FAST_CLIP); + wa_mcr_masked_en(wal, CHICKEN_RASTER_2, TBIMR_FAST_CLIP); wa_mcr_write_clr_set(wal, XEHP_L3SQCREG5, L3_PWM_TIMER_INIT_VAL_MASK, REG_FIELD_PREP(L3_PWM_TIMER_INIT_VAL_MASK, 0x7f)); wa_mcr_add(wal, @@ -771,11 +771,19 @@ static void dg2_ctx_workarounds_init(struct intel_engine_cs *engine, /* Wa_14014947963:dg2 */ if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_B0, STEP_FOREVER) || - IS_DG2_G11(engine->i915) || IS_DG2_G12(engine->i915)) + IS_DG2_G11(engine->i915) || IS_DG2_G12(engine->i915)) wa_masked_field_set(wal, VF_PREEMPTION, PREEMPTION_VERTEX_COUNT, 0x4000); + /* Wa_18018764978:dg2 */ + if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_C0, STEP_FOREVER) || + IS_DG2_G11(engine->i915) || IS_DG2_G12(engine->i915)) + wa_masked_en(wal, PSS_MODE2, SCOREBOARD_STALL_FLUSH_CONTROL); + /* Wa_15010599737:dg2 */ - wa_masked_en(wal, CHICKEN_RASTER_1, DIS_SF_ROUND_NEAREST_EVEN); + wa_mcr_masked_en(wal, CHICKEN_RASTER_1, DIS_SF_ROUND_NEAREST_EVEN); + + /* Wa_18019271663:dg2 */ + wa_masked_en(wal, CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE); } static void fakewa_disable_nestedbb_mode(struct intel_engine_cs *engine, @@ -1347,6 +1355,13 @@ icl_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) GAMT_CHKN_BIT_REG, GAMT_CHKN_DISABLE_L3_COH_PIPE); + /* + * Wa_1408615072:icl,ehl (vsunit) + * Wa_1407596294:icl,ehl (hsunit) + */ + wa_write_or(wal, UNSLICE_UNIT_LEVEL_CLKGATE, + VSUNIT_CLKGATE_DIS | HSUNIT_CLKGATE_DIS); + /* Wa_1407352427:icl,ehl */ wa_write_or(wal, UNSLICE_UNIT_LEVEL_CLKGATE2, PSDUNIT_CLKGATE_DIS); @@ -2532,13 +2547,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) GEN11_ENABLE_32_PLANE_MODE); /* - * Wa_1408615072:icl,ehl (vsunit) - * Wa_1407596294:icl,ehl (hsunit) - */ - wa_write_or(wal, UNSLICE_UNIT_LEVEL_CLKGATE, - VSUNIT_CLKGATE_DIS | HSUNIT_CLKGATE_DIS); - - /* * Wa_1408767742:icl[a2..forever],ehl[all] * Wa_1605460711:icl[a0..c0] */ diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 0a42f1807f52..c10977cb06b9 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -1702,7 +1702,7 @@ static void __guc_reset_context(struct intel_context *ce, intel_engine_mask_t st goto next_context; guilty = false; - rq = intel_context_find_active_request(ce); + rq = intel_context_get_active_request(ce); if (!rq) { head = ce->ring->tail; goto out_replay; @@ -1715,6 +1715,7 @@ static void __guc_reset_context(struct intel_context *ce, intel_engine_mask_t st head = intel_ring_wrap(ce->ring, rq->head); __i915_request_reset(rq, guilty); + i915_request_put(rq); out_replay: guc_reset_state(ce, head, guilty); next_context: @@ -4817,6 +4818,8 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine) xa_lock_irqsave(&guc->context_lookup, flags); xa_for_each(&guc->context_lookup, index, ce) { + bool found; + if (!kref_get_unless_zero(&ce->ref)) continue; @@ -4833,10 +4836,18 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine) goto next; } + found = false; + spin_lock(&ce->guc_state.lock); list_for_each_entry(rq, &ce->guc_state.requests, sched.link) { if (i915_test_request_state(rq) != I915_REQUEST_ACTIVE) continue; + found = true; + break; + } + spin_unlock(&ce->guc_state.lock); + + if (found) { intel_engine_set_hung_context(engine, ce); /* Can only cope with one hang at a time... */ @@ -4844,6 +4855,7 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine) xa_lock(&guc->context_lookup); goto done; } + next: intel_context_put(ce); xa_lock(&guc->context_lookup); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c index 0c80ba51a4bd..2bcdd192f814 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -545,6 +545,32 @@ static int check_ccs_header(struct intel_gt *gt, return 0; } +static int try_firmware_load(struct intel_uc_fw *uc_fw, const struct firmware **fw) +{ + struct intel_gt *gt = __uc_fw_to_gt(uc_fw); + struct device *dev = gt->i915->drm.dev; + int err; + + err = firmware_request_nowarn(fw, uc_fw->file_selected.path, dev); + + if (err) + return err; + + if ((*fw)->size > INTEL_UC_RSVD_GGTT_PER_FW) { + drm_err(>->i915->drm, + "%s firmware %s: size (%zuKB) exceeds max supported size (%uKB)\n", + intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path, + (*fw)->size / SZ_1K, INTEL_UC_RSVD_GGTT_PER_FW / SZ_1K); + + /* try to find another blob to load */ + release_firmware(*fw); + *fw = NULL; + return -ENOENT; + } + + return 0; +} + /** * intel_uc_fw_fetch - fetch uC firmware * @uc_fw: uC firmware @@ -558,7 +584,6 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw) struct intel_gt *gt = __uc_fw_to_gt(uc_fw); struct drm_i915_private *i915 = gt->i915; struct intel_uc_fw_file file_ideal; - struct device *dev = i915->drm.dev; struct drm_i915_gem_object *obj; const struct firmware *fw = NULL; bool old_ver = false; @@ -574,20 +599,9 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw) __force_fw_fetch_failures(uc_fw, -EINVAL); __force_fw_fetch_failures(uc_fw, -ESTALE); - err = firmware_request_nowarn(&fw, uc_fw->file_selected.path, dev); + err = try_firmware_load(uc_fw, &fw); memcpy(&file_ideal, &uc_fw->file_wanted, sizeof(file_ideal)); - if (!err && fw->size > INTEL_UC_RSVD_GGTT_PER_FW) { - drm_err(&i915->drm, - "%s firmware %s: size (%zuKB) exceeds max supported size (%uKB)\n", - intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path, - fw->size / SZ_1K, INTEL_UC_RSVD_GGTT_PER_FW / SZ_1K); - - /* try to find another blob to load */ - release_firmware(fw); - err = -ENOENT; - } - /* Any error is terminal if overriding. Don't bother searching for older versions */ if (err && intel_uc_fw_is_overridden(uc_fw)) goto fail; @@ -608,7 +622,7 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw) break; } - err = firmware_request_nowarn(&fw, uc_fw->file_selected.path, dev); + err = try_firmware_load(uc_fw, &fw); } if (err) diff --git a/drivers/gpu/drm/i915/gvt/debugfs.c b/drivers/gpu/drm/i915/gvt/debugfs.c index 9f1c209d9251..0616b73175f3 100644 --- a/drivers/gpu/drm/i915/gvt/debugfs.c +++ b/drivers/gpu/drm/i915/gvt/debugfs.c @@ -151,6 +151,22 @@ DEFINE_SIMPLE_ATTRIBUTE(vgpu_scan_nonprivbb_fops, vgpu_scan_nonprivbb_get, vgpu_scan_nonprivbb_set, "0x%llx\n"); +static int vgpu_status_get(void *data, u64 *val) +{ + struct intel_vgpu *vgpu = (struct intel_vgpu *)data; + + *val = 0; + + if (test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) + *val |= (1 << INTEL_VGPU_STATUS_ATTACHED); + if (test_bit(INTEL_VGPU_STATUS_ACTIVE, vgpu->status)) + *val |= (1 << INTEL_VGPU_STATUS_ACTIVE); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(vgpu_status_fops, vgpu_status_get, NULL, "0x%llx\n"); + /** * intel_gvt_debugfs_add_vgpu - register debugfs entries for a vGPU * @vgpu: a vGPU @@ -162,11 +178,12 @@ void intel_gvt_debugfs_add_vgpu(struct intel_vgpu *vgpu) snprintf(name, 16, "vgpu%d", vgpu->id); vgpu->debugfs = debugfs_create_dir(name, vgpu->gvt->debugfs_root); - debugfs_create_bool("active", 0444, vgpu->debugfs, &vgpu->active); debugfs_create_file("mmio_diff", 0444, vgpu->debugfs, vgpu, &vgpu_mmio_diff_fops); debugfs_create_file("scan_nonprivbb", 0644, vgpu->debugfs, vgpu, &vgpu_scan_nonprivbb_fops); + debugfs_create_file("status", 0644, vgpu->debugfs, vgpu, + &vgpu_status_fops); } /** @@ -175,8 +192,13 @@ void intel_gvt_debugfs_add_vgpu(struct intel_vgpu *vgpu) */ void intel_gvt_debugfs_remove_vgpu(struct intel_vgpu *vgpu) { - debugfs_remove_recursive(vgpu->debugfs); - vgpu->debugfs = NULL; + struct intel_gvt *gvt = vgpu->gvt; + struct drm_minor *minor = gvt->gt->i915->drm.primary; + + if (minor->debugfs_root && gvt->debugfs_root) { + debugfs_remove_recursive(vgpu->debugfs); + vgpu->debugfs = NULL; + } } /** @@ -199,6 +221,10 @@ void intel_gvt_debugfs_init(struct intel_gvt *gvt) */ void intel_gvt_debugfs_clean(struct intel_gvt *gvt) { - debugfs_remove_recursive(gvt->debugfs_root); - gvt->debugfs_root = NULL; + struct drm_minor *minor = gvt->gt->i915->drm.primary; + + if (minor->debugfs_root) { + debugfs_remove_recursive(gvt->debugfs_root); + gvt->debugfs_root = NULL; + } } diff --git a/drivers/gpu/drm/i915/gvt/dmabuf.c b/drivers/gpu/drm/i915/gvt/dmabuf.c index 355f1c0e8664..ffe41e9be04f 100644 --- a/drivers/gpu/drm/i915/gvt/dmabuf.c +++ b/drivers/gpu/drm/i915/gvt/dmabuf.c @@ -134,7 +134,8 @@ static void dmabuf_gem_object_free(struct kref *kref) struct list_head *pos; struct intel_vgpu_dmabuf_obj *dmabuf_obj; - if (vgpu && vgpu->active && !list_empty(&vgpu->dmabuf_obj_list_head)) { + if (vgpu && test_bit(INTEL_VGPU_STATUS_ACTIVE, vgpu->status) && + !list_empty(&vgpu->dmabuf_obj_list_head)) { list_for_each(pos, &vgpu->dmabuf_obj_list_head) { dmabuf_obj = list_entry(pos, struct intel_vgpu_dmabuf_obj, list); if (dmabuf_obj == obj) { diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 51e5e8fb505b..4ec85308379a 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -55,7 +55,7 @@ static bool intel_gvt_is_valid_gfn(struct intel_vgpu *vgpu, unsigned long gfn) int idx; bool ret; - if (!vgpu->attached) + if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) return false; idx = srcu_read_lock(&kvm->srcu); @@ -1178,7 +1178,7 @@ static int is_2MB_gtt_possible(struct intel_vgpu *vgpu, if (!HAS_PAGE_SIZES(vgpu->gvt->gt->i915, I915_GTT_PAGE_SIZE_2M)) return 0; - if (!vgpu->attached) + if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) return -EINVAL; pfn = gfn_to_pfn(vgpu->vfio_device.kvm, ops->get_pfn(entry)); if (is_error_noslot_pfn(pfn)) @@ -1209,10 +1209,8 @@ static int split_2MB_gtt_entry(struct intel_vgpu *vgpu, for_each_shadow_entry(sub_spt, &sub_se, sub_index) { ret = intel_gvt_dma_map_guest_page(vgpu, start_gfn + sub_index, PAGE_SIZE, &dma_addr); - if (ret) { - ppgtt_invalidate_spt(spt); - return ret; - } + if (ret) + goto err; sub_se.val64 = se->val64; /* Copy the PAT field from PDE. */ @@ -1231,6 +1229,17 @@ static int split_2MB_gtt_entry(struct intel_vgpu *vgpu, ops->set_pfn(se, sub_spt->shadow_page.mfn); ppgtt_set_shadow_entry(spt, se, index); return 0; +err: + /* Cancel the existing addess mappings of DMA addr. */ + for_each_present_shadow_entry(sub_spt, &sub_se, sub_index) { + gvt_vdbg_mm("invalidate 4K entry\n"); + ppgtt_invalidate_pte(sub_spt, &sub_se); + } + /* Release the new allocated spt. */ + trace_spt_change(sub_spt->vgpu->id, "release", sub_spt, + sub_spt->guest_page.gfn, sub_spt->shadow_page.type); + ppgtt_free_spt(sub_spt); + return ret; } static int split_64KB_gtt_entry(struct intel_vgpu *vgpu, diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index 62823c0e13ab..2d65800d8e93 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h @@ -172,13 +172,18 @@ struct intel_vgpu_submission { #define KVMGT_DEBUGFS_FILENAME "kvmgt_nr_cache_entries" +enum { + INTEL_VGPU_STATUS_ATTACHED = 0, + INTEL_VGPU_STATUS_ACTIVE, + INTEL_VGPU_STATUS_NR_BITS, +}; + struct intel_vgpu { struct vfio_device vfio_device; struct intel_gvt *gvt; struct mutex vgpu_lock; int id; - bool active; - bool attached; + DECLARE_BITMAP(status, INTEL_VGPU_STATUS_NR_BITS); bool pv_notified; bool failsafe; unsigned int resetting_eng; @@ -467,7 +472,7 @@ void intel_vgpu_write_fence(struct intel_vgpu *vgpu, #define for_each_active_vgpu(gvt, vgpu, id) \ idr_for_each_entry((&(gvt)->vgpu_idr), (vgpu), (id)) \ - for_each_if(vgpu->active) + for_each_if(test_bit(INTEL_VGPU_STATUS_ACTIVE, vgpu->status)) static inline void intel_vgpu_write_pci_bar(struct intel_vgpu *vgpu, u32 offset, u32 val, bool low) @@ -725,7 +730,7 @@ static inline bool intel_gvt_mmio_is_cmd_write_patch( static inline int intel_gvt_read_gpa(struct intel_vgpu *vgpu, unsigned long gpa, void *buf, unsigned long len) { - if (!vgpu->attached) + if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) return -ESRCH; return vfio_dma_rw(&vgpu->vfio_device, gpa, buf, len, false); } @@ -743,7 +748,7 @@ static inline int intel_gvt_read_gpa(struct intel_vgpu *vgpu, unsigned long gpa, static inline int intel_gvt_write_gpa(struct intel_vgpu *vgpu, unsigned long gpa, void *buf, unsigned long len) { - if (!vgpu->attached) + if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) return -ESRCH; return vfio_dma_rw(&vgpu->vfio_device, gpa, buf, len, true); } diff --git a/drivers/gpu/drm/i915/gvt/interrupt.c b/drivers/gpu/drm/i915/gvt/interrupt.c index a6b2021b665f..68eca023bbc6 100644 --- a/drivers/gpu/drm/i915/gvt/interrupt.c +++ b/drivers/gpu/drm/i915/gvt/interrupt.c @@ -433,7 +433,7 @@ static int inject_virtual_interrupt(struct intel_vgpu *vgpu) * enabled by guest. so if msi_trigger is null, success is still * returned and don't inject interrupt into guest. */ - if (!vgpu->attached) + if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) return -ESRCH; if (vgpu->msi_trigger && eventfd_signal(vgpu->msi_trigger, 1) != 1) return -EFAULT; diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index f5451adcd489..8ae7039b3683 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -638,7 +638,7 @@ static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu) mutex_lock(&vgpu->gvt->lock); for_each_active_vgpu(vgpu->gvt, itr, id) { - if (!itr->attached) + if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, itr->status)) continue; if (vgpu->vfio_device.kvm == itr->vfio_device.kvm) { @@ -655,9 +655,6 @@ static int intel_vgpu_open_device(struct vfio_device *vfio_dev) { struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev); - if (vgpu->attached) - return -EEXIST; - if (!vgpu->vfio_device.kvm || vgpu->vfio_device.kvm->mm != current->mm) { gvt_vgpu_err("KVM is required to use Intel vGPU\n"); @@ -667,14 +664,14 @@ static int intel_vgpu_open_device(struct vfio_device *vfio_dev) if (__kvmgt_vgpu_exist(vgpu)) return -EEXIST; - vgpu->attached = true; - vgpu->track_node.track_write = kvmgt_page_track_write; vgpu->track_node.track_flush_slot = kvmgt_page_track_flush_slot; kvm_get_kvm(vgpu->vfio_device.kvm); kvm_page_track_register_notifier(vgpu->vfio_device.kvm, &vgpu->track_node); + set_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status); + debugfs_create_ulong(KVMGT_DEBUGFS_FILENAME, 0444, vgpu->debugfs, &vgpu->nr_cache_entries); @@ -698,11 +695,10 @@ static void intel_vgpu_close_device(struct vfio_device *vfio_dev) { struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev); - if (!vgpu->attached) - return; - intel_gvt_release_vgpu(vgpu); + clear_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status); + debugfs_remove(debugfs_lookup(KVMGT_DEBUGFS_FILENAME, vgpu->debugfs)); kvm_page_track_unregister_notifier(vgpu->vfio_device.kvm, @@ -718,8 +714,6 @@ static void intel_vgpu_close_device(struct vfio_device *vfio_dev) vgpu->dma_addr_cache = RB_ROOT; intel_vgpu_release_msi_eventfd_ctx(vgpu); - - vgpu->attached = false; } static u64 intel_vgpu_get_bar_addr(struct intel_vgpu *vgpu, int bar) @@ -1512,9 +1506,6 @@ static void intel_vgpu_remove(struct mdev_device *mdev) { struct intel_vgpu *vgpu = dev_get_drvdata(&mdev->dev); - if (WARN_ON_ONCE(vgpu->attached)) - return; - vfio_unregister_group_dev(&vgpu->vfio_device); vfio_put_device(&vgpu->vfio_device); } @@ -1559,7 +1550,7 @@ int intel_gvt_page_track_add(struct intel_vgpu *info, u64 gfn) struct kvm_memory_slot *slot; int idx; - if (!info->attached) + if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, info->status)) return -ESRCH; idx = srcu_read_lock(&kvm->srcu); @@ -1589,8 +1580,8 @@ int intel_gvt_page_track_remove(struct intel_vgpu *info, u64 gfn) struct kvm_memory_slot *slot; int idx; - if (!info->attached) - return 0; + if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, info->status)) + return -ESRCH; idx = srcu_read_lock(&kvm->srcu); slot = gfn_to_memslot(kvm, gfn); @@ -1668,7 +1659,7 @@ int intel_gvt_dma_map_guest_page(struct intel_vgpu *vgpu, unsigned long gfn, struct gvt_dma *entry; int ret; - if (!vgpu->attached) + if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) return -EINVAL; mutex_lock(&vgpu->cache_lock); @@ -1714,8 +1705,8 @@ int intel_gvt_dma_pin_guest_page(struct intel_vgpu *vgpu, dma_addr_t dma_addr) struct gvt_dma *entry; int ret = 0; - if (!vgpu->attached) - return -ENODEV; + if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) + return -EINVAL; mutex_lock(&vgpu->cache_lock); entry = __gvt_cache_find_dma_addr(vgpu, dma_addr); @@ -1742,7 +1733,7 @@ void intel_gvt_dma_unmap_guest_page(struct intel_vgpu *vgpu, { struct gvt_dma *entry; - if (!vgpu->attached) + if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) return; mutex_lock(&vgpu->cache_lock); @@ -1778,7 +1769,7 @@ static void intel_gvt_test_and_emulate_vblank(struct intel_gvt *gvt) idr_for_each_entry((&(gvt)->vgpu_idr), (vgpu), (id)) { if (test_and_clear_bit(INTEL_GVT_REQUEST_EMULATE_VBLANK + id, (void *)&gvt->service_request)) { - if (vgpu->active) + if (test_bit(INTEL_VGPU_STATUS_ACTIVE, vgpu->status)) intel_vgpu_emulate_vblank(vgpu); } } diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index 9cd8fcbf7cad..f4055804aad1 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -695,6 +695,7 @@ intel_vgpu_shadow_mm_pin(struct intel_vgpu_workload *workload) if (workload->shadow_mm->type != INTEL_GVT_MM_PPGTT || !workload->shadow_mm->ppgtt_mm.shadowed) { + intel_vgpu_unpin_mm(workload->shadow_mm); gvt_vgpu_err("workload shadow ppgtt isn't ready\n"); return -EINVAL; } @@ -865,7 +866,8 @@ pick_next_workload(struct intel_gvt *gvt, struct intel_engine_cs *engine) goto out; } - if (!scheduler->current_vgpu->active || + if (!test_bit(INTEL_VGPU_STATUS_ACTIVE, + scheduler->current_vgpu->status) || list_empty(workload_q_head(scheduler->current_vgpu, engine))) goto out; diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c index 3c529c2705dd..a5497440484f 100644 --- a/drivers/gpu/drm/i915/gvt/vgpu.c +++ b/drivers/gpu/drm/i915/gvt/vgpu.c @@ -166,9 +166,7 @@ void intel_gvt_clean_vgpu_types(struct intel_gvt *gvt) */ void intel_gvt_activate_vgpu(struct intel_vgpu *vgpu) { - mutex_lock(&vgpu->vgpu_lock); - vgpu->active = true; - mutex_unlock(&vgpu->vgpu_lock); + set_bit(INTEL_VGPU_STATUS_ACTIVE, vgpu->status); } /** @@ -183,7 +181,7 @@ void intel_gvt_deactivate_vgpu(struct intel_vgpu *vgpu) { mutex_lock(&vgpu->vgpu_lock); - vgpu->active = false; + clear_bit(INTEL_VGPU_STATUS_ACTIVE, vgpu->status); if (atomic_read(&vgpu->submission.running_workload_num)) { mutex_unlock(&vgpu->vgpu_lock); @@ -228,7 +226,8 @@ void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu) struct intel_gvt *gvt = vgpu->gvt; struct drm_i915_private *i915 = gvt->gt->i915; - drm_WARN(&i915->drm, vgpu->active, "vGPU is still active!\n"); + drm_WARN(&i915->drm, test_bit(INTEL_VGPU_STATUS_ACTIVE, vgpu->status), + "vGPU is still active!\n"); /* * remove idr first so later clean can judge if need to stop @@ -285,8 +284,7 @@ struct intel_vgpu *intel_gvt_create_idle_vgpu(struct intel_gvt *gvt) if (ret) goto out_free_vgpu; - vgpu->active = false; - + clear_bit(INTEL_VGPU_STATUS_ACTIVE, vgpu->status); return vgpu; out_free_vgpu: diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 69103ae37779..61c38fc734cf 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -1069,12 +1069,9 @@ static int i915_driver_open(struct drm_device *dev, struct drm_file *file) */ static void i915_driver_lastclose(struct drm_device *dev) { - struct drm_i915_private *i915 = to_i915(dev); - intel_fbdev_restore_mode(dev); - if (HAS_DISPLAY(i915)) - vga_switcheroo_process_delayed_switch(); + vga_switcheroo_process_delayed_switch(); } static void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index f025ee4fa526..a4b4d9b7d26c 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -416,6 +416,11 @@ int i915_gem_evict_for_node(struct i915_address_space *vm, * @vm: Address space to cleanse * @ww: An optional struct i915_gem_ww_ctx. If not NULL, i915_gem_evict_vm * will be able to evict vma's locked by the ww as well. + * @busy_bo: Optional pointer to struct drm_i915_gem_object. If not NULL, then + * in the event i915_gem_evict_vm() is unable to trylock an object for eviction, + * then @busy_bo will point to it. -EBUSY is also returned. The caller must drop + * the vm->mutex, before trying again to acquire the contended lock. The caller + * also owns a reference to the object. * * This function evicts all vmas from a vm. * @@ -425,7 +430,8 @@ int i915_gem_evict_for_node(struct i915_address_space *vm, * To clarify: This is for freeing up virtual address space, not for freeing * memory in e.g. the shrinker. */ -int i915_gem_evict_vm(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww) +int i915_gem_evict_vm(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww, + struct drm_i915_gem_object **busy_bo) { int ret = 0; @@ -457,15 +463,22 @@ int i915_gem_evict_vm(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww) * the resv is shared among multiple objects, we still * need the object ref. */ - if (dying_vma(vma) || + if (!i915_gem_object_get_rcu(vma->obj) || (ww && (dma_resv_locking_ctx(vma->obj->base.resv) == &ww->ctx))) { __i915_vma_pin(vma); list_add(&vma->evict_link, &locked_eviction_list); continue; } - if (!i915_gem_object_trylock(vma->obj, ww)) + if (!i915_gem_object_trylock(vma->obj, ww)) { + if (busy_bo) { + *busy_bo = vma->obj; /* holds ref */ + ret = -EBUSY; + break; + } + i915_gem_object_put(vma->obj); continue; + } __i915_vma_pin(vma); list_add(&vma->evict_link, &eviction_list); @@ -473,25 +486,29 @@ int i915_gem_evict_vm(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww) if (list_empty(&eviction_list) && list_empty(&locked_eviction_list)) break; - ret = 0; /* Unbind locked objects first, before unlocking the eviction_list */ list_for_each_entry_safe(vma, vn, &locked_eviction_list, evict_link) { __i915_vma_unpin(vma); - if (ret == 0) + if (ret == 0) { ret = __i915_vma_unbind(vma); - if (ret != -EINTR) /* "Get me out of here!" */ - ret = 0; + if (ret != -EINTR) /* "Get me out of here!" */ + ret = 0; + } + if (!dying_vma(vma)) + i915_gem_object_put(vma->obj); } list_for_each_entry_safe(vma, vn, &eviction_list, evict_link) { __i915_vma_unpin(vma); - if (ret == 0) + if (ret == 0) { ret = __i915_vma_unbind(vma); - if (ret != -EINTR) /* "Get me out of here!" */ - ret = 0; + if (ret != -EINTR) /* "Get me out of here!" */ + ret = 0; + } i915_gem_object_unlock(vma->obj); + i915_gem_object_put(vma->obj); } } while (ret == 0); diff --git a/drivers/gpu/drm/i915/i915_gem_evict.h b/drivers/gpu/drm/i915/i915_gem_evict.h index e593c530f9bd..bf0ee0e4fe60 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.h +++ b/drivers/gpu/drm/i915/i915_gem_evict.h @@ -11,6 +11,7 @@ struct drm_mm_node; struct i915_address_space; struct i915_gem_ww_ctx; +struct drm_i915_gem_object; int __must_check i915_gem_evict_something(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww, @@ -23,6 +24,7 @@ int __must_check i915_gem_evict_for_node(struct i915_address_space *vm, struct drm_mm_node *node, unsigned int flags); int i915_gem_evict_vm(struct i915_address_space *vm, - struct i915_gem_ww_ctx *ww); + struct i915_gem_ww_ctx *ww, + struct drm_i915_gem_object **busy_bo); #endif /* __I915_GEM_EVICT_H__ */ diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 9d5d5a397b64..b20bd6365615 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1596,43 +1596,20 @@ capture_engine(struct intel_engine_cs *engine, { struct intel_engine_capture_vma *capture = NULL; struct intel_engine_coredump *ee; - struct intel_context *ce; + struct intel_context *ce = NULL; struct i915_request *rq = NULL; - unsigned long flags; ee = intel_engine_coredump_alloc(engine, ALLOW_FAIL, dump_flags); if (!ee) return NULL; - ce = intel_engine_get_hung_context(engine); - if (ce) { - intel_engine_clear_hung_context(engine); - rq = intel_context_find_active_request(ce); - if (!rq || !i915_request_started(rq)) - goto no_request_capture; - } else { - /* - * Getting here with GuC enabled means it is a forced error capture - * with no actual hang. So, no need to attempt the execlist search. - */ - if (!intel_uc_uses_guc_submission(&engine->gt->uc)) { - spin_lock_irqsave(&engine->sched_engine->lock, flags); - rq = intel_engine_execlist_find_hung_request(engine); - spin_unlock_irqrestore(&engine->sched_engine->lock, - flags); - } - } - if (rq) - rq = i915_request_get_rcu(rq); - - if (!rq) + intel_engine_get_hung_entity(engine, &ce, &rq); + if (!rq || !i915_request_started(rq)) goto no_request_capture; capture = intel_engine_coredump_add_request(ee, rq, ATOMIC_MAYFAIL); - if (!capture) { - i915_request_put(rq); + if (!capture) goto no_request_capture; - } if (dump_flags & CORE_DUMP_FLAG_IS_GUC_CAPTURE) intel_guc_capture_get_matching_node(engine->gt, ee, ce); @@ -1642,6 +1619,8 @@ capture_engine(struct intel_engine_cs *engine, return ee; no_request_capture: + if (rq) + i915_request_put(rq); kfree(ee); return NULL; } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index edfe363af838..91c533986041 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1974,7 +1974,10 @@ static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) if (ddi_hotplug_trigger) { u32 dig_hotplug_reg; + /* Locking due to DSI native GPIO sequences */ + spin_lock(&dev_priv->irq_lock); dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_DDI, 0, 0); + spin_unlock(&dev_priv->irq_lock); intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, ddi_hotplug_trigger, dig_hotplug_reg, diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 6da9784fe4a2..4fada7ebe8d8 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -423,7 +423,8 @@ static const struct intel_device_info ilk_m_info = { .has_coherent_ggtt = true, \ .has_llc = 1, \ .has_rc6 = 1, \ - .has_rc6p = 1, \ + /* snb does support rc6p, but enabling it causes various issues */ \ + .has_rc6p = 0, \ .has_rps = true, \ .dma_mask_size = 40, \ .__runtime.ppgtt_type = INTEL_PPGTT_ALIASING, \ @@ -1129,7 +1130,6 @@ static const struct intel_gt_definition xelpmp_extra_gt[] = { {} }; -__maybe_unused static const struct intel_device_info mtl_info = { XE_HP_FEATURES, XE_LPDP_FEATURES, diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8e1892d14774..916176872544 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5988,6 +5988,7 @@ #define SHOTPLUG_CTL_DDI _MMIO(0xc4030) #define SHOTPLUG_CTL_DDI_HPD_ENABLE(hpd_pin) (0x8 << (_HPD_PIN_DDI(hpd_pin) * 4)) +#define SHOTPLUG_CTL_DDI_HPD_OUTPUT_DATA(hpd_pin) (0x4 << (_HPD_PIN_DDI(hpd_pin) * 4)) #define SHOTPLUG_CTL_DDI_HPD_STATUS_MASK(hpd_pin) (0x3 << (_HPD_PIN_DDI(hpd_pin) * 4)) #define SHOTPLUG_CTL_DDI_HPD_NO_DETECT(hpd_pin) (0x0 << (_HPD_PIN_DDI(hpd_pin) * 4)) #define SHOTPLUG_CTL_DDI_HPD_SHORT_DETECT(hpd_pin) (0x1 << (_HPD_PIN_DDI(hpd_pin) * 4)) diff --git a/drivers/gpu/drm/i915/i915_switcheroo.c b/drivers/gpu/drm/i915/i915_switcheroo.c index 23777d500cdf..f45bd6b6cede 100644 --- a/drivers/gpu/drm/i915/i915_switcheroo.c +++ b/drivers/gpu/drm/i915/i915_switcheroo.c @@ -19,6 +19,10 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, dev_err(&pdev->dev, "DRM not initialized, aborting switch.\n"); return; } + if (!HAS_DISPLAY(i915)) { + dev_err(&pdev->dev, "Device state not initialized, aborting switch.\n"); + return; + } if (state == VGA_SWITCHEROO_ON) { drm_info(&i915->drm, "switched on\n"); @@ -44,7 +48,7 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev) * locking inversion with the driver load path. And the access here is * completely racy anyway. So don't bother with locking for now. */ - return i915 && atomic_read(&i915->drm.open_count) == 0; + return i915 && HAS_DISPLAY(i915) && atomic_read(&i915->drm.open_count) == 0; } static const struct vga_switcheroo_client_ops i915_switcheroo_ops = { diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 703fee6b5f75..135390d975b6 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -1566,7 +1566,7 @@ static int __i915_ggtt_pin(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, * locked objects when called from execbuf when pinning * is removed. This would probably regress badly. */ - i915_gem_evict_vm(vm, NULL); + i915_gem_evict_vm(vm, NULL, NULL); mutex_unlock(&vm->mutex); } } while (1); @@ -2116,7 +2116,7 @@ int i915_vma_unbind_async(struct i915_vma *vma, bool trylock_vm) if (!obj->mm.rsgt) return -EBUSY; - err = dma_resv_reserve_fences(obj->base.resv, 1); + err = dma_resv_reserve_fences(obj->base.resv, 2); if (err) return -EBUSY; diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_evict.c b/drivers/gpu/drm/i915/selftests/i915_gem_evict.c index 8c6517d29b8e..37068542aafe 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_evict.c @@ -344,7 +344,7 @@ static int igt_evict_vm(void *arg) /* Everything is pinned, nothing should happen */ mutex_lock(&ggtt->vm.mutex); - err = i915_gem_evict_vm(&ggtt->vm, NULL); + err = i915_gem_evict_vm(&ggtt->vm, NULL, NULL); mutex_unlock(&ggtt->vm.mutex); if (err) { pr_err("i915_gem_evict_vm on a full GGTT returned err=%d]\n", @@ -356,7 +356,7 @@ static int igt_evict_vm(void *arg) for_i915_gem_ww(&ww, err, false) { mutex_lock(&ggtt->vm.mutex); - err = i915_gem_evict_vm(&ggtt->vm, &ww); + err = i915_gem_evict_vm(&ggtt->vm, &ww, NULL); mutex_unlock(&ggtt->vm.mutex); } diff --git a/drivers/gpu/drm/i915/selftests/intel_scheduler_helpers.c b/drivers/gpu/drm/i915/selftests/intel_scheduler_helpers.c index 310fb83c527e..2990dd4d4a0d 100644 --- a/drivers/gpu/drm/i915/selftests/intel_scheduler_helpers.c +++ b/drivers/gpu/drm/i915/selftests/intel_scheduler_helpers.c @@ -28,8 +28,7 @@ struct intel_engine_cs *intel_selftest_find_any_engine(struct intel_gt *gt) int intel_selftest_modify_policy(struct intel_engine_cs *engine, struct intel_selftest_saved_policy *saved, - u32 modify_type) - + enum selftest_scheduler_modify modify_type) { int err; diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index dba4f7d81d69..80142d9a4a55 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -614,6 +614,11 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, break; } + if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_BG) + width = ipu_src_rect_width(new_state); + else + width = drm_rect_width(&new_state->src) >> 16; + eba = drm_plane_state_to_eba(new_state, 0); /* @@ -622,8 +627,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, */ if (ipu_state->use_pre) { axi_id = ipu_chan_assign_axi_id(ipu_plane->dma); - ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id, - ipu_src_rect_width(new_state), + ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id, width, drm_rect_height(&new_state->src) >> 16, fb->pitches[0], fb->format->format, fb->modifier, &eba); @@ -678,9 +682,8 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, break; } - ipu_dmfc_config_wait4eot(ipu_plane->dmfc, ALIGN(drm_rect_width(dst), 8)); + ipu_dmfc_config_wait4eot(ipu_plane->dmfc, width); - width = ipu_src_rect_width(new_state); height = drm_rect_height(&new_state->src) >> 16; info = drm_format_info(fb->format->format); ipu_calculate_bursts(width, info->cpp[0], fb->pitches[0], @@ -744,8 +747,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, 16); ipu_cpmem_zero(ipu_plane->alpha_ch); - ipu_cpmem_set_resolution(ipu_plane->alpha_ch, - ipu_src_rect_width(new_state), + ipu_cpmem_set_resolution(ipu_plane->alpha_ch, width, drm_rect_height(&new_state->src) >> 16); ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8); ipu_cpmem_set_high_priority(ipu_plane->alpha_ch); diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c index d4b907889a21..cd399b0b7181 100644 --- a/drivers/gpu/drm/meson/meson_viu.c +++ b/drivers/gpu/drm/meson/meson_viu.c @@ -436,15 +436,14 @@ void meson_viu_init(struct meson_drm *priv) /* Initialize OSD1 fifo control register */ reg = VIU_OSD_DDR_PRIORITY_URGENT | - VIU_OSD_HOLD_FIFO_LINES(31) | VIU_OSD_FIFO_DEPTH_VAL(32) | /* fifo_depth_val: 32*8=256 */ VIU_OSD_WORDS_PER_BURST(4) | /* 4 words in 1 burst */ VIU_OSD_FIFO_LIMITS(2); /* fifo_lim: 2*16=32 */ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) - reg |= VIU_OSD_BURST_LENGTH_32; + reg |= (VIU_OSD_BURST_LENGTH_32 | VIU_OSD_HOLD_FIFO_LINES(31)); else - reg |= VIU_OSD_BURST_LENGTH_64; + reg |= (VIU_OSD_BURST_LENGTH_64 | VIU_OSD_HOLD_FIFO_LINES(4)); writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT)); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 6484b97c5344..f3c9600221d4 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -876,7 +876,8 @@ static void a6xx_gmu_rpmh_off(struct a6xx_gmu *gmu) #define GBIF_CLIENT_HALT_MASK BIT(0) #define GBIF_ARB_HALT_MASK BIT(1) -static void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu) +static void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, + bool gx_off) { struct msm_gpu *gpu = &adreno_gpu->base; @@ -889,9 +890,11 @@ static void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu) return; } - /* Halt the gx side of GBIF */ - gpu_write(gpu, REG_A6XX_RBBM_GBIF_HALT, 1); - spin_until(gpu_read(gpu, REG_A6XX_RBBM_GBIF_HALT_ACK) & 1); + if (gx_off) { + /* Halt the gx side of GBIF */ + gpu_write(gpu, REG_A6XX_RBBM_GBIF_HALT, 1); + spin_until(gpu_read(gpu, REG_A6XX_RBBM_GBIF_HALT_ACK) & 1); + } /* Halt new client requests on GBIF */ gpu_write(gpu, REG_A6XX_GBIF_HALT, GBIF_CLIENT_HALT_MASK); @@ -929,7 +932,7 @@ static void a6xx_gmu_force_off(struct a6xx_gmu *gmu) /* Halt the gmu cm3 core */ gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 1); - a6xx_bus_clear_pending_transactions(adreno_gpu); + a6xx_bus_clear_pending_transactions(adreno_gpu, true); /* Reset GPU core blocks */ gpu_write(gpu, REG_A6XX_RBBM_SW_RESET_CMD, 1); @@ -1083,7 +1086,7 @@ static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu) return; } - a6xx_bus_clear_pending_transactions(adreno_gpu); + a6xx_bus_clear_pending_transactions(adreno_gpu, a6xx_gpu->hung); /* tell the GMU we want to slumber */ ret = a6xx_gmu_notify_slumber(gmu); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 36c8fb699b56..3be0f2928b57 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -1270,6 +1270,12 @@ static void a6xx_recover(struct msm_gpu *gpu) if (hang_debug) a6xx_dump(gpu); + /* + * To handle recovery specific sequences during the rpm suspend we are + * about to trigger + */ + a6xx_gpu->hung = true; + /* Halt SQE first */ gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 3); @@ -1312,6 +1318,7 @@ static void a6xx_recover(struct msm_gpu *gpu) mutex_unlock(&gpu->active_lock); msm_gpu_hw_init(gpu); + a6xx_gpu->hung = false; } static const char *a6xx_uche_fault_block(struct msm_gpu *gpu, u32 mid) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h index ab853f61db63..eea2e60ce3b7 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h @@ -32,6 +32,7 @@ struct a6xx_gpu { void *llc_slice; void *htw_llc_slice; bool have_mmu500; + bool hung; }; #define to_a6xx_gpu(x) container_of(x, struct a6xx_gpu, base) diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 628806423f7d..36f062c7582f 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -551,13 +551,14 @@ static int adreno_bind(struct device *dev, struct device *master, void *data) return 0; } +static int adreno_system_suspend(struct device *dev); static void adreno_unbind(struct device *dev, struct device *master, void *data) { struct msm_drm_private *priv = dev_get_drvdata(master); struct msm_gpu *gpu = dev_to_gpu(dev); - pm_runtime_force_suspend(dev); + WARN_ON_ONCE(adreno_system_suspend(dev)); gpu->funcs->destroy(gpu); priv->gpu_pdev = NULL; @@ -609,7 +610,7 @@ static int adreno_remove(struct platform_device *pdev) static void adreno_shutdown(struct platform_device *pdev) { - pm_runtime_force_suspend(&pdev->dev); + WARN_ON_ONCE(adreno_system_suspend(&pdev->dev)); } static const struct of_device_id dt_match[] = { diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 57586c794b84..3605f095b2de 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -352,6 +352,8 @@ int adreno_set_param(struct msm_gpu *gpu, struct msm_file_private *ctx, /* Ensure string is null terminated: */ str[len] = '\0'; + mutex_lock(&gpu->lock); + if (param == MSM_PARAM_COMM) { paramp = &ctx->comm; } else { @@ -361,6 +363,8 @@ int adreno_set_param(struct msm_gpu *gpu, struct msm_file_private *ctx, kfree(*paramp); *paramp = str; + mutex_unlock(&gpu->lock); + return 0; } case MSM_PARAM_SYSPROF: diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 5d4b1c95033f..b4f9b1343d63 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -29,11 +29,9 @@ enum { ADRENO_FW_MAX, }; -enum adreno_quirks { - ADRENO_QUIRK_TWO_PASS_USE_WFI = 1, - ADRENO_QUIRK_FAULT_DETECT_MASK = 2, - ADRENO_QUIRK_LMLOADKILL_DISABLE = 3, -}; +#define ADRENO_QUIRK_TWO_PASS_USE_WFI BIT(0) +#define ADRENO_QUIRK_FAULT_DETECT_MASK BIT(1) +#define ADRENO_QUIRK_LMLOADKILL_DISABLE BIT(2) struct adreno_rev { uint8_t core; @@ -65,7 +63,7 @@ struct adreno_info { const char *name; const char *fw[ADRENO_FW_MAX]; uint32_t gmem; - enum adreno_quirks quirks; + u64 quirks; struct msm_gpu *(*init)(struct drm_device *dev); const char *zapfw; u32 inactive_period; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c index 7cbcef6efe17..62f6ff6abf41 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c @@ -132,7 +132,6 @@ static void dpu_encoder_phys_wb_set_qos(struct dpu_encoder_phys *phys_enc) * dpu_encoder_phys_wb_setup_fb - setup output framebuffer * @phys_enc: Pointer to physical encoder * @fb: Pointer to output framebuffer - * @wb_roi: Pointer to output region of interest */ static void dpu_encoder_phys_wb_setup_fb(struct dpu_encoder_phys *phys_enc, struct drm_framebuffer *fb) @@ -692,7 +691,7 @@ static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops) /** * dpu_encoder_phys_wb_init - initialize writeback encoder - * @init: Pointer to init info structure with initialization params + * @p: Pointer to init info structure with initialization params */ struct dpu_encoder_phys *dpu_encoder_phys_wb_init( struct dpu_enc_phys_init_params *p) diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c index d030a93a08c3..cc3efed593aa 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -423,6 +423,10 @@ void dp_aux_isr(struct drm_dp_aux *dp_aux) isr = dp_catalog_aux_get_irq(aux->catalog); + /* no interrupts pending, return immediately */ + if (!isr) + return; + if (!aux->cmd_busy) return; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 4d3fdc806bef..97372bb241d8 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -532,11 +532,19 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev) ret = devm_pm_runtime_enable(&pdev->dev); if (ret) - return ret; + goto err_put_phy; platform_set_drvdata(pdev, hdmi); - return component_add(&pdev->dev, &msm_hdmi_ops); + ret = component_add(&pdev->dev, &msm_hdmi_ops); + if (ret) + goto err_put_phy; + + return 0; + +err_put_phy: + msm_hdmi_put_phy(hdmi); + return ret; } static int msm_hdmi_dev_remove(struct platform_device *pdev) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 8b0b0ac74a6f..45e81eb148a8 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1278,7 +1278,7 @@ void msm_drv_shutdown(struct platform_device *pdev) * msm_drm_init, drm_dev->registered is used as an indicator that the * shutdown will be successful. */ - if (drm && drm->registered) + if (drm && drm->registered && priv->kms) drm_atomic_helper_shutdown(drm); } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 30ed45af76ad..380249500325 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -335,6 +335,8 @@ static void get_comm_cmdline(struct msm_gem_submit *submit, char **comm, char ** struct msm_file_private *ctx = submit->queue->ctx; struct task_struct *task; + WARN_ON(!mutex_is_locked(&submit->gpu->lock)); + /* Note that kstrdup will return NULL if argument is NULL: */ *comm = kstrdup(ctx->comm, GFP_KERNEL); *cmd = kstrdup(ctx->cmdline, GFP_KERNEL); diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 651786bc55e5..732295e25683 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -376,10 +376,18 @@ struct msm_file_private { */ int sysprof; - /** comm: Overridden task comm, see MSM_PARAM_COMM */ + /** + * comm: Overridden task comm, see MSM_PARAM_COMM + * + * Accessed under msm_gpu::lock + */ char *comm; - /** cmdline: Overridden task cmdline, see MSM_PARAM_CMDLINE */ + /** + * cmdline: Overridden task cmdline, see MSM_PARAM_CMDLINE + * + * Accessed under msm_gpu::lock + */ char *cmdline; /** diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 86b28add1fff..2527afef9c19 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -47,15 +47,17 @@ struct msm_mdss { static int msm_mdss_parse_data_bus_icc_path(struct device *dev, struct msm_mdss *msm_mdss) { - struct icc_path *path0 = of_icc_get(dev, "mdp0-mem"); - struct icc_path *path1 = of_icc_get(dev, "mdp1-mem"); + struct icc_path *path0; + struct icc_path *path1; + path0 = of_icc_get(dev, "mdp0-mem"); if (IS_ERR_OR_NULL(path0)) return PTR_ERR_OR_ZERO(path0); msm_mdss->path[0] = path0; msm_mdss->num_paths = 1; + path1 = of_icc_get(dev, "mdp1-mem"); if (!IS_ERR_OR_NULL(path1)) { msm_mdss->path[1] = path1; msm_mdss->num_paths++; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h index 40768373cdd9..c5a4f49ee206 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h @@ -97,6 +97,7 @@ int gp100_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct n int gp102_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fb **); int gp10b_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fb **); int gv100_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fb **); +int tu102_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fb **); int ga100_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fb **); int ga102_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fb **); diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c deleted file mode 100644 index e87de7906f78..000000000000 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ /dev/null @@ -1,613 +0,0 @@ -/* - * Copyright © 2007 David Airlie - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * David Airlie - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/tty.h> -#include <linux/sysrq.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/screen_info.h> -#include <linux/vga_switcheroo.h> -#include <linux/console.h> - -#include <drm/drm_crtc.h> -#include <drm/drm_crtc_helper.h> -#include <drm/drm_probe_helper.h> -#include <drm/drm_fb_helper.h> -#include <drm/drm_fourcc.h> -#include <drm/drm_atomic.h> - -#include "nouveau_drv.h" -#include "nouveau_gem.h" -#include "nouveau_bo.h" -#include "nouveau_fbcon.h" -#include "nouveau_chan.h" -#include "nouveau_vmm.h" - -#include "nouveau_crtc.h" - -MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration"); -int nouveau_nofbaccel = 0; -module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400); - -MODULE_PARM_DESC(fbcon_bpp, "fbcon bits-per-pixel (default: auto)"); -static int nouveau_fbcon_bpp; -module_param_named(fbcon_bpp, nouveau_fbcon_bpp, int, 0400); - -static void -nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -{ - struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); - struct nvif_device *device = &drm->client.device; - int ret; - - if (info->state != FBINFO_STATE_RUNNING) - return; - - ret = -ENODEV; - if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && - mutex_trylock(&drm->client.mutex)) { - if (device->info.family < NV_DEVICE_INFO_V0_TESLA) - ret = nv04_fbcon_fillrect(info, rect); - else - if (device->info.family < NV_DEVICE_INFO_V0_FERMI) - ret = nv50_fbcon_fillrect(info, rect); - else - ret = nvc0_fbcon_fillrect(info, rect); - mutex_unlock(&drm->client.mutex); - } - - if (ret == 0) - return; - - if (ret != -ENODEV) - nouveau_fbcon_gpu_lockup(info); - drm_fb_helper_cfb_fillrect(info, rect); -} - -static void -nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image) -{ - struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); - struct nvif_device *device = &drm->client.device; - int ret; - - if (info->state != FBINFO_STATE_RUNNING) - return; - - ret = -ENODEV; - if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && - mutex_trylock(&drm->client.mutex)) { - if (device->info.family < NV_DEVICE_INFO_V0_TESLA) - ret = nv04_fbcon_copyarea(info, image); - else - if (device->info.family < NV_DEVICE_INFO_V0_FERMI) - ret = nv50_fbcon_copyarea(info, image); - else - ret = nvc0_fbcon_copyarea(info, image); - mutex_unlock(&drm->client.mutex); - } - - if (ret == 0) - return; - - if (ret != -ENODEV) - nouveau_fbcon_gpu_lockup(info); - drm_fb_helper_cfb_copyarea(info, image); -} - -static void -nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) -{ - struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); - struct nvif_device *device = &drm->client.device; - int ret; - - if (info->state != FBINFO_STATE_RUNNING) - return; - - ret = -ENODEV; - if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && - mutex_trylock(&drm->client.mutex)) { - if (device->info.family < NV_DEVICE_INFO_V0_TESLA) - ret = nv04_fbcon_imageblit(info, image); - else - if (device->info.family < NV_DEVICE_INFO_V0_FERMI) - ret = nv50_fbcon_imageblit(info, image); - else - ret = nvc0_fbcon_imageblit(info, image); - mutex_unlock(&drm->client.mutex); - } - - if (ret == 0) - return; - - if (ret != -ENODEV) - nouveau_fbcon_gpu_lockup(info); - drm_fb_helper_cfb_imageblit(info, image); -} - -static int -nouveau_fbcon_sync(struct fb_info *info) -{ - struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); - struct nouveau_channel *chan = drm->channel; - int ret; - - if (!chan || !chan->accel_done || in_interrupt() || - info->state != FBINFO_STATE_RUNNING || - info->flags & FBINFO_HWACCEL_DISABLED) - return 0; - - if (!mutex_trylock(&drm->client.mutex)) - return 0; - - ret = nouveau_channel_idle(chan); - mutex_unlock(&drm->client.mutex); - if (ret) { - nouveau_fbcon_gpu_lockup(info); - return 0; - } - - chan->accel_done = false; - return 0; -} - -static int -nouveau_fbcon_open(struct fb_info *info, int user) -{ - struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); - int ret = pm_runtime_get_sync(drm->dev->dev); - if (ret < 0 && ret != -EACCES) { - pm_runtime_put(drm->dev->dev); - return ret; - } - return 0; -} - -static int -nouveau_fbcon_release(struct fb_info *info, int user) -{ - struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); - pm_runtime_put(drm->dev->dev); - return 0; -} - -static const struct fb_ops nouveau_fbcon_ops = { - .owner = THIS_MODULE, - DRM_FB_HELPER_DEFAULT_OPS, - .fb_open = nouveau_fbcon_open, - .fb_release = nouveau_fbcon_release, - .fb_fillrect = nouveau_fbcon_fillrect, - .fb_copyarea = nouveau_fbcon_copyarea, - .fb_imageblit = nouveau_fbcon_imageblit, - .fb_sync = nouveau_fbcon_sync, -}; - -static const struct fb_ops nouveau_fbcon_sw_ops = { - .owner = THIS_MODULE, - DRM_FB_HELPER_DEFAULT_OPS, - .fb_open = nouveau_fbcon_open, - .fb_release = nouveau_fbcon_release, - .fb_fillrect = drm_fb_helper_cfb_fillrect, - .fb_copyarea = drm_fb_helper_cfb_copyarea, - .fb_imageblit = drm_fb_helper_cfb_imageblit, -}; - -void -nouveau_fbcon_accel_save_disable(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - if (drm->fbcon && drm->fbcon->helper.info) { - drm->fbcon->saved_flags = drm->fbcon->helper.info->flags; - drm->fbcon->helper.info->flags |= FBINFO_HWACCEL_DISABLED; - } -} - -void -nouveau_fbcon_accel_restore(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - if (drm->fbcon && drm->fbcon->helper.info) - drm->fbcon->helper.info->flags = drm->fbcon->saved_flags; -} - -static void -nouveau_fbcon_accel_fini(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_fbdev *fbcon = drm->fbcon; - if (fbcon && drm->channel) { - console_lock(); - if (fbcon->helper.info) - fbcon->helper.info->flags |= FBINFO_HWACCEL_DISABLED; - console_unlock(); - nouveau_channel_idle(drm->channel); - nvif_object_dtor(&fbcon->twod); - nvif_object_dtor(&fbcon->blit); - nvif_object_dtor(&fbcon->gdi); - nvif_object_dtor(&fbcon->patt); - nvif_object_dtor(&fbcon->rop); - nvif_object_dtor(&fbcon->clip); - nvif_object_dtor(&fbcon->surf2d); - } -} - -static void -nouveau_fbcon_accel_init(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_fbdev *fbcon = drm->fbcon; - struct fb_info *info = fbcon->helper.info; - int ret; - - if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) - ret = nv04_fbcon_accel_init(info); - else - if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI) - ret = nv50_fbcon_accel_init(info); - else - ret = nvc0_fbcon_accel_init(info); - - if (ret == 0) - info->fbops = &nouveau_fbcon_ops; -} - -static void -nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *fbcon) -{ - struct fb_info *info = fbcon->helper.info; - struct fb_fillrect rect; - - /* Clear the entire fbcon. The drm will program every connector - * with it's preferred mode. If the sizes differ, one display will - * quite likely have garbage around the console. - */ - rect.dx = rect.dy = 0; - rect.width = info->var.xres_virtual; - rect.height = info->var.yres_virtual; - rect.color = 0; - rect.rop = ROP_COPY; - info->fbops->fb_fillrect(info, &rect); -} - -static int -nouveau_fbcon_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct nouveau_fbdev *fbcon = - container_of(helper, struct nouveau_fbdev, helper); - struct drm_device *dev = fbcon->helper.dev; - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvif_device *device = &drm->client.device; - struct fb_info *info; - struct drm_framebuffer *fb; - struct nouveau_channel *chan; - struct nouveau_bo *nvbo; - struct drm_mode_fb_cmd2 mode_cmd = {}; - int ret; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - - mode_cmd.pitches[0] = mode_cmd.width * (sizes->surface_bpp >> 3); - mode_cmd.pitches[0] = roundup(mode_cmd.pitches[0], 256); - - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - ret = nouveau_gem_new(&drm->client, mode_cmd.pitches[0] * - mode_cmd.height, 0, NOUVEAU_GEM_DOMAIN_VRAM, - 0, 0x0000, &nvbo); - if (ret) { - NV_ERROR(drm, "failed to allocate framebuffer\n"); - goto out; - } - - ret = nouveau_framebuffer_new(dev, &mode_cmd, &nvbo->bo.base, &fb); - if (ret) - goto out_unref; - - ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false); - if (ret) { - NV_ERROR(drm, "failed to pin fb: %d\n", ret); - goto out_unref; - } - - ret = nouveau_bo_map(nvbo); - if (ret) { - NV_ERROR(drm, "failed to map fb: %d\n", ret); - goto out_unpin; - } - - chan = nouveau_nofbaccel ? NULL : drm->channel; - if (chan && device->info.family >= NV_DEVICE_INFO_V0_TESLA) { - ret = nouveau_vma_new(nvbo, chan->vmm, &fbcon->vma); - if (ret) { - NV_ERROR(drm, "failed to map fb into chan: %d\n", ret); - chan = NULL; - } - } - - info = drm_fb_helper_alloc_info(helper); - if (IS_ERR(info)) { - ret = PTR_ERR(info); - goto out_unlock; - } - - /* setup helper */ - fbcon->helper.fb = fb; - - if (!chan) - info->flags = FBINFO_HWACCEL_DISABLED; - else - info->flags = FBINFO_HWACCEL_COPYAREA | - FBINFO_HWACCEL_FILLRECT | - FBINFO_HWACCEL_IMAGEBLIT; - info->fbops = &nouveau_fbcon_sw_ops; - info->fix.smem_start = nvbo->bo.resource->bus.offset; - info->fix.smem_len = nvbo->bo.base.size; - - info->screen_base = nvbo_kmap_obj_iovirtual(nvbo); - info->screen_size = nvbo->bo.base.size; - - drm_fb_helper_fill_info(info, &fbcon->helper, sizes); - - /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ - - if (chan) - nouveau_fbcon_accel_init(dev); - nouveau_fbcon_zfill(dev, fbcon); - - /* To allow resizeing without swapping buffers */ - NV_INFO(drm, "allocated %dx%d fb: 0x%llx, bo %p\n", - fb->width, fb->height, nvbo->offset, nvbo); - - if (dev_is_pci(dev->dev)) - vga_switcheroo_client_fb_set(to_pci_dev(dev->dev), info); - - return 0; - -out_unlock: - if (chan) - nouveau_vma_del(&fbcon->vma); - nouveau_bo_unmap(nvbo); -out_unpin: - nouveau_bo_unpin(nvbo); -out_unref: - nouveau_bo_ref(NULL, &nvbo); -out: - return ret; -} - -static int -nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon) -{ - struct drm_framebuffer *fb = fbcon->helper.fb; - struct nouveau_bo *nvbo; - - drm_fb_helper_unregister_info(&fbcon->helper); - drm_fb_helper_fini(&fbcon->helper); - - if (fb && fb->obj[0]) { - nvbo = nouveau_gem_object(fb->obj[0]); - nouveau_vma_del(&fbcon->vma); - nouveau_bo_unmap(nvbo); - nouveau_bo_unpin(nvbo); - drm_framebuffer_put(fb); - } - - return 0; -} - -void nouveau_fbcon_gpu_lockup(struct fb_info *info) -{ - struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); - - NV_ERROR(drm, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; -} - -static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { - .fb_probe = nouveau_fbcon_create, -}; - -static void -nouveau_fbcon_set_suspend_work(struct work_struct *work) -{ - struct nouveau_drm *drm = container_of(work, typeof(*drm), fbcon_work); - int state = READ_ONCE(drm->fbcon_new_state); - - if (state == FBINFO_STATE_RUNNING) - pm_runtime_get_sync(drm->dev->dev); - - console_lock(); - if (state == FBINFO_STATE_RUNNING) - nouveau_fbcon_accel_restore(drm->dev); - drm_fb_helper_set_suspend(&drm->fbcon->helper, state); - if (state != FBINFO_STATE_RUNNING) - nouveau_fbcon_accel_save_disable(drm->dev); - console_unlock(); - - if (state == FBINFO_STATE_RUNNING) { - nouveau_fbcon_hotplug_resume(drm->fbcon); - pm_runtime_mark_last_busy(drm->dev->dev); - pm_runtime_put_autosuspend(drm->dev->dev); - } -} - -void -nouveau_fbcon_set_suspend(struct drm_device *dev, int state) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - - if (!drm->fbcon) - return; - - drm->fbcon_new_state = state; - /* Since runtime resume can happen as a result of a sysfs operation, - * it's possible we already have the console locked. So handle fbcon - * init/deinit from a seperate work thread - */ - schedule_work(&drm->fbcon_work); -} - -void -nouveau_fbcon_output_poll_changed(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_fbdev *fbcon = drm->fbcon; - int ret; - - if (!fbcon) - return; - - mutex_lock(&fbcon->hotplug_lock); - - ret = pm_runtime_get(dev->dev); - if (ret == 1 || ret == -EACCES) { - drm_fb_helper_hotplug_event(&fbcon->helper); - - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); - } else if (ret == 0) { - /* If the GPU was already in the process of suspending before - * this event happened, then we can't block here as we'll - * deadlock the runtime pmops since they wait for us to - * finish. So, just defer this event for when we runtime - * resume again. It will be handled by fbcon_work. - */ - NV_DEBUG(drm, "fbcon HPD event deferred until runtime resume\n"); - fbcon->hotplug_waiting = true; - pm_runtime_put_noidle(drm->dev->dev); - } else { - DRM_WARN("fbcon HPD event lost due to RPM failure: %d\n", - ret); - } - - mutex_unlock(&fbcon->hotplug_lock); -} - -void -nouveau_fbcon_hotplug_resume(struct nouveau_fbdev *fbcon) -{ - struct nouveau_drm *drm; - - if (!fbcon) - return; - drm = nouveau_drm(fbcon->helper.dev); - - mutex_lock(&fbcon->hotplug_lock); - if (fbcon->hotplug_waiting) { - fbcon->hotplug_waiting = false; - - NV_DEBUG(drm, "Handling deferred fbcon HPD events\n"); - drm_fb_helper_hotplug_event(&fbcon->helper); - } - mutex_unlock(&fbcon->hotplug_lock); -} - -int -nouveau_fbcon_init(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_fbdev *fbcon; - int preferred_bpp = nouveau_fbcon_bpp; - int ret; - - if (!dev->mode_config.num_crtc || - (to_pci_dev(dev->dev)->class >> 8) != PCI_CLASS_DISPLAY_VGA) - return 0; - - fbcon = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL); - if (!fbcon) - return -ENOMEM; - - drm->fbcon = fbcon; - INIT_WORK(&drm->fbcon_work, nouveau_fbcon_set_suspend_work); - mutex_init(&fbcon->hotplug_lock); - - drm_fb_helper_prepare(dev, &fbcon->helper, &nouveau_fbcon_helper_funcs); - - ret = drm_fb_helper_init(dev, &fbcon->helper); - if (ret) - goto free; - - if (preferred_bpp != 8 && preferred_bpp != 16 && preferred_bpp != 32) { - if (drm->client.device.info.ram_size <= 32 * 1024 * 1024) - preferred_bpp = 8; - else - if (drm->client.device.info.ram_size <= 64 * 1024 * 1024) - preferred_bpp = 16; - else - preferred_bpp = 32; - } - - /* disable all the possible outputs/crtcs before entering KMS mode */ - if (!drm_drv_uses_atomic_modeset(dev)) - drm_helper_disable_unused_functions(dev); - - ret = drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp); - if (ret) - goto fini; - - if (fbcon->helper.info) - fbcon->helper.info->pixmap.buf_align = 4; - return 0; - -fini: - drm_fb_helper_fini(&fbcon->helper); -free: - kfree(fbcon); - drm->fbcon = NULL; - return ret; -} - -void -nouveau_fbcon_fini(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - - if (!drm->fbcon) - return; - - drm_kms_helper_poll_fini(dev); - nouveau_fbcon_accel_fini(dev); - nouveau_fbcon_destroy(dev, drm->fbcon); - kfree(drm->fbcon); - drm->fbcon = NULL; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/core/firmware.c b/drivers/gpu/drm/nouveau/nvkm/core/firmware.c index fcf2a002f6cb..91fb494d4009 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/firmware.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/firmware.c @@ -151,6 +151,9 @@ nvkm_firmware_mem_page(struct nvkm_memory *memory) static enum nvkm_memory_target nvkm_firmware_mem_target(struct nvkm_memory *memory) { + if (nvkm_firmware_mem(memory)->device->func->tegra) + return NVKM_MEM_TARGET_NCOH; + return NVKM_MEM_TARGET_HOST; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 364fea320cb3..1c81e5b34d29 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2405,7 +2405,7 @@ nv162_chipset = { .bus = { 0x00000001, gf100_bus_new }, .devinit = { 0x00000001, tu102_devinit_new }, .fault = { 0x00000001, tu102_fault_new }, - .fb = { 0x00000001, gv100_fb_new }, + .fb = { 0x00000001, tu102_fb_new }, .fuse = { 0x00000001, gm107_fuse_new }, .gpio = { 0x00000001, gk104_gpio_new }, .gsp = { 0x00000001, gv100_gsp_new }, @@ -2440,7 +2440,7 @@ nv164_chipset = { .bus = { 0x00000001, gf100_bus_new }, .devinit = { 0x00000001, tu102_devinit_new }, .fault = { 0x00000001, tu102_fault_new }, - .fb = { 0x00000001, gv100_fb_new }, + .fb = { 0x00000001, tu102_fb_new }, .fuse = { 0x00000001, gm107_fuse_new }, .gpio = { 0x00000001, gk104_gpio_new }, .gsp = { 0x00000001, gv100_gsp_new }, @@ -2475,7 +2475,7 @@ nv166_chipset = { .bus = { 0x00000001, gf100_bus_new }, .devinit = { 0x00000001, tu102_devinit_new }, .fault = { 0x00000001, tu102_fault_new }, - .fb = { 0x00000001, gv100_fb_new }, + .fb = { 0x00000001, tu102_fb_new }, .fuse = { 0x00000001, gm107_fuse_new }, .gpio = { 0x00000001, gk104_gpio_new }, .gsp = { 0x00000001, gv100_gsp_new }, @@ -2510,7 +2510,7 @@ nv167_chipset = { .bus = { 0x00000001, gf100_bus_new }, .devinit = { 0x00000001, tu102_devinit_new }, .fault = { 0x00000001, tu102_fault_new }, - .fb = { 0x00000001, gv100_fb_new }, + .fb = { 0x00000001, tu102_fb_new }, .fuse = { 0x00000001, gm107_fuse_new }, .gpio = { 0x00000001, gk104_gpio_new }, .gsp = { 0x00000001, gv100_gsp_new }, @@ -2545,7 +2545,7 @@ nv168_chipset = { .bus = { 0x00000001, gf100_bus_new }, .devinit = { 0x00000001, tu102_devinit_new }, .fault = { 0x00000001, tu102_fault_new }, - .fb = { 0x00000001, gv100_fb_new }, + .fb = { 0x00000001, tu102_fb_new }, .fuse = { 0x00000001, gm107_fuse_new }, .gpio = { 0x00000001, gk104_gpio_new }, .gsp = { 0x00000001, gv100_gsp_new }, diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c b/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c index 393ade9f7e6c..b7da3ab44c27 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c @@ -48,6 +48,16 @@ gm200_flcn_pio_dmem_rd(struct nvkm_falcon *falcon, u8 port, const u8 *img, int l img += 4; len -= 4; } + + /* Sigh. Tegra PMU FW's init message... */ + if (len) { + u32 data = nvkm_falcon_rd32(falcon, 0x1c4 + (port * 8)); + + while (len--) { + *(u8 *)img++ = data & 0xff; + data >>= 8; + } + } } static void @@ -64,6 +74,8 @@ gm200_flcn_pio_dmem_wr(struct nvkm_falcon *falcon, u8 port, const u8 *img, int l img += 4; len -= 4; } + + WARN_ON(len); } static void @@ -74,7 +86,7 @@ gm200_flcn_pio_dmem_wr_init(struct nvkm_falcon *falcon, u8 port, bool sec, u32 d const struct nvkm_falcon_func_pio gm200_flcn_dmem_pio = { - .min = 4, + .min = 1, .max = 0x100, .wr_init = gm200_flcn_pio_dmem_wr_init, .wr = gm200_flcn_pio_dmem_wr, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c index 634f64f88fc8..81a1ad2c88a7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c @@ -65,10 +65,33 @@ tu102_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq) return ret; } +static int +tu102_devinit_wait(struct nvkm_device *device) +{ + unsigned timeout = 50 + 2000; + + do { + if (nvkm_rd32(device, 0x118128) & 0x00000001) { + if ((nvkm_rd32(device, 0x118234) & 0x000000ff) == 0xff) + return 0; + } + + usleep_range(1000, 2000); + } while (timeout--); + + return -ETIMEDOUT; +} + int tu102_devinit_post(struct nvkm_devinit *base, bool post) { struct nv50_devinit *init = nv50_devinit(base); + int ret; + + ret = tu102_devinit_wait(init->base.subdev.device); + if (ret) + return ret; + gm200_devinit_preos(init, post); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild index 5d0bab8ecb43..6ba5120a2ebe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild @@ -32,6 +32,7 @@ nvkm-y += nvkm/subdev/fb/gp100.o nvkm-y += nvkm/subdev/fb/gp102.o nvkm-y += nvkm/subdev/fb/gp10b.o nvkm-y += nvkm/subdev/fb/gv100.o +nvkm-y += nvkm/subdev/fb/tu102.o nvkm-y += nvkm/subdev/fb/ga100.o nvkm-y += nvkm/subdev/fb/ga102.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c index 8b7c8ea5e8a5..5a21b0ae4595 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c @@ -40,12 +40,6 @@ ga102_fb_vpr_scrub(struct nvkm_fb *fb) return ret; } -static bool -ga102_fb_vpr_scrub_required(struct nvkm_fb *fb) -{ - return (nvkm_rd32(fb->subdev.device, 0x1fa80c) & 0x00000010) != 0; -} - static const struct nvkm_fb_func ga102_fb = { .dtor = gf100_fb_dtor, @@ -56,7 +50,7 @@ ga102_fb = { .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .ram_new = ga102_ram_new, .default_bigpage = 16, - .vpr.scrub_required = ga102_fb_vpr_scrub_required, + .vpr.scrub_required = tu102_fb_vpr_scrub_required, .vpr.scrub = ga102_fb_vpr_scrub, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c index 1f0126437c1a..0e3c0a8f5d71 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c @@ -49,8 +49,3 @@ gv100_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, s } MODULE_FIRMWARE("nvidia/gv100/nvdec/scrubber.bin"); -MODULE_FIRMWARE("nvidia/tu102/nvdec/scrubber.bin"); -MODULE_FIRMWARE("nvidia/tu104/nvdec/scrubber.bin"); -MODULE_FIRMWARE("nvidia/tu106/nvdec/scrubber.bin"); -MODULE_FIRMWARE("nvidia/tu116/nvdec/scrubber.bin"); -MODULE_FIRMWARE("nvidia/tu117/nvdec/scrubber.bin"); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h index ac03eac0f261..f517751f94ac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h @@ -89,4 +89,6 @@ bool gp102_fb_vpr_scrub_required(struct nvkm_fb *); int gp102_fb_vpr_scrub(struct nvkm_fb *); int gv100_fb_init_page(struct nvkm_fb *); + +bool tu102_fb_vpr_scrub_required(struct nvkm_fb *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/tu102.c new file mode 100644 index 000000000000..be82af0364ee --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/tu102.c @@ -0,0 +1,55 @@ +/* + * Copyright 2018 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "gf100.h" +#include "ram.h" + +bool +tu102_fb_vpr_scrub_required(struct nvkm_fb *fb) +{ + return (nvkm_rd32(fb->subdev.device, 0x1fa80c) & 0x00000010) != 0; +} + +static const struct nvkm_fb_func +tu102_fb = { + .dtor = gf100_fb_dtor, + .oneinit = gf100_fb_oneinit, + .init = gm200_fb_init, + .init_page = gv100_fb_init_page, + .init_unkn = gp100_fb_init_unkn, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, + .vpr.scrub_required = tu102_fb_vpr_scrub_required, + .vpr.scrub = gp102_fb_vpr_scrub, + .ram_new = gp100_ram_new, + .default_bigpage = 16, +}; + +int +tu102_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb) +{ + return gp102_fb_new_(&tu102_fb, device, type, inst, pfb); +} + +MODULE_FIRMWARE("nvidia/tu102/nvdec/scrubber.bin"); +MODULE_FIRMWARE("nvidia/tu104/nvdec/scrubber.bin"); +MODULE_FIRMWARE("nvidia/tu106/nvdec/scrubber.bin"); +MODULE_FIRMWARE("nvidia/tu116/nvdec/scrubber.bin"); +MODULE_FIRMWARE("nvidia/tu117/nvdec/scrubber.bin"); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c index a72403777329..2ed04da3621d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c @@ -225,7 +225,7 @@ gm20b_pmu_init(struct nvkm_pmu *pmu) pmu->initmsg_received = false; - nvkm_falcon_load_dmem(falcon, &args, addr_args, sizeof(args), 0); + nvkm_falcon_pio_wr(falcon, (u8 *)&args, 0, 0, DMEM, addr_args, sizeof(args), 0, false); nvkm_falcon_start(falcon); return 0; } diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c index 857a2f0420d7..c924f1124ebc 100644 --- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c +++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c @@ -1193,14 +1193,11 @@ static int boe_panel_enter_sleep_mode(struct boe_panel *boe) return 0; } -static int boe_panel_unprepare(struct drm_panel *panel) +static int boe_panel_disable(struct drm_panel *panel) { struct boe_panel *boe = to_boe_panel(panel); int ret; - if (!boe->prepared) - return 0; - ret = boe_panel_enter_sleep_mode(boe); if (ret < 0) { dev_err(panel->dev, "failed to set panel off: %d\n", ret); @@ -1209,6 +1206,16 @@ static int boe_panel_unprepare(struct drm_panel *panel) msleep(150); + return 0; +} + +static int boe_panel_unprepare(struct drm_panel *panel) +{ + struct boe_panel *boe = to_boe_panel(panel); + + if (!boe->prepared) + return 0; + if (boe->desc->discharge_on_disable) { regulator_disable(boe->avee); regulator_disable(boe->avdd); @@ -1528,6 +1535,7 @@ static enum drm_panel_orientation boe_panel_get_orientation(struct drm_panel *pa } static const struct drm_panel_funcs boe_panel_funcs = { + .disable = boe_panel_disable, .unprepare = boe_panel_unprepare, .prepare = boe_panel_prepare, .enable = boe_panel_enable, diff --git a/drivers/gpu/drm/panfrost/Kconfig b/drivers/gpu/drm/panfrost/Kconfig index 079600328be1..e6403a9d66ad 100644 --- a/drivers/gpu/drm/panfrost/Kconfig +++ b/drivers/gpu/drm/panfrost/Kconfig @@ -3,7 +3,8 @@ config DRM_PANFROST tristate "Panfrost (DRM support for ARM Mali Midgard/Bifrost GPUs)" depends on DRM - depends on ARM || ARM64 || (COMPILE_TEST && !GENERIC_ATOMIC64) + depends on ARM || ARM64 || COMPILE_TEST + depends on !GENERIC_ATOMIC64 # for IOMMU_IO_PGTABLE_LPAE depends on MMU select DRM_SCHED select IOMMU_SUPPORT diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index 2fa5afe21288..919e6cc04982 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -82,6 +82,7 @@ static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data, struct panfrost_gem_object *bo; struct drm_panfrost_create_bo *args = data; struct panfrost_gem_mapping *mapping; + int ret; if (!args->size || args->pad || (args->flags & ~(PANFROST_BO_NOEXEC | PANFROST_BO_HEAP))) @@ -92,21 +93,29 @@ static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data, !(args->flags & PANFROST_BO_NOEXEC)) return -EINVAL; - bo = panfrost_gem_create_with_handle(file, dev, args->size, args->flags, - &args->handle); + bo = panfrost_gem_create(dev, args->size, args->flags); if (IS_ERR(bo)) return PTR_ERR(bo); + ret = drm_gem_handle_create(file, &bo->base.base, &args->handle); + if (ret) + goto out; + mapping = panfrost_gem_mapping_get(bo, priv); - if (!mapping) { - drm_gem_object_put(&bo->base.base); - return -EINVAL; + if (mapping) { + args->offset = mapping->mmnode.start << PAGE_SHIFT; + panfrost_gem_mapping_put(mapping); + } else { + /* This can only happen if the handle from + * drm_gem_handle_create() has already been guessed and freed + * by user space + */ + ret = -EINVAL; } - args->offset = mapping->mmnode.start << PAGE_SHIFT; - panfrost_gem_mapping_put(mapping); - - return 0; +out: + drm_gem_object_put(&bo->base.base); + return ret; } /** diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c index 293e799e2fe8..3c812fbd126f 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gem.c +++ b/drivers/gpu/drm/panfrost/panfrost_gem.c @@ -235,12 +235,8 @@ struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t } struct panfrost_gem_object * -panfrost_gem_create_with_handle(struct drm_file *file_priv, - struct drm_device *dev, size_t size, - u32 flags, - uint32_t *handle) +panfrost_gem_create(struct drm_device *dev, size_t size, u32 flags) { - int ret; struct drm_gem_shmem_object *shmem; struct panfrost_gem_object *bo; @@ -256,16 +252,6 @@ panfrost_gem_create_with_handle(struct drm_file *file_priv, bo->noexec = !!(flags & PANFROST_BO_NOEXEC); bo->is_heap = !!(flags & PANFROST_BO_HEAP); - /* - * Allocate an id of idr table where the obj is registered - * and handle has the id what user can see. - */ - ret = drm_gem_handle_create(file_priv, &shmem->base, handle); - /* drop reference from allocate - handle holds it now. */ - drm_gem_object_put(&shmem->base); - if (ret) - return ERR_PTR(ret); - return bo; } diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h b/drivers/gpu/drm/panfrost/panfrost_gem.h index 8088d5fd8480..ad2877eeeccd 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gem.h +++ b/drivers/gpu/drm/panfrost/panfrost_gem.h @@ -69,10 +69,7 @@ panfrost_gem_prime_import_sg_table(struct drm_device *dev, struct sg_table *sgt); struct panfrost_gem_object * -panfrost_gem_create_with_handle(struct drm_file *file_priv, - struct drm_device *dev, size_t size, - u32 flags, - uint32_t *handle); +panfrost_gem_create(struct drm_device *dev, size_t size, u32 flags); int panfrost_gem_open(struct drm_gem_object *obj, struct drm_file *file_priv); void panfrost_gem_close(struct drm_gem_object *obj, diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index fe09e5be79bd..15d04a0ec623 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -81,7 +81,7 @@ int drm_sched_entity_init(struct drm_sched_entity *entity, init_completion(&entity->entity_idle); /* We start in an idle state. */ - complete(&entity->entity_idle); + complete_all(&entity->entity_idle); spin_lock_init(&entity->rq_lock); spsc_queue_init(&entity->job_queue); diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 31f3a1267be4..fd22d753b4ed 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -987,7 +987,7 @@ static int drm_sched_main(void *param) sched_job = drm_sched_entity_pop_job(entity); if (!sched_job) { - complete(&entity->entity_idle); + complete_all(&entity->entity_idle); continue; } @@ -998,7 +998,7 @@ static int drm_sched_main(void *param) trace_drm_run_job(sched_job, entity); fence = sched->ops->run_job(sched_job); - complete(&entity->entity_idle); + complete_all(&entity->entity_idle); drm_sched_fence_scheduled(s_fence); if (!IS_ERR_OR_NULL(fence)) { diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index 53464afc2b9a..91f69e62430b 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -656,18 +656,8 @@ static const struct drm_crtc_helper_funcs ssd130x_crtc_helper_funcs = { .atomic_check = drm_crtc_helper_atomic_check, }; -static void ssd130x_crtc_reset(struct drm_crtc *crtc) -{ - struct drm_device *drm = crtc->dev; - struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); - - ssd130x_init(ssd130x); - - drm_atomic_helper_crtc_reset(crtc); -} - static const struct drm_crtc_funcs ssd130x_crtc_funcs = { - .reset = ssd130x_crtc_reset, + .reset = drm_atomic_helper_crtc_reset, .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, @@ -686,6 +676,12 @@ static void ssd130x_encoder_helper_atomic_enable(struct drm_encoder *encoder, if (ret) return; + ret = ssd130x_init(ssd130x); + if (ret) { + ssd130x_power_off(ssd130x); + return; + } + ssd130x_write_cmd(ssd130x, 1, SSD130X_DISPLAY_ON); backlight_enable(ssd130x->bl_dev); diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile index b29ef1085cad..f896ef85c2f2 100644 --- a/drivers/gpu/drm/tests/Makefile +++ b/drivers/gpu/drm/tests/Makefile @@ -12,3 +12,5 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \ drm_mm_test.o \ drm_plane_helper_test.o \ drm_rect_test.o + +CFLAGS_drm_mm_test.o := $(DISABLE_STRUCTLEAK_PLUGIN) diff --git a/drivers/gpu/drm/tests/drm_mm_test.c b/drivers/gpu/drm/tests/drm_mm_test.c index 89f12d3b4a21..186b28dc7038 100644 --- a/drivers/gpu/drm/tests/drm_mm_test.c +++ b/drivers/gpu/drm/tests/drm_mm_test.c @@ -298,9 +298,9 @@ static bool expect_reserve_fail(struct kunit *test, struct drm_mm *mm, struct dr return false; } -static bool check_reserve_boundaries(struct kunit *test, struct drm_mm *mm, - unsigned int count, - u64 size) +static bool noinline_for_stack check_reserve_boundaries(struct kunit *test, struct drm_mm *mm, + unsigned int count, + u64 size) { const struct boundary { u64 start, size; diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index ba3aa0a0fc43..da5493f789df 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -173,7 +173,7 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, clear = src_iter->ops->maps_tt && (!ttm || !ttm_tt_is_populated(ttm)); if (!(clear && ttm && !(ttm->page_flags & TTM_TT_FLAG_ZERO_ALLOC))) - ttm_move_memcpy(clear, ttm->num_pages, dst_iter, src_iter); + ttm_move_memcpy(clear, PFN_UP(dst_mem->size), dst_iter, src_iter); if (!src_iter->ops->maps_tt) ttm_kmap_iter_linear_io_fini(&_src_iter.io, bdev, src_mem); diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index 43d9b3a6a352..c5947ed8cc81 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -179,6 +179,7 @@ static void vc4_bo_destroy(struct vc4_bo *bo) bo->validated_shader = NULL; } + mutex_destroy(&bo->madv_lock); drm_gem_dma_free(&bo->base); } @@ -394,7 +395,6 @@ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size) { struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_bo *bo; - int ret; if (WARN_ON_ONCE(vc4->is_vc5)) return ERR_PTR(-ENODEV); @@ -406,9 +406,7 @@ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size) bo->madv = VC4_MADV_WILLNEED; refcount_set(&bo->usecnt, 0); - ret = drmm_mutex_init(dev, &bo->madv_lock); - if (ret) - return ERR_PTR(ret); + mutex_init(&bo->madv_lock); mutex_lock(&vc4->bo_lock); bo->label = VC4_BO_TYPE_KERNEL; diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 0108613e79d5..7258975331ca 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -711,7 +711,7 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc, struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder); if (vc4_encoder->type == VC4_ENCODER_TYPE_HDMI0) { - vc4_state->hvs_load = max(mode->clock * mode->hdisplay / mode->htotal + 1000, + vc4_state->hvs_load = max(mode->clock * mode->hdisplay / mode->htotal + 8000, mode->clock * 9 / 10) * 1000; } else { vc4_state->hvs_load = mode->clock * 1000; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 12a00d644b61..7546103f1499 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -97,6 +97,10 @@ #define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_SHIFT 8 #define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_MASK VC4_MASK(15, 8) +#define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_0_MASK VC4_MASK(7, 0) +#define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_0_SET_AVMUTE BIT(0) +#define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_0_CLEAR_AVMUTE BIT(4) + # define VC4_HD_M_SW_RST BIT(2) # define VC4_HD_M_ENABLE BIT(0) @@ -1306,7 +1310,6 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, VC4_HDMI_VERTB_VBP)); unsigned long flags; unsigned char gcp; - bool gcp_en; u32 reg; int idx; @@ -1341,16 +1344,13 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, switch (vc4_state->output_bpc) { case 12: gcp = 6; - gcp_en = true; break; case 10: gcp = 5; - gcp_en = true; break; case 8: default: - gcp = 4; - gcp_en = false; + gcp = 0; break; } @@ -1359,8 +1359,7 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, * doesn't signal in GCP. */ if (vc4_state->output_format == VC4_HDMI_OUTPUT_YUV422) { - gcp = 4; - gcp_en = false; + gcp = 0; } reg = HDMI_READ(HDMI_DEEP_COLOR_CONFIG_1); @@ -1373,11 +1372,12 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, reg = HDMI_READ(HDMI_GCP_WORD_1); reg &= ~VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_MASK; reg |= VC4_SET_FIELD(gcp, VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1); + reg &= ~VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_0_MASK; + reg |= VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_0_CLEAR_AVMUTE; HDMI_WRITE(HDMI_GCP_WORD_1, reg); reg = HDMI_READ(HDMI_GCP_CONFIG); - reg &= ~VC5_HDMI_GCP_CONFIG_GCP_ENABLE; - reg |= gcp_en ? VC5_HDMI_GCP_CONFIG_GCP_ENABLE : 0; + reg |= VC5_HDMI_GCP_CONFIG_GCP_ENABLE; HDMI_WRITE(HDMI_GCP_CONFIG, reg); reg = HDMI_READ(HDMI_MISC_CONTROL); @@ -3018,7 +3018,8 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) } vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops, - vc4_hdmi, "vc4", + vc4_hdmi, + vc4_hdmi->variant->card_name, CEC_CAP_DEFAULTS | CEC_CAP_CONNECTOR_INFO, 1); ret = PTR_ERR_OR_ZERO(vc4_hdmi->cec_adap); diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 8b92a45a3c89..bd5acc4a8687 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -340,7 +340,7 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) { struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); struct drm_framebuffer *fb = state->fb; - struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, 0); + struct drm_gem_dma_object *bo; int num_planes = fb->format->num_planes; struct drm_crtc_state *crtc_state; u32 h_subsample = fb->format->hsub; @@ -359,8 +359,10 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) if (ret) return ret; - for (i = 0; i < num_planes; i++) + for (i = 0; i < num_planes; i++) { + bo = drm_fb_dma_get_gem_obj(fb, i); vc4_state->offsets[i] = bo->dma_addr + fb->offsets[i]; + } /* * We don't support subpixel source positioning for scaling, diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 5d05093014ac..da45215a933d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -126,7 +126,6 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, void __user *user_bo_handles = NULL; struct virtio_gpu_object_array *buflist = NULL; struct sync_file *sync_file; - int in_fence_fd = exbuf->fence_fd; int out_fence_fd = -1; void *buf; uint64_t fence_ctx; @@ -152,13 +151,11 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, ring_idx = exbuf->ring_idx; } - exbuf->fence_fd = -1; - virtio_gpu_create_context(dev, file); if (exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_IN) { struct dma_fence *in_fence; - in_fence = sync_file_get_fence(in_fence_fd); + in_fence = sync_file_get_fence(exbuf->fence_fd); if (!in_fence) return -EINVAL; @@ -358,10 +355,18 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data, drm_gem_object_release(obj); return ret; } - drm_gem_object_put(obj); rc->res_handle = qobj->hw_res_handle; /* similiar to a VM address */ rc->bo_handle = handle; + + /* + * The handle owns the reference now. But we must drop our + * remaining reference *after* we no longer need to dereference + * the obj. Otherwise userspace could guess the handle and + * race closing it from another thread. + */ + drm_gem_object_put(obj); + return 0; } @@ -723,11 +728,18 @@ static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev, drm_gem_object_release(obj); return ret; } - drm_gem_object_put(obj); rc_blob->res_handle = bo->hw_res_handle; rc_blob->bo_handle = handle; + /* + * The handle owns the reference now. But we must drop our + * remaining reference *after* we no longer need to dereference + * the obj. Otherwise userspace could guess the handle and + * race closing it from another thread. + */ + drm_gem_object_put(obj); + return 0; } diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index 8d7728181de0..c7e74cf13022 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -184,7 +184,7 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, struct virtio_gpu_object_array *objs = NULL; struct drm_gem_shmem_object *shmem_obj; struct virtio_gpu_object *bo; - struct virtio_gpu_mem_entry *ents; + struct virtio_gpu_mem_entry *ents = NULL; unsigned int nents; int ret; @@ -210,7 +210,7 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, ret = -ENOMEM; objs = virtio_gpu_array_alloc(1); if (!objs) - goto err_put_id; + goto err_free_entry; virtio_gpu_array_add_obj(objs, &bo->base.base); ret = virtio_gpu_array_lock_resv(objs); @@ -239,6 +239,8 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, err_put_objs: virtio_gpu_array_put_free(objs); +err_free_entry: + kvfree(ents); err_put_id: virtio_gpu_resource_id_put(vgdev, bo->hw_res_handle); err_free_gem: diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.c b/drivers/gpu/drm/vmwgfx/ttm_object.c index 932b125ebf3d..ddf8373c1d77 100644 --- a/drivers/gpu/drm/vmwgfx/ttm_object.c +++ b/drivers/gpu/drm/vmwgfx/ttm_object.c @@ -254,40 +254,6 @@ void ttm_base_object_unref(struct ttm_base_object **p_base) kref_put(&base->refcount, ttm_release_base); } -/** - * ttm_base_object_noref_lookup - look up a base object without reference - * @tfile: The struct ttm_object_file the object is registered with. - * @key: The object handle. - * - * This function looks up a ttm base object and returns a pointer to it - * without refcounting the pointer. The returned pointer is only valid - * until ttm_base_object_noref_release() is called, and the object - * pointed to by the returned pointer may be doomed. Any persistent usage - * of the object requires a refcount to be taken using kref_get_unless_zero(). - * Iff this function returns successfully it needs to be paired with - * ttm_base_object_noref_release() and no sleeping- or scheduling functions - * may be called inbetween these function callse. - * - * Return: A pointer to the object if successful or NULL otherwise. - */ -struct ttm_base_object * -ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key) -{ - struct vmwgfx_hash_item *hash; - int ret; - - rcu_read_lock(); - ret = ttm_tfile_find_ref_rcu(tfile, key, &hash); - if (ret) { - rcu_read_unlock(); - return NULL; - } - - __release(RCU); - return hlist_entry(hash, struct ttm_ref_object, hash)->obj; -} -EXPORT_SYMBOL(ttm_base_object_noref_lookup); - struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, uint64_t key) { @@ -295,15 +261,16 @@ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, struct vmwgfx_hash_item *hash; int ret; - rcu_read_lock(); - ret = ttm_tfile_find_ref_rcu(tfile, key, &hash); + spin_lock(&tfile->lock); + ret = ttm_tfile_find_ref(tfile, key, &hash); if (likely(ret == 0)) { base = hlist_entry(hash, struct ttm_ref_object, hash)->obj; if (!kref_get_unless_zero(&base->refcount)) base = NULL; } - rcu_read_unlock(); + spin_unlock(&tfile->lock); + return base; } diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.h b/drivers/gpu/drm/vmwgfx/ttm_object.h index f0ebbe340ad6..8098a3846bae 100644 --- a/drivers/gpu/drm/vmwgfx/ttm_object.h +++ b/drivers/gpu/drm/vmwgfx/ttm_object.h @@ -307,18 +307,4 @@ extern int ttm_prime_handle_to_fd(struct ttm_object_file *tfile, #define ttm_prime_object_kfree(__obj, __prime) \ kfree_rcu(__obj, __prime.base.rhead) -struct ttm_base_object * -ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key); - -/** - * ttm_base_object_noref_release - release a base object pointer looked up - * without reference - * - * Releases a base object pointer looked up with ttm_base_object_noref_lookup(). - */ -static inline void ttm_base_object_noref_release(void) -{ - __acquire(RCU); - rcu_read_unlock(); -} #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index 321c551784a1..4dcf2eb7aa80 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -462,6 +462,9 @@ int vmw_bo_create(struct vmw_private *vmw, return -ENOMEM; } + /* + * vmw_bo_init will delete the *p_bo object if it fails + */ ret = vmw_bo_init(vmw, *p_bo, size, placement, interruptible, pin, bo_free); @@ -470,7 +473,6 @@ int vmw_bo_create(struct vmw_private *vmw, return ret; out_error: - kfree(*p_bo); *p_bo = NULL; return ret; } @@ -596,6 +598,7 @@ static int vmw_user_bo_synccpu_release(struct drm_file *filp, ttm_bo_put(&vmw_bo->base); } + drm_gem_object_put(&vmw_bo->base.base); return ret; } @@ -636,6 +639,7 @@ int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, ret = vmw_user_bo_synccpu_grab(vbo, arg->flags); vmw_bo_unreference(&vbo); + drm_gem_object_put(&vbo->base.base); if (unlikely(ret != 0)) { if (ret == -ERESTARTSYS || ret == -EBUSY) return -EBUSY; @@ -693,7 +697,7 @@ int vmw_bo_unref_ioctl(struct drm_device *dev, void *data, * struct vmw_buffer_object should be placed. * Return: Zero on success, Negative error code on error. * - * The vmw buffer object pointer will be refcounted. + * The vmw buffer object pointer will be refcounted (both ttm and gem) */ int vmw_user_bo_lookup(struct drm_file *filp, uint32_t handle, @@ -710,50 +714,11 @@ int vmw_user_bo_lookup(struct drm_file *filp, *out = gem_to_vmw_bo(gobj); ttm_bo_get(&(*out)->base); - drm_gem_object_put(gobj); return 0; } /** - * vmw_user_bo_noref_lookup - Look up a vmw user buffer object without reference - * @filp: The TTM object file the handle is registered with. - * @handle: The user buffer object handle. - * - * This function looks up a struct vmw_bo and returns a pointer to the - * struct vmw_buffer_object it derives from without refcounting the pointer. - * The returned pointer is only valid until vmw_user_bo_noref_release() is - * called, and the object pointed to by the returned pointer may be doomed. - * Any persistent usage of the object requires a refcount to be taken using - * ttm_bo_reference_unless_doomed(). Iff this function returns successfully it - * needs to be paired with vmw_user_bo_noref_release() and no sleeping- - * or scheduling functions may be called in between these function calls. - * - * Return: A struct vmw_buffer_object pointer if successful or negative - * error pointer on failure. - */ -struct vmw_buffer_object * -vmw_user_bo_noref_lookup(struct drm_file *filp, u32 handle) -{ - struct vmw_buffer_object *vmw_bo; - struct ttm_buffer_object *bo; - struct drm_gem_object *gobj = drm_gem_object_lookup(filp, handle); - - if (!gobj) { - DRM_ERROR("Invalid buffer object handle 0x%08lx.\n", - (unsigned long)handle); - return ERR_PTR(-ESRCH); - } - vmw_bo = gem_to_vmw_bo(gobj); - bo = ttm_bo_get_unless_zero(&vmw_bo->base); - vmw_bo = vmw_buffer_object(bo); - drm_gem_object_put(gobj); - - return vmw_bo; -} - - -/** * vmw_bo_fence_single - Utility function to fence a single TTM buffer * object without unreserving it. * @@ -829,7 +794,8 @@ int vmw_dumb_create(struct drm_file *file_priv, ret = vmw_gem_object_create_with_handle(dev_priv, file_priv, args->size, &args->handle, &vbo); - + /* drop reference from allocate - handle holds it now */ + drm_gem_object_put(&vbo->base.base); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index b062b020b378..5acbf5849b27 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -830,12 +830,7 @@ extern int vmw_user_resource_lookup_handle( uint32_t handle, const struct vmw_user_resource_conv *converter, struct vmw_resource **p_res); -extern struct vmw_resource * -vmw_user_resource_noref_lookup_handle(struct vmw_private *dev_priv, - struct ttm_object_file *tfile, - uint32_t handle, - const struct vmw_user_resource_conv * - converter); + extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data, @@ -875,15 +870,6 @@ static inline bool vmw_resource_mob_attached(const struct vmw_resource *res) } /** - * vmw_user_resource_noref_release - release a user resource pointer looked up - * without reference - */ -static inline void vmw_user_resource_noref_release(void) -{ - ttm_base_object_noref_release(); -} - -/** * Buffer object helper functions - vmwgfx_bo.c */ extern int vmw_bo_pin_in_placement(struct vmw_private *vmw_priv, @@ -934,8 +920,6 @@ extern void vmw_bo_unmap(struct vmw_buffer_object *vbo); extern void vmw_bo_move_notify(struct ttm_buffer_object *bo, struct ttm_resource *mem); extern void vmw_bo_swap_notify(struct ttm_buffer_object *bo); -extern struct vmw_buffer_object * -vmw_user_bo_noref_lookup(struct drm_file *filp, u32 handle); /** * vmw_bo_adjust_prio - Adjust the buffer object eviction priority diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index a5379f6fb5ab..c0686283ffd1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -290,20 +290,26 @@ static void vmw_execbuf_rcache_update(struct vmw_res_cache_entry *rcache, rcache->valid_handle = 0; } +enum vmw_val_add_flags { + vmw_val_add_flag_none = 0, + vmw_val_add_flag_noctx = 1 << 0, +}; + /** - * vmw_execbuf_res_noref_val_add - Add a resource described by an unreferenced - * rcu-protected pointer to the validation list. + * vmw_execbuf_res_val_add - Add a resource to the validation list. * * @sw_context: Pointer to the software context. * @res: Unreferenced rcu-protected pointer to the resource. * @dirty: Whether to change dirty status. + * @flags: specifies whether to use the context or not * * Returns: 0 on success. Negative error code on failure. Typical error codes * are %-EINVAL on inconsistency and %-ESRCH if the resource was doomed. */ -static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context, - struct vmw_resource *res, - u32 dirty) +static int vmw_execbuf_res_val_add(struct vmw_sw_context *sw_context, + struct vmw_resource *res, + u32 dirty, + u32 flags) { struct vmw_private *dev_priv = res->dev_priv; int ret; @@ -318,24 +324,30 @@ static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context, if (dirty) vmw_validation_res_set_dirty(sw_context->ctx, rcache->private, dirty); - vmw_user_resource_noref_release(); return 0; } - priv_size = vmw_execbuf_res_size(dev_priv, res_type); - ret = vmw_validation_add_resource(sw_context->ctx, res, priv_size, - dirty, (void **)&ctx_info, - &first_usage); - vmw_user_resource_noref_release(); - if (ret) - return ret; + if ((flags & vmw_val_add_flag_noctx) != 0) { + ret = vmw_validation_add_resource(sw_context->ctx, res, 0, dirty, + (void **)&ctx_info, NULL); + if (ret) + return ret; - if (priv_size && first_usage) { - ret = vmw_cmd_ctx_first_setup(dev_priv, sw_context, res, - ctx_info); - if (ret) { - VMW_DEBUG_USER("Failed first usage context setup.\n"); + } else { + priv_size = vmw_execbuf_res_size(dev_priv, res_type); + ret = vmw_validation_add_resource(sw_context->ctx, res, priv_size, + dirty, (void **)&ctx_info, + &first_usage); + if (ret) return ret; + + if (priv_size && first_usage) { + ret = vmw_cmd_ctx_first_setup(dev_priv, sw_context, res, + ctx_info); + if (ret) { + VMW_DEBUG_USER("Failed first usage context setup.\n"); + return ret; + } } } @@ -344,43 +356,6 @@ static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context, } /** - * vmw_execbuf_res_noctx_val_add - Add a non-context resource to the resource - * validation list if it's not already on it - * - * @sw_context: Pointer to the software context. - * @res: Pointer to the resource. - * @dirty: Whether to change dirty status. - * - * Returns: Zero on success. Negative error code on failure. - */ -static int vmw_execbuf_res_noctx_val_add(struct vmw_sw_context *sw_context, - struct vmw_resource *res, - u32 dirty) -{ - struct vmw_res_cache_entry *rcache; - enum vmw_res_type res_type = vmw_res_type(res); - void *ptr; - int ret; - - rcache = &sw_context->res_cache[res_type]; - if (likely(rcache->valid && rcache->res == res)) { - if (dirty) - vmw_validation_res_set_dirty(sw_context->ctx, - rcache->private, dirty); - return 0; - } - - ret = vmw_validation_add_resource(sw_context->ctx, res, 0, dirty, - &ptr, NULL); - if (ret) - return ret; - - vmw_execbuf_rcache_update(rcache, res, ptr); - - return 0; -} - -/** * vmw_view_res_val_add - Add a view and the surface it's pointing to to the * validation list * @@ -398,13 +373,13 @@ static int vmw_view_res_val_add(struct vmw_sw_context *sw_context, * First add the resource the view is pointing to, otherwise it may be * swapped out when the view is validated. */ - ret = vmw_execbuf_res_noctx_val_add(sw_context, vmw_view_srf(view), - vmw_view_dirtying(view)); + ret = vmw_execbuf_res_val_add(sw_context, vmw_view_srf(view), + vmw_view_dirtying(view), vmw_val_add_flag_noctx); if (ret) return ret; - return vmw_execbuf_res_noctx_val_add(sw_context, view, - VMW_RES_DIRTY_NONE); + return vmw_execbuf_res_val_add(sw_context, view, VMW_RES_DIRTY_NONE, + vmw_val_add_flag_noctx); } /** @@ -475,8 +450,9 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv, if (IS_ERR(res)) continue; - ret = vmw_execbuf_res_noctx_val_add(sw_context, res, - VMW_RES_DIRTY_SET); + ret = vmw_execbuf_res_val_add(sw_context, res, + VMW_RES_DIRTY_SET, + vmw_val_add_flag_noctx); if (unlikely(ret != 0)) return ret; } @@ -490,9 +466,9 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv, if (vmw_res_type(entry->res) == vmw_res_view) ret = vmw_view_res_val_add(sw_context, entry->res); else - ret = vmw_execbuf_res_noctx_val_add - (sw_context, entry->res, - vmw_binding_dirtying(entry->bt)); + ret = vmw_execbuf_res_val_add(sw_context, entry->res, + vmw_binding_dirtying(entry->bt), + vmw_val_add_flag_noctx); if (unlikely(ret != 0)) break; } @@ -658,7 +634,8 @@ vmw_cmd_res_check(struct vmw_private *dev_priv, { struct vmw_res_cache_entry *rcache = &sw_context->res_cache[res_type]; struct vmw_resource *res; - int ret; + int ret = 0; + bool needs_unref = false; if (p_res) *p_res = NULL; @@ -683,17 +660,18 @@ vmw_cmd_res_check(struct vmw_private *dev_priv, if (ret) return ret; - res = vmw_user_resource_noref_lookup_handle - (dev_priv, sw_context->fp->tfile, *id_loc, converter); - if (IS_ERR(res)) { + ret = vmw_user_resource_lookup_handle + (dev_priv, sw_context->fp->tfile, *id_loc, converter, &res); + if (ret != 0) { VMW_DEBUG_USER("Could not find/use resource 0x%08x.\n", (unsigned int) *id_loc); - return PTR_ERR(res); + return ret; } + needs_unref = true; - ret = vmw_execbuf_res_noref_val_add(sw_context, res, dirty); + ret = vmw_execbuf_res_val_add(sw_context, res, dirty, vmw_val_add_flag_none); if (unlikely(ret != 0)) - return ret; + goto res_check_done; if (rcache->valid && rcache->res == res) { rcache->valid_handle = true; @@ -708,7 +686,11 @@ vmw_cmd_res_check(struct vmw_private *dev_priv, if (p_res) *p_res = res; - return 0; +res_check_done: + if (needs_unref) + vmw_resource_unreference(&res); + + return ret; } /** @@ -1171,13 +1153,14 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, int ret; vmw_validation_preload_bo(sw_context->ctx); - vmw_bo = vmw_user_bo_noref_lookup(sw_context->filp, handle); - if (IS_ERR(vmw_bo)) { - VMW_DEBUG_USER("Could not find or use MOB buffer.\n"); + ret = vmw_user_bo_lookup(sw_context->filp, handle, &vmw_bo); + if (ret != 0) { + drm_dbg(&dev_priv->drm, "Could not find or use MOB buffer.\n"); return PTR_ERR(vmw_bo); } ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo, true, false); ttm_bo_put(&vmw_bo->base); + drm_gem_object_put(&vmw_bo->base.base); if (unlikely(ret != 0)) return ret; @@ -1225,13 +1208,14 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, int ret; vmw_validation_preload_bo(sw_context->ctx); - vmw_bo = vmw_user_bo_noref_lookup(sw_context->filp, handle); - if (IS_ERR(vmw_bo)) { - VMW_DEBUG_USER("Could not find or use GMR region.\n"); + ret = vmw_user_bo_lookup(sw_context->filp, handle, &vmw_bo); + if (ret != 0) { + drm_dbg(&dev_priv->drm, "Could not find or use GMR region.\n"); return PTR_ERR(vmw_bo); } ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo, false, false); ttm_bo_put(&vmw_bo->base); + drm_gem_object_put(&vmw_bo->base.base); if (unlikely(ret != 0)) return ret; @@ -2025,8 +2009,9 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv, res = vmw_shader_lookup(vmw_context_res_man(ctx), cmd->body.shid, cmd->body.type); if (!IS_ERR(res)) { - ret = vmw_execbuf_res_noctx_val_add(sw_context, res, - VMW_RES_DIRTY_NONE); + ret = vmw_execbuf_res_val_add(sw_context, res, + VMW_RES_DIRTY_NONE, + vmw_val_add_flag_noctx); if (unlikely(ret != 0)) return ret; @@ -2273,8 +2258,9 @@ static int vmw_cmd_dx_set_shader(struct vmw_private *dev_priv, return PTR_ERR(res); } - ret = vmw_execbuf_res_noctx_val_add(sw_context, res, - VMW_RES_DIRTY_NONE); + ret = vmw_execbuf_res_val_add(sw_context, res, + VMW_RES_DIRTY_NONE, + vmw_val_add_flag_noctx); if (ret) return ret; } @@ -2777,8 +2763,8 @@ static int vmw_cmd_dx_bind_shader(struct vmw_private *dev_priv, return PTR_ERR(res); } - ret = vmw_execbuf_res_noctx_val_add(sw_context, res, - VMW_RES_DIRTY_NONE); + ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE, + vmw_val_add_flag_noctx); if (ret) { VMW_DEBUG_USER("Error creating resource validation node.\n"); return ret; @@ -3098,8 +3084,8 @@ static int vmw_cmd_dx_bind_streamoutput(struct vmw_private *dev_priv, vmw_dx_streamoutput_set_size(res, cmd->body.sizeInBytes); - ret = vmw_execbuf_res_noctx_val_add(sw_context, res, - VMW_RES_DIRTY_NONE); + ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE, + vmw_val_add_flag_noctx); if (ret) { DRM_ERROR("Error creating resource validation node.\n"); return ret; @@ -3148,8 +3134,8 @@ static int vmw_cmd_dx_set_streamoutput(struct vmw_private *dev_priv, return 0; } - ret = vmw_execbuf_res_noctx_val_add(sw_context, res, - VMW_RES_DIRTY_NONE); + ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE, + vmw_val_add_flag_noctx); if (ret) { DRM_ERROR("Error creating resource validation node.\n"); return ret; @@ -4066,22 +4052,26 @@ static int vmw_execbuf_tie_context(struct vmw_private *dev_priv, if (ret) return ret; - res = vmw_user_resource_noref_lookup_handle + ret = vmw_user_resource_lookup_handle (dev_priv, sw_context->fp->tfile, handle, - user_context_converter); - if (IS_ERR(res)) { + user_context_converter, &res); + if (ret != 0) { VMW_DEBUG_USER("Could not find or user DX context 0x%08x.\n", (unsigned int) handle); - return PTR_ERR(res); + return ret; } - ret = vmw_execbuf_res_noref_val_add(sw_context, res, VMW_RES_DIRTY_SET); - if (unlikely(ret != 0)) + ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_SET, + vmw_val_add_flag_none); + if (unlikely(ret != 0)) { + vmw_resource_unreference(&res); return ret; + } sw_context->dx_ctx_node = vmw_execbuf_info_from_res(sw_context, res); sw_context->man = vmw_context_res_man(res); + vmw_resource_unreference(&res); return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c index ce609e7d758f..4d2c28e39f4e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c @@ -146,14 +146,12 @@ int vmw_gem_object_create_with_handle(struct vmw_private *dev_priv, &vmw_sys_placement : &vmw_vram_sys_placement, true, false, &vmw_gem_destroy, p_vbo); - - (*p_vbo)->base.base.funcs = &vmw_gem_object_funcs; if (ret != 0) goto out_no_bo; + (*p_vbo)->base.base.funcs = &vmw_gem_object_funcs; + ret = drm_gem_handle_create(filp, &(*p_vbo)->base.base, handle); - /* drop reference from allocate - handle holds it now */ - drm_gem_object_put(&(*p_vbo)->base.base); out_no_bo: return ret; } @@ -180,6 +178,8 @@ int vmw_gem_object_create_ioctl(struct drm_device *dev, void *data, rep->map_handle = drm_vma_node_offset_addr(&vbo->base.base.vma_node); rep->cur_gmr_id = handle; rep->cur_gmr_offset = 0; + /* drop reference from allocate - handle holds it now */ + drm_gem_object_put(&vbo->base.base); out_no_bo: return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 257f090071f1..445d619e1fdc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1815,8 +1815,10 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, err_out: /* vmw_user_lookup_handle takes one ref so does new_fb */ - if (bo) + if (bo) { vmw_bo_unreference(&bo); + drm_gem_object_put(&bo->base.base); + } if (surface) vmw_surface_unreference(&surface); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg_arm64.h b/drivers/gpu/drm/vmwgfx/vmwgfx_msg_arm64.h index 4f40167ad61f..4f40167ad61f 100755..100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg_arm64.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg_arm64.h diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index e9f5c89b4ca6..b5b311f2a91a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -458,6 +458,7 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data, ret = vmw_overlay_update_stream(dev_priv, buf, arg, true); vmw_bo_unreference(&buf); + drm_gem_object_put(&buf->base.base); out_unlock: mutex_unlock(&overlay->mutex); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index f66caa540e14..c7d645e5ec7b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -281,39 +281,6 @@ out_bad_resource: return ret; } -/** - * vmw_user_resource_noref_lookup_handle - lookup a struct resource from a - * TTM user-space handle and perform basic type checks - * - * @dev_priv: Pointer to a device private struct - * @tfile: Pointer to a struct ttm_object_file identifying the caller - * @handle: The TTM user-space handle - * @converter: Pointer to an object describing the resource type - * - * If the handle can't be found or is associated with an incorrect resource - * type, -EINVAL will be returned. - */ -struct vmw_resource * -vmw_user_resource_noref_lookup_handle(struct vmw_private *dev_priv, - struct ttm_object_file *tfile, - uint32_t handle, - const struct vmw_user_resource_conv - *converter) -{ - struct ttm_base_object *base; - - base = ttm_base_object_noref_lookup(tfile, handle); - if (!base) - return ERR_PTR(-ESRCH); - - if (unlikely(ttm_base_object_type(base) != converter->object_type)) { - ttm_base_object_noref_release(); - return ERR_PTR(-EINVAL); - } - - return converter->base_obj_to_res(base); -} - /* * Helper function that looks either a surface or bo. * diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index 108a496b5d18..51e83dfa1cac 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -807,6 +807,7 @@ static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv, num_output_sig, tfile, shader_handle); out_bad_arg: vmw_bo_unreference(&buffer); + drm_gem_object_put(&buffer->base.base); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 3bc63ae768f3..dcfb003841b3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -683,7 +683,7 @@ static void vmw_user_surface_base_release(struct ttm_base_object **p_base) container_of(base, struct vmw_user_surface, prime.base); struct vmw_resource *res = &user_srf->srf.res; - if (base->shareable && res && res->backup) + if (res && res->backup) drm_gem_object_put(&res->backup->base.base); *p_base = NULL; @@ -864,7 +864,11 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, goto out_unlock; } vmw_bo_reference(res->backup); - drm_gem_object_get(&res->backup->base.base); + /* + * We don't expose the handle to the userspace and surface + * already holds a gem reference + */ + drm_gem_handle_delete(file_priv, backup_handle); } tmp = vmw_resource_reference(&srf->res); @@ -1568,8 +1572,6 @@ vmw_gb_surface_define_internal(struct drm_device *dev, drm_vma_node_offset_addr(&res->backup->base.base.vma_node); rep->buffer_size = res->backup->base.base.size; rep->buffer_handle = backup_handle; - if (user_srf->prime.base.shareable) - drm_gem_object_get(&res->backup->base.base); } else { rep->buffer_map_handle = 0; rep->buffer_size = 0; diff --git a/drivers/gpu/drm/xen/xen_drm_front.c b/drivers/gpu/drm/xen/xen_drm_front.c index 0d8e6bd1ccbf..90996c108146 100644 --- a/drivers/gpu/drm/xen/xen_drm_front.c +++ b/drivers/gpu/drm/xen/xen_drm_front.c @@ -717,7 +717,7 @@ static int xen_drv_probe(struct xenbus_device *xb_dev, return xenbus_switch_state(xb_dev, XenbusStateInitialising); } -static int xen_drv_remove(struct xenbus_device *dev) +static void xen_drv_remove(struct xenbus_device *dev) { struct xen_drm_front_info *front_info = dev_get_drvdata(&dev->dev); int to = 100; @@ -751,7 +751,6 @@ static int xen_drv_remove(struct xenbus_device *dev) xen_drm_drv_fini(front_info); xenbus_frontend_closed(dev); - return 0; } static const struct xenbus_device_id xen_driver_ids[] = { diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c index ab125f79408f..c751d12f5df8 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c @@ -227,6 +227,7 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]); if (cl_data->num_hid_devices == 0) return -ENODEV; + cl_data->is_any_sensor_enabled = false; INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work); INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer); @@ -282,11 +283,12 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) } rc = mp2_ops->get_rep_desc(cl_idx, cl_data->report_descr[i]); if (rc) - return rc; + goto cleanup; mp2_ops->start(privdata, info); status = amd_sfh_wait_for_response (privdata, cl_data->sensor_idx[i], SENSOR_ENABLED); if (status == SENSOR_ENABLED) { + cl_data->is_any_sensor_enabled = true; cl_data->sensor_sts[i] = SENSOR_ENABLED; rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data); if (rc) { @@ -301,19 +303,26 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) cl_data->sensor_sts[i]); goto cleanup; } + } else { + cl_data->sensor_sts[i] = SENSOR_DISABLED; + dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n", + cl_data->sensor_idx[i], + get_sensor_name(cl_data->sensor_idx[i]), + cl_data->sensor_sts[i]); } dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n", cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), cl_data->sensor_sts[i]); } - if (mp2_ops->discovery_status && mp2_ops->discovery_status(privdata) == 0) { + if (!cl_data->is_any_sensor_enabled || + (mp2_ops->discovery_status && mp2_ops->discovery_status(privdata) == 0)) { amd_sfh_hid_client_deinit(privdata); for (i = 0; i < cl_data->num_hid_devices; i++) { devm_kfree(dev, cl_data->feature_report[i]); devm_kfree(dev, in_data->input_report[i]); devm_kfree(dev, cl_data->report_descr[i]); } - dev_warn(dev, "Failed to discover, sensors not enabled\n"); + dev_warn(dev, "Failed to discover, sensors not enabled is %d\n", cl_data->is_any_sensor_enabled); return -EOPNOTSUPP; } schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h index 3754fb423e3a..528036892c9d 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h @@ -32,6 +32,7 @@ struct amd_input_data { struct amdtp_cl_data { u8 init_done; u32 cur_hid_dev; + bool is_any_sensor_enabled; u32 hid_dev_count; u32 num_hid_devices; struct device_info *hid_devices; diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c index 4da2f9f62aba..a1d6e08fab7d 100644 --- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c @@ -160,7 +160,7 @@ static int amd_sfh1_1_hid_client_init(struct amd_mp2_dev *privdata) } rc = mp2_ops->get_rep_desc(cl_idx, cl_data->report_descr[i]); if (rc) - return rc; + goto cleanup; writel(0, privdata->mmio + AMD_P2C_MSG(0)); mp2_ops->start(privdata, info); diff --git a/drivers/hid/hid-betopff.c b/drivers/hid/hid-betopff.c index 467d789f9bc2..25ed7b9a917e 100644 --- a/drivers/hid/hid-betopff.c +++ b/drivers/hid/hid-betopff.c @@ -60,7 +60,6 @@ static int betopff_init(struct hid_device *hid) struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct input_dev *dev; - int field_count = 0; int error; int i, j; @@ -86,19 +85,21 @@ static int betopff_init(struct hid_device *hid) * ----------------------------------------- * Do init them with default value. */ + if (report->maxfield < 4) { + hid_err(hid, "not enough fields in the report: %d\n", + report->maxfield); + return -ENODEV; + } for (i = 0; i < report->maxfield; i++) { + if (report->field[i]->report_count < 1) { + hid_err(hid, "no values in the field\n"); + return -ENODEV; + } for (j = 0; j < report->field[i]->report_count; j++) { report->field[i]->value[j] = 0x00; - field_count++; } } - if (field_count < 4) { - hid_err(hid, "not enough fields in the report: %d\n", - field_count); - return -ENODEV; - } - betopff = kzalloc(sizeof(*betopff), GFP_KERNEL); if (!betopff) return -ENOMEM; diff --git a/drivers/hid/hid-bigbenff.c b/drivers/hid/hid-bigbenff.c index e8c5e3ac9fff..e8b16665860d 100644 --- a/drivers/hid/hid-bigbenff.c +++ b/drivers/hid/hid-bigbenff.c @@ -344,6 +344,11 @@ static int bigben_probe(struct hid_device *hid, } report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + if (list_empty(report_list)) { + hid_err(hid, "no output report found\n"); + error = -ENODEV; + goto error_hw_stop; + } bigben->report = list_entry(report_list->next, struct hid_report, list); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index bd47628da6be..5c72aef3d3dd 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -993,8 +993,8 @@ struct hid_report *hid_validate_values(struct hid_device *hid, * Validating on id 0 means we should examine the first * report in the list. */ - report = list_entry( - hid->report_enum[type].report_list.next, + report = list_first_entry_or_null( + &hid->report_enum[type].report_list, struct hid_report, list); } else { report = hid->report_enum[type].report_id_hash[id]; @@ -1202,6 +1202,7 @@ int hid_open_report(struct hid_device *device) __u8 *end; __u8 *next; int ret; + int i; static int (*dispatch_type[])(struct hid_parser *parser, struct hid_item *item) = { hid_parser_main, @@ -1252,6 +1253,8 @@ int hid_open_report(struct hid_device *device) goto err; } device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; + for (i = 0; i < HID_DEFAULT_NUM_COLLECTIONS; i++) + device->collection[i].parent_idx = -1; ret = -EINVAL; while ((next = fetch_item(start, end, &item)) != NULL) { diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c index e59e9911fc37..4fa45ee77503 100644 --- a/drivers/hid/hid-elecom.c +++ b/drivers/hid/hid-elecom.c @@ -12,6 +12,7 @@ * Copyright (c) 2017 Alex Manoussakis <amanou@gnu.org> * Copyright (c) 2017 Tomasz Kramkowski <tk@the-tk.com> * Copyright (c) 2020 YOSHIOKA Takuma <lo48576@hard-wi.red> + * Copyright (c) 2022 Takahiro Fujii <fujii@xaxxi.net> */ /* @@ -89,7 +90,7 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, case USB_DEVICE_ID_ELECOM_M_DT1URBK: case USB_DEVICE_ID_ELECOM_M_DT1DRBK: case USB_DEVICE_ID_ELECOM_M_HT1URBK: - case USB_DEVICE_ID_ELECOM_M_HT1DRBK: + case USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D: /* * Report descriptor format: * 12: button bit count @@ -99,6 +100,16 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, */ mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 8); break; + case USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C: + /* + * Report descriptor format: + * 22: button bit count + * 30: padding bit count + * 24: button report size + * 16: button usage maximum + */ + mouse_button_fixup(hdev, rdesc, *rsize, 22, 30, 24, 16, 8); + break; } return rdesc; } @@ -112,7 +123,8 @@ static const struct hid_device_id elecom_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C) }, { } }; MODULE_DEVICE_TABLE(hid, elecom_devices); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 82713ef3aaa6..9e36b4cd905e 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -274,7 +274,6 @@ #define USB_DEVICE_ID_CH_AXIS_295 0x001c #define USB_VENDOR_ID_CHERRY 0x046a -#define USB_DEVICE_ID_CHERRY_MOUSE_000C 0x000c #define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023 #define USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR 0x0027 @@ -414,6 +413,8 @@ #define I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100 0x29CF #define I2C_DEVICE_ID_HP_ENVY_X360_EU0009NV 0x2CF9 #define I2C_DEVICE_ID_HP_SPECTRE_X360_15 0x2817 +#define I2C_DEVICE_ID_HP_SPECTRE_X360_13_AW0020NG 0x29DF +#define I2C_DEVICE_ID_ASUS_TP420IA_TOUCHSCREEN 0x2BC8 #define USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN 0x2544 #define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN 0x2706 #define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN 0x261A @@ -429,7 +430,8 @@ #define USB_DEVICE_ID_ELECOM_M_DT1URBK 0x00fe #define USB_DEVICE_ID_ELECOM_M_DT1DRBK 0x00ff #define USB_DEVICE_ID_ELECOM_M_HT1URBK 0x010c -#define USB_DEVICE_ID_ELECOM_M_HT1DRBK 0x010d +#define USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D 0x010d +#define USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C 0x011c #define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34 #define USB_DEVICE_ID_DREAM_CHEEKY_WN 0x0004 @@ -1295,6 +1297,7 @@ #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540 0x0075 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042 +#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2 0x0905 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S 0x0909 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 9b59e436df0a..77c8c49852b5 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -370,6 +370,8 @@ static const struct hid_device_id hid_battery_quirks[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD), HID_BATTERY_QUIRK_IGNORE }, + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_TP420IA_TOUCHSCREEN), + HID_BATTERY_QUIRK_IGNORE }, { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN), HID_BATTERY_QUIRK_IGNORE }, { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN), @@ -384,6 +386,8 @@ static const struct hid_device_id hid_battery_quirks[] = { HID_BATTERY_QUIRK_IGNORE }, { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_15), HID_BATTERY_QUIRK_IGNORE }, + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_13_AW0020NG), + HID_BATTERY_QUIRK_IGNORE }, { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN), HID_BATTERY_QUIRK_IGNORE }, { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN), diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index abf2c95e4d0b..9c1ee8e91e0c 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -3978,7 +3978,8 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) } hidpp_initialize_battery(hidpp); - hidpp_initialize_hires_scroll(hidpp); + if (!hid_is_usb(hidpp->hid_dev)) + hidpp_initialize_hires_scroll(hidpp); /* forward current battery state */ if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP10_BATTERY) { diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index f399bf0d3c8c..27c40894acab 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -944,6 +944,7 @@ ATTRIBUTE_GROUPS(ps_device); static int dualsense_get_calibration_data(struct dualsense *ds) { + struct hid_device *hdev = ds->base.hdev; short gyro_pitch_bias, gyro_pitch_plus, gyro_pitch_minus; short gyro_yaw_bias, gyro_yaw_plus, gyro_yaw_minus; short gyro_roll_bias, gyro_roll_plus, gyro_roll_minus; @@ -954,6 +955,7 @@ static int dualsense_get_calibration_data(struct dualsense *ds) int speed_2x; int range_2g; int ret = 0; + int i; uint8_t *buf; buf = kzalloc(DS_FEATURE_REPORT_CALIBRATION_SIZE, GFP_KERNEL); @@ -1006,6 +1008,21 @@ static int dualsense_get_calibration_data(struct dualsense *ds) ds->gyro_calib_data[2].sens_denom = gyro_roll_plus - gyro_roll_minus; /* + * Sanity check gyro calibration data. This is needed to prevent crashes + * during report handling of virtual, clone or broken devices not implementing + * calibration data properly. + */ + for (i = 0; i < ARRAY_SIZE(ds->gyro_calib_data); i++) { + if (ds->gyro_calib_data[i].sens_denom == 0) { + hid_warn(hdev, "Invalid gyro calibration data for axis (%d), disabling calibration.", + ds->gyro_calib_data[i].abs_code); + ds->gyro_calib_data[i].bias = 0; + ds->gyro_calib_data[i].sens_numer = DS_GYRO_RANGE; + ds->gyro_calib_data[i].sens_denom = S16_MAX; + } + } + + /* * Set accelerometer calibration and normalization parameters. * Data values will be normalized to 1/DS_ACC_RES_PER_G g. */ @@ -1027,6 +1044,21 @@ static int dualsense_get_calibration_data(struct dualsense *ds) ds->accel_calib_data[2].sens_numer = 2*DS_ACC_RES_PER_G; ds->accel_calib_data[2].sens_denom = range_2g; + /* + * Sanity check accelerometer calibration data. This is needed to prevent crashes + * during report handling of virtual, clone or broken devices not implementing calibration + * data properly. + */ + for (i = 0; i < ARRAY_SIZE(ds->accel_calib_data); i++) { + if (ds->accel_calib_data[i].sens_denom == 0) { + hid_warn(hdev, "Invalid accelerometer calibration data for axis (%d), disabling calibration.", + ds->accel_calib_data[i].abs_code); + ds->accel_calib_data[i].bias = 0; + ds->accel_calib_data[i].sens_numer = DS_ACC_RANGE; + ds->accel_calib_data[i].sens_denom = S16_MAX; + } + } + err_free: kfree(buf); return ret; @@ -1737,6 +1769,7 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) int speed_2x; int range_2g; int ret = 0; + int i; uint8_t *buf; if (ds4->base.hdev->bus == BUS_USB) { @@ -1831,6 +1864,21 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) ds4->gyro_calib_data[2].sens_denom = gyro_roll_plus - gyro_roll_minus; /* + * Sanity check gyro calibration data. This is needed to prevent crashes + * during report handling of virtual, clone or broken devices not implementing + * calibration data properly. + */ + for (i = 0; i < ARRAY_SIZE(ds4->gyro_calib_data); i++) { + if (ds4->gyro_calib_data[i].sens_denom == 0) { + hid_warn(hdev, "Invalid gyro calibration data for axis (%d), disabling calibration.", + ds4->gyro_calib_data[i].abs_code); + ds4->gyro_calib_data[i].bias = 0; + ds4->gyro_calib_data[i].sens_numer = DS4_GYRO_RANGE; + ds4->gyro_calib_data[i].sens_denom = S16_MAX; + } + } + + /* * Set accelerometer calibration and normalization parameters. * Data values will be normalized to 1/DS4_ACC_RES_PER_G g. */ @@ -1852,6 +1900,21 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) ds4->accel_calib_data[2].sens_numer = 2*DS4_ACC_RES_PER_G; ds4->accel_calib_data[2].sens_denom = range_2g; + /* + * Sanity check accelerometer calibration data. This is needed to prevent crashes + * during report handling of virtual, clone or broken devices not implementing calibration + * data properly. + */ + for (i = 0; i < ARRAY_SIZE(ds4->accel_calib_data); i++) { + if (ds4->accel_calib_data[i].sens_denom == 0) { + hid_warn(hdev, "Invalid accelerometer calibration data for axis (%d), disabling calibration.", + ds4->accel_calib_data[i].abs_code); + ds4->accel_calib_data[i].bias = 0; + ds4->accel_calib_data[i].sens_numer = DS4_ACC_RANGE; + ds4->accel_calib_data[i].sens_denom = S16_MAX; + } + } + err_free: kfree(buf); return ret; diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 0e9702c7f7d6..5bc91f68b374 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -54,7 +54,6 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_THROTTLE), HID_QUIRK_NOGET }, - { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_MOUSE_000C), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB_RAPIDFIRE), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB), HID_QUIRK_NO_INIT_REPORTS }, @@ -394,7 +393,8 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C) }, #endif #if IS_ENABLED(CONFIG_HID_ELO) { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) }, diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index 7fa6fe04f1b2..cfbbc39807a6 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -526,6 +526,8 @@ static const struct hid_device_id uclogic_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, + USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S) }, diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index cd1233d7e253..3c5eea3df328 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -1656,6 +1656,8 @@ int uclogic_params_init(struct uclogic_params *params, case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_PARBLO_A610_PRO): case VID_PID(USB_VENDOR_ID_UGEE, + USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2): + case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L): case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S): diff --git a/drivers/hid/intel-ish-hid/ishtp/dma-if.c b/drivers/hid/intel-ish-hid/ishtp/dma-if.c index 40554c8daca0..00046cbfd4ed 100644 --- a/drivers/hid/intel-ish-hid/ishtp/dma-if.c +++ b/drivers/hid/intel-ish-hid/ishtp/dma-if.c @@ -104,6 +104,11 @@ void *ishtp_cl_get_dma_send_buf(struct ishtp_device *dev, int required_slots = (size / DMA_SLOT_SIZE) + 1 * (size % DMA_SLOT_SIZE != 0); + if (!dev->ishtp_dma_tx_map) { + dev_err(dev->devc, "Fail to allocate Tx map\n"); + return NULL; + } + spin_lock_irqsave(&dev->ishtp_dma_tx_lock, flags); for (i = 0; i <= (dev->ishtp_dma_num_slots - required_slots); i++) { free = 1; @@ -150,6 +155,11 @@ void ishtp_cl_release_dma_acked_mem(struct ishtp_device *dev, return; } + if (!dev->ishtp_dma_tx_map) { + dev_err(dev->devc, "Fail to allocate Tx map\n"); + return; + } + i = (msg_addr - dev->ishtp_host_dma_tx_buf) / DMA_SLOT_SIZE; spin_lock_irqsave(&dev->ishtp_dma_tx_lock, flags); for (j = 0; j < acked_slots; j++) { diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index cbe43e2567a7..64ac5bdee3a6 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -1963,7 +1963,7 @@ static void hv_balloon_debugfs_init(struct hv_dynmem_device *b) static void hv_balloon_debugfs_exit(struct hv_dynmem_device *b) { - debugfs_remove(debugfs_lookup("hv-balloon", NULL)); + debugfs_lookup_and_remove("hv-balloon", NULL); } #else diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 3176c33af6c6..497cbfb460e5 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1749,23 +1749,6 @@ config SENSORS_SHTC1 This driver can also be built as a module. If so, the module will be called shtc1. -config SENSORS_S3C - tristate "Samsung built-in ADC" - depends on S3C_ADC - help - If you say yes here you get support for the on-board ADCs of - the Samsung S3C24XX, S3C64XX and other series of SoC - - This driver can also be built as a module. If so, the module - will be called s3c-hwmon. - -config SENSORS_S3C_RAW - bool "Include raw channel attributes in sysfs" - depends on SENSORS_S3C - help - Say Y here if you want to include raw copies of all the ADC - channels in sysfs. - config SENSORS_SIS5595 tristate "Silicon Integrated Systems Corp. SiS5595" depends on PCI diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index e2e4e87b282f..4f71d9807dae 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -174,7 +174,6 @@ obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o -obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c deleted file mode 100644 index 70ae665db477..000000000000 --- a/drivers/hwmon/s3c-hwmon.c +++ /dev/null @@ -1,379 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* linux/drivers/hwmon/s3c-hwmon.c - * - * Copyright (C) 2005, 2008, 2009 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks <ben@simtec.co.uk> - * - * S3C24XX/S3C64XX ADC hwmon support -*/ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/io.h> -#include <linux/init.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> - -#include <linux/hwmon.h> -#include <linux/hwmon-sysfs.h> - -#include <linux/soc/samsung/s3c-adc.h> -#include <linux/platform_data/hwmon-s3c.h> - -struct s3c_hwmon_attr { - struct sensor_device_attribute in; - struct sensor_device_attribute label; - char in_name[12]; - char label_name[12]; -}; - -/** - * struct s3c_hwmon - ADC hwmon client information - * @lock: Access lock to serialise the conversions. - * @client: The client we registered with the S3C ADC core. - * @hwmon_dev: The hwmon device we created. - * @attr: The holders for the channel attributes. -*/ -struct s3c_hwmon { - struct mutex lock; - struct s3c_adc_client *client; - struct device *hwmon_dev; - - struct s3c_hwmon_attr attrs[8]; -}; - -/** - * s3c_hwmon_read_ch - read a value from a given adc channel. - * @dev: The device. - * @hwmon: Our state. - * @channel: The channel we're reading from. - * - * Read a value from the @channel with the proper locking and sleep until - * either the read completes or we timeout awaiting the ADC core to get - * back to us. - */ -static int s3c_hwmon_read_ch(struct device *dev, - struct s3c_hwmon *hwmon, int channel) -{ - int ret; - - ret = mutex_lock_interruptible(&hwmon->lock); - if (ret < 0) - return ret; - - dev_dbg(dev, "reading channel %d\n", channel); - - ret = s3c_adc_read(hwmon->client, channel); - mutex_unlock(&hwmon->lock); - - return ret; -} - -#ifdef CONFIG_SENSORS_S3C_RAW -/** - * s3c_hwmon_show_raw - show a conversion from the raw channel number. - * @dev: The device that the attribute belongs to. - * @attr: The attribute being read. - * @buf: The result buffer. - * - * This show deals with the raw attribute, registered for each possible - * ADC channel. This does a conversion and returns the raw (un-scaled) - * value returned from the hardware. - */ -static ssize_t s3c_hwmon_show_raw(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct s3c_hwmon *adc = dev_get_drvdata(dev); - struct sensor_device_attribute *sa = to_sensor_dev_attr(attr); - int ret; - - ret = s3c_hwmon_read_ch(dev, adc, sa->index); - - return (ret < 0) ? ret : snprintf(buf, PAGE_SIZE, "%d\n", ret); -} - -static SENSOR_DEVICE_ATTR(adc0_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 0); -static SENSOR_DEVICE_ATTR(adc1_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 1); -static SENSOR_DEVICE_ATTR(adc2_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 2); -static SENSOR_DEVICE_ATTR(adc3_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 3); -static SENSOR_DEVICE_ATTR(adc4_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 4); -static SENSOR_DEVICE_ATTR(adc5_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 5); -static SENSOR_DEVICE_ATTR(adc6_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 6); -static SENSOR_DEVICE_ATTR(adc7_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 7); - -static struct attribute *s3c_hwmon_attrs[9] = { - &sensor_dev_attr_adc0_raw.dev_attr.attr, - &sensor_dev_attr_adc1_raw.dev_attr.attr, - &sensor_dev_attr_adc2_raw.dev_attr.attr, - &sensor_dev_attr_adc3_raw.dev_attr.attr, - &sensor_dev_attr_adc4_raw.dev_attr.attr, - &sensor_dev_attr_adc5_raw.dev_attr.attr, - &sensor_dev_attr_adc6_raw.dev_attr.attr, - &sensor_dev_attr_adc7_raw.dev_attr.attr, - NULL, -}; - -static struct attribute_group s3c_hwmon_attrgroup = { - .attrs = s3c_hwmon_attrs, -}; - -static inline int s3c_hwmon_add_raw(struct device *dev) -{ - return sysfs_create_group(&dev->kobj, &s3c_hwmon_attrgroup); -} - -static inline void s3c_hwmon_remove_raw(struct device *dev) -{ - sysfs_remove_group(&dev->kobj, &s3c_hwmon_attrgroup); -} - -#else - -static inline int s3c_hwmon_add_raw(struct device *dev) { return 0; } -static inline void s3c_hwmon_remove_raw(struct device *dev) { } - -#endif /* CONFIG_SENSORS_S3C_RAW */ - -/** - * s3c_hwmon_ch_show - show value of a given channel - * @dev: The device that the attribute belongs to. - * @attr: The attribute being read. - * @buf: The result buffer. - * - * Read a value from the ADC and scale it before returning it to the - * caller. The scale factor is gained from the channel configuration - * passed via the platform data when the device was registered. - */ -static ssize_t s3c_hwmon_ch_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr); - struct s3c_hwmon *hwmon = dev_get_drvdata(dev); - struct s3c_hwmon_pdata *pdata = dev_get_platdata(dev); - struct s3c_hwmon_chcfg *cfg; - int ret; - - cfg = pdata->in[sen_attr->index]; - - ret = s3c_hwmon_read_ch(dev, hwmon, sen_attr->index); - if (ret < 0) - return ret; - - ret *= cfg->mult; - ret = DIV_ROUND_CLOSEST(ret, cfg->div); - - return sysfs_emit(buf, "%d\n", ret); -} - -/** - * s3c_hwmon_label_show - show label name of the given channel. - * @dev: The device that the attribute belongs to. - * @attr: The attribute being read. - * @buf: The result buffer. - * - * Return the label name of a given channel - */ -static ssize_t s3c_hwmon_label_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr); - struct s3c_hwmon_pdata *pdata = dev_get_platdata(dev); - struct s3c_hwmon_chcfg *cfg; - - cfg = pdata->in[sen_attr->index]; - - return sysfs_emit(buf, "%s\n", cfg->name); -} - -/** - * s3c_hwmon_create_attr - create hwmon attribute for given channel. - * @dev: The device to create the attribute on. - * @cfg: The channel configuration passed from the platform data. - * @channel: The ADC channel number to process. - * - * Create the scaled attribute for use with hwmon from the specified - * platform data in @pdata. The sysfs entry is handled by the routine - * s3c_hwmon_ch_show(). - * - * The attribute name is taken from the configuration data if present - * otherwise the name is taken by concatenating in_ with the channel - * number. - */ -static int s3c_hwmon_create_attr(struct device *dev, - struct s3c_hwmon_chcfg *cfg, - struct s3c_hwmon_attr *attrs, - int channel) -{ - struct sensor_device_attribute *attr; - int ret; - - snprintf(attrs->in_name, sizeof(attrs->in_name), "in%d_input", channel); - - attr = &attrs->in; - attr->index = channel; - sysfs_attr_init(&attr->dev_attr.attr); - attr->dev_attr.attr.name = attrs->in_name; - attr->dev_attr.attr.mode = S_IRUGO; - attr->dev_attr.show = s3c_hwmon_ch_show; - - ret = device_create_file(dev, &attr->dev_attr); - if (ret < 0) { - dev_err(dev, "failed to create input attribute\n"); - return ret; - } - - /* if this has a name, add a label */ - if (cfg->name) { - snprintf(attrs->label_name, sizeof(attrs->label_name), - "in%d_label", channel); - - attr = &attrs->label; - attr->index = channel; - sysfs_attr_init(&attr->dev_attr.attr); - attr->dev_attr.attr.name = attrs->label_name; - attr->dev_attr.attr.mode = S_IRUGO; - attr->dev_attr.show = s3c_hwmon_label_show; - - ret = device_create_file(dev, &attr->dev_attr); - if (ret < 0) { - device_remove_file(dev, &attrs->in.dev_attr); - dev_err(dev, "failed to create label attribute\n"); - } - } - - return ret; -} - -static void s3c_hwmon_remove_attr(struct device *dev, - struct s3c_hwmon_attr *attrs) -{ - device_remove_file(dev, &attrs->in.dev_attr); - device_remove_file(dev, &attrs->label.dev_attr); -} - -/** - * s3c_hwmon_probe - device probe entry. - * @dev: The device being probed. -*/ -static int s3c_hwmon_probe(struct platform_device *dev) -{ - struct s3c_hwmon_pdata *pdata = dev_get_platdata(&dev->dev); - struct s3c_hwmon *hwmon; - int ret = 0; - int i; - - if (!pdata) { - dev_err(&dev->dev, "no platform data supplied\n"); - return -EINVAL; - } - - hwmon = devm_kzalloc(&dev->dev, sizeof(struct s3c_hwmon), GFP_KERNEL); - if (hwmon == NULL) - return -ENOMEM; - - platform_set_drvdata(dev, hwmon); - - mutex_init(&hwmon->lock); - - /* Register with the core ADC driver. */ - - hwmon->client = s3c_adc_register(dev, NULL, NULL, 0); - if (IS_ERR(hwmon->client)) { - dev_err(&dev->dev, "cannot register adc\n"); - return PTR_ERR(hwmon->client); - } - - /* add attributes for our adc devices. */ - - ret = s3c_hwmon_add_raw(&dev->dev); - if (ret) - goto err_registered; - - /* register with the hwmon core */ - - hwmon->hwmon_dev = hwmon_device_register(&dev->dev); - if (IS_ERR(hwmon->hwmon_dev)) { - dev_err(&dev->dev, "error registering with hwmon\n"); - ret = PTR_ERR(hwmon->hwmon_dev); - goto err_raw_attribute; - } - - for (i = 0; i < ARRAY_SIZE(pdata->in); i++) { - struct s3c_hwmon_chcfg *cfg = pdata->in[i]; - - if (!cfg) - continue; - - if (cfg->mult >= 0x10000) - dev_warn(&dev->dev, - "channel %d multiplier too large\n", - i); - - if (cfg->div == 0) { - dev_err(&dev->dev, "channel %d divider zero\n", i); - continue; - } - - ret = s3c_hwmon_create_attr(&dev->dev, pdata->in[i], - &hwmon->attrs[i], i); - if (ret) { - dev_err(&dev->dev, - "error creating channel %d\n", i); - - for (i--; i >= 0; i--) - s3c_hwmon_remove_attr(&dev->dev, - &hwmon->attrs[i]); - - goto err_hwmon_register; - } - } - - return 0; - - err_hwmon_register: - hwmon_device_unregister(hwmon->hwmon_dev); - - err_raw_attribute: - s3c_hwmon_remove_raw(&dev->dev); - - err_registered: - s3c_adc_release(hwmon->client); - - return ret; -} - -static int s3c_hwmon_remove(struct platform_device *dev) -{ - struct s3c_hwmon *hwmon = platform_get_drvdata(dev); - int i; - - s3c_hwmon_remove_raw(&dev->dev); - - for (i = 0; i < ARRAY_SIZE(hwmon->attrs); i++) - s3c_hwmon_remove_attr(&dev->dev, &hwmon->attrs[i]); - - hwmon_device_unregister(hwmon->hwmon_dev); - s3c_adc_release(hwmon->client); - - return 0; -} - -static struct platform_driver s3c_hwmon_driver = { - .driver = { - .name = "s3c-hwmon", - }, - .probe = s3c_hwmon_probe, - .remove = s3c_hwmon_remove, -}; - -module_platform_driver(s3c_hwmon_driver); - -MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); -MODULE_DESCRIPTION("S3C ADC HWMon driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:s3c-hwmon"); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a7bfddf08fa7..d4975444a32d 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -723,11 +723,11 @@ config I2C_IMX_LPI2C will be called i2c-imx-lpi2c. config I2C_IOP3XX - tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface" - depends on ARCH_IOP32X || ARCH_IXP4XX || COMPILE_TEST + tristate "Intel IXP4xx on-chip I2C interface" + depends on ARCH_IXP4XX || COMPILE_TEST help Say Y here if you want to use the IIC bus controller on - the Intel IOPx3xx I/O Processors or IXP4xx Network Processors. + the Intel IXP4xx Network Processors. This driver can also be built as a module. If so, the module will be called i2c-iop3xx. @@ -874,7 +874,7 @@ config I2C_OCORES config I2C_OMAP tristate "OMAP I2C adapter" depends on ARCH_OMAP || ARCH_K3 || COMPILE_TEST - default y if MACH_OMAP_H3 || MACH_OMAP_OSK + default MACH_OMAP_OSK help If you say yes to this option, support will be included for the I2C interface on the Texas Instruments OMAP1/2 family of processors. @@ -1010,8 +1010,7 @@ config I2C_RZV2M config I2C_S3C2410 tristate "S3C/Exynos I2C Driver" - depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || \ - ARCH_S5PV210 || COMPILE_TEST + depends on ARCH_EXYNOS || ARCH_S3C64XX || ARCH_S5PV210 || COMPILE_TEST help Say Y here to include support for I2C controller in the Samsung SoCs (S3C, S5Pv210, Exynos). diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c index bdf3b50de8ad..c1c74ce08407 100644 --- a/drivers/i2c/busses/i2c-axxia.c +++ b/drivers/i2c/busses/i2c-axxia.c @@ -118,7 +118,7 @@ #define SDA_HOLD_TIME 0x90 /** - * axxia_i2c_dev - I2C device context + * struct axxia_i2c_dev - I2C device context * @base: pointer to register struct * @msg: pointer to current message * @msg_r: pointer to current read message (sequence transfer) diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index a3240ece55b2..581e02cc979a 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -351,7 +351,8 @@ u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset) * * If your hardware is free from tHD;STA issue, try this one. */ - return DIV_ROUND_CLOSEST(ic_clk * tSYMBOL, MICRO) - 8 + offset; + return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * tSYMBOL, MICRO) - + 8 + offset; else /* * Conditional expression: @@ -367,7 +368,8 @@ u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset) * The reason why we need to take into account "tf" here, * is the same as described in i2c_dw_scl_lcnt(). */ - return DIV_ROUND_CLOSEST(ic_clk * (tSYMBOL + tf), MICRO) - 3 + offset; + return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tSYMBOL + tf), MICRO) - + 3 + offset; } u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) @@ -383,7 +385,8 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) * account the fall time of SCL signal (tf). Default tf value * should be 0.3 us, for safety. */ - return DIV_ROUND_CLOSEST(ic_clk * (tLOW + tf), MICRO) - 1 + offset; + return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tLOW + tf), MICRO) - + 1 + offset; } int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev) diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index e499f96506c5..782fe1ef3ca1 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -396,6 +396,8 @@ static const struct pci_device_id i2_designware_pci_ids[] = { { PCI_VDEVICE(ATI, 0x73a4), navi_amd }, { PCI_VDEVICE(ATI, 0x73e4), navi_amd }, { PCI_VDEVICE(ATI, 0x73c4), navi_amd }, + { PCI_VDEVICE(ATI, 0x7444), navi_amd }, + { PCI_VDEVICE(ATI, 0x7464), navi_amd }, { 0,} }; MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index ba043b547393..74182db03a88 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -351,13 +351,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) if (dev->flags & ACCESS_NO_IRQ_SUSPEND) { dev_pm_set_driver_flags(&pdev->dev, - DPM_FLAG_SMART_PREPARE | - DPM_FLAG_MAY_SKIP_RESUME); + DPM_FLAG_SMART_PREPARE); } else { dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_SMART_PREPARE | - DPM_FLAG_SMART_SUSPEND | - DPM_FLAG_MAY_SKIP_RESUME); + DPM_FLAG_SMART_SUSPEND); } device_enable_async_suspend(&pdev->dev); @@ -419,21 +417,8 @@ static int dw_i2c_plat_prepare(struct device *dev) */ return !has_acpi_companion(dev); } - -static void dw_i2c_plat_complete(struct device *dev) -{ - /* - * The device can only be in runtime suspend at this point if it has not - * been resumed throughout the ending system suspend/resume cycle, so if - * the platform firmware might mess up with it, request the runtime PM - * framework to resume it. - */ - if (pm_runtime_suspended(dev) && pm_resume_via_firmware()) - pm_request_resume(dev); -} #else #define dw_i2c_plat_prepare NULL -#define dw_i2c_plat_complete NULL #endif #ifdef CONFIG_PM @@ -483,7 +468,6 @@ static int __maybe_unused dw_i2c_plat_resume(struct device *dev) static const struct dev_pm_ops dw_i2c_dev_pm_ops = { .prepare = dw_i2c_plat_prepare, - .complete = dw_i2c_plat_complete, SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume) SET_RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend, dw_i2c_plat_runtime_resume, NULL) }; diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 5af5cffc444e..d113bed79545 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -826,8 +826,8 @@ static int mxs_i2c_probe(struct platform_device *pdev) /* Setup the DMA */ i2c->dmach = dma_request_chan(dev, "rx-tx"); if (IS_ERR(i2c->dmach)) { - dev_err(dev, "Failed to request dma\n"); - return PTR_ERR(i2c->dmach); + return dev_err_probe(dev, PTR_ERR(i2c->dmach), + "Failed to request dma\n"); } platform_set_drvdata(pdev, i2c); diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index d1658ed76562..b31cf4f18f85 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -80,7 +80,7 @@ enum { #define DEFAULT_SCL_RATE (100 * 1000) /* Hz */ /** - * struct i2c_spec_values: + * struct i2c_spec_values - I2C specification values for various modes * @min_hold_start_ns: min hold time (repeated) START condition * @min_low_ns: min LOW period of the SCL clock * @min_high_ns: min HIGH period of the SCL cloc @@ -136,7 +136,7 @@ static const struct i2c_spec_values fast_mode_plus_spec = { }; /** - * struct rk3x_i2c_calced_timings: + * struct rk3x_i2c_calced_timings - calculated V1 timings * @div_low: Divider output for low * @div_high: Divider output for high * @tuning: Used to adjust setup/hold data time, @@ -159,7 +159,7 @@ enum rk3x_i2c_state { }; /** - * struct rk3x_i2c_soc_data: + * struct rk3x_i2c_soc_data - SOC-specific data * @grf_offset: offset inside the grf regmap for setting the i2c type * @calc_timings: Callback function for i2c timing information calculated */ @@ -239,7 +239,8 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c) } /** - * Generate a START condition, which triggers a REG_INT_START interrupt. + * rk3x_i2c_start - Generate a START condition, which triggers a REG_INT_START interrupt. + * @i2c: target controller data */ static void rk3x_i2c_start(struct rk3x_i2c *i2c) { @@ -258,8 +259,8 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c) } /** - * Generate a STOP condition, which triggers a REG_INT_STOP interrupt. - * + * rk3x_i2c_stop - Generate a STOP condition, which triggers a REG_INT_STOP interrupt. + * @i2c: target controller data * @error: Error code to return in rk3x_i2c_xfer */ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) @@ -298,7 +299,8 @@ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) } /** - * Setup a read according to i2c->msg + * rk3x_i2c_prepare_read - Setup a read according to i2c->msg + * @i2c: target controller data */ static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c) { @@ -329,7 +331,8 @@ static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c) } /** - * Fill the transmit buffer with data from i2c->msg + * rk3x_i2c_fill_transmit_buf - Fill the transmit buffer with data from i2c->msg + * @i2c: target controller data */ static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c) { @@ -532,11 +535,10 @@ out: } /** - * Get timing values of I2C specification - * + * rk3x_i2c_get_spec - Get timing values of I2C specification * @speed: Desired SCL frequency * - * Returns: Matched i2c spec values. + * Return: Matched i2c_spec_values. */ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed) { @@ -549,13 +551,12 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed) } /** - * Calculate divider values for desired SCL frequency - * + * rk3x_i2c_v0_calc_timings - Calculate divider values for desired SCL frequency * @clk_rate: I2C input clock rate * @t: Known I2C timing information * @t_calc: Caculated rk3x private timings that would be written into regs * - * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case + * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case * a best-effort divider value is returned in divs. If the target rate is * too high, we silently use the highest possible rate. */ @@ -710,13 +711,12 @@ static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate, } /** - * Calculate timing values for desired SCL frequency - * + * rk3x_i2c_v1_calc_timings - Calculate timing values for desired SCL frequency * @clk_rate: I2C input clock rate * @t: Known I2C timing information * @t_calc: Caculated rk3x private timings that would be written into regs * - * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case + * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case * a best-effort divider value is returned in divs. If the target rate is * too high, we silently use the highest possible rate. * The following formulas are v1's method to calculate timings. @@ -960,14 +960,14 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long } /** - * Setup I2C registers for an I2C operation specified by msgs, num. - * - * Must be called with i2c->lock held. - * + * rk3x_i2c_setup - Setup I2C registers for an I2C operation specified by msgs, num. + * @i2c: target controller data * @msgs: I2C msgs to process * @num: Number of msgs * - * returns: Number of I2C msgs processed or negative in case of error + * Must be called with i2c->lock held. + * + * Return: Number of I2C msgs processed or negative in case of error */ static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num) { diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 36dab9cd208c..45e9df81345a 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -116,9 +116,6 @@ struct s3c24xx_i2c { struct s3c2410_platform_i2c *pdata; struct gpio_desc *gpios[2]; struct pinctrl *pctrl; -#if defined(CONFIG_ARM_S3C24XX_CPUFREQ) - struct notifier_block freq_transition; -#endif struct regmap *sysreg; unsigned int sys_i2c_cfg; }; @@ -885,65 +882,6 @@ static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got) return 0; } -#if defined(CONFIG_ARM_S3C24XX_CPUFREQ) - -#define freq_to_i2c(_n) container_of(_n, struct s3c24xx_i2c, freq_transition) - -static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct s3c24xx_i2c *i2c = freq_to_i2c(nb); - unsigned int got; - int delta_f; - int ret; - - delta_f = clk_get_rate(i2c->clk) - i2c->clkrate; - - /* if we're post-change and the input clock has slowed down - * or at pre-change and the clock is about to speed up, then - * adjust our clock rate. <0 is slow, >0 speedup. - */ - - if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) || - (val == CPUFREQ_PRECHANGE && delta_f > 0)) { - i2c_lock_bus(&i2c->adap, I2C_LOCK_ROOT_ADAPTER); - ret = s3c24xx_i2c_clockrate(i2c, &got); - i2c_unlock_bus(&i2c->adap, I2C_LOCK_ROOT_ADAPTER); - - if (ret < 0) - dev_err(i2c->dev, "cannot find frequency (%d)\n", ret); - else - dev_info(i2c->dev, "setting freq %d\n", got); - } - - return 0; -} - -static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c) -{ - i2c->freq_transition.notifier_call = s3c24xx_i2c_cpufreq_transition; - - return cpufreq_register_notifier(&i2c->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c) -{ - cpufreq_unregister_notifier(&i2c->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -#else -static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c) -{ - return 0; -} - -static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c) -{ -} -#endif - #ifdef CONFIG_OF static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) { @@ -1152,13 +1090,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) } } - ret = s3c24xx_i2c_register_cpufreq(i2c); - if (ret < 0) { - dev_err(&pdev->dev, "failed to register cpufreq notifier\n"); - clk_unprepare(i2c->clk); - return ret; - } - /* * Note, previous versions of the driver used i2c_add_adapter() * to add the bus at any number. We now pass the bus number via @@ -1175,7 +1106,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { pm_runtime_disable(&pdev->dev); - s3c24xx_i2c_deregister_cpufreq(i2c); clk_unprepare(i2c->clk); return ret; } @@ -1192,8 +1122,6 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); - s3c24xx_i2c_deregister_cpufreq(i2c); - i2c_del_adapter(&i2c->adap); return 0; diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index cfeb24d40d37..e2d64a8f9422 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -168,13 +168,7 @@ static __cpuidle int intel_idle_irq(struct cpuidle_device *dev, raw_local_irq_enable(); ret = __intel_idle(dev, drv, index); - - /* - * The lockdep hardirqs state may be changed to 'on' with timer - * tick interrupt followed by __do_softirq(). Use local_irq_disable() - * to keep the hardirqs state correct. - */ - local_irq_disable(); + raw_local_irq_disable(); return ret; } @@ -187,12 +181,12 @@ static __cpuidle int intel_idle_ibrs(struct cpuidle_device *dev, int ret; if (smt_active) - wrmsrl(MSR_IA32_SPEC_CTRL, 0); + native_wrmsrl(MSR_IA32_SPEC_CTRL, 0); ret = __intel_idle(dev, drv, index); if (smt_active) - wrmsrl(MSR_IA32_SPEC_CTRL, spec_ctrl); + native_wrmsrl(MSR_IA32_SPEC_CTRL, spec_ctrl); return ret; } @@ -1843,6 +1837,9 @@ static bool __init intel_idle_verify_cstate(unsigned int mwait_hint) return true; } +static bool force_irq_on __read_mostly; +module_param(force_irq_on, bool, 0444); + static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv) { int cstate; @@ -1895,8 +1892,10 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv) /* Structure copy. */ drv->states[drv->state_count] = cpuidle_state_table[cstate]; - if (cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE) + if ((cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE) || force_irq_on) { + printk("intel_idle: forced intel_idle_irq for state %d\n", cstate); drv->states[drv->state_count].enter = intel_idle_irq; + } if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) && cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IBRS) { diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index a2def6f9380a..5eac7ea19993 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -280,6 +280,7 @@ static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev, hid_sensor_convert_timestamp( &accel_state->common_attributes, *(int64_t *)raw_data); + ret = 0; break; default: break; diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 63f80d747cbd..99cd305b59d9 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -452,11 +452,11 @@ config EP93XX_ADC config EXYNOS_ADC tristate "Exynos ADC driver support" - depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210 || (OF && COMPILE_TEST) + depends on ARCH_EXYNOS || ARCH_S3C64XX || ARCH_S5PV210 || (OF && COMPILE_TEST) depends on HAS_IOMEM help - Driver for the ADC block found in the Samsung S3C (S3C2410, S3C2416, - S3C2440, S3C2443, S3C6410), S5Pv210 and Exynos SoCs. + Driver for the ADC block found in the Samsung S3C6410, S5Pv210 and + Exynos SoCs. Choose Y here only if you build for such Samsung SoC. To compile this driver as a module, choose M here: the module will be diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index 3d2e8b4db61a..a4e7c7eff5ac 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -298,8 +298,10 @@ static int berlin2_adc_probe(struct platform_device *pdev) int ret; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); - if (!indio_dev) + if (!indio_dev) { + of_node_put(parent_np); return -ENOMEM; + } priv = iio_priv(indio_dev); diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c index 36777b827165..f5a0fc9e64c5 100644 --- a/drivers/iio/adc/imx8qxp-adc.c +++ b/drivers/iio/adc/imx8qxp-adc.c @@ -86,6 +86,8 @@ #define IMX8QXP_ADC_TIMEOUT msecs_to_jiffies(100) +#define IMX8QXP_ADC_MAX_FIFO_SIZE 16 + struct imx8qxp_adc { struct device *dev; void __iomem *regs; @@ -95,6 +97,7 @@ struct imx8qxp_adc { /* Serialise ADC channel reads */ struct mutex lock; struct completion completion; + u32 fifo[IMX8QXP_ADC_MAX_FIFO_SIZE]; }; #define IMX8QXP_ADC_CHAN(_idx) { \ @@ -238,8 +241,7 @@ static int imx8qxp_adc_read_raw(struct iio_dev *indio_dev, return ret; } - *val = FIELD_GET(IMX8QXP_ADC_RESFIFO_VAL_MASK, - readl(adc->regs + IMX8QXP_ADR_ADC_RESFIFO)); + *val = adc->fifo[0]; mutex_unlock(&adc->lock); return IIO_VAL_INT; @@ -265,10 +267,15 @@ static irqreturn_t imx8qxp_adc_isr(int irq, void *dev_id) { struct imx8qxp_adc *adc = dev_id; u32 fifo_count; + int i; fifo_count = FIELD_GET(IMX8QXP_ADC_FCTRL_FCOUNT_MASK, readl(adc->regs + IMX8QXP_ADR_ADC_FCTRL)); + for (i = 0; i < fifo_count; i++) + adc->fifo[i] = FIELD_GET(IMX8QXP_ADC_RESFIFO_VAL_MASK, + readl_relaxed(adc->regs + IMX8QXP_ADR_ADC_RESFIFO)); + if (fifo_count) complete(&adc->completion); diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 6d21ea84fa82..a428bdb567d5 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -1520,6 +1520,7 @@ static const struct of_device_id stm32_dfsdm_adc_match[] = { }, {} }; +MODULE_DEVICE_TABLE(of, stm32_dfsdm_adc_match); static int stm32_dfsdm_adc_probe(struct platform_device *pdev) { diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index f53e8558b560..32873fb5f367 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -57,6 +57,18 @@ #define TWL6030_GPADCS BIT(1) #define TWL6030_GPADCR BIT(0) +#define USB_VBUS_CTRL_SET 0x04 +#define USB_ID_CTRL_SET 0x06 + +#define TWL6030_MISC1 0xE4 +#define VBUS_MEAS 0x01 +#define ID_MEAS 0x01 + +#define VAC_MEAS 0x04 +#define VBAT_MEAS 0x02 +#define BB_MEAS 0x01 + + /** * struct twl6030_chnl_calib - channel calibration * @gain: slope coefficient for ideal curve @@ -927,6 +939,26 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) return ret; } + ret = twl_i2c_write_u8(TWL_MODULE_USB, VBUS_MEAS, USB_VBUS_CTRL_SET); + if (ret < 0) { + dev_err(dev, "failed to wire up inputs\n"); + return ret; + } + + ret = twl_i2c_write_u8(TWL_MODULE_USB, ID_MEAS, USB_ID_CTRL_SET); + if (ret < 0) { + dev_err(dev, "failed to wire up inputs\n"); + return ret; + } + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, + VBAT_MEAS | BB_MEAS | VAC_MEAS, + TWL6030_MISC1); + if (ret < 0) { + dev_err(dev, "failed to wire up inputs\n"); + return ret; + } + indio_dev->name = DRIVER_NAME; indio_dev->info = &twl6030_gpadc_iio_info; indio_dev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index 5b4bdf3a26bb..a507d2e17079 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -1329,7 +1329,7 @@ static int ams_parse_firmware(struct iio_dev *indio_dev) dev_channels = devm_krealloc(dev, ams_channels, dev_size, GFP_KERNEL); if (!dev_channels) - ret = -ENOMEM; + return -ENOMEM; indio_dev->channels = dev_channels; indio_dev->num_channels = num_channels; diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index 8f0ad022c7f1..698c50da1f10 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -231,6 +231,7 @@ static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev, gyro_state->timestamp = hid_sensor_convert_timestamp(&gyro_state->common_attributes, *(s64 *)raw_data); + ret = 0; break; default: break; diff --git a/drivers/iio/imu/fxos8700_core.c b/drivers/iio/imu/fxos8700_core.c index 423cfe526f2a..6d189c4b9ff9 100644 --- a/drivers/iio/imu/fxos8700_core.c +++ b/drivers/iio/imu/fxos8700_core.c @@ -10,6 +10,7 @@ #include <linux/regmap.h> #include <linux/acpi.h> #include <linux/bitops.h> +#include <linux/bitfield.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -144,9 +145,8 @@ #define FXOS8700_NVM_DATA_BNK0 0xa7 /* Bit definitions for FXOS8700_CTRL_REG1 */ -#define FXOS8700_CTRL_ODR_MSK 0x38 #define FXOS8700_CTRL_ODR_MAX 0x00 -#define FXOS8700_CTRL_ODR_MIN GENMASK(4, 3) +#define FXOS8700_CTRL_ODR_MSK GENMASK(5, 3) /* Bit definitions for FXOS8700_M_CTRL_REG1 */ #define FXOS8700_HMS_MASK GENMASK(1, 0) @@ -320,7 +320,7 @@ static enum fxos8700_sensor fxos8700_to_sensor(enum iio_chan_type iio_type) switch (iio_type) { case IIO_ACCEL: return FXOS8700_ACCEL; - case IIO_ANGL_VEL: + case IIO_MAGN: return FXOS8700_MAGN; default: return -EINVAL; @@ -345,15 +345,35 @@ static int fxos8700_set_active_mode(struct fxos8700_data *data, static int fxos8700_set_scale(struct fxos8700_data *data, enum fxos8700_sensor t, int uscale) { - int i; + int i, ret, val; + bool active_mode; static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale); struct device *dev = regmap_get_device(data->regmap); if (t == FXOS8700_MAGN) { - dev_err(dev, "Magnetometer scale is locked at 1200uT\n"); + dev_err(dev, "Magnetometer scale is locked at 0.001Gs\n"); return -EINVAL; } + /* + * When device is in active mode, it failed to set an ACCEL + * full-scale range(2g/4g/8g) in FXOS8700_XYZ_DATA_CFG. + * This is not align with the datasheet, but it is a fxos8700 + * chip behavier. Set the device in standby mode before setting + * an ACCEL full-scale range. + */ + ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val); + if (ret) + return ret; + + active_mode = val & FXOS8700_ACTIVE; + if (active_mode) { + ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, + val & ~FXOS8700_ACTIVE); + if (ret) + return ret; + } + for (i = 0; i < scale_num; i++) if (fxos8700_accel_scale[i].uscale == uscale) break; @@ -361,8 +381,12 @@ static int fxos8700_set_scale(struct fxos8700_data *data, if (i == scale_num) return -EINVAL; - return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, + ret = regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, fxos8700_accel_scale[i].bits); + if (ret) + return ret; + return regmap_write(data->regmap, FXOS8700_CTRL_REG1, + active_mode); } static int fxos8700_get_scale(struct fxos8700_data *data, @@ -372,7 +396,7 @@ static int fxos8700_get_scale(struct fxos8700_data *data, static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale); if (t == FXOS8700_MAGN) { - *uscale = 1200; /* Magnetometer is locked at 1200uT */ + *uscale = 1000; /* Magnetometer is locked at 0.001Gs */ return 0; } @@ -394,22 +418,61 @@ static int fxos8700_get_data(struct fxos8700_data *data, int chan_type, int axis, int *val) { u8 base, reg; + s16 tmp; int ret; - enum fxos8700_sensor type = fxos8700_to_sensor(chan_type); - base = type ? FXOS8700_OUT_X_MSB : FXOS8700_M_OUT_X_MSB; + /* + * Different register base addresses varies with channel types. + * This bug hasn't been noticed before because using an enum is + * really hard to read. Use an a switch statement to take over that. + */ + switch (chan_type) { + case IIO_ACCEL: + base = FXOS8700_OUT_X_MSB; + break; + case IIO_MAGN: + base = FXOS8700_M_OUT_X_MSB; + break; + default: + return -EINVAL; + } /* Block read 6 bytes of device output registers to avoid data loss */ ret = regmap_bulk_read(data->regmap, base, data->buf, - FXOS8700_DATA_BUF_SIZE); + sizeof(data->buf)); if (ret) return ret; /* Convert axis to buffer index */ reg = axis - IIO_MOD_X; + /* + * Convert to native endianness. The accel data and magn data + * are signed, so a forced type conversion is needed. + */ + tmp = be16_to_cpu(data->buf[reg]); + + /* + * ACCEL output data registers contain the X-axis, Y-axis, and Z-axis + * 14-bit left-justified sample data and MAGN output data registers + * contain the X-axis, Y-axis, and Z-axis 16-bit sample data. Apply + * a signed 2 bits right shift to the readback raw data from ACCEL + * output data register and keep that from MAGN sensor as the origin. + * Value should be extended to 32 bit. + */ + switch (chan_type) { + case IIO_ACCEL: + tmp = tmp >> 2; + break; + case IIO_MAGN: + /* Nothing to do */ + break; + default: + return -EINVAL; + } + /* Convert to native endianness */ - *val = sign_extend32(be16_to_cpu(data->buf[reg]), 15); + *val = sign_extend32(tmp, 15); return 0; } @@ -445,10 +508,9 @@ static int fxos8700_set_odr(struct fxos8700_data *data, enum fxos8700_sensor t, if (i >= odr_num) return -EINVAL; - return regmap_update_bits(data->regmap, - FXOS8700_CTRL_REG1, - FXOS8700_CTRL_ODR_MSK + FXOS8700_ACTIVE, - fxos8700_odr[i].bits << 3 | active_mode); + val &= ~FXOS8700_CTRL_ODR_MSK; + val |= FIELD_PREP(FXOS8700_CTRL_ODR_MSK, fxos8700_odr[i].bits) | FXOS8700_ACTIVE; + return regmap_write(data->regmap, FXOS8700_CTRL_REG1, val); } static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t, @@ -461,7 +523,7 @@ static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t, if (ret) return ret; - val &= FXOS8700_CTRL_ODR_MSK; + val = FIELD_GET(FXOS8700_CTRL_ODR_MSK, val); for (i = 0; i < odr_num; i++) if (val == fxos8700_odr[i].bits) @@ -526,7 +588,7 @@ static IIO_CONST_ATTR(in_accel_sampling_frequency_available, static IIO_CONST_ATTR(in_magn_sampling_frequency_available, "1.5625 6.25 12.5 50 100 200 400 800"); static IIO_CONST_ATTR(in_accel_scale_available, "0.000244 0.000488 0.000976"); -static IIO_CONST_ATTR(in_magn_scale_available, "0.000001200"); +static IIO_CONST_ATTR(in_magn_scale_available, "0.001000"); static struct attribute *fxos8700_attrs[] = { &iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr, @@ -592,14 +654,19 @@ static int fxos8700_chip_init(struct fxos8700_data *data, bool use_spi) if (ret) return ret; - /* Max ODR (800Hz individual or 400Hz hybrid), active mode */ - ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, - FXOS8700_CTRL_ODR_MAX | FXOS8700_ACTIVE); + /* + * Set max full-scale range (+/-8G) for ACCEL sensor in chip + * initialization then activate the device. + */ + ret = regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G); if (ret) return ret; - /* Set for max full-scale range (+/-8G) */ - return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G); + /* Max ODR (800Hz individual or 400Hz hybrid), active mode */ + return regmap_update_bits(data->regmap, FXOS8700_CTRL_REG1, + FXOS8700_CTRL_ODR_MSK | FXOS8700_ACTIVE, + FIELD_PREP(FXOS8700_CTRL_ODR_MSK, FXOS8700_CTRL_ODR_MAX) | + FXOS8700_ACTIVE); } static void fxos8700_chip_uninit(void *data) diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index f6660847fb58..8c16cdacf2f2 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -4,6 +4,7 @@ config IIO_ST_LSM6DSX tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" depends on (I2C || SPI || I3C) select IIO_BUFFER + select IIO_TRIGGERED_BUFFER select IIO_KFIFO_BUF select IIO_ST_LSM6DSX_I2C if (I2C) select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c index 001055d09750..b1674a5bfa36 100644 --- a/drivers/iio/light/cm32181.c +++ b/drivers/iio/light/cm32181.c @@ -440,6 +440,8 @@ static int cm32181_probe(struct i2c_client *client) if (!indio_dev) return -ENOMEM; + i2c_set_clientdata(client, indio_dev); + /* * Some ACPI systems list 2 I2C resources for the CM3218 sensor, the * SMBus Alert Response Address (ARA, 0x0c) and the actual I2C address. @@ -460,8 +462,6 @@ static int cm32181_probe(struct i2c_client *client) return PTR_ERR(client); } - i2c_set_clientdata(client, indio_dev); - cm32181 = iio_priv(indio_dev); cm32181->client = client; cm32181->dev = dev; @@ -490,7 +490,8 @@ static int cm32181_probe(struct i2c_client *client) static int cm32181_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); + struct cm32181_chip *cm32181 = iio_priv(dev_get_drvdata(dev)); + struct i2c_client *client = cm32181->client; return i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD, CM32181_CMD_ALS_DISABLE); @@ -498,8 +499,8 @@ static int cm32181_suspend(struct device *dev) static int cm32181_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); struct cm32181_chip *cm32181 = iio_priv(dev_get_drvdata(dev)); + struct i2c_client *client = cm32181->client; return i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD, cm32181->conf_regs[CM32181_REG_ADDR_CMD]); diff --git a/drivers/infiniband/core/umem_dmabuf.c b/drivers/infiniband/core/umem_dmabuf.c index 43b26bc12288..39357dc2d229 100644 --- a/drivers/infiniband/core/umem_dmabuf.c +++ b/drivers/infiniband/core/umem_dmabuf.c @@ -26,8 +26,8 @@ int ib_umem_dmabuf_map_pages(struct ib_umem_dmabuf *umem_dmabuf) if (umem_dmabuf->sgt) goto wait_fence; - sgt = dma_buf_map_attachment_unlocked(umem_dmabuf->attach, - DMA_BIDIRECTIONAL); + sgt = dma_buf_map_attachment(umem_dmabuf->attach, + DMA_BIDIRECTIONAL); if (IS_ERR(sgt)) return PTR_ERR(sgt); @@ -103,8 +103,8 @@ void ib_umem_dmabuf_unmap_pages(struct ib_umem_dmabuf *umem_dmabuf) umem_dmabuf->last_sg_trim = 0; } - dma_buf_unmap_attachment_unlocked(umem_dmabuf->attach, umem_dmabuf->sgt, - DMA_BIDIRECTIONAL); + dma_buf_unmap_attachment(umem_dmabuf->attach, umem_dmabuf->sgt, + DMA_BIDIRECTIONAL); umem_dmabuf->sgt = NULL; } diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 26b021f43ba4..11b1c1603aeb 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -2957,15 +2957,18 @@ EXPORT_SYMBOL(__rdma_block_iter_start); bool __rdma_block_iter_next(struct ib_block_iter *biter) { unsigned int block_offset; + unsigned int sg_delta; if (!biter->__sg_nents || !biter->__sg) return false; biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance; block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1); - biter->__sg_advance += BIT_ULL(biter->__pg_bit) - block_offset; + sg_delta = BIT_ULL(biter->__pg_bit) - block_offset; - if (biter->__sg_advance >= sg_dma_len(biter->__sg)) { + if (sg_dma_len(biter->__sg) - biter->__sg_advance > sg_delta) { + biter->__sg_advance += sg_delta; + } else { biter->__sg_advance = 0; biter->__sg = sg_next(biter->__sg); biter->__sg_nents--; diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index f5f9269fdc16..7c5d487ec916 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -1318,12 +1318,15 @@ static int user_exp_rcv_setup(struct hfi1_filedata *fd, unsigned long arg, addr = arg + offsetof(struct hfi1_tid_info, tidcnt); if (copy_to_user((void __user *)addr, &tinfo.tidcnt, sizeof(tinfo.tidcnt))) - return -EFAULT; + ret = -EFAULT; addr = arg + offsetof(struct hfi1_tid_info, length); - if (copy_to_user((void __user *)addr, &tinfo.length, + if (!ret && copy_to_user((void __user *)addr, &tinfo.length, sizeof(tinfo.length))) ret = -EFAULT; + + if (ret) + hfi1_user_exp_rcv_invalid(fd, &tinfo); } return ret; diff --git a/drivers/infiniband/hw/hfi1/user_exp_rcv.c b/drivers/infiniband/hw/hfi1/user_exp_rcv.c index 186d30291260..350884d5f089 100644 --- a/drivers/infiniband/hw/hfi1/user_exp_rcv.c +++ b/drivers/infiniband/hw/hfi1/user_exp_rcv.c @@ -23,18 +23,25 @@ static void cacheless_tid_rb_remove(struct hfi1_filedata *fdata, static bool tid_rb_invalidate(struct mmu_interval_notifier *mni, const struct mmu_notifier_range *range, unsigned long cur_seq); +static bool tid_cover_invalidate(struct mmu_interval_notifier *mni, + const struct mmu_notifier_range *range, + unsigned long cur_seq); static int program_rcvarray(struct hfi1_filedata *fd, struct tid_user_buf *, struct tid_group *grp, unsigned int start, u16 count, u32 *tidlist, unsigned int *tididx, unsigned int *pmapped); -static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo, - struct tid_group **grp); +static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo); +static void __clear_tid_node(struct hfi1_filedata *fd, + struct tid_rb_node *node); static void clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node); static const struct mmu_interval_notifier_ops tid_mn_ops = { .invalidate = tid_rb_invalidate, }; +static const struct mmu_interval_notifier_ops tid_cover_ops = { + .invalidate = tid_cover_invalidate, +}; /* * Initialize context and file private data needed for Expected @@ -153,16 +160,11 @@ static void unpin_rcv_pages(struct hfi1_filedata *fd, static int pin_rcv_pages(struct hfi1_filedata *fd, struct tid_user_buf *tidbuf) { int pinned; - unsigned int npages; + unsigned int npages = tidbuf->npages; unsigned long vaddr = tidbuf->vaddr; struct page **pages = NULL; struct hfi1_devdata *dd = fd->uctxt->dd; - /* Get the number of pages the user buffer spans */ - npages = num_user_pages(vaddr, tidbuf->length); - if (!npages) - return -EINVAL; - if (npages > fd->uctxt->expected_count) { dd_dev_err(dd, "Expected buffer too big\n"); return -EINVAL; @@ -189,7 +191,6 @@ static int pin_rcv_pages(struct hfi1_filedata *fd, struct tid_user_buf *tidbuf) return pinned; } tidbuf->pages = pages; - tidbuf->npages = npages; fd->tid_n_pinned += pinned; return pinned; } @@ -253,53 +254,66 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd, tididx = 0, mapped, mapped_pages = 0; u32 *tidlist = NULL; struct tid_user_buf *tidbuf; + unsigned long mmu_seq = 0; if (!PAGE_ALIGNED(tinfo->vaddr)) return -EINVAL; + if (tinfo->length == 0) + return -EINVAL; tidbuf = kzalloc(sizeof(*tidbuf), GFP_KERNEL); if (!tidbuf) return -ENOMEM; + mutex_init(&tidbuf->cover_mutex); tidbuf->vaddr = tinfo->vaddr; tidbuf->length = tinfo->length; + tidbuf->npages = num_user_pages(tidbuf->vaddr, tidbuf->length); tidbuf->psets = kcalloc(uctxt->expected_count, sizeof(*tidbuf->psets), GFP_KERNEL); if (!tidbuf->psets) { - kfree(tidbuf); - return -ENOMEM; + ret = -ENOMEM; + goto fail_release_mem; + } + + if (fd->use_mn) { + ret = mmu_interval_notifier_insert( + &tidbuf->notifier, current->mm, + tidbuf->vaddr, tidbuf->npages * PAGE_SIZE, + &tid_cover_ops); + if (ret) + goto fail_release_mem; + mmu_seq = mmu_interval_read_begin(&tidbuf->notifier); } pinned = pin_rcv_pages(fd, tidbuf); if (pinned <= 0) { - kfree(tidbuf->psets); - kfree(tidbuf); - return pinned; + ret = (pinned < 0) ? pinned : -ENOSPC; + goto fail_unpin; } /* Find sets of physically contiguous pages */ tidbuf->n_psets = find_phys_blocks(tidbuf, pinned); - /* - * We don't need to access this under a lock since tid_used is per - * process and the same process cannot be in hfi1_user_exp_rcv_clear() - * and hfi1_user_exp_rcv_setup() at the same time. - */ + /* Reserve the number of expected tids to be used. */ spin_lock(&fd->tid_lock); if (fd->tid_used + tidbuf->n_psets > fd->tid_limit) pageset_count = fd->tid_limit - fd->tid_used; else pageset_count = tidbuf->n_psets; + fd->tid_used += pageset_count; spin_unlock(&fd->tid_lock); - if (!pageset_count) - goto bail; + if (!pageset_count) { + ret = -ENOSPC; + goto fail_unreserve; + } ngroups = pageset_count / dd->rcv_entries.group_size; tidlist = kcalloc(pageset_count, sizeof(*tidlist), GFP_KERNEL); if (!tidlist) { ret = -ENOMEM; - goto nomem; + goto fail_unreserve; } tididx = 0; @@ -395,43 +409,78 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd, } unlock: mutex_unlock(&uctxt->exp_mutex); -nomem: hfi1_cdbg(TID, "total mapped: tidpairs:%u pages:%u (%d)", tididx, mapped_pages, ret); - if (tididx) { - spin_lock(&fd->tid_lock); - fd->tid_used += tididx; - spin_unlock(&fd->tid_lock); - tinfo->tidcnt = tididx; - tinfo->length = mapped_pages * PAGE_SIZE; - - if (copy_to_user(u64_to_user_ptr(tinfo->tidlist), - tidlist, sizeof(tidlist[0]) * tididx)) { - /* - * On failure to copy to the user level, we need to undo - * everything done so far so we don't leak resources. - */ - tinfo->tidlist = (unsigned long)&tidlist; - hfi1_user_exp_rcv_clear(fd, tinfo); - tinfo->tidlist = 0; - ret = -EFAULT; - goto bail; + + /* fail if nothing was programmed, set error if none provided */ + if (tididx == 0) { + if (ret >= 0) + ret = -ENOSPC; + goto fail_unreserve; + } + + /* adjust reserved tid_used to actual count */ + spin_lock(&fd->tid_lock); + fd->tid_used -= pageset_count - tididx; + spin_unlock(&fd->tid_lock); + + /* unpin all pages not covered by a TID */ + unpin_rcv_pages(fd, tidbuf, NULL, mapped_pages, pinned - mapped_pages, + false); + + if (fd->use_mn) { + /* check for an invalidate during setup */ + bool fail = false; + + mutex_lock(&tidbuf->cover_mutex); + fail = mmu_interval_read_retry(&tidbuf->notifier, mmu_seq); + mutex_unlock(&tidbuf->cover_mutex); + + if (fail) { + ret = -EBUSY; + goto fail_unprogram; } } - /* - * If not everything was mapped (due to insufficient RcvArray entries, - * for example), unpin all unmapped pages so we can pin them nex time. - */ - if (mapped_pages != pinned) - unpin_rcv_pages(fd, tidbuf, NULL, mapped_pages, - (pinned - mapped_pages), false); -bail: + tinfo->tidcnt = tididx; + tinfo->length = mapped_pages * PAGE_SIZE; + + if (copy_to_user(u64_to_user_ptr(tinfo->tidlist), + tidlist, sizeof(tidlist[0]) * tididx)) { + ret = -EFAULT; + goto fail_unprogram; + } + + if (fd->use_mn) + mmu_interval_notifier_remove(&tidbuf->notifier); + kfree(tidbuf->pages); kfree(tidbuf->psets); + kfree(tidbuf); kfree(tidlist); + return 0; + +fail_unprogram: + /* unprogram, unmap, and unpin all allocated TIDs */ + tinfo->tidlist = (unsigned long)tidlist; + hfi1_user_exp_rcv_clear(fd, tinfo); + tinfo->tidlist = 0; + pinned = 0; /* nothing left to unpin */ + pageset_count = 0; /* nothing left reserved */ +fail_unreserve: + spin_lock(&fd->tid_lock); + fd->tid_used -= pageset_count; + spin_unlock(&fd->tid_lock); +fail_unpin: + if (fd->use_mn) + mmu_interval_notifier_remove(&tidbuf->notifier); + if (pinned > 0) + unpin_rcv_pages(fd, tidbuf, NULL, 0, pinned, false); +fail_release_mem: kfree(tidbuf->pages); + kfree(tidbuf->psets); kfree(tidbuf); - return ret > 0 ? 0 : ret; + kfree(tidlist); + return ret; } int hfi1_user_exp_rcv_clear(struct hfi1_filedata *fd, @@ -452,7 +501,7 @@ int hfi1_user_exp_rcv_clear(struct hfi1_filedata *fd, mutex_lock(&uctxt->exp_mutex); for (tididx = 0; tididx < tinfo->tidcnt; tididx++) { - ret = unprogram_rcvarray(fd, tidinfo[tididx], NULL); + ret = unprogram_rcvarray(fd, tidinfo[tididx]); if (ret) { hfi1_cdbg(TID, "Failed to unprogram rcv array %d", ret); @@ -706,6 +755,7 @@ static int set_rcvarray_entry(struct hfi1_filedata *fd, } node->fdata = fd; + mutex_init(&node->invalidate_mutex); node->phys = page_to_phys(pages[0]); node->npages = npages; node->rcventry = rcventry; @@ -721,11 +771,6 @@ static int set_rcvarray_entry(struct hfi1_filedata *fd, &tid_mn_ops); if (ret) goto out_unmap; - /* - * FIXME: This is in the wrong order, the notifier should be - * established before the pages are pinned by pin_rcv_pages. - */ - mmu_interval_read_begin(&node->notifier); } fd->entry_to_rb[node->rcventry - uctxt->expected_base] = node; @@ -745,8 +790,7 @@ out_unmap: return -EFAULT; } -static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo, - struct tid_group **grp) +static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo) { struct hfi1_ctxtdata *uctxt = fd->uctxt; struct hfi1_devdata *dd = uctxt->dd; @@ -769,9 +813,6 @@ static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo, if (!node || node->rcventry != (uctxt->expected_base + rcventry)) return -EBADF; - if (grp) - *grp = node->grp; - if (fd->use_mn) mmu_interval_notifier_remove(&node->notifier); cacheless_tid_rb_remove(fd, node); @@ -779,23 +820,34 @@ static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo, return 0; } -static void clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node) +static void __clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node) { struct hfi1_ctxtdata *uctxt = fd->uctxt; struct hfi1_devdata *dd = uctxt->dd; + mutex_lock(&node->invalidate_mutex); + if (node->freed) + goto done; + node->freed = true; + trace_hfi1_exp_tid_unreg(uctxt->ctxt, fd->subctxt, node->rcventry, node->npages, node->notifier.interval_tree.start, node->phys, node->dma_addr); - /* - * Make sure device has seen the write before we unpin the - * pages. - */ + /* Make sure device has seen the write before pages are unpinned */ hfi1_put_tid(dd, node->rcventry, PT_INVALID_FLUSH, 0, 0); unpin_rcv_pages(fd, NULL, node, 0, node->npages, true); +done: + mutex_unlock(&node->invalidate_mutex); +} + +static void clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node) +{ + struct hfi1_ctxtdata *uctxt = fd->uctxt; + + __clear_tid_node(fd, node); node->grp->used--; node->grp->map &= ~(1 << (node->rcventry - node->grp->base)); @@ -854,10 +906,16 @@ static bool tid_rb_invalidate(struct mmu_interval_notifier *mni, if (node->freed) return true; + /* take action only if unmapping */ + if (range->event != MMU_NOTIFY_UNMAP) + return true; + trace_hfi1_exp_tid_inval(uctxt->ctxt, fdata->subctxt, node->notifier.interval_tree.start, node->rcventry, node->npages, node->dma_addr); - node->freed = true; + + /* clear the hardware rcvarray entry */ + __clear_tid_node(fdata, node); spin_lock(&fdata->invalid_lock); if (fdata->invalid_tid_idx < uctxt->expected_count) { @@ -887,6 +945,23 @@ static bool tid_rb_invalidate(struct mmu_interval_notifier *mni, return true; } +static bool tid_cover_invalidate(struct mmu_interval_notifier *mni, + const struct mmu_notifier_range *range, + unsigned long cur_seq) +{ + struct tid_user_buf *tidbuf = + container_of(mni, struct tid_user_buf, notifier); + + /* take action only if unmapping */ + if (range->event == MMU_NOTIFY_UNMAP) { + mutex_lock(&tidbuf->cover_mutex); + mmu_interval_set_seq(mni, cur_seq); + mutex_unlock(&tidbuf->cover_mutex); + } + + return true; +} + static void cacheless_tid_rb_remove(struct hfi1_filedata *fdata, struct tid_rb_node *tnode) { diff --git a/drivers/infiniband/hw/hfi1/user_exp_rcv.h b/drivers/infiniband/hw/hfi1/user_exp_rcv.h index 8c53e416bf84..f8ee997d0050 100644 --- a/drivers/infiniband/hw/hfi1/user_exp_rcv.h +++ b/drivers/infiniband/hw/hfi1/user_exp_rcv.h @@ -16,6 +16,8 @@ struct tid_pageset { }; struct tid_user_buf { + struct mmu_interval_notifier notifier; + struct mutex cover_mutex; unsigned long vaddr; unsigned long length; unsigned int npages; @@ -27,6 +29,7 @@ struct tid_user_buf { struct tid_rb_node { struct mmu_interval_notifier notifier; struct hfi1_filedata *fdata; + struct mutex invalidate_mutex; /* covers hw removal */ unsigned long phys; struct tid_group *grp; u32 rcventry; diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c index 7b086fe63a24..195aa9ea18b6 100644 --- a/drivers/infiniband/hw/irdma/cm.c +++ b/drivers/infiniband/hw/irdma/cm.c @@ -1722,6 +1722,9 @@ static int irdma_add_mqh_4(struct irdma_device *iwdev, continue; idev = in_dev_get(ip_dev); + if (!idev) + continue; + in_dev_for_each_ifa_rtnl(ifa, idev) { ibdev_dbg(&iwdev->ibdev, "CM: Allocating child CM Listener forIP=%pI4, vlan_id=%d, MAC=%pM\n", diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c index ea15ec77e321..54b61930a7fd 100644 --- a/drivers/infiniband/hw/mana/qp.c +++ b/drivers/infiniband/hw/mana/qp.c @@ -289,7 +289,7 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd, /* IB ports start with 1, MANA Ethernet ports start with 0 */ port = ucmd.port; - if (ucmd.port > mc->num_ports) + if (port < 1 || port > mc->num_ports) return -EINVAL; if (attr->cap.max_send_wr > MAX_SEND_BUFFERS_PER_QUEUE) { diff --git a/drivers/infiniband/hw/mlx5/counters.c b/drivers/infiniband/hw/mlx5/counters.c index 945758f39523..3e1272695d99 100644 --- a/drivers/infiniband/hw/mlx5/counters.c +++ b/drivers/infiniband/hw/mlx5/counters.c @@ -278,7 +278,6 @@ static int do_get_hw_stats(struct ib_device *ibdev, const struct mlx5_ib_counters *cnts = get_counters(dev, port_num - 1); struct mlx5_core_dev *mdev; int ret, num_counters; - u32 mdev_port_num; if (!stats) return -EINVAL; @@ -299,8 +298,9 @@ static int do_get_hw_stats(struct ib_device *ibdev, } if (MLX5_CAP_GEN(dev->mdev, cc_query_allowed)) { - mdev = mlx5_ib_get_native_port_mdev(dev, port_num, - &mdev_port_num); + if (!port_num) + port_num = 1; + mdev = mlx5_ib_get_native_port_mdev(dev, port_num, NULL); if (!mdev) { /* If port is not affiliated yet, its in down state * which doesn't have any counters yet, so it would be diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 40d9410ec303..cf953d23d18d 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -4502,6 +4502,40 @@ static bool mlx5_ib_modify_qp_allowed(struct mlx5_ib_dev *dev, return false; } +static int validate_rd_atomic(struct mlx5_ib_dev *dev, struct ib_qp_attr *attr, + int attr_mask, enum ib_qp_type qp_type) +{ + int log_max_ra_res; + int log_max_ra_req; + + if (qp_type == MLX5_IB_QPT_DCI) { + log_max_ra_res = 1 << MLX5_CAP_GEN(dev->mdev, + log_max_ra_res_dc); + log_max_ra_req = 1 << MLX5_CAP_GEN(dev->mdev, + log_max_ra_req_dc); + } else { + log_max_ra_res = 1 << MLX5_CAP_GEN(dev->mdev, + log_max_ra_res_qp); + log_max_ra_req = 1 << MLX5_CAP_GEN(dev->mdev, + log_max_ra_req_qp); + } + + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && + attr->max_rd_atomic > log_max_ra_res) { + mlx5_ib_dbg(dev, "invalid max_rd_atomic value %d\n", + attr->max_rd_atomic); + return false; + } + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && + attr->max_dest_rd_atomic > log_max_ra_req) { + mlx5_ib_dbg(dev, "invalid max_dest_rd_atomic value %d\n", + attr->max_dest_rd_atomic); + return false; + } + return true; +} + int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, struct ib_udata *udata) { @@ -4589,21 +4623,8 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, goto out; } - if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && - attr->max_rd_atomic > - (1 << MLX5_CAP_GEN(dev->mdev, log_max_ra_res_qp))) { - mlx5_ib_dbg(dev, "invalid max_rd_atomic value %d\n", - attr->max_rd_atomic); - goto out; - } - - if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && - attr->max_dest_rd_atomic > - (1 << MLX5_CAP_GEN(dev->mdev, log_max_ra_req_qp))) { - mlx5_ib_dbg(dev, "invalid max_dest_rd_atomic value %d\n", - attr->max_dest_rd_atomic); + if (!validate_rd_atomic(dev, attr, attr_mask, qp_type)) goto out; - } if (cur_state == new_state && cur_state == IB_QPS_RESET) { err = 0; diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c index c301b3be9f30..a2857accc427 100644 --- a/drivers/infiniband/hw/usnic/usnic_uiom.c +++ b/drivers/infiniband/hw/usnic/usnic_uiom.c @@ -276,8 +276,8 @@ iter_chunk: size = pa_end - pa_start + PAGE_SIZE; usnic_dbg("va 0x%lx pa %pa size 0x%zx flags 0x%x", va_start, &pa_start, size, flags); - err = iommu_map(pd->domain, va_start, pa_start, - size, flags); + err = iommu_map_atomic(pd->domain, va_start, + pa_start, size, flags); if (err) { usnic_err("Failed to map va 0x%lx pa %pa size 0x%zx with err %d\n", va_start, &pa_start, size, err); @@ -293,8 +293,8 @@ iter_chunk: size = pa - pa_start + PAGE_SIZE; usnic_dbg("va 0x%lx pa %pa size 0x%zx flags 0x%x\n", va_start, &pa_start, size, flags); - err = iommu_map(pd->domain, va_start, pa_start, - size, flags); + err = iommu_map_atomic(pd->domain, va_start, + pa_start, size, flags); if (err) { usnic_err("Failed to map va 0x%lx pa %pa size 0x%zx with err %d\n", va_start, &pa_start, size, err); diff --git a/drivers/infiniband/sw/rxe/rxe_param.h b/drivers/infiniband/sw/rxe/rxe_param.h index a754fc902e3d..7b41d79e72b2 100644 --- a/drivers/infiniband/sw/rxe/rxe_param.h +++ b/drivers/infiniband/sw/rxe/rxe_param.h @@ -98,11 +98,11 @@ enum rxe_device_param { RXE_MAX_SRQ = DEFAULT_MAX_VALUE - RXE_MIN_SRQ_INDEX, RXE_MIN_MR_INDEX = 0x00000001, - RXE_MAX_MR_INDEX = DEFAULT_MAX_VALUE, - RXE_MAX_MR = DEFAULT_MAX_VALUE - RXE_MIN_MR_INDEX, - RXE_MIN_MW_INDEX = 0x00010001, - RXE_MAX_MW_INDEX = 0x00020000, - RXE_MAX_MW = 0x00001000, + RXE_MAX_MR_INDEX = DEFAULT_MAX_VALUE >> 1, + RXE_MAX_MR = RXE_MAX_MR_INDEX - RXE_MIN_MR_INDEX, + RXE_MIN_MW_INDEX = RXE_MAX_MR_INDEX + 1, + RXE_MAX_MW_INDEX = DEFAULT_MAX_VALUE, + RXE_MAX_MW = RXE_MAX_MW_INDEX - RXE_MIN_MW_INDEX, RXE_MAX_PKT_PER_ACK = 64, diff --git a/drivers/infiniband/sw/rxe/rxe_pool.c b/drivers/infiniband/sw/rxe/rxe_pool.c index f50620f5a0a1..1151c0b5ccea 100644 --- a/drivers/infiniband/sw/rxe/rxe_pool.c +++ b/drivers/infiniband/sw/rxe/rxe_pool.c @@ -23,16 +23,16 @@ static const struct rxe_type_info { .size = sizeof(struct rxe_ucontext), .elem_offset = offsetof(struct rxe_ucontext, elem), .min_index = 1, - .max_index = UINT_MAX, - .max_elem = UINT_MAX, + .max_index = RXE_MAX_UCONTEXT, + .max_elem = RXE_MAX_UCONTEXT, }, [RXE_TYPE_PD] = { .name = "pd", .size = sizeof(struct rxe_pd), .elem_offset = offsetof(struct rxe_pd, elem), .min_index = 1, - .max_index = UINT_MAX, - .max_elem = UINT_MAX, + .max_index = RXE_MAX_PD, + .max_elem = RXE_MAX_PD, }, [RXE_TYPE_AH] = { .name = "ah", @@ -40,7 +40,7 @@ static const struct rxe_type_info { .elem_offset = offsetof(struct rxe_ah, elem), .min_index = RXE_MIN_AH_INDEX, .max_index = RXE_MAX_AH_INDEX, - .max_elem = RXE_MAX_AH_INDEX - RXE_MIN_AH_INDEX + 1, + .max_elem = RXE_MAX_AH, }, [RXE_TYPE_SRQ] = { .name = "srq", @@ -49,7 +49,7 @@ static const struct rxe_type_info { .cleanup = rxe_srq_cleanup, .min_index = RXE_MIN_SRQ_INDEX, .max_index = RXE_MAX_SRQ_INDEX, - .max_elem = RXE_MAX_SRQ_INDEX - RXE_MIN_SRQ_INDEX + 1, + .max_elem = RXE_MAX_SRQ, }, [RXE_TYPE_QP] = { .name = "qp", @@ -58,7 +58,7 @@ static const struct rxe_type_info { .cleanup = rxe_qp_cleanup, .min_index = RXE_MIN_QP_INDEX, .max_index = RXE_MAX_QP_INDEX, - .max_elem = RXE_MAX_QP_INDEX - RXE_MIN_QP_INDEX + 1, + .max_elem = RXE_MAX_QP, }, [RXE_TYPE_CQ] = { .name = "cq", @@ -66,8 +66,8 @@ static const struct rxe_type_info { .elem_offset = offsetof(struct rxe_cq, elem), .cleanup = rxe_cq_cleanup, .min_index = 1, - .max_index = UINT_MAX, - .max_elem = UINT_MAX, + .max_index = RXE_MAX_CQ, + .max_elem = RXE_MAX_CQ, }, [RXE_TYPE_MR] = { .name = "mr", @@ -76,7 +76,7 @@ static const struct rxe_type_info { .cleanup = rxe_mr_cleanup, .min_index = RXE_MIN_MR_INDEX, .max_index = RXE_MAX_MR_INDEX, - .max_elem = RXE_MAX_MR_INDEX - RXE_MIN_MR_INDEX + 1, + .max_elem = RXE_MAX_MR, }, [RXE_TYPE_MW] = { .name = "mw", @@ -85,7 +85,7 @@ static const struct rxe_type_info { .cleanup = rxe_mw_cleanup, .min_index = RXE_MIN_MW_INDEX, .max_index = RXE_MAX_MW_INDEX, - .max_elem = RXE_MAX_MW_INDEX - RXE_MIN_MW_INDEX + 1, + .max_elem = RXE_MAX_MW, }, }; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index ac25fc80fb33..f10d4bcf87d2 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -2200,6 +2200,14 @@ int ipoib_intf_init(struct ib_device *hca, u32 port, const char *name, rn->attach_mcast = ipoib_mcast_attach; rn->detach_mcast = ipoib_mcast_detach; rn->hca = hca; + + rc = netif_set_real_num_tx_queues(dev, 1); + if (rc) + goto out; + + rc = netif_set_real_num_rx_queues(dev, 1); + if (rc) + goto out; } priv->rn_ops = dev->netdev_ops; diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c b/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c index c76ba29da1e2..5adba0f754b6 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c @@ -312,9 +312,8 @@ void rtrs_srv_destroy_path_files(struct rtrs_srv_path *srv_path) if (srv_path->kobj.state_in_sysfs) { sysfs_remove_group(&srv_path->kobj, &rtrs_srv_path_attr_group); - kobject_del(&srv_path->kobj); kobject_put(&srv_path->kobj); + rtrs_srv_destroy_once_sysfs_root_folders(srv_path); } - rtrs_srv_destroy_once_sysfs_root_folders(srv_path); } diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index 00b0068fda20..5d94db453df3 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -62,9 +62,6 @@ enum { SRP_DEFAULT_CMD_SQ_SIZE = SRP_DEFAULT_QUEUE_SIZE - SRP_RSP_SQ_SIZE - SRP_TSK_MGMT_SQ_SIZE, - SRP_TAG_NO_REQ = ~0U, - SRP_TAG_TSK_MGMT = 1U << 31, - SRP_MAX_PAGES_PER_MR = 512, SRP_MAX_ADD_CDB_LEN = 16, @@ -79,6 +76,11 @@ enum { sizeof(struct srp_imm_buf), }; +enum { + SRP_TAG_NO_REQ = ~0U, + SRP_TAG_TSK_MGMT = BIT(31), +}; + enum srp_target_state { SRP_TARGET_SCANNING, SRP_TARGET_LIVE, diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 84490915ae4d..d98650426dc2 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -550,15 +550,6 @@ config KEYBOARD_PXA27x To compile this driver as a module, choose M here: the module will be called pxa27x_keypad. -config KEYBOARD_PXA930_ROTARY - tristate "PXA930/PXA935 Enhanced Rotary Controller Support" - depends on CPU_PXA930 || CPU_PXA935 - help - Enable support for PXA930/PXA935 Enhanced Rotary Controller. - - To compile this driver as a module, choose M here: the - module will be called pxa930_rotary. - config KEYBOARD_PMIC8XXX tristate "Qualcomm PMIC8XXX keypad support" depends on MFD_PM8XXX @@ -657,16 +648,6 @@ config KEYBOARD_SUN4I_LRADC To compile this driver as a module, choose M here: the module will be called sun4i-lradc-keys. -config KEYBOARD_DAVINCI - tristate "TI DaVinci Key Scan" - depends on ARCH_DAVINCI_DM365 - help - Say Y to enable keypad module support for the TI DaVinci - platforms (DM365). - - To compile this driver as a module, choose M here: the - module will be called davinci_keyscan. - config KEYBOARD_IPAQ_MICRO tristate "Buttons on Micro SoC (iPaq h3100,h3600,h3700)" depends on MFD_IPAQ_MICRO diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 5f67196bb2c1..aecef00c5d09 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o obj-$(CONFIG_KEYBOARD_CYPRESS_SF) += cypress-sf.o -obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o obj-$(CONFIG_KEYBOARD_DLINK_DIR685) += dlink-dir685-touchkeys.o obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o @@ -55,7 +54,6 @@ obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o obj-$(CONFIG_KEYBOARD_PINEPHONE) += pinephone-keyboard.o obj-$(CONFIG_KEYBOARD_PMIC8XXX) += pmic8xxx-keypad.o obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o -obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o obj-$(CONFIG_KEYBOARD_QT1050) += qt1050.o obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c deleted file mode 100644 index f489cd585b33..000000000000 --- a/drivers/input/keyboard/davinci_keyscan.c +++ /dev/null @@ -1,315 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * DaVinci Key Scan Driver for TI platforms - * - * Copyright (C) 2009 Texas Instruments, Inc - * - * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com> - * - * Initial Code: Sandeep Paulraj <s-paulraj@ti.com> - */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/types.h> -#include <linux/input.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/platform_device.h> -#include <linux/errno.h> -#include <linux/slab.h> - -#include <linux/platform_data/keyscan-davinci.h> - -/* Key scan registers */ -#define DAVINCI_KEYSCAN_KEYCTRL 0x0000 -#define DAVINCI_KEYSCAN_INTENA 0x0004 -#define DAVINCI_KEYSCAN_INTFLAG 0x0008 -#define DAVINCI_KEYSCAN_INTCLR 0x000c -#define DAVINCI_KEYSCAN_STRBWIDTH 0x0010 -#define DAVINCI_KEYSCAN_INTERVAL 0x0014 -#define DAVINCI_KEYSCAN_CONTTIME 0x0018 -#define DAVINCI_KEYSCAN_CURRENTST 0x001c -#define DAVINCI_KEYSCAN_PREVSTATE 0x0020 -#define DAVINCI_KEYSCAN_EMUCTRL 0x0024 -#define DAVINCI_KEYSCAN_IODFTCTRL 0x002c - -/* Key Control Register (KEYCTRL) */ -#define DAVINCI_KEYSCAN_KEYEN 0x00000001 -#define DAVINCI_KEYSCAN_PREVMODE 0x00000002 -#define DAVINCI_KEYSCAN_CHATOFF 0x00000004 -#define DAVINCI_KEYSCAN_AUTODET 0x00000008 -#define DAVINCI_KEYSCAN_SCANMODE 0x00000010 -#define DAVINCI_KEYSCAN_OUTTYPE 0x00000020 - -/* Masks for the interrupts */ -#define DAVINCI_KEYSCAN_INT_CONT 0x00000008 -#define DAVINCI_KEYSCAN_INT_OFF 0x00000004 -#define DAVINCI_KEYSCAN_INT_ON 0x00000002 -#define DAVINCI_KEYSCAN_INT_CHANGE 0x00000001 -#define DAVINCI_KEYSCAN_INT_ALL 0x0000000f - -struct davinci_ks { - struct input_dev *input; - struct davinci_ks_platform_data *pdata; - int irq; - void __iomem *base; - resource_size_t pbase; - size_t base_size; - unsigned short keymap[]; -}; - -/* Initializing the kp Module */ -static int __init davinci_ks_initialize(struct davinci_ks *davinci_ks) -{ - struct device *dev = &davinci_ks->input->dev; - struct davinci_ks_platform_data *pdata = davinci_ks->pdata; - u32 matrix_ctrl; - - /* Enable all interrupts */ - __raw_writel(DAVINCI_KEYSCAN_INT_ALL, - davinci_ks->base + DAVINCI_KEYSCAN_INTENA); - - /* Clear interrupts if any */ - __raw_writel(DAVINCI_KEYSCAN_INT_ALL, - davinci_ks->base + DAVINCI_KEYSCAN_INTCLR); - - /* Setup the scan period = strobe + interval */ - __raw_writel(pdata->strobe, - davinci_ks->base + DAVINCI_KEYSCAN_STRBWIDTH); - __raw_writel(pdata->interval, - davinci_ks->base + DAVINCI_KEYSCAN_INTERVAL); - __raw_writel(0x01, - davinci_ks->base + DAVINCI_KEYSCAN_CONTTIME); - - /* Define matrix type */ - switch (pdata->matrix_type) { - case DAVINCI_KEYSCAN_MATRIX_4X4: - matrix_ctrl = 0; - break; - case DAVINCI_KEYSCAN_MATRIX_5X3: - matrix_ctrl = (1 << 6); - break; - default: - dev_err(dev->parent, "wrong matrix type\n"); - return -EINVAL; - } - - /* Enable key scan module and set matrix type */ - __raw_writel(DAVINCI_KEYSCAN_AUTODET | DAVINCI_KEYSCAN_KEYEN | - matrix_ctrl, davinci_ks->base + DAVINCI_KEYSCAN_KEYCTRL); - - return 0; -} - -static irqreturn_t davinci_ks_interrupt(int irq, void *dev_id) -{ - struct davinci_ks *davinci_ks = dev_id; - struct device *dev = &davinci_ks->input->dev; - unsigned short *keymap = davinci_ks->keymap; - int keymapsize = davinci_ks->pdata->keymapsize; - u32 prev_status, new_status, changed; - bool release; - int keycode = KEY_UNKNOWN; - int i; - - /* Disable interrupt */ - __raw_writel(0x0, davinci_ks->base + DAVINCI_KEYSCAN_INTENA); - - /* Reading previous and new status of the key scan */ - prev_status = __raw_readl(davinci_ks->base + DAVINCI_KEYSCAN_PREVSTATE); - new_status = __raw_readl(davinci_ks->base + DAVINCI_KEYSCAN_CURRENTST); - - changed = prev_status ^ new_status; - - if (changed) { - /* - * It goes through all bits in 'changed' to ensure - * that no key changes are being missed - */ - for (i = 0 ; i < keymapsize; i++) { - if ((changed>>i) & 0x1) { - keycode = keymap[i]; - release = (new_status >> i) & 0x1; - dev_dbg(dev->parent, "key %d %s\n", keycode, - release ? "released" : "pressed"); - input_report_key(davinci_ks->input, keycode, - !release); - input_sync(davinci_ks->input); - } - } - /* Clearing interrupt */ - __raw_writel(DAVINCI_KEYSCAN_INT_ALL, - davinci_ks->base + DAVINCI_KEYSCAN_INTCLR); - } - - /* Enable interrupts */ - __raw_writel(0x1, davinci_ks->base + DAVINCI_KEYSCAN_INTENA); - - return IRQ_HANDLED; -} - -static int __init davinci_ks_probe(struct platform_device *pdev) -{ - struct davinci_ks *davinci_ks; - struct input_dev *key_dev; - struct resource *res, *mem; - struct device *dev = &pdev->dev; - struct davinci_ks_platform_data *pdata = dev_get_platdata(dev); - int error, i; - - if (pdata->device_enable) { - error = pdata->device_enable(dev); - if (error < 0) { - dev_dbg(dev, "device enable function failed\n"); - return error; - } - } - - if (!pdata->keymap) { - dev_dbg(dev, "no keymap from pdata\n"); - return -EINVAL; - } - - davinci_ks = kzalloc(sizeof(struct davinci_ks) + - sizeof(unsigned short) * pdata->keymapsize, GFP_KERNEL); - if (!davinci_ks) { - dev_dbg(dev, "could not allocate memory for private data\n"); - return -ENOMEM; - } - - memcpy(davinci_ks->keymap, pdata->keymap, - sizeof(unsigned short) * pdata->keymapsize); - - key_dev = input_allocate_device(); - if (!key_dev) { - dev_dbg(dev, "could not allocate input device\n"); - error = -ENOMEM; - goto fail1; - } - - davinci_ks->input = key_dev; - - davinci_ks->irq = platform_get_irq(pdev, 0); - if (davinci_ks->irq < 0) { - error = davinci_ks->irq; - goto fail2; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "no mem resource\n"); - error = -EINVAL; - goto fail2; - } - - davinci_ks->pbase = res->start; - davinci_ks->base_size = resource_size(res); - - mem = request_mem_region(davinci_ks->pbase, davinci_ks->base_size, - pdev->name); - if (!mem) { - dev_err(dev, "key scan registers at %08x are not free\n", - davinci_ks->pbase); - error = -EBUSY; - goto fail2; - } - - davinci_ks->base = ioremap(davinci_ks->pbase, davinci_ks->base_size); - if (!davinci_ks->base) { - dev_err(dev, "can't ioremap MEM resource.\n"); - error = -ENOMEM; - goto fail3; - } - - /* Enable auto repeat feature of Linux input subsystem */ - if (pdata->rep) - __set_bit(EV_REP, key_dev->evbit); - - /* Setup input device */ - __set_bit(EV_KEY, key_dev->evbit); - - /* Setup the platform data */ - davinci_ks->pdata = pdata; - - for (i = 0; i < davinci_ks->pdata->keymapsize; i++) - __set_bit(davinci_ks->pdata->keymap[i], key_dev->keybit); - - key_dev->name = "davinci_keyscan"; - key_dev->phys = "davinci_keyscan/input0"; - key_dev->dev.parent = dev; - key_dev->id.bustype = BUS_HOST; - key_dev->id.vendor = 0x0001; - key_dev->id.product = 0x0001; - key_dev->id.version = 0x0001; - key_dev->keycode = davinci_ks->keymap; - key_dev->keycodesize = sizeof(davinci_ks->keymap[0]); - key_dev->keycodemax = davinci_ks->pdata->keymapsize; - - error = input_register_device(davinci_ks->input); - if (error < 0) { - dev_err(dev, "unable to register davinci key scan device\n"); - goto fail4; - } - - error = request_irq(davinci_ks->irq, davinci_ks_interrupt, - 0, pdev->name, davinci_ks); - if (error < 0) { - dev_err(dev, "unable to register davinci key scan interrupt\n"); - goto fail5; - } - - error = davinci_ks_initialize(davinci_ks); - if (error < 0) { - dev_err(dev, "unable to initialize davinci key scan device\n"); - goto fail6; - } - - platform_set_drvdata(pdev, davinci_ks); - return 0; - -fail6: - free_irq(davinci_ks->irq, davinci_ks); -fail5: - input_unregister_device(davinci_ks->input); - key_dev = NULL; -fail4: - iounmap(davinci_ks->base); -fail3: - release_mem_region(davinci_ks->pbase, davinci_ks->base_size); -fail2: - input_free_device(key_dev); -fail1: - kfree(davinci_ks); - - return error; -} - -static int davinci_ks_remove(struct platform_device *pdev) -{ - struct davinci_ks *davinci_ks = platform_get_drvdata(pdev); - - free_irq(davinci_ks->irq, davinci_ks); - - input_unregister_device(davinci_ks->input); - - iounmap(davinci_ks->base); - release_mem_region(davinci_ks->pbase, davinci_ks->base_size); - - kfree(davinci_ks); - - return 0; -} - -static struct platform_driver davinci_ks_driver = { - .driver = { - .name = "davinci_keyscan", - }, - .remove = davinci_ks_remove, -}; - -module_platform_driver_probe(davinci_ks_driver, davinci_ks_probe); - -MODULE_AUTHOR("Miguel Aguilar"); -MODULE_DESCRIPTION("Texas Instruments DaVinci Key Scan Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c deleted file mode 100644 index 2fe9dcfe0a6f..000000000000 --- a/drivers/input/keyboard/pxa930_rotary.c +++ /dev/null @@ -1,195 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for the enhanced rotary controller on pxa930 and pxa935 - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/input.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/slab.h> - -#include <linux/platform_data/keyboard-pxa930_rotary.h> - -#define SBCR (0x04) -#define ERCR (0x0c) - -#define SBCR_ERSB (1 << 5) - -struct pxa930_rotary { - struct input_dev *input_dev; - void __iomem *mmio_base; - int last_ercr; - - struct pxa930_rotary_platform_data *pdata; -}; - -static void clear_sbcr(struct pxa930_rotary *r) -{ - uint32_t sbcr = __raw_readl(r->mmio_base + SBCR); - - __raw_writel(sbcr | SBCR_ERSB, r->mmio_base + SBCR); - __raw_writel(sbcr & ~SBCR_ERSB, r->mmio_base + SBCR); -} - -static irqreturn_t rotary_irq(int irq, void *dev_id) -{ - struct pxa930_rotary *r = dev_id; - struct pxa930_rotary_platform_data *pdata = r->pdata; - int ercr, delta, key; - - ercr = __raw_readl(r->mmio_base + ERCR) & 0xf; - clear_sbcr(r); - - delta = ercr - r->last_ercr; - if (delta == 0) - return IRQ_HANDLED; - - r->last_ercr = ercr; - - if (pdata->up_key && pdata->down_key) { - key = (delta > 0) ? pdata->up_key : pdata->down_key; - input_report_key(r->input_dev, key, 1); - input_sync(r->input_dev); - input_report_key(r->input_dev, key, 0); - } else - input_report_rel(r->input_dev, pdata->rel_code, delta); - - input_sync(r->input_dev); - - return IRQ_HANDLED; -} - -static int pxa930_rotary_open(struct input_dev *dev) -{ - struct pxa930_rotary *r = input_get_drvdata(dev); - - clear_sbcr(r); - - return 0; -} - -static void pxa930_rotary_close(struct input_dev *dev) -{ - struct pxa930_rotary *r = input_get_drvdata(dev); - - clear_sbcr(r); -} - -static int pxa930_rotary_probe(struct platform_device *pdev) -{ - struct pxa930_rotary_platform_data *pdata = - dev_get_platdata(&pdev->dev); - struct pxa930_rotary *r; - struct input_dev *input_dev; - struct resource *res; - int irq; - int err; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -ENXIO; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "no I/O memory defined\n"); - return -ENXIO; - } - - if (!pdata) { - dev_err(&pdev->dev, "no platform data defined\n"); - return -EINVAL; - } - - r = kzalloc(sizeof(struct pxa930_rotary), GFP_KERNEL); - if (!r) - return -ENOMEM; - - r->mmio_base = ioremap(res->start, resource_size(res)); - if (r->mmio_base == NULL) { - dev_err(&pdev->dev, "failed to remap IO memory\n"); - err = -ENXIO; - goto failed_free; - } - - r->pdata = pdata; - platform_set_drvdata(pdev, r); - - /* allocate and register the input device */ - input_dev = input_allocate_device(); - if (!input_dev) { - dev_err(&pdev->dev, "failed to allocate input device\n"); - err = -ENOMEM; - goto failed_free_io; - } - - input_dev->name = pdev->name; - input_dev->id.bustype = BUS_HOST; - input_dev->open = pxa930_rotary_open; - input_dev->close = pxa930_rotary_close; - input_dev->dev.parent = &pdev->dev; - - if (pdata->up_key && pdata->down_key) { - __set_bit(pdata->up_key, input_dev->keybit); - __set_bit(pdata->down_key, input_dev->keybit); - __set_bit(EV_KEY, input_dev->evbit); - } else { - __set_bit(pdata->rel_code, input_dev->relbit); - __set_bit(EV_REL, input_dev->evbit); - } - - r->input_dev = input_dev; - input_set_drvdata(input_dev, r); - - err = request_irq(irq, rotary_irq, 0, - "enhanced rotary", r); - if (err) { - dev_err(&pdev->dev, "failed to request IRQ\n"); - goto failed_free_input; - } - - err = input_register_device(input_dev); - if (err) { - dev_err(&pdev->dev, "failed to register input device\n"); - goto failed_free_irq; - } - - return 0; - -failed_free_irq: - free_irq(irq, r); -failed_free_input: - input_free_device(input_dev); -failed_free_io: - iounmap(r->mmio_base); -failed_free: - kfree(r); - return err; -} - -static int pxa930_rotary_remove(struct platform_device *pdev) -{ - struct pxa930_rotary *r = platform_get_drvdata(pdev); - - free_irq(platform_get_irq(pdev, 0), r); - input_unregister_device(r->input_dev); - iounmap(r->mmio_base); - kfree(r); - - return 0; -} - -static struct platform_driver pxa930_rotary_driver = { - .driver = { - .name = "pxa930-rotary", - }, - .probe = pxa930_rotary_probe, - .remove = pxa930_rotary_remove, -}; -module_platform_driver(pxa930_rotary_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Driver for PXA93x Enhanced Rotary Controller"); -MODULE_AUTHOR("Yao Yong <yaoyong@marvell.com>"); diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 8d8ebdc2039b..67f1c7364c95 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -51,7 +51,7 @@ module_param_array(ptr_size, int, NULL, 0444); MODULE_PARM_DESC(ptr_size, "Pointing device width, height in pixels (default 800,600)"); -static int xenkbd_remove(struct xenbus_device *); +static void xenkbd_remove(struct xenbus_device *); static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); static void xenkbd_disconnect_backend(struct xenkbd_info *); @@ -404,7 +404,7 @@ static int xenkbd_resume(struct xenbus_device *dev) return xenkbd_connect_backend(dev, info); } -static int xenkbd_remove(struct xenbus_device *dev) +static void xenkbd_remove(struct xenbus_device *dev) { struct xenkbd_info *info = dev_get_drvdata(&dev->dev); @@ -417,7 +417,6 @@ static int xenkbd_remove(struct xenbus_device *dev) input_unregister_device(info->mtouch); free_page((unsigned long)info->page); kfree(info); - return 0; } static int xenkbd_connect_backend(struct xenbus_device *dev, diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 63c9cda555c3..32cc4c62a716 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -393,12 +393,6 @@ config MOUSE_GPIO To compile this driver as a module, choose M here: the module will be called gpio_mouse. -config MOUSE_PXA930_TRKBALL - tristate "PXA930 Trackball mouse" - depends on CPU_PXA930 || CPU_PXA935 - help - Say Y here to support PXA930 Trackball mouse. - config MOUSE_MAPLE tristate "Maple mouse (for the Dreamcast)" depends on MAPLE diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index e49f08565076..92b3204ce84e 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o obj-$(CONFIG_MOUSE_NAVPOINT_PXA27x) += navpoint.o obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o obj-$(CONFIG_MOUSE_PS2) += psmouse.o -obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c deleted file mode 100644 index f04ba12dbfa8..000000000000 --- a/drivers/input/mouse/pxa930_trkball.c +++ /dev/null @@ -1,250 +0,0 @@ -// 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 - */ - -#include <linux/input.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/slab.h> - -#include <linux/platform_data/mouse-pxa930_trkball.h> - -/* Trackball Controller Register Definitions */ -#define TBCR (0x000C) -#define TBCNTR (0x0010) -#define TBSBC (0x0014) - -#define TBCR_TBRST (1 << 1) -#define TBCR_TBSB (1 << 10) - -#define TBCR_Y_FLT(n) (((n) & 0xf) << 6) -#define TBCR_X_FLT(n) (((n) & 0xf) << 2) - -#define TBCNTR_YM(n) (((n) >> 24) & 0xff) -#define TBCNTR_YP(n) (((n) >> 16) & 0xff) -#define TBCNTR_XM(n) (((n) >> 8) & 0xff) -#define TBCNTR_XP(n) ((n) & 0xff) - -#define TBSBC_TBSBC (0x1) - -struct pxa930_trkball { - struct pxa930_trkball_platform_data *pdata; - - /* Memory Mapped Register */ - struct resource *mem; - void __iomem *mmio_base; - - struct input_dev *input; -}; - -static irqreturn_t pxa930_trkball_interrupt(int irq, void *dev_id) -{ - struct pxa930_trkball *trkball = dev_id; - struct input_dev *input = trkball->input; - int tbcntr, x, y; - - /* According to the spec software must read TBCNTR twice: - * if the read value is the same, the reading is valid - */ - tbcntr = __raw_readl(trkball->mmio_base + TBCNTR); - - if (tbcntr == __raw_readl(trkball->mmio_base + TBCNTR)) { - x = (TBCNTR_XP(tbcntr) - TBCNTR_XM(tbcntr)) / 2; - y = (TBCNTR_YP(tbcntr) - TBCNTR_YM(tbcntr)) / 2; - - input_report_rel(input, REL_X, x); - input_report_rel(input, REL_Y, y); - input_sync(input); - } - - __raw_writel(TBSBC_TBSBC, trkball->mmio_base + TBSBC); - __raw_writel(0, trkball->mmio_base + TBSBC); - - return IRQ_HANDLED; -} - -/* For TBCR, we need to wait for a while to make sure it has been modified. */ -static int write_tbcr(struct pxa930_trkball *trkball, int v) -{ - int i = 100; - - __raw_writel(v, trkball->mmio_base + TBCR); - - while (--i) { - if (__raw_readl(trkball->mmio_base + TBCR) == v) - break; - msleep(1); - } - - if (i == 0) { - pr_err("%s: timed out writing TBCR(%x)!\n", __func__, v); - return -ETIMEDOUT; - } - - return 0; -} - -static void pxa930_trkball_config(struct pxa930_trkball *trkball) -{ - uint32_t tbcr; - - /* According to spec, need to write the filters of x,y to 0xf first! */ - tbcr = __raw_readl(trkball->mmio_base + TBCR); - write_tbcr(trkball, tbcr | TBCR_X_FLT(0xf) | TBCR_Y_FLT(0xf)); - write_tbcr(trkball, TBCR_X_FLT(trkball->pdata->x_filter) | - TBCR_Y_FLT(trkball->pdata->y_filter)); - - /* According to spec, set TBCR_TBRST first, before clearing it! */ - tbcr = __raw_readl(trkball->mmio_base + TBCR); - write_tbcr(trkball, tbcr | TBCR_TBRST); - write_tbcr(trkball, tbcr & ~TBCR_TBRST); - - __raw_writel(TBSBC_TBSBC, trkball->mmio_base + TBSBC); - __raw_writel(0, trkball->mmio_base + TBSBC); - - pr_debug("%s: final TBCR=%x!\n", __func__, - __raw_readl(trkball->mmio_base + TBCR)); -} - -static int pxa930_trkball_open(struct input_dev *dev) -{ - struct pxa930_trkball *trkball = input_get_drvdata(dev); - - pxa930_trkball_config(trkball); - - return 0; -} - -static void pxa930_trkball_disable(struct pxa930_trkball *trkball) -{ - uint32_t tbcr = __raw_readl(trkball->mmio_base + TBCR); - - /* Held in reset, gate the 32-KHz input clock off */ - write_tbcr(trkball, tbcr | TBCR_TBRST); -} - -static void pxa930_trkball_close(struct input_dev *dev) -{ - struct pxa930_trkball *trkball = input_get_drvdata(dev); - - pxa930_trkball_disable(trkball); -} - -static int pxa930_trkball_probe(struct platform_device *pdev) -{ - struct pxa930_trkball *trkball; - struct input_dev *input; - struct resource *res; - int irq, error; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -ENXIO; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get register memory\n"); - return -ENXIO; - } - - trkball = kzalloc(sizeof(struct pxa930_trkball), GFP_KERNEL); - if (!trkball) - return -ENOMEM; - - trkball->pdata = dev_get_platdata(&pdev->dev); - if (!trkball->pdata) { - dev_err(&pdev->dev, "no platform data defined\n"); - error = -EINVAL; - goto failed; - } - - trkball->mmio_base = ioremap(res->start, resource_size(res)); - if (!trkball->mmio_base) { - dev_err(&pdev->dev, "failed to ioremap registers\n"); - error = -ENXIO; - goto failed; - } - - /* held the module in reset, will be enabled in open() */ - pxa930_trkball_disable(trkball); - - error = request_irq(irq, pxa930_trkball_interrupt, 0, - pdev->name, trkball); - if (error) { - dev_err(&pdev->dev, "failed to request irq: %d\n", error); - goto failed_free_io; - } - - platform_set_drvdata(pdev, trkball); - - input = input_allocate_device(); - if (!input) { - dev_err(&pdev->dev, "failed to allocate input device\n"); - error = -ENOMEM; - goto failed_free_irq; - } - - input->name = pdev->name; - input->id.bustype = BUS_HOST; - input->open = pxa930_trkball_open; - input->close = pxa930_trkball_close; - input->dev.parent = &pdev->dev; - input_set_drvdata(input, trkball); - - trkball->input = input; - - input_set_capability(input, EV_REL, REL_X); - input_set_capability(input, EV_REL, REL_Y); - - error = input_register_device(input); - if (error) { - dev_err(&pdev->dev, "unable to register input device\n"); - goto failed_free_input; - } - - return 0; - -failed_free_input: - input_free_device(input); -failed_free_irq: - free_irq(irq, trkball); -failed_free_io: - iounmap(trkball->mmio_base); -failed: - kfree(trkball); - return error; -} - -static int pxa930_trkball_remove(struct platform_device *pdev) -{ - struct pxa930_trkball *trkball = platform_get_drvdata(pdev); - int irq = platform_get_irq(pdev, 0); - - input_unregister_device(trkball->input); - free_irq(irq, trkball); - iounmap(trkball->mmio_base); - kfree(trkball); - - return 0; -} - -static struct platform_driver pxa930_trkball_driver = { - .driver = { - .name = "pxa930-trkball", - }, - .probe = pxa930_trkball_probe, - .remove = pxa930_trkball_remove, -}; -module_platform_driver(pxa930_trkball_driver); - -MODULE_AUTHOR("Yong Yao <yaoyong@marvell.com>"); -MODULE_DESCRIPTION("PXA930 Trackball Mouse Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index b0f776448a1c..fa021af8506e 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -192,7 +192,6 @@ static const char * const smbus_pnp_ids[] = { "SYN3221", /* HP 15-ay000 */ "SYN323d", /* HP Spectre X360 13-w013dx */ "SYN3257", /* HP Envy 13-ad105ng */ - "SYN3286", /* HP Laptop 15-da3001TU */ NULL }; diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h index 46f8a694291e..efc61736099b 100644 --- a/drivers/input/serio/i8042-acpipnpio.h +++ b/drivers/input/serio/i8042-acpipnpio.h @@ -1240,6 +1240,13 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { }, { .matches = { + DMI_MATCH(DMI_BOARD_NAME, "PCX0DX"), + }, + .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | + SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "X170SM"), }, .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 68d99a112e14..1a2049b336a6 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -490,18 +490,6 @@ config TOUCHSCREEN_IPROC To compile this driver as a module, choose M here: the module will be called bcm_iproc_tsc. -config TOUCHSCREEN_S3C2410 - tristate "Samsung S3C2410/generic touchscreen input driver" - depends on ARCH_S3C24XX || SAMSUNG_DEV_TS - depends on S3C_ADC - help - Say Y here if you have the s3c2410 touchscreen. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called s3c2410_ts. - config TOUCHSCREEN_S6SY761 tristate "Samsung S6SY761 Touchscreen driver" depends on I2C @@ -839,22 +827,6 @@ config TOUCHSCREEN_TI_AM335X_TSC To compile this driver as a module, choose M here: the module will be called ti_am335x_tsc. -config TOUCHSCREEN_UCB1400 - tristate "Philips UCB1400 touchscreen" - depends on AC97_BUS - depends on UCB1400_CORE - help - This enables support for the Philips UCB1400 touchscreen interface. - The UCB1400 is an AC97 audio codec. The touchscreen interface - will be initialized only after the ALSA subsystem has been - brought up and the UCB1400 detected. You therefore have to - configure ALSA support as well (either built-in or modular, - independently of whether this driver is itself built-in or - modular) for this driver to work. - - To compile this driver as a module, choose M here: the - module will be called ucb1400_ts. - config TOUCHSCREEN_PIXCIR tristate "PIXCIR I2C touchscreens" depends on I2C @@ -940,20 +912,6 @@ config TOUCHSCREEN_WM97XX_MAINSTONE To compile this driver as a module, choose M here: the module will be called mainstone-wm97xx. -config TOUCHSCREEN_WM97XX_ZYLONITE - tristate "Zylonite accelerated touch" - depends on TOUCHSCREEN_WM97XX && MACH_ZYLONITE - depends on SND_PXA2XX_LIB_AC97 - select TOUCHSCREEN_WM9713 - help - Say Y here for support for streaming mode with the touchscreen - on Zylonite systems. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called zylonite-wm97xx. - config TOUCHSCREEN_USB_COMPOSITE tristate "USB Touchscreen Driver" depends on USB_ARCH_HAS_HCD diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 4968c370479a..f2fd28cc34a6 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -76,7 +76,6 @@ obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o -obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o obj-$(CONFIG_TOUCHSCREEN_S6SY761) += s6sy761.o obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o @@ -98,7 +97,6 @@ obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o tsc2007-y := tsc2007_core.o tsc2007-$(CONFIG_TOUCHSCREEN_TSC2007_IIO) += tsc2007_iio.o obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o -obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o obj-$(CONFIG_TOUCHSCREEN_WACOM_I2C) += wacom_i2c.o obj-$(CONFIG_TOUCHSCREEN_WDT87XX_I2C) += wdt87xx_i2c.o @@ -108,7 +106,6 @@ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o -obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o obj-$(CONFIG_TOUCHSCREEN_ZET6223) += zet6223.o diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index c39f49720fe4..85b95ed461e7 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -187,16 +187,6 @@ static int wm97xx_acc_startup(struct wm97xx *wm) "mainstone accelerated touchscreen driver, %d samples/sec\n", cinfo[sp_idx].speed); - /* IRQ driven touchscreen is used on Palm hardware */ - if (machine_is_palmt5() || machine_is_palmtx() || machine_is_palmld()) { - pen_int = 1; - /* There is some obscure mutant of WM9712 interbred with WM9713 - * used on Palm HW */ - wm->variant = WM97xx_WM1613; - } else if (machine_is_zylonite()) { - pen_int = 1; - } - if (pen_int) { gpiod_irq = gpiod_get(wm->dev, "touch", GPIOD_IN); if (IS_ERR(gpiod_irq)) diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c deleted file mode 100644 index 2e70c0b79444..000000000000 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ /dev/null @@ -1,464 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Samsung S3C24XX touchscreen driver - * - * Copyright 2004 Arnaud Patard <arnaud.patard@rtp-net.org> - * Copyright 2008 Ben Dooks <ben-linux@fluff.org> - * Copyright 2009 Simtec Electronics <linux@simtec.co.uk> - * - * Additional work by Herbert Pötzl <herbert@13thfloor.at> and - * Harald Welte <laforge@openmoko.org> - */ - -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/input.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/io.h> - -#include <linux/soc/samsung/s3c-adc.h> -#include <linux/platform_data/touchscreen-s3c2410.h> - -#define S3C2410_ADCCON (0x00) -#define S3C2410_ADCTSC (0x04) -#define S3C2410_ADCDLY (0x08) -#define S3C2410_ADCDAT0 (0x0C) -#define S3C2410_ADCDAT1 (0x10) -#define S3C64XX_ADCUPDN (0x14) -#define S3C2443_ADCMUX (0x18) -#define S3C64XX_ADCCLRINT (0x18) -#define S5P_ADCMUX (0x1C) -#define S3C64XX_ADCCLRINTPNDNUP (0x20) - -/* ADCTSC Register Bits */ -#define S3C2443_ADCTSC_UD_SEN (1 << 8) -#define S3C2410_ADCTSC_YM_SEN (1<<7) -#define S3C2410_ADCTSC_YP_SEN (1<<6) -#define S3C2410_ADCTSC_XM_SEN (1<<5) -#define S3C2410_ADCTSC_XP_SEN (1<<4) -#define S3C2410_ADCTSC_PULL_UP_DISABLE (1<<3) -#define S3C2410_ADCTSC_AUTO_PST (1<<2) -#define S3C2410_ADCTSC_XY_PST(x) (((x)&0x3)<<0) - -/* ADCDAT0 Bits */ -#define S3C2410_ADCDAT0_UPDOWN (1<<15) -#define S3C2410_ADCDAT0_AUTO_PST (1<<14) -#define S3C2410_ADCDAT0_XY_PST (0x3<<12) -#define S3C2410_ADCDAT0_XPDATA_MASK (0x03FF) - -/* ADCDAT1 Bits */ -#define S3C2410_ADCDAT1_UPDOWN (1<<15) -#define S3C2410_ADCDAT1_AUTO_PST (1<<14) -#define S3C2410_ADCDAT1_XY_PST (0x3<<12) -#define S3C2410_ADCDAT1_YPDATA_MASK (0x03FF) - - -#define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0)) - -#define INT_DOWN (0) -#define INT_UP (1 << 8) - -#define WAIT4INT (S3C2410_ADCTSC_YM_SEN | \ - S3C2410_ADCTSC_YP_SEN | \ - S3C2410_ADCTSC_XP_SEN | \ - S3C2410_ADCTSC_XY_PST(3)) - -#define AUTOPST (S3C2410_ADCTSC_YM_SEN | \ - S3C2410_ADCTSC_YP_SEN | \ - S3C2410_ADCTSC_XP_SEN | \ - S3C2410_ADCTSC_AUTO_PST | \ - S3C2410_ADCTSC_XY_PST(0)) - -#define FEAT_PEN_IRQ (1 << 0) /* HAS ADCCLRINTPNDNUP */ - -/* Per-touchscreen data. */ - -/** - * struct s3c2410ts - driver touchscreen state. - * @client: The ADC client we registered with the core driver. - * @dev: The device we are bound to. - * @input: The input device we registered with the input subsystem. - * @clock: The clock for the adc. - * @io: Pointer to the IO base. - * @xp: The accumulated X position data. - * @yp: The accumulated Y position data. - * @irq_tc: The interrupt number for pen up/down interrupt - * @count: The number of samples collected. - * @shift: The log2 of the maximum count to read in one go. - * @features: The features supported by the TSADC MOdule. - */ -struct s3c2410ts { - struct s3c_adc_client *client; - struct device *dev; - struct input_dev *input; - struct clk *clock; - void __iomem *io; - unsigned long xp; - unsigned long yp; - int irq_tc; - int count; - int shift; - int features; -}; - -static struct s3c2410ts ts; - -/** - * get_down - return the down state of the pen - * @data0: The data read from ADCDAT0 register. - * @data1: The data read from ADCDAT1 register. - * - * Return non-zero if both readings show that the pen is down. - */ -static inline bool get_down(unsigned long data0, unsigned long data1) -{ - /* returns true if both data values show stylus down */ - return (!(data0 & S3C2410_ADCDAT0_UPDOWN) && - !(data1 & S3C2410_ADCDAT0_UPDOWN)); -} - -static void touch_timer_fire(struct timer_list *unused) -{ - unsigned long data0; - unsigned long data1; - bool down; - - data0 = readl(ts.io + S3C2410_ADCDAT0); - data1 = readl(ts.io + S3C2410_ADCDAT1); - - down = get_down(data0, data1); - - if (down) { - if (ts.count == (1 << ts.shift)) { - ts.xp >>= ts.shift; - ts.yp >>= ts.shift; - - dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n", - __func__, ts.xp, ts.yp, ts.count); - - input_report_abs(ts.input, ABS_X, ts.xp); - input_report_abs(ts.input, ABS_Y, ts.yp); - - input_report_key(ts.input, BTN_TOUCH, 1); - input_sync(ts.input); - - ts.xp = 0; - ts.yp = 0; - ts.count = 0; - } - - s3c_adc_start(ts.client, 0, 1 << ts.shift); - } else { - ts.xp = 0; - ts.yp = 0; - ts.count = 0; - - input_report_key(ts.input, BTN_TOUCH, 0); - input_sync(ts.input); - - writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); - } -} - -static DEFINE_TIMER(touch_timer, touch_timer_fire); - -/** - * stylus_irq - touchscreen stylus event interrupt - * @irq: The interrupt number - * @dev_id: The device ID. - * - * Called when the IRQ_TC is fired for a pen up or down event. - */ -static irqreturn_t stylus_irq(int irq, void *dev_id) -{ - unsigned long data0; - unsigned long data1; - bool down; - - data0 = readl(ts.io + S3C2410_ADCDAT0); - data1 = readl(ts.io + S3C2410_ADCDAT1); - - down = get_down(data0, data1); - - /* TODO we should never get an interrupt with down set while - * the timer is running, but maybe we ought to verify that the - * timer isn't running anyways. */ - - if (down) - s3c_adc_start(ts.client, 0, 1 << ts.shift); - else - dev_dbg(ts.dev, "%s: count=%d\n", __func__, ts.count); - - if (ts.features & FEAT_PEN_IRQ) { - /* Clear pen down/up interrupt */ - writel(0x0, ts.io + S3C64XX_ADCCLRINTPNDNUP); - } - - return IRQ_HANDLED; -} - -/** - * s3c24xx_ts_conversion - ADC conversion callback - * @client: The client that was registered with the ADC core. - * @data0: The reading from ADCDAT0. - * @data1: The reading from ADCDAT1. - * @left: The number of samples left. - * - * Called when a conversion has finished. - */ -static void s3c24xx_ts_conversion(struct s3c_adc_client *client, - unsigned data0, unsigned data1, - unsigned *left) -{ - dev_dbg(ts.dev, "%s: %d,%d\n", __func__, data0, data1); - - ts.xp += data0; - ts.yp += data1; - - ts.count++; - - /* From tests, it seems that it is unlikely to get a pen-up - * event during the conversion process which means we can - * ignore any pen-up events with less than the requisite - * count done. - * - * In several thousand conversions, no pen-ups where detected - * before count completed. - */ -} - -/** - * s3c24xx_ts_select - ADC selection callback. - * @client: The client that was registered with the ADC core. - * @select: The reason for select. - * - * Called when the ADC core selects (or deslects) us as a client. - */ -static void s3c24xx_ts_select(struct s3c_adc_client *client, unsigned select) -{ - if (select) { - writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, - ts.io + S3C2410_ADCTSC); - } else { - mod_timer(&touch_timer, jiffies+1); - writel(WAIT4INT | INT_UP, ts.io + S3C2410_ADCTSC); - } -} - -/** - * s3c2410ts_probe - device core probe entry point - * @pdev: The device we are being bound to. - * - * Initialise, find and allocate any resources we need to run and then - * register with the ADC and input systems. - */ -static int s3c2410ts_probe(struct platform_device *pdev) -{ - struct s3c2410_ts_mach_info *info; - struct device *dev = &pdev->dev; - struct input_dev *input_dev; - struct resource *res; - int ret = -EINVAL; - - /* Initialise input stuff */ - memset(&ts, 0, sizeof(struct s3c2410ts)); - - ts.dev = dev; - - info = dev_get_platdata(dev); - if (!info) { - dev_err(dev, "no platform data, cannot attach\n"); - return -EINVAL; - } - - dev_dbg(dev, "initialising touchscreen\n"); - - ts.clock = clk_get(dev, "adc"); - if (IS_ERR(ts.clock)) { - dev_err(dev, "cannot get adc clock source\n"); - return -ENOENT; - } - - ret = clk_prepare_enable(ts.clock); - if (ret) { - dev_err(dev, "Failed! to enabled clocks\n"); - goto err_clk_get; - } - dev_dbg(dev, "got and enabled clocks\n"); - - ts.irq_tc = ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(dev, "no resource for interrupt\n"); - goto err_clk; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "no resource for registers\n"); - ret = -ENOENT; - goto err_clk; - } - - ts.io = ioremap(res->start, resource_size(res)); - if (ts.io == NULL) { - dev_err(dev, "cannot map registers\n"); - ret = -ENOMEM; - goto err_clk; - } - - /* inititalise the gpio */ - if (info->cfg_gpio) - info->cfg_gpio(to_platform_device(ts.dev)); - - ts.client = s3c_adc_register(pdev, s3c24xx_ts_select, - s3c24xx_ts_conversion, 1); - if (IS_ERR(ts.client)) { - dev_err(dev, "failed to register adc client\n"); - ret = PTR_ERR(ts.client); - goto err_iomap; - } - - /* Initialise registers */ - if ((info->delay & 0xffff) > 0) - writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY); - - writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); - - input_dev = input_allocate_device(); - if (!input_dev) { - dev_err(dev, "Unable to allocate the input device !!\n"); - ret = -ENOMEM; - goto err_iomap; - } - - ts.input = input_dev; - ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0); - input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0); - - ts.input->name = "S3C24XX TouchScreen"; - ts.input->id.bustype = BUS_HOST; - ts.input->id.vendor = 0xDEAD; - ts.input->id.product = 0xBEEF; - ts.input->id.version = 0x0102; - - ts.shift = info->oversampling_shift; - ts.features = platform_get_device_id(pdev)->driver_data; - - ret = request_irq(ts.irq_tc, stylus_irq, 0, - "s3c2410_ts_pen", ts.input); - if (ret) { - dev_err(dev, "cannot get TC interrupt\n"); - goto err_inputdev; - } - - dev_info(dev, "driver attached, registering input device\n"); - - /* All went ok, so register to the input system */ - ret = input_register_device(ts.input); - if (ret < 0) { - dev_err(dev, "failed to register input device\n"); - ret = -EIO; - goto err_tcirq; - } - - return 0; - - err_tcirq: - free_irq(ts.irq_tc, ts.input); - err_inputdev: - input_free_device(ts.input); - err_iomap: - iounmap(ts.io); - err_clk: - clk_disable_unprepare(ts.clock); - del_timer_sync(&touch_timer); - err_clk_get: - clk_put(ts.clock); - return ret; -} - -/** - * s3c2410ts_remove - device core removal entry point - * @pdev: The device we are being removed from. - * - * Free up our state ready to be removed. - */ -static int s3c2410ts_remove(struct platform_device *pdev) -{ - free_irq(ts.irq_tc, ts.input); - del_timer_sync(&touch_timer); - - clk_disable_unprepare(ts.clock); - clk_put(ts.clock); - - input_unregister_device(ts.input); - iounmap(ts.io); - - return 0; -} - -#ifdef CONFIG_PM -static int s3c2410ts_suspend(struct device *dev) -{ - writel(TSC_SLEEP, ts.io + S3C2410_ADCTSC); - disable_irq(ts.irq_tc); - clk_disable(ts.clock); - - return 0; -} - -static int s3c2410ts_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct s3c2410_ts_mach_info *info = dev_get_platdata(&pdev->dev); - - clk_enable(ts.clock); - enable_irq(ts.irq_tc); - - /* Initialise registers */ - if ((info->delay & 0xffff) > 0) - writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY); - - writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); - - return 0; -} - -static const struct dev_pm_ops s3c_ts_pmops = { - .suspend = s3c2410ts_suspend, - .resume = s3c2410ts_resume, -}; -#endif - -static const struct platform_device_id s3cts_driver_ids[] = { - { "s3c2410-ts", 0 }, - { "s3c2440-ts", 0 }, - { "s3c64xx-ts", FEAT_PEN_IRQ }, - { } -}; -MODULE_DEVICE_TABLE(platform, s3cts_driver_ids); - -static struct platform_driver s3c_ts_driver = { - .driver = { - .name = "samsung-ts", -#ifdef CONFIG_PM - .pm = &s3c_ts_pmops, -#endif - }, - .id_table = s3cts_driver_ids, - .probe = s3c2410ts_probe, - .remove = s3c2410ts_remove, -}; -module_platform_driver(s3c_ts_driver); - -MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, " - "Ben Dooks <ben@simtec.co.uk>, " - "Simtec Electronics <linux@simtec.co.uk>"); -MODULE_DESCRIPTION("S3C24XX Touchscreen driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c deleted file mode 100644 index dfd3b35590c3..000000000000 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ /dev/null @@ -1,458 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Philips UCB1400 touchscreen driver - * - * Author: Nicolas Pitre - * Created: September 25, 2006 - * Copyright: MontaVista Software, Inc. - * - * Spliting done by: Marek Vasut <marek.vasut@gmail.com> - * If something doesn't work and it worked before spliting, e-mail me, - * dont bother Nicolas please ;-) - * - * 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. - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/sched.h> -#include <linux/wait.h> -#include <linux/input.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/ucb1400.h> - -#define UCB1400_TS_POLL_PERIOD 10 /* ms */ - -static bool adcsync; -static int ts_delay = 55; /* us */ -static int ts_delay_pressure; /* us */ - -/* Switch to interrupt mode. */ -static void ucb1400_ts_mode_int(struct ucb1400_ts *ucb) -{ - ucb1400_reg_write(ucb->ac97, UCB_TS_CR, - UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | - UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | - UCB_TS_CR_MODE_INT); -} - -/* - * Switch to pressure mode, and read pressure. We don't need to wait - * here, since both plates are being driven. - */ -static unsigned int ucb1400_ts_read_pressure(struct ucb1400_ts *ucb) -{ - ucb1400_reg_write(ucb->ac97, UCB_TS_CR, - UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | - UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | - UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - - udelay(ts_delay_pressure); - - return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPY, adcsync); -} - -/* - * Switch to X position mode and measure Y plate. We switch the plate - * configuration in pressure mode, then switch to position mode. This - * gives a faster response time. Even so, we need to wait about 55us - * for things to stabilise. - */ -static unsigned int ucb1400_ts_read_xpos(struct ucb1400_ts *ucb) -{ - ucb1400_reg_write(ucb->ac97, UCB_TS_CR, - UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | - UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - ucb1400_reg_write(ucb->ac97, UCB_TS_CR, - UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | - UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - ucb1400_reg_write(ucb->ac97, UCB_TS_CR, - UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | - UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); - - udelay(ts_delay); - - return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPY, adcsync); -} - -/* - * Switch to Y position mode and measure X plate. We switch the plate - * configuration in pressure mode, then switch to position mode. This - * gives a faster response time. Even so, we need to wait about 55us - * for things to stabilise. - */ -static int ucb1400_ts_read_ypos(struct ucb1400_ts *ucb) -{ - ucb1400_reg_write(ucb->ac97, UCB_TS_CR, - UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | - UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - ucb1400_reg_write(ucb->ac97, UCB_TS_CR, - UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | - UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - ucb1400_reg_write(ucb->ac97, UCB_TS_CR, - UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | - UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); - - udelay(ts_delay); - - return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPX, adcsync); -} - -/* - * Switch to X plate resistance mode. Set MX to ground, PX to - * supply. Measure current. - */ -static unsigned int ucb1400_ts_read_xres(struct ucb1400_ts *ucb) -{ - ucb1400_reg_write(ucb->ac97, UCB_TS_CR, - UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | - UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - return ucb1400_adc_read(ucb->ac97, 0, adcsync); -} - -/* - * Switch to Y plate resistance mode. Set MY to ground, PY to - * supply. Measure current. - */ -static unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb) -{ - ucb1400_reg_write(ucb->ac97, UCB_TS_CR, - UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | - UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - return ucb1400_adc_read(ucb->ac97, 0, adcsync); -} - -static int ucb1400_ts_pen_up(struct ucb1400_ts *ucb) -{ - unsigned short val = ucb1400_reg_read(ucb->ac97, UCB_TS_CR); - - return val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW); -} - -static void ucb1400_ts_irq_enable(struct ucb1400_ts *ucb) -{ - ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, UCB_IE_TSPX); - ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0); - ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, UCB_IE_TSPX); -} - -static void ucb1400_ts_irq_disable(struct ucb1400_ts *ucb) -{ - ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, 0); -} - -static void ucb1400_ts_report_event(struct input_dev *idev, u16 pressure, u16 x, u16 y) -{ - input_report_abs(idev, ABS_X, x); - input_report_abs(idev, ABS_Y, y); - input_report_abs(idev, ABS_PRESSURE, pressure); - input_report_key(idev, BTN_TOUCH, 1); - input_sync(idev); -} - -static void ucb1400_ts_event_release(struct input_dev *idev) -{ - input_report_abs(idev, ABS_PRESSURE, 0); - input_report_key(idev, BTN_TOUCH, 0); - input_sync(idev); -} - -static void ucb1400_clear_pending_irq(struct ucb1400_ts *ucb) -{ - unsigned int isr; - - isr = ucb1400_reg_read(ucb->ac97, UCB_IE_STATUS); - ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, isr); - ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0); - - if (isr & UCB_IE_TSPX) - ucb1400_ts_irq_disable(ucb); - else - dev_dbg(&ucb->ts_idev->dev, - "ucb1400: unexpected IE_STATUS = %#x\n", isr); -} - -/* - * A restriction with interrupts exists when using the ucb1400, as - * the codec read/write routines may sleep while waiting for codec - * access completion and uses semaphores for access control to the - * AC97 bus. Therefore the driver is forced to use threaded interrupt - * handler. - */ -static irqreturn_t ucb1400_irq(int irqnr, void *devid) -{ - struct ucb1400_ts *ucb = devid; - unsigned int x, y, p; - - if (unlikely(irqnr != ucb->irq)) - return IRQ_NONE; - - ucb1400_clear_pending_irq(ucb); - - /* Start with a small delay before checking pendown state */ - msleep(UCB1400_TS_POLL_PERIOD); - - while (!ucb->stopped && !ucb1400_ts_pen_up(ucb)) { - ucb1400_adc_enable(ucb->ac97); - x = ucb1400_ts_read_xpos(ucb); - y = ucb1400_ts_read_ypos(ucb); - p = ucb1400_ts_read_pressure(ucb); - ucb1400_adc_disable(ucb->ac97); - - ucb1400_ts_report_event(ucb->ts_idev, p, x, y); - - wait_event_timeout(ucb->ts_wait, ucb->stopped, - msecs_to_jiffies(UCB1400_TS_POLL_PERIOD)); - } - - ucb1400_ts_event_release(ucb->ts_idev); - - if (!ucb->stopped) { - /* Switch back to interrupt mode. */ - ucb1400_ts_mode_int(ucb); - ucb1400_ts_irq_enable(ucb); - } - - return IRQ_HANDLED; -} - -static void ucb1400_ts_stop(struct ucb1400_ts *ucb) -{ - /* Signal IRQ thread to stop polling and disable the handler. */ - ucb->stopped = true; - mb(); - wake_up(&ucb->ts_wait); - disable_irq(ucb->irq); - - ucb1400_ts_irq_disable(ucb); - ucb1400_reg_write(ucb->ac97, UCB_TS_CR, 0); -} - -/* Must be called with ts->lock held */ -static void ucb1400_ts_start(struct ucb1400_ts *ucb) -{ - /* Tell IRQ thread that it may poll the device. */ - ucb->stopped = false; - mb(); - - ucb1400_ts_mode_int(ucb); - ucb1400_ts_irq_enable(ucb); - - enable_irq(ucb->irq); -} - -static int ucb1400_ts_open(struct input_dev *idev) -{ - struct ucb1400_ts *ucb = input_get_drvdata(idev); - - ucb1400_ts_start(ucb); - - return 0; -} - -static void ucb1400_ts_close(struct input_dev *idev) -{ - struct ucb1400_ts *ucb = input_get_drvdata(idev); - - ucb1400_ts_stop(ucb); -} - -#ifndef NO_IRQ -#define NO_IRQ 0 -#endif - -/* - * Try to probe our interrupt, rather than relying on lots of - * hard-coded machine dependencies. - */ -static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb, - struct platform_device *pdev) -{ - unsigned long mask, timeout; - - mask = probe_irq_on(); - - /* Enable the ADC interrupt. */ - ucb1400_reg_write(ucb->ac97, UCB_IE_RIS, UCB_IE_ADC); - ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, UCB_IE_ADC); - ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0xffff); - ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0); - - /* Cause an ADC interrupt. */ - ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, UCB_ADC_ENA); - ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START); - - /* Wait for the conversion to complete. */ - timeout = jiffies + HZ/2; - while (!(ucb1400_reg_read(ucb->ac97, UCB_ADC_DATA) & - UCB_ADC_DAT_VALID)) { - cpu_relax(); - if (time_after(jiffies, timeout)) { - dev_err(&pdev->dev, "timed out in IRQ probe\n"); - probe_irq_off(mask); - return -ENODEV; - } - } - ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, 0); - - /* Disable and clear interrupt. */ - ucb1400_reg_write(ucb->ac97, UCB_IE_RIS, 0); - ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, 0); - ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0xffff); - ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0); - - /* Read triggered interrupt. */ - ucb->irq = probe_irq_off(mask); - if (ucb->irq < 0 || ucb->irq == NO_IRQ) - return -ENODEV; - - return 0; -} - -static int ucb1400_ts_probe(struct platform_device *pdev) -{ - struct ucb1400_ts *ucb = dev_get_platdata(&pdev->dev); - int error, x_res, y_res; - u16 fcsr; - - ucb->ts_idev = input_allocate_device(); - if (!ucb->ts_idev) { - error = -ENOMEM; - goto err; - } - - /* Only in case the IRQ line wasn't supplied, try detecting it */ - if (ucb->irq < 0) { - error = ucb1400_ts_detect_irq(ucb, pdev); - if (error) { - dev_err(&pdev->dev, "IRQ probe failed\n"); - goto err_free_devs; - } - } - dev_dbg(&pdev->dev, "found IRQ %d\n", ucb->irq); - - init_waitqueue_head(&ucb->ts_wait); - - input_set_drvdata(ucb->ts_idev, ucb); - - ucb->ts_idev->dev.parent = &pdev->dev; - ucb->ts_idev->name = "UCB1400 touchscreen interface"; - ucb->ts_idev->id.vendor = ucb1400_reg_read(ucb->ac97, - AC97_VENDOR_ID1); - ucb->ts_idev->id.product = ucb->id; - ucb->ts_idev->open = ucb1400_ts_open; - ucb->ts_idev->close = ucb1400_ts_close; - ucb->ts_idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); - ucb->ts_idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - - /* - * Enable ADC filter to prevent horrible jitter on Colibri. - * This also further reduces jitter on boards where ADCSYNC - * pin is connected. - */ - fcsr = ucb1400_reg_read(ucb->ac97, UCB_FCSR); - ucb1400_reg_write(ucb->ac97, UCB_FCSR, fcsr | UCB_FCSR_AVE); - - ucb1400_adc_enable(ucb->ac97); - x_res = ucb1400_ts_read_xres(ucb); - y_res = ucb1400_ts_read_yres(ucb); - ucb1400_adc_disable(ucb->ac97); - dev_dbg(&pdev->dev, "x/y = %d/%d\n", x_res, y_res); - - input_set_abs_params(ucb->ts_idev, ABS_X, 0, x_res, 0, 0); - input_set_abs_params(ucb->ts_idev, ABS_Y, 0, y_res, 0, 0); - input_set_abs_params(ucb->ts_idev, ABS_PRESSURE, 0, 0, 0, 0); - - ucb1400_ts_stop(ucb); - - error = request_threaded_irq(ucb->irq, NULL, ucb1400_irq, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - "UCB1400", ucb); - if (error) { - dev_err(&pdev->dev, - "unable to grab irq%d: %d\n", ucb->irq, error); - goto err_free_devs; - } - - error = input_register_device(ucb->ts_idev); - if (error) - goto err_free_irq; - - return 0; - -err_free_irq: - free_irq(ucb->irq, ucb); -err_free_devs: - input_free_device(ucb->ts_idev); -err: - return error; -} - -static int ucb1400_ts_remove(struct platform_device *pdev) -{ - struct ucb1400_ts *ucb = dev_get_platdata(&pdev->dev); - - free_irq(ucb->irq, ucb); - input_unregister_device(ucb->ts_idev); - - return 0; -} - -static int __maybe_unused ucb1400_ts_suspend(struct device *dev) -{ - struct ucb1400_ts *ucb = dev_get_platdata(dev); - struct input_dev *idev = ucb->ts_idev; - - mutex_lock(&idev->mutex); - - if (input_device_enabled(idev)) - ucb1400_ts_stop(ucb); - - mutex_unlock(&idev->mutex); - return 0; -} - -static int __maybe_unused ucb1400_ts_resume(struct device *dev) -{ - struct ucb1400_ts *ucb = dev_get_platdata(dev); - struct input_dev *idev = ucb->ts_idev; - - mutex_lock(&idev->mutex); - - if (input_device_enabled(idev)) - ucb1400_ts_start(ucb); - - mutex_unlock(&idev->mutex); - return 0; -} - -static SIMPLE_DEV_PM_OPS(ucb1400_ts_pm_ops, - ucb1400_ts_suspend, ucb1400_ts_resume); - -static struct platform_driver ucb1400_ts_driver = { - .probe = ucb1400_ts_probe, - .remove = ucb1400_ts_remove, - .driver = { - .name = "ucb1400_ts", - .pm = &ucb1400_ts_pm_ops, - }, -}; -module_platform_driver(ucb1400_ts_driver); - -module_param(adcsync, bool, 0444); -MODULE_PARM_DESC(adcsync, "Synchronize touch readings with ADCSYNC pin."); - -module_param(ts_delay, int, 0444); -MODULE_PARM_DESC(ts_delay, "Delay between panel setup and" - " position read. Default = 55us."); - -module_param(ts_delay_pressure, int, 0444); -MODULE_PARM_DESC(ts_delay_pressure, - "delay between panel setup and pressure read." - " Default = 0us."); - -MODULE_DESCRIPTION("Philips UCB1400 touchscreen driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/zylonite-wm97xx.c b/drivers/input/touchscreen/zylonite-wm97xx.c deleted file mode 100644 index a70fe4abe520..000000000000 --- a/drivers/input/touchscreen/zylonite-wm97xx.c +++ /dev/null @@ -1,220 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * zylonite-wm97xx.c -- Zylonite Continuous Touch screen driver - * - * Copyright 2004, 2007, 2008 Wolfson Microelectronics PLC. - * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * Parts Copyright : Ian Molton <spyro@f2s.com> - * Andrew Zabolotny <zap@homelink.ru> - * - * Notes: - * This is a wm97xx extended touch driver supporting interrupt driven - * and continuous operation on Marvell Zylonite development systems - * (which have a WM9713 on board). - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/gpio/consumer.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/soc/pxa/cpu.h> -#include <linux/wm97xx.h> - -#include <sound/pxa2xx-lib.h> - -struct continuous { - u16 id; /* codec id */ - u8 code; /* continuous code */ - u8 reads; /* number of coord reads per read cycle */ - u32 speed; /* number of coords per second */ -}; - -#define WM_READS(sp) ((sp / HZ) + 1) - -static const struct continuous cinfo[] = { - { WM9713_ID2, 0, WM_READS(94), 94 }, - { WM9713_ID2, 1, WM_READS(120), 120 }, - { WM9713_ID2, 2, WM_READS(154), 154 }, - { WM9713_ID2, 3, WM_READS(188), 188 }, -}; - -/* continuous speed index */ -static int sp_idx; - -/* - * Pen sampling frequency (Hz) in continuous mode. - */ -static int cont_rate = 200; -module_param(cont_rate, int, 0); -MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)"); - -/* - * Pressure readback. - * - * Set to 1 to read back pen down pressure - */ -static int pressure; -module_param(pressure, int, 0); -MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)"); - -/* - * AC97 touch data slot. - * - * Touch screen readback data ac97 slot - */ -static int ac97_touch_slot = 5; -module_param(ac97_touch_slot, int, 0); -MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number"); - - -/* flush AC97 slot 5 FIFO machines */ -static void wm97xx_acc_pen_up(struct wm97xx *wm) -{ - int i; - - msleep(1); - - for (i = 0; i < 16; i++) - pxa2xx_ac97_read_modr(); -} - -static int wm97xx_acc_pen_down(struct wm97xx *wm) -{ - u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES; - int reads = 0; - static u16 last, tries; - - /* When the AC97 queue has been drained we need to allow time - * to buffer up samples otherwise we end up spinning polling - * for samples. The controller can't have a suitably low - * threshold set to use the notifications it gives. - */ - msleep(1); - - if (tries > 5) { - tries = 0; - return RC_PENUP; - } - - x = pxa2xx_ac97_read_modr(); - if (x == last) { - tries++; - return RC_AGAIN; - } - last = x; - do { - if (reads) - x = pxa2xx_ac97_read_modr(); - y = pxa2xx_ac97_read_modr(); - if (pressure) - p = pxa2xx_ac97_read_modr(); - - dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n", - x, y, p); - - /* are samples valid */ - if ((x & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_X || - (y & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_Y || - (p & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_PRES) - goto up; - - /* coordinate is good */ - tries = 0; - input_report_abs(wm->input_dev, ABS_X, x & 0xfff); - input_report_abs(wm->input_dev, ABS_Y, y & 0xfff); - input_report_abs(wm->input_dev, ABS_PRESSURE, p & 0xfff); - input_report_key(wm->input_dev, BTN_TOUCH, (p != 0)); - input_sync(wm->input_dev); - reads++; - } while (reads < cinfo[sp_idx].reads); -up: - return RC_PENDOWN | RC_AGAIN; -} - -static int wm97xx_acc_startup(struct wm97xx *wm) -{ - int idx; - - /* check we have a codec */ - if (wm->ac97 == NULL) - return -ENODEV; - - /* Go you big red fire engine */ - for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) { - if (wm->id != cinfo[idx].id) - continue; - sp_idx = idx; - if (cont_rate <= cinfo[idx].speed) - break; - } - wm->acc_rate = cinfo[sp_idx].code; - wm->acc_slot = ac97_touch_slot; - dev_info(wm->dev, - "zylonite accelerated touchscreen driver, %d samples/sec\n", - cinfo[sp_idx].speed); - - return 0; -} - -static struct wm97xx_mach_ops zylonite_mach_ops = { - .acc_enabled = 1, - .acc_pen_up = wm97xx_acc_pen_up, - .acc_pen_down = wm97xx_acc_pen_down, - .acc_startup = wm97xx_acc_startup, - .irq_gpio = WM97XX_GPIO_2, -}; - -static int zylonite_wm97xx_probe(struct platform_device *pdev) -{ - struct wm97xx *wm = platform_get_drvdata(pdev); - struct gpio_desc *gpio_touch_irq; - int err; - - gpio_touch_irq = devm_gpiod_get(&pdev->dev, "touch", GPIOD_IN); - err = PTR_ERR_OR_ZERO(gpio_touch_irq); - if (err) { - dev_err(&pdev->dev, "Cannot get irq gpio: %d\n", err); - return err; - } - - wm->pen_irq = gpiod_to_irq(gpio_touch_irq); - irq_set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH); - - wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, - WM97XX_GPIO_POL_HIGH, - WM97XX_GPIO_STICKY, - WM97XX_GPIO_WAKE); - wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT, - WM97XX_GPIO_POL_HIGH, - WM97XX_GPIO_NOTSTICKY, - WM97XX_GPIO_NOWAKE); - - return wm97xx_register_mach_ops(wm, &zylonite_mach_ops); -} - -static int zylonite_wm97xx_remove(struct platform_device *pdev) -{ - struct wm97xx *wm = platform_get_drvdata(pdev); - - wm97xx_unregister_mach_ops(wm); - - return 0; -} - -static struct platform_driver zylonite_wm97xx_driver = { - .probe = zylonite_wm97xx_probe, - .remove = zylonite_wm97xx_remove, - .driver = { - .name = "wm97xx-touch", - }, -}; -module_platform_driver(zylonite_wm97xx_driver); - -/* Module information */ -MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); -MODULE_DESCRIPTION("wm97xx continuous touch driver for Zylonite"); -MODULE_LICENSE("GPL"); diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig index 1a1c941635a2..cd689b782f97 100644 --- a/drivers/interconnect/qcom/Kconfig +++ b/drivers/interconnect/qcom/Kconfig @@ -69,6 +69,15 @@ config INTERCONNECT_QCOM_QCS404 This is a driver for the Qualcomm Network-on-Chip on qcs404-based platforms. +config INTERCONNECT_QCOM_QDU1000 + tristate "Qualcomm QDU1000/QRU1000 interconnect driver" + depends on INTERCONNECT_QCOM_RPMH_POSSIBLE + select INTERCONNECT_QCOM_RPMH + select INTERCONNECT_QCOM_BCM_VOTER + help + This is a driver for the Qualcomm Network-on-Chip on QDU1000-based + and QRU1000-based platforms. + config INTERCONNECT_QCOM_RPMH_POSSIBLE tristate default INTERCONNECT_QCOM @@ -200,5 +209,14 @@ config INTERCONNECT_QCOM_SM8450 This is a driver for the Qualcomm Network-on-Chip on SM8450-based platforms. +config INTERCONNECT_QCOM_SM8550 + tristate "Qualcomm SM8550 interconnect driver" + depends on INTERCONNECT_QCOM_RPMH_POSSIBLE + select INTERCONNECT_QCOM_RPMH + select INTERCONNECT_QCOM_BCM_VOTER + help + This is a driver for the Qualcomm Network-on-Chip on SM8550-based + platforms. + config INTERCONNECT_QCOM_SMD_RPM tristate diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile index 8e357528185d..3fd4c2713c4a 100644 --- a/drivers/interconnect/qcom/Makefile +++ b/drivers/interconnect/qcom/Makefile @@ -11,6 +11,7 @@ qnoc-msm8996-objs := msm8996.o icc-osm-l3-objs := osm-l3.o qnoc-qcm2290-objs := qcm2290.o qnoc-qcs404-objs := qcs404.o +qnoc-qdu1000-objs := qdu1000.o icc-rpmh-obj := icc-rpmh.o qnoc-sc7180-objs := sc7180.o qnoc-sc7280-objs := sc7280.o @@ -25,6 +26,7 @@ qnoc-sm8150-objs := sm8150.o qnoc-sm8250-objs := sm8250.o qnoc-sm8350-objs := sm8350.o qnoc-sm8450-objs := sm8450.o +qnoc-sm8550-objs := sm8550.o icc-smd-rpm-objs := smd-rpm.o icc-rpm.o obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o @@ -35,6 +37,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_MSM8996) += qnoc-msm8996.o obj-$(CONFIG_INTERCONNECT_QCOM_OSM_L3) += icc-osm-l3.o obj-$(CONFIG_INTERCONNECT_QCOM_QCM2290) += qnoc-qcm2290.o obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o +obj-$(CONFIG_INTERCONNECT_QCOM_QDU1000) += qnoc-qdu1000.o obj-$(CONFIG_INTERCONNECT_QCOM_RPMH) += icc-rpmh.o obj-$(CONFIG_INTERCONNECT_QCOM_SC7180) += qnoc-sc7180.o obj-$(CONFIG_INTERCONNECT_QCOM_SC7280) += qnoc-sc7280.o @@ -49,4 +52,5 @@ obj-$(CONFIG_INTERCONNECT_QCOM_SM8150) += qnoc-sm8150.o obj-$(CONFIG_INTERCONNECT_QCOM_SM8250) += qnoc-sm8250.o obj-$(CONFIG_INTERCONNECT_QCOM_SM8350) += qnoc-sm8350.o obj-$(CONFIG_INTERCONNECT_QCOM_SM8450) += qnoc-sm8450.o +obj-$(CONFIG_INTERCONNECT_QCOM_SM8550) += qnoc-sm8550.o obj-$(CONFIG_INTERCONNECT_QCOM_SMD_RPM) += icc-smd-rpm.o diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c index ba6781f54ab7..df3196f72536 100644 --- a/drivers/interconnect/qcom/icc-rpm.c +++ b/drivers/interconnect/qcom/icc-rpm.c @@ -488,7 +488,7 @@ int qnoc_probe(struct platform_device *pdev) } regmap_done: - ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks); + ret = devm_clk_bulk_get_optional(dev, qp->num_clks, qp->bus_clks); if (ret) return ret; diff --git a/drivers/interconnect/qcom/msm8996.c b/drivers/interconnect/qcom/msm8996.c index c2903ae3b3bc..25a1a32bc611 100644 --- a/drivers/interconnect/qcom/msm8996.c +++ b/drivers/interconnect/qcom/msm8996.c @@ -33,6 +33,13 @@ static const char * const bus_a0noc_clocks[] = { "aggre0_noc_mpu_cfg" }; +static const char * const bus_a2noc_clocks[] = { + "bus", + "bus_a", + "aggre2_ufs_axi", + "ufs_axi" +}; + static const u16 mas_a0noc_common_links[] = { MSM8996_SLAVE_A0NOC_SNOC }; @@ -1806,7 +1813,7 @@ static const struct regmap_config msm8996_a0noc_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = 0x9000, + .max_register = 0x6000, .fast_io = true }; @@ -1830,7 +1837,7 @@ static const struct regmap_config msm8996_a1noc_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = 0x7000, + .max_register = 0x5000, .fast_io = true }; @@ -1851,7 +1858,7 @@ static const struct regmap_config msm8996_a2noc_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = 0xa000, + .max_register = 0x7000, .fast_io = true }; @@ -1859,6 +1866,8 @@ static const struct qcom_icc_desc msm8996_a2noc = { .type = QCOM_ICC_NOC, .nodes = a2noc_nodes, .num_nodes = ARRAY_SIZE(a2noc_nodes), + .clocks = bus_a2noc_clocks, + .num_clocks = ARRAY_SIZE(bus_a2noc_clocks), .regmap_cfg = &msm8996_a2noc_regmap_config }; @@ -1877,7 +1886,7 @@ static const struct regmap_config msm8996_bimc_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = 0x62000, + .max_register = 0x5a000, .fast_io = true }; @@ -1988,7 +1997,7 @@ static const struct regmap_config msm8996_mnoc_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = 0x20000, + .max_register = 0x1c000, .fast_io = true }; diff --git a/drivers/interconnect/qcom/qdu1000.c b/drivers/interconnect/qcom/qdu1000.c new file mode 100644 index 000000000000..a4cf559de2b0 --- /dev/null +++ b/drivers/interconnect/qcom/qdu1000.c @@ -0,0 +1,1067 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + */ + +#include <linux/device.h> +#include <linux/interconnect.h> +#include <linux/interconnect-provider.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <dt-bindings/interconnect/qcom,qdu1000-rpmh.h> + +#include "bcm-voter.h" +#include "icc-common.h" +#include "icc-rpmh.h" +#include "qdu1000.h" + +static struct qcom_icc_node qup0_core_master = { + .name = "qup0_core_master", + .id = QDU1000_MASTER_QUP_CORE_0, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QDU1000_SLAVE_QUP_CORE_0 }, +}; + +static struct qcom_icc_node qup1_core_master = { + .name = "qup1_core_master", + .id = QDU1000_MASTER_QUP_CORE_1, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QDU1000_SLAVE_QUP_CORE_1 }, +}; + +static struct qcom_icc_node alm_sys_tcu = { + .name = "alm_sys_tcu", + .id = QDU1000_MASTER_SYS_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 2, + .links = { QDU1000_SLAVE_GEM_NOC_CNOC, QDU1000_SLAVE_LLCC }, +}; + +static struct qcom_icc_node chm_apps = { + .name = "chm_apps", + .id = QDU1000_MASTER_APPSS_PROC, + .channels = 1, + .buswidth = 16, + .num_links = 4, + .links = { QDU1000_SLAVE_GEM_NOC_CNOC, QDU1000_SLAVE_LLCC, + QDU1000_SLAVE_GEMNOC_MODEM_CNOC, QDU1000_SLAVE_MEM_NOC_PCIE_SNOC + }, +}; + +static struct qcom_icc_node qnm_ecpri_dma = { + .name = "qnm_ecpri_dma", + .id = QDU1000_MASTER_GEMNOC_ECPRI_DMA, + .channels = 2, + .buswidth = 32, + .num_links = 2, + .links = { QDU1000_SLAVE_GEM_NOC_CNOC, QDU1000_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_fec_2_gemnoc = { + .name = "qnm_fec_2_gemnoc", + .id = QDU1000_MASTER_FEC_2_GEMNOC, + .channels = 2, + .buswidth = 32, + .num_links = 2, + .links = { QDU1000_SLAVE_GEM_NOC_CNOC, QDU1000_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_pcie = { + .name = "qnm_pcie", + .id = QDU1000_MASTER_ANOC_PCIE_GEM_NOC, + .channels = 1, + .buswidth = 64, + .num_links = 3, + .links = { QDU1000_SLAVE_GEM_NOC_CNOC, QDU1000_SLAVE_LLCC, + QDU1000_SLAVE_GEMNOC_MODEM_CNOC + }, +}; + +static struct qcom_icc_node qnm_snoc_gc = { + .name = "qnm_snoc_gc", + .id = QDU1000_MASTER_SNOC_GC_MEM_NOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QDU1000_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_snoc_sf = { + .name = "qnm_snoc_sf", + .id = QDU1000_MASTER_SNOC_SF_MEM_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 4, + .links = { QDU1000_SLAVE_GEM_NOC_CNOC, QDU1000_SLAVE_LLCC, + QDU1000_SLAVE_GEMNOC_MODEM_CNOC, QDU1000_SLAVE_MEM_NOC_PCIE_SNOC + }, +}; + +static struct qcom_icc_node qxm_mdsp = { + .name = "qxm_mdsp", + .id = QDU1000_MASTER_MSS_PROC, + .channels = 1, + .buswidth = 16, + .num_links = 3, + .links = { QDU1000_SLAVE_GEM_NOC_CNOC, QDU1000_SLAVE_LLCC, + QDU1000_SLAVE_MEM_NOC_PCIE_SNOC + }, +}; + +static struct qcom_icc_node llcc_mc = { + .name = "llcc_mc", + .id = QDU1000_MASTER_LLCC, + .channels = 8, + .buswidth = 4, + .num_links = 1, + .links = { QDU1000_SLAVE_EBI1 }, +}; + +static struct qcom_icc_node qhm_gic = { + .name = "qhm_gic", + .id = QDU1000_MASTER_GIC_AHB, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QDU1000_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node qhm_qdss_bam = { + .name = "qhm_qdss_bam", + .id = QDU1000_MASTER_QDSS_BAM, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QDU1000_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node qhm_qpic = { + .name = "qhm_qpic", + .id = QDU1000_MASTER_QPIC, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QDU1000_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qhm_qspi = { + .name = "qhm_qspi", + .id = QDU1000_MASTER_QSPI_0, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QDU1000_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qhm_qup0 = { + .name = "qhm_qup0", + .id = QDU1000_MASTER_QUP_0, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QDU1000_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qhm_qup1 = { + .name = "qhm_qup1", + .id = QDU1000_MASTER_QUP_1, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QDU1000_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qhm_system_noc_cfg = { + .name = "qhm_system_noc_cfg", + .id = QDU1000_MASTER_SNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QDU1000_SLAVE_SERVICE_SNOC }, +}; + +static struct qcom_icc_node qnm_aggre_noc = { + .name = "qnm_aggre_noc", + .id = QDU1000_MASTER_ANOC_SNOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QDU1000_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node qnm_aggre_noc_gsi = { + .name = "qnm_aggre_noc_gsi", + .id = QDU1000_MASTER_ANOC_GSI, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QDU1000_SLAVE_SNOC_GEM_NOC_GC }, +}; + +static struct qcom_icc_node qnm_gemnoc_cnoc = { + .name = "qnm_gemnoc_cnoc", + .id = QDU1000_MASTER_GEM_NOC_CNOC, + .channels = 1, + .buswidth = 16, + .num_links = 36, + .links = { QDU1000_SLAVE_AHB2PHY_SOUTH, QDU1000_SLAVE_AHB2PHY_NORTH, + QDU1000_SLAVE_AHB2PHY_EAST, QDU1000_SLAVE_AOSS, + QDU1000_SLAVE_CLK_CTL, QDU1000_SLAVE_RBCPR_CX_CFG, + QDU1000_SLAVE_RBCPR_MX_CFG, QDU1000_SLAVE_CRYPTO_0_CFG, + QDU1000_SLAVE_ECPRI_CFG, QDU1000_SLAVE_IMEM_CFG, + QDU1000_SLAVE_IPC_ROUTER_CFG, QDU1000_SLAVE_CNOC_MSS, + QDU1000_SLAVE_PCIE_CFG, QDU1000_SLAVE_PDM, + QDU1000_SLAVE_PIMEM_CFG, QDU1000_SLAVE_PRNG, + QDU1000_SLAVE_QDSS_CFG, QDU1000_SLAVE_QPIC, + QDU1000_SLAVE_QSPI_0, QDU1000_SLAVE_QUP_0, + QDU1000_SLAVE_QUP_1, QDU1000_SLAVE_SDCC_2, + QDU1000_SLAVE_SMBUS_CFG, QDU1000_SLAVE_SNOC_CFG, + QDU1000_SLAVE_TCSR, QDU1000_SLAVE_TLMM, + QDU1000_SLAVE_TME_CFG, QDU1000_SLAVE_TSC_CFG, + QDU1000_SLAVE_USB3_0, QDU1000_SLAVE_VSENSE_CTRL_CFG, + QDU1000_SLAVE_DDRSS_CFG, QDU1000_SLAVE_IMEM, + QDU1000_SLAVE_PIMEM, QDU1000_SLAVE_ETHERNET_SS, + QDU1000_SLAVE_QDSS_STM, QDU1000_SLAVE_TCU + }, +}; + +static struct qcom_icc_node qnm_gemnoc_modem_slave = { + .name = "qnm_gemnoc_modem_slave", + .id = QDU1000_MASTER_GEMNOC_MODEM_CNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QDU1000_SLAVE_MODEM_OFFLINE }, +}; + +static struct qcom_icc_node qnm_gemnoc_pcie = { + .name = "qnm_gemnoc_pcie", + .id = QDU1000_MASTER_GEM_NOC_PCIE_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QDU1000_SLAVE_PCIE_0 }, +}; + +static struct qcom_icc_node qxm_crypto = { + .name = "qxm_crypto", + .id = QDU1000_MASTER_CRYPTO, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QDU1000_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qxm_ecpri_gsi = { + .name = "qxm_ecpri_gsi", + .id = QDU1000_MASTER_ECPRI_GSI, + .channels = 1, + .buswidth = 8, + .num_links = 2, + .links = { QDU1000_SLAVE_ANOC_SNOC_GSI, QDU1000_SLAVE_PCIE_0 }, +}; + +static struct qcom_icc_node qxm_pimem = { + .name = "qxm_pimem", + .id = QDU1000_MASTER_PIMEM, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QDU1000_SLAVE_SNOC_GEM_NOC_GC }, +}; + +static struct qcom_icc_node xm_ecpri_dma = { + .name = "xm_ecpri_dma", + .id = QDU1000_MASTER_SNOC_ECPRI_DMA, + .channels = 2, + .buswidth = 32, + .num_links = 2, + .links = { QDU1000_SLAVE_ECPRI_GEMNOC, QDU1000_SLAVE_PCIE_0 }, +}; + +static struct qcom_icc_node xm_gic = { + .name = "xm_gic", + .id = QDU1000_MASTER_GIC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QDU1000_SLAVE_SNOC_GEM_NOC_GC }, +}; + +static struct qcom_icc_node xm_pcie = { + .name = "xm_pcie", + .id = QDU1000_MASTER_PCIE, + .channels = 1, + .buswidth = 64, + .num_links = 1, + .links = { QDU1000_SLAVE_ANOC_PCIE_GEM_NOC }, +}; + +static struct qcom_icc_node xm_qdss_etr0 = { + .name = "xm_qdss_etr0", + .id = QDU1000_MASTER_QDSS_ETR, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QDU1000_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node xm_qdss_etr1 = { + .name = "xm_qdss_etr1", + .id = QDU1000_MASTER_QDSS_ETR_1, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QDU1000_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node xm_sdc = { + .name = "xm_sdc", + .id = QDU1000_MASTER_SDCC_1, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QDU1000_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_usb3 = { + .name = "xm_usb3", + .id = QDU1000_MASTER_USB3, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QDU1000_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qup0_core_slave = { + .name = "qup0_core_slave", + .id = QDU1000_SLAVE_QUP_CORE_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qup1_core_slave = { + .name = "qup1_core_slave", + .id = QDU1000_SLAVE_QUP_CORE_1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_gem_noc_cnoc = { + .name = "qns_gem_noc_cnoc", + .id = QDU1000_SLAVE_GEM_NOC_CNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QDU1000_MASTER_GEM_NOC_CNOC }, +}; + +static struct qcom_icc_node qns_llcc = { + .name = "qns_llcc", + .id = QDU1000_SLAVE_LLCC, + .channels = 8, + .buswidth = 16, + .num_links = 1, + .links = { QDU1000_MASTER_LLCC }, +}; + +static struct qcom_icc_node qns_modem_slave = { + .name = "qns_modem_slave", + .id = QDU1000_SLAVE_GEMNOC_MODEM_CNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QDU1000_MASTER_GEMNOC_MODEM_CNOC }, +}; + +static struct qcom_icc_node qns_pcie = { + .name = "qns_pcie", + .id = QDU1000_SLAVE_MEM_NOC_PCIE_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QDU1000_MASTER_GEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node ebi = { + .name = "ebi", + .id = QDU1000_SLAVE_EBI1, + .channels = 8, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ahb2phy0_south = { + .name = "qhs_ahb2phy0_south", + .id = QDU1000_SLAVE_AHB2PHY_SOUTH, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ahb2phy1_north = { + .name = "qhs_ahb2phy1_north", + .id = QDU1000_SLAVE_AHB2PHY_NORTH, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ahb2phy2_east = { + .name = "qhs_ahb2phy2_east", + .id = QDU1000_SLAVE_AHB2PHY_EAST, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_aoss = { + .name = "qhs_aoss", + .id = QDU1000_SLAVE_AOSS, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_clk_ctl = { + .name = "qhs_clk_ctl", + .id = QDU1000_SLAVE_CLK_CTL, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_cx = { + .name = "qhs_cpr_cx", + .id = QDU1000_SLAVE_RBCPR_CX_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_mx = { + .name = "qhs_cpr_mx", + .id = QDU1000_SLAVE_RBCPR_MX_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_crypto_cfg = { + .name = "qhs_crypto_cfg", + .id = QDU1000_SLAVE_CRYPTO_0_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ecpri_cfg = { + .name = "qhs_ecpri_cfg", + .id = QDU1000_SLAVE_ECPRI_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_imem_cfg = { + .name = "qhs_imem_cfg", + .id = QDU1000_SLAVE_IMEM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ipc_router = { + .name = "qhs_ipc_router", + .id = QDU1000_SLAVE_IPC_ROUTER_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_mss_cfg = { + .name = "qhs_mss_cfg", + .id = QDU1000_SLAVE_CNOC_MSS, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pcie_cfg = { + .name = "qhs_pcie_cfg", + .id = QDU1000_SLAVE_PCIE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pdm = { + .name = "qhs_pdm", + .id = QDU1000_SLAVE_PDM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pimem_cfg = { + .name = "qhs_pimem_cfg", + .id = QDU1000_SLAVE_PIMEM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_prng = { + .name = "qhs_prng", + .id = QDU1000_SLAVE_PRNG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qdss_cfg = { + .name = "qhs_qdss_cfg", + .id = QDU1000_SLAVE_QDSS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qpic = { + .name = "qhs_qpic", + .id = QDU1000_SLAVE_QPIC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qspi = { + .name = "qhs_qspi", + .id = QDU1000_SLAVE_QSPI_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qup0 = { + .name = "qhs_qup0", + .id = QDU1000_SLAVE_QUP_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qup1 = { + .name = "qhs_qup1", + .id = QDU1000_SLAVE_QUP_1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_sdc2 = { + .name = "qhs_sdc2", + .id = QDU1000_SLAVE_SDCC_2, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_smbus_cfg = { + .name = "qhs_smbus_cfg", + .id = QDU1000_SLAVE_SMBUS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_system_noc_cfg = { + .name = "qhs_system_noc_cfg", + .id = QDU1000_SLAVE_SNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QDU1000_MASTER_SNOC_CFG }, +}; + +static struct qcom_icc_node qhs_tcsr = { + .name = "qhs_tcsr", + .id = QDU1000_SLAVE_TCSR, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tlmm = { + .name = "qhs_tlmm", + .id = QDU1000_SLAVE_TLMM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tme_cfg = { + .name = "qhs_tme_cfg", + .id = QDU1000_SLAVE_TME_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tsc_cfg = { + .name = "qhs_tsc_cfg", + .id = QDU1000_SLAVE_TSC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_usb3 = { + .name = "qhs_usb3", + .id = QDU1000_SLAVE_USB3_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_vsense_ctrl_cfg = { + .name = "qhs_vsense_ctrl_cfg", + .id = QDU1000_SLAVE_VSENSE_CTRL_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_a1noc_snoc = { + .name = "qns_a1noc_snoc", + .id = QDU1000_SLAVE_A1NOC_SNOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QDU1000_MASTER_ANOC_SNOC }, +}; + +static struct qcom_icc_node qns_anoc_snoc_gsi = { + .name = "qns_anoc_snoc_gsi", + .id = QDU1000_SLAVE_ANOC_SNOC_GSI, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QDU1000_MASTER_ANOC_GSI }, +}; + +static struct qcom_icc_node qns_ddrss_cfg = { + .name = "qns_ddrss_cfg", + .id = QDU1000_SLAVE_DDRSS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_ecpri_gemnoc = { + .name = "qns_ecpri_gemnoc", + .id = QDU1000_SLAVE_ECPRI_GEMNOC, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { QDU1000_MASTER_GEMNOC_ECPRI_DMA }, +}; + +static struct qcom_icc_node qns_gemnoc_gc = { + .name = "qns_gemnoc_gc", + .id = QDU1000_SLAVE_SNOC_GEM_NOC_GC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QDU1000_MASTER_SNOC_GC_MEM_NOC }, +}; + +static struct qcom_icc_node qns_gemnoc_sf = { + .name = "qns_gemnoc_sf", + .id = QDU1000_SLAVE_SNOC_GEM_NOC_SF, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QDU1000_MASTER_SNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qns_modem = { + .name = "qns_modem", + .id = QDU1000_SLAVE_MODEM_OFFLINE, + .channels = 1, + .buswidth = 32, + .num_links = 0, +}; + +static struct qcom_icc_node qns_pcie_gemnoc = { + .name = "qns_pcie_gemnoc", + .id = QDU1000_SLAVE_ANOC_PCIE_GEM_NOC, + .channels = 1, + .buswidth = 64, + .num_links = 1, + .links = { QDU1000_MASTER_ANOC_PCIE_GEM_NOC }, +}; + +static struct qcom_icc_node qxs_imem = { + .name = "qxs_imem", + .id = QDU1000_SLAVE_IMEM, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qxs_pimem = { + .name = "qxs_pimem", + .id = QDU1000_SLAVE_PIMEM, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node srvc_system_noc = { + .name = "srvc_system_noc", + .id = QDU1000_SLAVE_SERVICE_SNOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node xs_ethernet_ss = { + .name = "xs_ethernet_ss", + .id = QDU1000_SLAVE_ETHERNET_SS, + .channels = 1, + .buswidth = 32, + .num_links = 0, +}; + +static struct qcom_icc_node xs_pcie = { + .name = "xs_pcie", + .id = QDU1000_SLAVE_PCIE_0, + .channels = 1, + .buswidth = 64, + .num_links = 0, +}; + +static struct qcom_icc_node xs_qdss_stm = { + .name = "xs_qdss_stm", + .id = QDU1000_SLAVE_QDSS_STM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node xs_sys_tcu_cfg = { + .name = "xs_sys_tcu_cfg", + .id = QDU1000_SLAVE_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_bcm bcm_acv = { + .name = "ACV", + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_ce0 = { + .name = "CE0", + .num_nodes = 1, + .nodes = { &qxm_crypto }, +}; + +static struct qcom_icc_bcm bcm_cn0 = { + .name = "CN0", + .num_nodes = 44, + .nodes = { &qhm_qpic, &qhm_qspi, + &qnm_gemnoc_cnoc, &qnm_gemnoc_modem_slave, + &qnm_gemnoc_pcie, &xm_sdc, + &xm_usb3, &qhs_ahb2phy0_south, + &qhs_ahb2phy1_north, &qhs_ahb2phy2_east, + &qhs_aoss, &qhs_clk_ctl, + &qhs_cpr_cx, &qhs_cpr_mx, + &qhs_crypto_cfg, &qhs_ecpri_cfg, + &qhs_imem_cfg, &qhs_ipc_router, + &qhs_mss_cfg, &qhs_pcie_cfg, + &qhs_pdm, &qhs_pimem_cfg, + &qhs_prng, &qhs_qdss_cfg, + &qhs_qpic, &qhs_qspi, + &qhs_qup0, &qhs_qup1, + &qhs_sdc2, &qhs_smbus_cfg, + &qhs_system_noc_cfg, &qhs_tcsr, + &qhs_tlmm, &qhs_tme_cfg, + &qhs_tsc_cfg, &qhs_usb3, + &qhs_vsense_ctrl_cfg, &qns_ddrss_cfg, + &qns_modem, &qxs_imem, + &qxs_pimem, &xs_ethernet_ss, + &xs_qdss_stm, &xs_sys_tcu_cfg + }, +}; + +static struct qcom_icc_bcm bcm_mc0 = { + .name = "MC0", + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_qup0 = { + .name = "QUP0", + .num_nodes = 2, + .nodes = { &qup0_core_slave, &qup1_core_slave }, +}; + +static struct qcom_icc_bcm bcm_sh0 = { + .name = "SH0", + .num_nodes = 1, + .nodes = { &qns_llcc }, +}; + +static struct qcom_icc_bcm bcm_sh1 = { + .name = "SH1", + .num_nodes = 11, + .nodes = { &alm_sys_tcu, &chm_apps, + &qnm_ecpri_dma, &qnm_fec_2_gemnoc, + &qnm_pcie, &qnm_snoc_gc, + &qnm_snoc_sf, &qxm_mdsp, + &qns_gem_noc_cnoc, &qns_modem_slave, + &qns_pcie + }, +}; + +static struct qcom_icc_bcm bcm_sn0 = { + .name = "SN0", + .num_nodes = 1, + .nodes = { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_bcm bcm_sn1 = { + .name = "SN1", + .num_nodes = 6, + .nodes = { &qhm_gic, &qxm_pimem, + &xm_gic, &xm_qdss_etr0, + &xm_qdss_etr1, &qns_gemnoc_gc + }, +}; + +static struct qcom_icc_bcm bcm_sn2 = { + .name = "SN2", + .num_nodes = 5, + .nodes = { &qnm_aggre_noc, &qxm_ecpri_gsi, + &xm_ecpri_dma, &qns_anoc_snoc_gsi, + &qns_ecpri_gemnoc + }, +}; + +static struct qcom_icc_bcm bcm_sn7 = { + .name = "SN7", + .num_nodes = 2, + .nodes = { &qns_pcie_gemnoc, &xs_pcie }, +}; + +static struct qcom_icc_bcm * const clk_virt_bcms[] = { + &bcm_qup0, +}; + +static struct qcom_icc_node * const clk_virt_nodes[] = { + [MASTER_QUP_CORE_0] = &qup0_core_master, + [MASTER_QUP_CORE_1] = &qup1_core_master, + [SLAVE_QUP_CORE_0] = &qup0_core_slave, + [SLAVE_QUP_CORE_1] = &qup1_core_slave, +}; + +static const struct qcom_icc_desc qdu1000_clk_virt = { + .nodes = clk_virt_nodes, + .num_nodes = ARRAY_SIZE(clk_virt_nodes), + .bcms = clk_virt_bcms, + .num_bcms = ARRAY_SIZE(clk_virt_bcms), +}; + +static struct qcom_icc_bcm * const gem_noc_bcms[] = { + &bcm_sh0, + &bcm_sh1, +}; + +static struct qcom_icc_node * const gem_noc_nodes[] = { + [MASTER_SYS_TCU] = &alm_sys_tcu, + [MASTER_APPSS_PROC] = &chm_apps, + [MASTER_GEMNOC_ECPRI_DMA] = &qnm_ecpri_dma, + [MASTER_FEC_2_GEMNOC] = &qnm_fec_2_gemnoc, + [MASTER_ANOC_PCIE_GEM_NOC] = &qnm_pcie, + [MASTER_SNOC_GC_MEM_NOC] = &qnm_snoc_gc, + [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf, + [MASTER_MSS_PROC] = &qxm_mdsp, + [SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc, + [SLAVE_LLCC] = &qns_llcc, + [SLAVE_GEMNOC_MODEM_CNOC] = &qns_modem_slave, + [SLAVE_MEM_NOC_PCIE_SNOC] = &qns_pcie, +}; + +static const struct qcom_icc_desc qdu1000_gem_noc = { + .nodes = gem_noc_nodes, + .num_nodes = ARRAY_SIZE(gem_noc_nodes), + .bcms = gem_noc_bcms, + .num_bcms = ARRAY_SIZE(gem_noc_bcms), +}; + +static struct qcom_icc_bcm * const mc_virt_bcms[] = { + &bcm_acv, + &bcm_mc0, +}; + +static struct qcom_icc_node * const mc_virt_nodes[] = { + [MASTER_LLCC] = &llcc_mc, + [SLAVE_EBI1] = &ebi, +}; + +static const struct qcom_icc_desc qdu1000_mc_virt = { + .nodes = mc_virt_nodes, + .num_nodes = ARRAY_SIZE(mc_virt_nodes), + .bcms = mc_virt_bcms, + .num_bcms = ARRAY_SIZE(mc_virt_bcms), +}; + +static struct qcom_icc_bcm * const system_noc_bcms[] = { + &bcm_ce0, + &bcm_cn0, + &bcm_sn0, + &bcm_sn1, + &bcm_sn2, + &bcm_sn7, +}; + +static struct qcom_icc_node * const system_noc_nodes[] = { + [MASTER_GIC_AHB] = &qhm_gic, + [MASTER_QDSS_BAM] = &qhm_qdss_bam, + [MASTER_QPIC] = &qhm_qpic, + [MASTER_QSPI_0] = &qhm_qspi, + [MASTER_QUP_0] = &qhm_qup0, + [MASTER_QUP_1] = &qhm_qup1, + [MASTER_SNOC_CFG] = &qhm_system_noc_cfg, + [MASTER_ANOC_SNOC] = &qnm_aggre_noc, + [MASTER_ANOC_GSI] = &qnm_aggre_noc_gsi, + [MASTER_GEM_NOC_CNOC] = &qnm_gemnoc_cnoc, + [MASTER_GEMNOC_MODEM_CNOC] = &qnm_gemnoc_modem_slave, + [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie, + [MASTER_CRYPTO] = &qxm_crypto, + [MASTER_ECPRI_GSI] = &qxm_ecpri_gsi, + [MASTER_PIMEM] = &qxm_pimem, + [MASTER_SNOC_ECPRI_DMA] = &xm_ecpri_dma, + [MASTER_GIC] = &xm_gic, + [MASTER_PCIE] = &xm_pcie, + [MASTER_QDSS_ETR] = &xm_qdss_etr0, + [MASTER_QDSS_ETR_1] = &xm_qdss_etr1, + [MASTER_SDCC_1] = &xm_sdc, + [MASTER_USB3] = &xm_usb3, + [SLAVE_AHB2PHY_SOUTH] = &qhs_ahb2phy0_south, + [SLAVE_AHB2PHY_NORTH] = &qhs_ahb2phy1_north, + [SLAVE_AHB2PHY_EAST] = &qhs_ahb2phy2_east, + [SLAVE_AOSS] = &qhs_aoss, + [SLAVE_CLK_CTL] = &qhs_clk_ctl, + [SLAVE_RBCPR_CX_CFG] = &qhs_cpr_cx, + [SLAVE_RBCPR_MX_CFG] = &qhs_cpr_mx, + [SLAVE_CRYPTO_0_CFG] = &qhs_crypto_cfg, + [SLAVE_ECPRI_CFG] = &qhs_ecpri_cfg, + [SLAVE_IMEM_CFG] = &qhs_imem_cfg, + [SLAVE_IPC_ROUTER_CFG] = &qhs_ipc_router, + [SLAVE_CNOC_MSS] = &qhs_mss_cfg, + [SLAVE_PCIE_CFG] = &qhs_pcie_cfg, + [SLAVE_PDM] = &qhs_pdm, + [SLAVE_PIMEM_CFG] = &qhs_pimem_cfg, + [SLAVE_PRNG] = &qhs_prng, + [SLAVE_QDSS_CFG] = &qhs_qdss_cfg, + [SLAVE_QPIC] = &qhs_qpic, + [SLAVE_QSPI_0] = &qhs_qspi, + [SLAVE_QUP_0] = &qhs_qup0, + [SLAVE_QUP_1] = &qhs_qup1, + [SLAVE_SDCC_2] = &qhs_sdc2, + [SLAVE_SMBUS_CFG] = &qhs_smbus_cfg, + [SLAVE_SNOC_CFG] = &qhs_system_noc_cfg, + [SLAVE_TCSR] = &qhs_tcsr, + [SLAVE_TLMM] = &qhs_tlmm, + [SLAVE_TME_CFG] = &qhs_tme_cfg, + [SLAVE_TSC_CFG] = &qhs_tsc_cfg, + [SLAVE_USB3_0] = &qhs_usb3, + [SLAVE_VSENSE_CTRL_CFG] = &qhs_vsense_ctrl_cfg, + [SLAVE_A1NOC_SNOC] = &qns_a1noc_snoc, + [SLAVE_ANOC_SNOC_GSI] = &qns_anoc_snoc_gsi, + [SLAVE_DDRSS_CFG] = &qns_ddrss_cfg, + [SLAVE_ECPRI_GEMNOC] = &qns_ecpri_gemnoc, + [SLAVE_SNOC_GEM_NOC_GC] = &qns_gemnoc_gc, + [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf, + [SLAVE_MODEM_OFFLINE] = &qns_modem, + [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_gemnoc, + [SLAVE_IMEM] = &qxs_imem, + [SLAVE_PIMEM] = &qxs_pimem, + [SLAVE_SERVICE_SNOC] = &srvc_system_noc, + [SLAVE_ETHERNET_SS] = &xs_ethernet_ss, + [SLAVE_PCIE_0] = &xs_pcie, + [SLAVE_QDSS_STM] = &xs_qdss_stm, + [SLAVE_TCU] = &xs_sys_tcu_cfg, +}; + +static const struct qcom_icc_desc qdu1000_system_noc = { + .nodes = system_noc_nodes, + .num_nodes = ARRAY_SIZE(system_noc_nodes), + .bcms = system_noc_bcms, + .num_bcms = ARRAY_SIZE(system_noc_bcms), +}; + +static int qnoc_probe(struct platform_device *pdev) +{ + int ret; + + ret = qcom_icc_rpmh_probe(pdev); + if (ret) + dev_err(&pdev->dev, "failed to register ICC provider\n"); + + return ret; +} + +static const struct of_device_id qnoc_of_match[] = { + { .compatible = "qcom,qdu1000-clk-virt", + .data = &qdu1000_clk_virt + }, + { .compatible = "qcom,qdu1000-gem-noc", + .data = &qdu1000_gem_noc + }, + { .compatible = "qcom,qdu1000-mc-virt", + .data = &qdu1000_mc_virt + }, + { .compatible = "qcom,qdu1000-system-noc", + .data = &qdu1000_system_noc + }, + { } +}; +MODULE_DEVICE_TABLE(of, qnoc_of_match); + +static struct platform_driver qnoc_driver = { + .probe = qnoc_probe, + .remove = qcom_icc_rpmh_remove, + .driver = { + .name = "qnoc-qdu1000", + .of_match_table = qnoc_of_match, + }, +}; + +static int __init qnoc_driver_init(void) +{ + return platform_driver_register(&qnoc_driver); +} +core_initcall(qnoc_driver_init); + +static void __exit qnoc_driver_exit(void) +{ + platform_driver_unregister(&qnoc_driver); +} +module_exit(qnoc_driver_exit); + +MODULE_DESCRIPTION("QDU1000 NoC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/interconnect/qcom/qdu1000.h b/drivers/interconnect/qcom/qdu1000.h new file mode 100644 index 000000000000..e75a6419df23 --- /dev/null +++ b/drivers/interconnect/qcom/qdu1000.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __DRIVERS_INTERCONNECT_QCOM_QDU1000_H +#define __DRIVERS_INTERCONNECT_QCOM_QDU1000_H + +#define QDU1000_MASTER_SYS_TCU 0 +#define QDU1000_MASTER_APPSS_PROC 1 +#define QDU1000_MASTER_LLCC 2 +#define QDU1000_MASTER_GIC_AHB 3 +#define QDU1000_MASTER_QDSS_BAM 4 +#define QDU1000_MASTER_QPIC 5 +#define QDU1000_MASTER_QSPI_0 6 +#define QDU1000_MASTER_QUP_0 7 +#define QDU1000_MASTER_QUP_1 8 +#define QDU1000_MASTER_SNOC_CFG 9 +#define QDU1000_MASTER_ANOC_SNOC 10 +#define QDU1000_MASTER_ANOC_GSI 11 +#define QDU1000_MASTER_GEMNOC_ECPRI_DMA 12 +#define QDU1000_MASTER_FEC_2_GEMNOC 13 +#define QDU1000_MASTER_GEM_NOC_CNOC 14 +#define QDU1000_MASTER_GEMNOC_MODEM_CNOC 15 +#define QDU1000_MASTER_GEM_NOC_PCIE_SNOC 16 +#define QDU1000_MASTER_ANOC_PCIE_GEM_NOC 17 +#define QDU1000_MASTER_SNOC_GC_MEM_NOC 18 +#define QDU1000_MASTER_SNOC_SF_MEM_NOC 19 +#define QDU1000_MASTER_QUP_CORE_0 20 +#define QDU1000_MASTER_QUP_CORE_1 21 +#define QDU1000_MASTER_CRYPTO 22 +#define QDU1000_MASTER_ECPRI_GSI 23 +#define QDU1000_MASTER_MSS_PROC 24 +#define QDU1000_MASTER_PIMEM 25 +#define QDU1000_MASTER_SNOC_ECPRI_DMA 26 +#define QDU1000_MASTER_GIC 27 +#define QDU1000_MASTER_PCIE 28 +#define QDU1000_MASTER_QDSS_ETR 29 +#define QDU1000_MASTER_QDSS_ETR_1 30 +#define QDU1000_MASTER_SDCC_1 31 +#define QDU1000_MASTER_USB3 32 +#define QDU1000_SLAVE_EBI1 512 +#define QDU1000_SLAVE_AHB2PHY_SOUTH 513 +#define QDU1000_SLAVE_AHB2PHY_NORTH 514 +#define QDU1000_SLAVE_AHB2PHY_EAST 515 +#define QDU1000_SLAVE_AOSS 516 +#define QDU1000_SLAVE_CLK_CTL 517 +#define QDU1000_SLAVE_RBCPR_CX_CFG 518 +#define QDU1000_SLAVE_RBCPR_MX_CFG 519 +#define QDU1000_SLAVE_CRYPTO_0_CFG 520 +#define QDU1000_SLAVE_ECPRI_CFG 521 +#define QDU1000_SLAVE_IMEM_CFG 522 +#define QDU1000_SLAVE_IPC_ROUTER_CFG 523 +#define QDU1000_SLAVE_CNOC_MSS 524 +#define QDU1000_SLAVE_PCIE_CFG 525 +#define QDU1000_SLAVE_PDM 526 +#define QDU1000_SLAVE_PIMEM_CFG 527 +#define QDU1000_SLAVE_PRNG 528 +#define QDU1000_SLAVE_QDSS_CFG 529 +#define QDU1000_SLAVE_QPIC 530 +#define QDU1000_SLAVE_QSPI_0 531 +#define QDU1000_SLAVE_QUP_0 532 +#define QDU1000_SLAVE_QUP_1 533 +#define QDU1000_SLAVE_SDCC_2 534 +#define QDU1000_SLAVE_SMBUS_CFG 535 +#define QDU1000_SLAVE_SNOC_CFG 536 +#define QDU1000_SLAVE_TCSR 537 +#define QDU1000_SLAVE_TLMM 538 +#define QDU1000_SLAVE_TME_CFG 539 +#define QDU1000_SLAVE_TSC_CFG 540 +#define QDU1000_SLAVE_USB3_0 541 +#define QDU1000_SLAVE_VSENSE_CTRL_CFG 542 +#define QDU1000_SLAVE_A1NOC_SNOC 543 +#define QDU1000_SLAVE_ANOC_SNOC_GSI 544 +#define QDU1000_SLAVE_DDRSS_CFG 545 +#define QDU1000_SLAVE_ECPRI_GEMNOC 546 +#define QDU1000_SLAVE_GEM_NOC_CNOC 547 +#define QDU1000_SLAVE_SNOC_GEM_NOC_GC 548 +#define QDU1000_SLAVE_SNOC_GEM_NOC_SF 549 +#define QDU1000_SLAVE_LLCC 550 +#define QDU1000_SLAVE_MODEM_OFFLINE 551 +#define QDU1000_SLAVE_GEMNOC_MODEM_CNOC 552 +#define QDU1000_SLAVE_MEM_NOC_PCIE_SNOC 553 +#define QDU1000_SLAVE_ANOC_PCIE_GEM_NOC 554 +#define QDU1000_SLAVE_QUP_CORE_0 555 +#define QDU1000_SLAVE_QUP_CORE_1 556 +#define QDU1000_SLAVE_IMEM 557 +#define QDU1000_SLAVE_PIMEM 558 +#define QDU1000_SLAVE_SERVICE_SNOC 559 +#define QDU1000_SLAVE_ETHERNET_SS 560 +#define QDU1000_SLAVE_PCIE_0 561 +#define QDU1000_SLAVE_QDSS_STM 562 +#define QDU1000_SLAVE_TCU 563 + +#endif diff --git a/drivers/interconnect/qcom/sm8550.c b/drivers/interconnect/qcom/sm8550.c new file mode 100644 index 000000000000..54fa027ab961 --- /dev/null +++ b/drivers/interconnect/qcom/sm8550.c @@ -0,0 +1,2318 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, Linaro Limited + * + */ + +#include <linux/device.h> +#include <linux/interconnect.h> +#include <linux/interconnect-provider.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <dt-bindings/interconnect/qcom,sm8550-rpmh.h> + +#include "bcm-voter.h" +#include "icc-common.h" +#include "icc-rpmh.h" +#include "sm8550.h" + +static struct qcom_icc_node qhm_qspi = { + .name = "qhm_qspi", + .id = SM8550_MASTER_QSPI_0, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qhm_qup1 = { + .name = "qhm_qup1", + .id = SM8550_MASTER_QUP_1, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_sdc4 = { + .name = "xm_sdc4", + .id = SM8550_MASTER_SDCC_4, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_ufs_mem = { + .name = "xm_ufs_mem", + .id = SM8550_MASTER_UFS_MEM, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_usb3_0 = { + .name = "xm_usb3_0", + .id = SM8550_MASTER_USB3_0, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qhm_qdss_bam = { + .name = "qhm_qdss_bam", + .id = SM8550_MASTER_QDSS_BAM, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qhm_qup2 = { + .name = "qhm_qup2", + .id = SM8550_MASTER_QUP_2, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qxm_crypto = { + .name = "qxm_crypto", + .id = SM8550_MASTER_CRYPTO, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qxm_ipa = { + .name = "qxm_ipa", + .id = SM8550_MASTER_IPA, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qxm_sp = { + .name = "qxm_sp", + .id = SM8550_MASTER_SP, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node xm_qdss_etr_0 = { + .name = "xm_qdss_etr_0", + .id = SM8550_MASTER_QDSS_ETR, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node xm_qdss_etr_1 = { + .name = "xm_qdss_etr_1", + .id = SM8550_MASTER_QDSS_ETR_1, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node xm_sdc2 = { + .name = "xm_sdc2", + .id = SM8550_MASTER_SDCC_2, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qup0_core_master = { + .name = "qup0_core_master", + .id = SM8550_MASTER_QUP_CORE_0, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_QUP_CORE_0 }, +}; + +static struct qcom_icc_node qup1_core_master = { + .name = "qup1_core_master", + .id = SM8550_MASTER_QUP_CORE_1, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_QUP_CORE_1 }, +}; + +static struct qcom_icc_node qup2_core_master = { + .name = "qup2_core_master", + .id = SM8550_MASTER_QUP_CORE_2, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_QUP_CORE_2 }, +}; + +static struct qcom_icc_node qsm_cfg = { + .name = "qsm_cfg", + .id = SM8550_MASTER_CNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 44, + .links = { SM8550_SLAVE_AHB2PHY_SOUTH, SM8550_SLAVE_AHB2PHY_NORTH, + SM8550_SLAVE_APPSS, SM8550_SLAVE_CAMERA_CFG, + SM8550_SLAVE_CLK_CTL, SM8550_SLAVE_RBCPR_CX_CFG, + SM8550_SLAVE_RBCPR_MMCX_CFG, SM8550_SLAVE_RBCPR_MXA_CFG, + SM8550_SLAVE_RBCPR_MXC_CFG, SM8550_SLAVE_CPR_NSPCX, + SM8550_SLAVE_CRYPTO_0_CFG, SM8550_SLAVE_CX_RDPM, + SM8550_SLAVE_DISPLAY_CFG, SM8550_SLAVE_GFX3D_CFG, + SM8550_SLAVE_I2C, SM8550_SLAVE_IMEM_CFG, + SM8550_SLAVE_IPA_CFG, SM8550_SLAVE_IPC_ROUTER_CFG, + SM8550_SLAVE_CNOC_MSS, SM8550_SLAVE_MX_RDPM, + SM8550_SLAVE_PCIE_0_CFG, SM8550_SLAVE_PCIE_1_CFG, + SM8550_SLAVE_PDM, SM8550_SLAVE_PIMEM_CFG, + SM8550_SLAVE_PRNG, SM8550_SLAVE_QDSS_CFG, + SM8550_SLAVE_QSPI_0, SM8550_SLAVE_QUP_1, + SM8550_SLAVE_QUP_2, SM8550_SLAVE_SDCC_2, + SM8550_SLAVE_SDCC_4, SM8550_SLAVE_SPSS_CFG, + SM8550_SLAVE_TCSR, SM8550_SLAVE_TLMM, + SM8550_SLAVE_UFS_MEM_CFG, SM8550_SLAVE_USB3_0, + SM8550_SLAVE_VENUS_CFG, SM8550_SLAVE_VSENSE_CTRL_CFG, + SM8550_SLAVE_LPASS_QTB_CFG, SM8550_SLAVE_CNOC_MNOC_CFG, + SM8550_SLAVE_NSP_QTB_CFG, SM8550_SLAVE_PCIE_ANOC_CFG, + SM8550_SLAVE_QDSS_STM, SM8550_SLAVE_TCU }, +}; + +static struct qcom_icc_node qnm_gemnoc_cnoc = { + .name = "qnm_gemnoc_cnoc", + .id = SM8550_MASTER_GEM_NOC_CNOC, + .channels = 1, + .buswidth = 16, + .num_links = 6, + .links = { SM8550_SLAVE_AOSS, SM8550_SLAVE_TME_CFG, + SM8550_SLAVE_CNOC_CFG, SM8550_SLAVE_DDRSS_CFG, + SM8550_SLAVE_BOOT_IMEM, SM8550_SLAVE_IMEM }, +}; + +static struct qcom_icc_node qnm_gemnoc_pcie = { + .name = "qnm_gemnoc_pcie", + .id = SM8550_MASTER_GEM_NOC_PCIE_SNOC, + .channels = 1, + .buswidth = 8, + .num_links = 2, + .links = { SM8550_SLAVE_PCIE_0, SM8550_SLAVE_PCIE_1 }, +}; + +static struct qcom_icc_node alm_gpu_tcu = { + .name = "alm_gpu_tcu", + .id = SM8550_MASTER_GPU_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 2, + .links = { SM8550_SLAVE_GEM_NOC_CNOC, SM8550_SLAVE_LLCC }, +}; + +static struct qcom_icc_node alm_sys_tcu = { + .name = "alm_sys_tcu", + .id = SM8550_MASTER_SYS_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 2, + .links = { SM8550_SLAVE_GEM_NOC_CNOC, SM8550_SLAVE_LLCC }, +}; + +static struct qcom_icc_node chm_apps = { + .name = "chm_apps", + .id = SM8550_MASTER_APPSS_PROC, + .channels = 3, + .buswidth = 32, + .num_links = 3, + .links = { SM8550_SLAVE_GEM_NOC_CNOC, SM8550_SLAVE_LLCC, + SM8550_SLAVE_MEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node qnm_gpu = { + .name = "qnm_gpu", + .id = SM8550_MASTER_GFX3D, + .channels = 2, + .buswidth = 32, + .num_links = 2, + .links = { SM8550_SLAVE_GEM_NOC_CNOC, SM8550_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_lpass_gemnoc = { + .name = "qnm_lpass_gemnoc", + .id = SM8550_MASTER_LPASS_GEM_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 3, + .links = { SM8550_SLAVE_GEM_NOC_CNOC, SM8550_SLAVE_LLCC, + SM8550_SLAVE_MEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node qnm_mdsp = { + .name = "qnm_mdsp", + .id = SM8550_MASTER_MSS_PROC, + .channels = 1, + .buswidth = 16, + .num_links = 3, + .links = { SM8550_SLAVE_GEM_NOC_CNOC, SM8550_SLAVE_LLCC, + SM8550_SLAVE_MEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node qnm_mnoc_hf = { + .name = "qnm_mnoc_hf", + .id = SM8550_MASTER_MNOC_HF_MEM_NOC, + .channels = 2, + .buswidth = 32, + .num_links = 2, + .links = { SM8550_SLAVE_GEM_NOC_CNOC, SM8550_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_mnoc_sf = { + .name = "qnm_mnoc_sf", + .id = SM8550_MASTER_MNOC_SF_MEM_NOC, + .channels = 2, + .buswidth = 32, + .num_links = 2, + .links = { SM8550_SLAVE_GEM_NOC_CNOC, SM8550_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_nsp_gemnoc = { + .name = "qnm_nsp_gemnoc", + .id = SM8550_MASTER_COMPUTE_NOC, + .channels = 2, + .buswidth = 32, + .num_links = 2, + .links = { SM8550_SLAVE_GEM_NOC_CNOC, SM8550_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_pcie = { + .name = "qnm_pcie", + .id = SM8550_MASTER_ANOC_PCIE_GEM_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 2, + .links = { SM8550_SLAVE_GEM_NOC_CNOC, SM8550_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_snoc_gc = { + .name = "qnm_snoc_gc", + .id = SM8550_MASTER_SNOC_GC_MEM_NOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_snoc_sf = { + .name = "qnm_snoc_sf", + .id = SM8550_MASTER_SNOC_SF_MEM_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 3, + .links = { SM8550_SLAVE_GEM_NOC_CNOC, SM8550_SLAVE_LLCC, + SM8550_SLAVE_MEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node qnm_lpiaon_noc = { + .name = "qnm_lpiaon_noc", + .id = SM8550_MASTER_LPIAON_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_SLAVE_LPASS_GEM_NOC }, +}; + +static struct qcom_icc_node qnm_lpass_lpinoc = { + .name = "qnm_lpass_lpinoc", + .id = SM8550_MASTER_LPASS_LPINOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_SLAVE_LPIAON_NOC_LPASS_AG_NOC }, +}; + +static struct qcom_icc_node qxm_lpinoc_dsp_axim = { + .name = "qxm_lpinoc_dsp_axim", + .id = SM8550_MASTER_LPASS_PROC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_SLAVE_LPICX_NOC_LPIAON_NOC }, +}; + +static struct qcom_icc_node llcc_mc = { + .name = "llcc_mc", + .id = SM8550_MASTER_LLCC, + .channels = 4, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_EBI1 }, +}; + +static struct qcom_icc_node qnm_camnoc_hf = { + .name = "qnm_camnoc_hf", + .id = SM8550_MASTER_CAMNOC_HF, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_HF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_camnoc_icp = { + .name = "qnm_camnoc_icp", + .id = SM8550_MASTER_CAMNOC_ICP, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_camnoc_sf = { + .name = "qnm_camnoc_sf", + .id = SM8550_MASTER_CAMNOC_SF, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_mdp = { + .name = "qnm_mdp", + .id = SM8550_MASTER_MDP, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_HF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_vapss_hcp = { + .name = "qnm_vapss_hcp", + .id = SM8550_MASTER_CDSP_HCP, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_video = { + .name = "qnm_video", + .id = SM8550_MASTER_VIDEO, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_video_cv_cpu = { + .name = "qnm_video_cv_cpu", + .id = SM8550_MASTER_VIDEO_CV_PROC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_video_cvp = { + .name = "qnm_video_cvp", + .id = SM8550_MASTER_VIDEO_PROC, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_video_v_cpu = { + .name = "qnm_video_v_cpu", + .id = SM8550_MASTER_VIDEO_V_PROC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qsm_mnoc_cfg = { + .name = "qsm_mnoc_cfg", + .id = SM8550_MASTER_CNOC_MNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_SERVICE_MNOC }, +}; + +static struct qcom_icc_node qxm_nsp = { + .name = "qxm_nsp", + .id = SM8550_MASTER_CDSP_PROC, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_CDSP_MEM_NOC }, +}; + +static struct qcom_icc_node qsm_pcie_anoc_cfg = { + .name = "qsm_pcie_anoc_cfg", + .id = SM8550_MASTER_PCIE_ANOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_SERVICE_PCIE_ANOC }, +}; + +static struct qcom_icc_node xm_pcie3_0 = { + .name = "xm_pcie3_0", + .id = SM8550_MASTER_PCIE_0, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_ANOC_PCIE_GEM_NOC }, +}; + +static struct qcom_icc_node xm_pcie3_1 = { + .name = "xm_pcie3_1", + .id = SM8550_MASTER_PCIE_1, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_SLAVE_ANOC_PCIE_GEM_NOC }, +}; + +static struct qcom_icc_node qhm_gic = { + .name = "qhm_gic", + .id = SM8550_MASTER_GIC_AHB, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node qnm_aggre1_noc = { + .name = "qnm_aggre1_noc", + .id = SM8550_MASTER_A1NOC_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node qnm_aggre2_noc = { + .name = "qnm_aggre2_noc", + .id = SM8550_MASTER_A2NOC_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node xm_gic = { + .name = "xm_gic", + .id = SM8550_MASTER_GIC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_SNOC_GEM_NOC_GC }, +}; + +static struct qcom_icc_node qnm_mnoc_hf_disp = { + .name = "qnm_mnoc_hf_disp", + .id = SM8550_MASTER_MNOC_HF_MEM_NOC_DISP, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_LLCC_DISP }, +}; + +static struct qcom_icc_node qnm_pcie_disp = { + .name = "qnm_pcie_disp", + .id = SM8550_MASTER_ANOC_PCIE_GEM_NOC_DISP, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_SLAVE_LLCC_DISP }, +}; + +static struct qcom_icc_node llcc_mc_disp = { + .name = "llcc_mc_disp", + .id = SM8550_MASTER_LLCC_DISP, + .channels = 4, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_EBI1_DISP }, +}; + +static struct qcom_icc_node qnm_mdp_disp = { + .name = "qnm_mdp_disp", + .id = SM8550_MASTER_MDP_DISP, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_HF_MEM_NOC_DISP }, +}; + +static struct qcom_icc_node qnm_mnoc_hf_cam_ife_0 = { + .name = "qnm_mnoc_hf_cam_ife_0", + .id = SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_0, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_LLCC_CAM_IFE_0 }, +}; + +static struct qcom_icc_node qnm_mnoc_sf_cam_ife_0 = { + .name = "qnm_mnoc_sf_cam_ife_0", + .id = SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_0, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_LLCC_CAM_IFE_0 }, +}; + +static struct qcom_icc_node qnm_pcie_cam_ife_0 = { + .name = "qnm_pcie_cam_ife_0", + .id = SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_0, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_SLAVE_LLCC_CAM_IFE_0 }, +}; + +static struct qcom_icc_node llcc_mc_cam_ife_0 = { + .name = "llcc_mc_cam_ife_0", + .id = SM8550_MASTER_LLCC_CAM_IFE_0, + .channels = 4, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_EBI1_CAM_IFE_0 }, +}; + +static struct qcom_icc_node qnm_camnoc_hf_cam_ife_0 = { + .name = "qnm_camnoc_hf_cam_ife_0", + .id = SM8550_MASTER_CAMNOC_HF_CAM_IFE_0, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_0 }, +}; + +static struct qcom_icc_node qnm_camnoc_icp_cam_ife_0 = { + .name = "qnm_camnoc_icp_cam_ife_0", + .id = SM8550_MASTER_CAMNOC_ICP_CAM_IFE_0, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0 }, +}; + +static struct qcom_icc_node qnm_camnoc_sf_cam_ife_0 = { + .name = "qnm_camnoc_sf_cam_ife_0", + .id = SM8550_MASTER_CAMNOC_SF_CAM_IFE_0, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0 }, +}; + +static struct qcom_icc_node qnm_mnoc_hf_cam_ife_1 = { + .name = "qnm_mnoc_hf_cam_ife_1", + .id = SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_1, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_LLCC_CAM_IFE_1 }, +}; + +static struct qcom_icc_node qnm_mnoc_sf_cam_ife_1 = { + .name = "qnm_mnoc_sf_cam_ife_1", + .id = SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_1, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_LLCC_CAM_IFE_1 }, +}; + +static struct qcom_icc_node qnm_pcie_cam_ife_1 = { + .name = "qnm_pcie_cam_ife_1", + .id = SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_1, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_SLAVE_LLCC_CAM_IFE_1 }, +}; + +static struct qcom_icc_node llcc_mc_cam_ife_1 = { + .name = "llcc_mc_cam_ife_1", + .id = SM8550_MASTER_LLCC_CAM_IFE_1, + .channels = 4, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_EBI1_CAM_IFE_1 }, +}; + +static struct qcom_icc_node qnm_camnoc_hf_cam_ife_1 = { + .name = "qnm_camnoc_hf_cam_ife_1", + .id = SM8550_MASTER_CAMNOC_HF_CAM_IFE_1, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_1 }, +}; + +static struct qcom_icc_node qnm_camnoc_icp_cam_ife_1 = { + .name = "qnm_camnoc_icp_cam_ife_1", + .id = SM8550_MASTER_CAMNOC_ICP_CAM_IFE_1, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1 }, +}; + +static struct qcom_icc_node qnm_camnoc_sf_cam_ife_1 = { + .name = "qnm_camnoc_sf_cam_ife_1", + .id = SM8550_MASTER_CAMNOC_SF_CAM_IFE_1, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1 }, +}; + +static struct qcom_icc_node qnm_mnoc_hf_cam_ife_2 = { + .name = "qnm_mnoc_hf_cam_ife_2", + .id = SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_2, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_LLCC_CAM_IFE_2 }, +}; + +static struct qcom_icc_node qnm_mnoc_sf_cam_ife_2 = { + .name = "qnm_mnoc_sf_cam_ife_2", + .id = SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_2, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_LLCC_CAM_IFE_2 }, +}; + +static struct qcom_icc_node qnm_pcie_cam_ife_2 = { + .name = "qnm_pcie_cam_ife_2", + .id = SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_2, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_SLAVE_LLCC_CAM_IFE_2 }, +}; + +static struct qcom_icc_node llcc_mc_cam_ife_2 = { + .name = "llcc_mc_cam_ife_2", + .id = SM8550_MASTER_LLCC_CAM_IFE_2, + .channels = 4, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_SLAVE_EBI1_CAM_IFE_2 }, +}; + +static struct qcom_icc_node qnm_camnoc_hf_cam_ife_2 = { + .name = "qnm_camnoc_hf_cam_ife_2", + .id = SM8550_MASTER_CAMNOC_HF_CAM_IFE_2, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_2 }, +}; + +static struct qcom_icc_node qnm_camnoc_icp_cam_ife_2 = { + .name = "qnm_camnoc_icp_cam_ife_2", + .id = SM8550_MASTER_CAMNOC_ICP_CAM_IFE_2, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2 }, +}; + +static struct qcom_icc_node qnm_camnoc_sf_cam_ife_2 = { + .name = "qnm_camnoc_sf_cam_ife_2", + .id = SM8550_MASTER_CAMNOC_SF_CAM_IFE_2, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2 }, +}; + +static struct qcom_icc_node qns_a1noc_snoc = { + .name = "qns_a1noc_snoc", + .id = SM8550_SLAVE_A1NOC_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_MASTER_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qns_a2noc_snoc = { + .name = "qns_a2noc_snoc", + .id = SM8550_SLAVE_A2NOC_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_MASTER_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qup0_core_slave = { + .name = "qup0_core_slave", + .id = SM8550_SLAVE_QUP_CORE_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qup1_core_slave = { + .name = "qup1_core_slave", + .id = SM8550_SLAVE_QUP_CORE_1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qup2_core_slave = { + .name = "qup2_core_slave", + .id = SM8550_SLAVE_QUP_CORE_2, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ahb2phy0 = { + .name = "qhs_ahb2phy0", + .id = SM8550_SLAVE_AHB2PHY_SOUTH, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ahb2phy1 = { + .name = "qhs_ahb2phy1", + .id = SM8550_SLAVE_AHB2PHY_NORTH, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_apss = { + .name = "qhs_apss", + .id = SM8550_SLAVE_APPSS, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_camera_cfg = { + .name = "qhs_camera_cfg", + .id = SM8550_SLAVE_CAMERA_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_clk_ctl = { + .name = "qhs_clk_ctl", + .id = SM8550_SLAVE_CLK_CTL, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_cx = { + .name = "qhs_cpr_cx", + .id = SM8550_SLAVE_RBCPR_CX_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_mmcx = { + .name = "qhs_cpr_mmcx", + .id = SM8550_SLAVE_RBCPR_MMCX_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_mxa = { + .name = "qhs_cpr_mxa", + .id = SM8550_SLAVE_RBCPR_MXA_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_mxc = { + .name = "qhs_cpr_mxc", + .id = SM8550_SLAVE_RBCPR_MXC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_nspcx = { + .name = "qhs_cpr_nspcx", + .id = SM8550_SLAVE_CPR_NSPCX, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_crypto0_cfg = { + .name = "qhs_crypto0_cfg", + .id = SM8550_SLAVE_CRYPTO_0_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cx_rdpm = { + .name = "qhs_cx_rdpm", + .id = SM8550_SLAVE_CX_RDPM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_display_cfg = { + .name = "qhs_display_cfg", + .id = SM8550_SLAVE_DISPLAY_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_gpuss_cfg = { + .name = "qhs_gpuss_cfg", + .id = SM8550_SLAVE_GFX3D_CFG, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_i2c = { + .name = "qhs_i2c", + .id = SM8550_SLAVE_I2C, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_imem_cfg = { + .name = "qhs_imem_cfg", + .id = SM8550_SLAVE_IMEM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ipa = { + .name = "qhs_ipa", + .id = SM8550_SLAVE_IPA_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ipc_router = { + .name = "qhs_ipc_router", + .id = SM8550_SLAVE_IPC_ROUTER_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_mss_cfg = { + .name = "qhs_mss_cfg", + .id = SM8550_SLAVE_CNOC_MSS, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_mx_rdpm = { + .name = "qhs_mx_rdpm", + .id = SM8550_SLAVE_MX_RDPM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pcie0_cfg = { + .name = "qhs_pcie0_cfg", + .id = SM8550_SLAVE_PCIE_0_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pcie1_cfg = { + .name = "qhs_pcie1_cfg", + .id = SM8550_SLAVE_PCIE_1_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pdm = { + .name = "qhs_pdm", + .id = SM8550_SLAVE_PDM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pimem_cfg = { + .name = "qhs_pimem_cfg", + .id = SM8550_SLAVE_PIMEM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_prng = { + .name = "qhs_prng", + .id = SM8550_SLAVE_PRNG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qdss_cfg = { + .name = "qhs_qdss_cfg", + .id = SM8550_SLAVE_QDSS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qspi = { + .name = "qhs_qspi", + .id = SM8550_SLAVE_QSPI_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qup1 = { + .name = "qhs_qup1", + .id = SM8550_SLAVE_QUP_1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qup2 = { + .name = "qhs_qup2", + .id = SM8550_SLAVE_QUP_2, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_sdc2 = { + .name = "qhs_sdc2", + .id = SM8550_SLAVE_SDCC_2, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_sdc4 = { + .name = "qhs_sdc4", + .id = SM8550_SLAVE_SDCC_4, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_spss_cfg = { + .name = "qhs_spss_cfg", + .id = SM8550_SLAVE_SPSS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tcsr = { + .name = "qhs_tcsr", + .id = SM8550_SLAVE_TCSR, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tlmm = { + .name = "qhs_tlmm", + .id = SM8550_SLAVE_TLMM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ufs_mem_cfg = { + .name = "qhs_ufs_mem_cfg", + .id = SM8550_SLAVE_UFS_MEM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_usb3_0 = { + .name = "qhs_usb3_0", + .id = SM8550_SLAVE_USB3_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_venus_cfg = { + .name = "qhs_venus_cfg", + .id = SM8550_SLAVE_VENUS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_vsense_ctrl_cfg = { + .name = "qhs_vsense_ctrl_cfg", + .id = SM8550_SLAVE_VSENSE_CTRL_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qss_lpass_qtb_cfg = { + .name = "qss_lpass_qtb_cfg", + .id = SM8550_SLAVE_LPASS_QTB_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qss_mnoc_cfg = { + .name = "qss_mnoc_cfg", + .id = SM8550_SLAVE_CNOC_MNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_MASTER_CNOC_MNOC_CFG }, +}; + +static struct qcom_icc_node qss_nsp_qtb_cfg = { + .name = "qss_nsp_qtb_cfg", + .id = SM8550_SLAVE_NSP_QTB_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qss_pcie_anoc_cfg = { + .name = "qss_pcie_anoc_cfg", + .id = SM8550_SLAVE_PCIE_ANOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_MASTER_PCIE_ANOC_CFG }, +}; + +static struct qcom_icc_node xs_qdss_stm = { + .name = "xs_qdss_stm", + .id = SM8550_SLAVE_QDSS_STM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node xs_sys_tcu_cfg = { + .name = "xs_sys_tcu_cfg", + .id = SM8550_SLAVE_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_aoss = { + .name = "qhs_aoss", + .id = SM8550_SLAVE_AOSS, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tme_cfg = { + .name = "qhs_tme_cfg", + .id = SM8550_SLAVE_TME_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qss_cfg = { + .name = "qss_cfg", + .id = SM8550_SLAVE_CNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SM8550_MASTER_CNOC_CFG }, +}; + +static struct qcom_icc_node qss_ddrss_cfg = { + .name = "qss_ddrss_cfg", + .id = SM8550_SLAVE_DDRSS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qxs_boot_imem = { + .name = "qxs_boot_imem", + .id = SM8550_SLAVE_BOOT_IMEM, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qxs_imem = { + .name = "qxs_imem", + .id = SM8550_SLAVE_IMEM, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node xs_pcie_0 = { + .name = "xs_pcie_0", + .id = SM8550_SLAVE_PCIE_0, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node xs_pcie_1 = { + .name = "xs_pcie_1", + .id = SM8550_SLAVE_PCIE_1, + .channels = 1, + .buswidth = 16, + .num_links = 0, +}; + +static struct qcom_icc_node qns_gem_noc_cnoc = { + .name = "qns_gem_noc_cnoc", + .id = SM8550_SLAVE_GEM_NOC_CNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_MASTER_GEM_NOC_CNOC }, +}; + +static struct qcom_icc_node qns_llcc = { + .name = "qns_llcc", + .id = SM8550_SLAVE_LLCC, + .channels = 4, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_MASTER_LLCC }, +}; + +static struct qcom_icc_node qns_pcie = { + .name = "qns_pcie", + .id = SM8550_SLAVE_MEM_NOC_PCIE_SNOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_MASTER_GEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node qns_lpass_ag_noc_gemnoc = { + .name = "qns_lpass_ag_noc_gemnoc", + .id = SM8550_SLAVE_LPASS_GEM_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_MASTER_LPASS_GEM_NOC }, +}; + +static struct qcom_icc_node qns_lpass_aggnoc = { + .name = "qns_lpass_aggnoc", + .id = SM8550_SLAVE_LPIAON_NOC_LPASS_AG_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_MASTER_LPIAON_NOC }, +}; + +static struct qcom_icc_node qns_lpi_aon_noc = { + .name = "qns_lpi_aon_noc", + .id = SM8550_SLAVE_LPICX_NOC_LPIAON_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_MASTER_LPASS_LPINOC }, +}; + +static struct qcom_icc_node ebi = { + .name = "ebi", + .id = SM8550_SLAVE_EBI1, + .channels = 4, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_mem_noc_hf = { + .name = "qns_mem_noc_hf", + .id = SM8550_SLAVE_MNOC_HF_MEM_NOC, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_MASTER_MNOC_HF_MEM_NOC }, +}; + +static struct qcom_icc_node qns_mem_noc_sf = { + .name = "qns_mem_noc_sf", + .id = SM8550_SLAVE_MNOC_SF_MEM_NOC, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_MASTER_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node srvc_mnoc = { + .name = "srvc_mnoc", + .id = SM8550_SLAVE_SERVICE_MNOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_nsp_gemnoc = { + .name = "qns_nsp_gemnoc", + .id = SM8550_SLAVE_CDSP_MEM_NOC, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_MASTER_COMPUTE_NOC }, +}; + +static struct qcom_icc_node qns_pcie_mem_noc = { + .name = "qns_pcie_mem_noc", + .id = SM8550_SLAVE_ANOC_PCIE_GEM_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_MASTER_ANOC_PCIE_GEM_NOC }, +}; + +static struct qcom_icc_node srvc_pcie_aggre_noc = { + .name = "srvc_pcie_aggre_noc", + .id = SM8550_SLAVE_SERVICE_PCIE_ANOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_gemnoc_gc = { + .name = "qns_gemnoc_gc", + .id = SM8550_SLAVE_SNOC_GEM_NOC_GC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SM8550_MASTER_SNOC_GC_MEM_NOC }, +}; + +static struct qcom_icc_node qns_gemnoc_sf = { + .name = "qns_gemnoc_sf", + .id = SM8550_SLAVE_SNOC_GEM_NOC_SF, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_MASTER_SNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qns_llcc_disp = { + .name = "qns_llcc_disp", + .id = SM8550_SLAVE_LLCC_DISP, + .channels = 4, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_MASTER_LLCC_DISP }, +}; + +static struct qcom_icc_node ebi_disp = { + .name = "ebi_disp", + .id = SM8550_SLAVE_EBI1_DISP, + .channels = 4, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_mem_noc_hf_disp = { + .name = "qns_mem_noc_hf_disp", + .id = SM8550_SLAVE_MNOC_HF_MEM_NOC_DISP, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_MASTER_MNOC_HF_MEM_NOC_DISP }, +}; + +static struct qcom_icc_node qns_llcc_cam_ife_0 = { + .name = "qns_llcc_cam_ife_0", + .id = SM8550_SLAVE_LLCC_CAM_IFE_0, + .channels = 4, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_MASTER_LLCC_CAM_IFE_0 }, +}; + +static struct qcom_icc_node ebi_cam_ife_0 = { + .name = "ebi_cam_ife_0", + .id = SM8550_SLAVE_EBI1_CAM_IFE_0, + .channels = 4, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_mem_noc_hf_cam_ife_0 = { + .name = "qns_mem_noc_hf_cam_ife_0", + .id = SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_0, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_0 }, +}; + +static struct qcom_icc_node qns_mem_noc_sf_cam_ife_0 = { + .name = "qns_mem_noc_sf_cam_ife_0", + .id = SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_0 }, +}; + +static struct qcom_icc_node qns_llcc_cam_ife_1 = { + .name = "qns_llcc_cam_ife_1", + .id = SM8550_SLAVE_LLCC_CAM_IFE_1, + .channels = 4, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_MASTER_LLCC_CAM_IFE_1 }, +}; + +static struct qcom_icc_node ebi_cam_ife_1 = { + .name = "ebi_cam_ife_1", + .id = SM8550_SLAVE_EBI1_CAM_IFE_1, + .channels = 4, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_mem_noc_hf_cam_ife_1 = { + .name = "qns_mem_noc_hf_cam_ife_1", + .id = SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_1, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_1 }, +}; + +static struct qcom_icc_node qns_mem_noc_sf_cam_ife_1 = { + .name = "qns_mem_noc_sf_cam_ife_1", + .id = SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_1 }, +}; + +static struct qcom_icc_node qns_llcc_cam_ife_2 = { + .name = "qns_llcc_cam_ife_2", + .id = SM8550_SLAVE_LLCC_CAM_IFE_2, + .channels = 4, + .buswidth = 16, + .num_links = 1, + .links = { SM8550_MASTER_LLCC_CAM_IFE_2 }, +}; + +static struct qcom_icc_node ebi_cam_ife_2 = { + .name = "ebi_cam_ife_2", + .id = SM8550_SLAVE_EBI1_CAM_IFE_2, + .channels = 4, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_mem_noc_hf_cam_ife_2 = { + .name = "qns_mem_noc_hf_cam_ife_2", + .id = SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_2, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_2 }, +}; + +static struct qcom_icc_node qns_mem_noc_sf_cam_ife_2 = { + .name = "qns_mem_noc_sf_cam_ife_2", + .id = SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_2 }, +}; + +static struct qcom_icc_bcm bcm_acv = { + .name = "ACV", + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_ce0 = { + .name = "CE0", + .num_nodes = 1, + .nodes = { &qxm_crypto }, +}; + +static struct qcom_icc_bcm bcm_cn0 = { + .name = "CN0", + .keepalive = true, + .num_nodes = 54, + .nodes = { &qsm_cfg, &qhs_ahb2phy0, + &qhs_ahb2phy1, &qhs_apss, + &qhs_camera_cfg, &qhs_clk_ctl, + &qhs_cpr_cx, &qhs_cpr_mmcx, + &qhs_cpr_mxa, &qhs_cpr_mxc, + &qhs_cpr_nspcx, &qhs_crypto0_cfg, + &qhs_cx_rdpm, &qhs_gpuss_cfg, + &qhs_i2c, &qhs_imem_cfg, + &qhs_ipa, &qhs_ipc_router, + &qhs_mss_cfg, &qhs_mx_rdpm, + &qhs_pcie0_cfg, &qhs_pcie1_cfg, + &qhs_pdm, &qhs_pimem_cfg, + &qhs_prng, &qhs_qdss_cfg, + &qhs_qspi, &qhs_qup1, + &qhs_qup2, &qhs_sdc2, + &qhs_sdc4, &qhs_spss_cfg, + &qhs_tcsr, &qhs_tlmm, + &qhs_ufs_mem_cfg, &qhs_usb3_0, + &qhs_venus_cfg, &qhs_vsense_ctrl_cfg, + &qss_lpass_qtb_cfg, &qss_mnoc_cfg, + &qss_nsp_qtb_cfg, &qss_pcie_anoc_cfg, + &xs_qdss_stm, &xs_sys_tcu_cfg, + &qnm_gemnoc_cnoc, &qnm_gemnoc_pcie, + &qhs_aoss, &qhs_tme_cfg, + &qss_cfg, &qss_ddrss_cfg, + &qxs_boot_imem, &qxs_imem, + &xs_pcie_0, &xs_pcie_1 }, +}; + +static struct qcom_icc_bcm bcm_cn1 = { + .name = "CN1", + .num_nodes = 1, + .nodes = { &qhs_display_cfg }, +}; + +static struct qcom_icc_bcm bcm_co0 = { + .name = "CO0", + .num_nodes = 2, + .nodes = { &qxm_nsp, &qns_nsp_gemnoc }, +}; + +static struct qcom_icc_bcm bcm_lp0 = { + .name = "LP0", + .num_nodes = 2, + .nodes = { &qnm_lpass_lpinoc, &qns_lpass_aggnoc }, +}; + +static struct qcom_icc_bcm bcm_mc0 = { + .name = "MC0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_mm0 = { + .name = "MM0", + .num_nodes = 1, + .nodes = { &qns_mem_noc_hf }, +}; + +static struct qcom_icc_bcm bcm_mm1 = { + .name = "MM1", + .num_nodes = 8, + .nodes = { &qnm_camnoc_hf, &qnm_camnoc_icp, + &qnm_camnoc_sf, &qnm_vapss_hcp, + &qnm_video_cv_cpu, &qnm_video_cvp, + &qnm_video_v_cpu, &qns_mem_noc_sf }, +}; + +static struct qcom_icc_bcm bcm_qup0 = { + .name = "QUP0", + .keepalive = true, + .vote_scale = 1, + .num_nodes = 1, + .nodes = { &qup0_core_slave }, +}; + +static struct qcom_icc_bcm bcm_qup1 = { + .name = "QUP1", + .keepalive = true, + .vote_scale = 1, + .num_nodes = 1, + .nodes = { &qup1_core_slave }, +}; + +static struct qcom_icc_bcm bcm_qup2 = { + .name = "QUP2", + .keepalive = true, + .vote_scale = 1, + .num_nodes = 1, + .nodes = { &qup2_core_slave }, +}; + +static struct qcom_icc_bcm bcm_sh0 = { + .name = "SH0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_llcc }, +}; + +static struct qcom_icc_bcm bcm_sh1 = { + .name = "SH1", + .num_nodes = 13, + .nodes = { &alm_gpu_tcu, &alm_sys_tcu, + &chm_apps, &qnm_gpu, + &qnm_mdsp, &qnm_mnoc_hf, + &qnm_mnoc_sf, &qnm_nsp_gemnoc, + &qnm_pcie, &qnm_snoc_gc, + &qnm_snoc_sf, &qns_gem_noc_cnoc, + &qns_pcie }, +}; + +static struct qcom_icc_bcm bcm_sn0 = { + .name = "SN0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_bcm bcm_sn1 = { + .name = "SN1", + .num_nodes = 3, + .nodes = { &qhm_gic, &xm_gic, + &qns_gemnoc_gc }, +}; + +static struct qcom_icc_bcm bcm_sn2 = { + .name = "SN2", + .num_nodes = 1, + .nodes = { &qnm_aggre1_noc }, +}; + +static struct qcom_icc_bcm bcm_sn3 = { + .name = "SN3", + .num_nodes = 1, + .nodes = { &qnm_aggre2_noc }, +}; + +static struct qcom_icc_bcm bcm_sn7 = { + .name = "SN7", + .num_nodes = 1, + .nodes = { &qns_pcie_mem_noc }, +}; + +static struct qcom_icc_bcm bcm_acv_disp = { + .name = "ACV", + .num_nodes = 1, + .nodes = { &ebi_disp }, +}; + +static struct qcom_icc_bcm bcm_mc0_disp = { + .name = "MC0", + .num_nodes = 1, + .nodes = { &ebi_disp }, +}; + +static struct qcom_icc_bcm bcm_mm0_disp = { + .name = "MM0", + .num_nodes = 1, + .nodes = { &qns_mem_noc_hf_disp }, +}; + +static struct qcom_icc_bcm bcm_sh0_disp = { + .name = "SH0", + .num_nodes = 1, + .nodes = { &qns_llcc_disp }, +}; + +static struct qcom_icc_bcm bcm_sh1_disp = { + .name = "SH1", + .num_nodes = 2, + .nodes = { &qnm_mnoc_hf_disp, &qnm_pcie_disp }, +}; + +static struct qcom_icc_bcm bcm_acv_cam_ife_0 = { + .name = "ACV", + .num_nodes = 1, + .nodes = { &ebi_cam_ife_0 }, +}; + +static struct qcom_icc_bcm bcm_mc0_cam_ife_0 = { + .name = "MC0", + .num_nodes = 1, + .nodes = { &ebi_cam_ife_0 }, +}; + +static struct qcom_icc_bcm bcm_mm0_cam_ife_0 = { + .name = "MM0", + .num_nodes = 1, + .nodes = { &qns_mem_noc_hf_cam_ife_0 }, +}; + +static struct qcom_icc_bcm bcm_mm1_cam_ife_0 = { + .name = "MM1", + .num_nodes = 4, + .nodes = { &qnm_camnoc_hf_cam_ife_0, &qnm_camnoc_icp_cam_ife_0, + &qnm_camnoc_sf_cam_ife_0, &qns_mem_noc_sf_cam_ife_0 }, +}; + +static struct qcom_icc_bcm bcm_sh0_cam_ife_0 = { + .name = "SH0", + .num_nodes = 1, + .nodes = { &qns_llcc_cam_ife_0 }, +}; + +static struct qcom_icc_bcm bcm_sh1_cam_ife_0 = { + .name = "SH1", + .num_nodes = 3, + .nodes = { &qnm_mnoc_hf_cam_ife_0, &qnm_mnoc_sf_cam_ife_0, + &qnm_pcie_cam_ife_0 }, +}; + +static struct qcom_icc_bcm bcm_acv_cam_ife_1 = { + .name = "ACV", + .num_nodes = 1, + .nodes = { &ebi_cam_ife_1 }, +}; + +static struct qcom_icc_bcm bcm_mc0_cam_ife_1 = { + .name = "MC0", + .num_nodes = 1, + .nodes = { &ebi_cam_ife_1 }, +}; + +static struct qcom_icc_bcm bcm_mm0_cam_ife_1 = { + .name = "MM0", + .num_nodes = 1, + .nodes = { &qns_mem_noc_hf_cam_ife_1 }, +}; + +static struct qcom_icc_bcm bcm_mm1_cam_ife_1 = { + .name = "MM1", + .num_nodes = 4, + .nodes = { &qnm_camnoc_hf_cam_ife_1, &qnm_camnoc_icp_cam_ife_1, + &qnm_camnoc_sf_cam_ife_1, &qns_mem_noc_sf_cam_ife_1 }, +}; + +static struct qcom_icc_bcm bcm_sh0_cam_ife_1 = { + .name = "SH0", + .num_nodes = 1, + .nodes = { &qns_llcc_cam_ife_1 }, +}; + +static struct qcom_icc_bcm bcm_sh1_cam_ife_1 = { + .name = "SH1", + .num_nodes = 3, + .nodes = { &qnm_mnoc_hf_cam_ife_1, &qnm_mnoc_sf_cam_ife_1, + &qnm_pcie_cam_ife_1 }, +}; + +static struct qcom_icc_bcm bcm_acv_cam_ife_2 = { + .name = "ACV", + .num_nodes = 1, + .nodes = { &ebi_cam_ife_2 }, +}; + +static struct qcom_icc_bcm bcm_mc0_cam_ife_2 = { + .name = "MC0", + .num_nodes = 1, + .nodes = { &ebi_cam_ife_2 }, +}; + +static struct qcom_icc_bcm bcm_mm0_cam_ife_2 = { + .name = "MM0", + .num_nodes = 1, + .nodes = { &qns_mem_noc_hf_cam_ife_2 }, +}; + +static struct qcom_icc_bcm bcm_mm1_cam_ife_2 = { + .name = "MM1", + .num_nodes = 4, + .nodes = { &qnm_camnoc_hf_cam_ife_2, &qnm_camnoc_icp_cam_ife_2, + &qnm_camnoc_sf_cam_ife_2, &qns_mem_noc_sf_cam_ife_2 }, +}; + +static struct qcom_icc_bcm bcm_sh0_cam_ife_2 = { + .name = "SH0", + .num_nodes = 1, + .nodes = { &qns_llcc_cam_ife_2 }, +}; + +static struct qcom_icc_bcm bcm_sh1_cam_ife_2 = { + .name = "SH1", + .num_nodes = 3, + .nodes = { &qnm_mnoc_hf_cam_ife_2, &qnm_mnoc_sf_cam_ife_2, + &qnm_pcie_cam_ife_2 }, +}; + +static struct qcom_icc_bcm * const aggre1_noc_bcms[] = { +}; + +static struct qcom_icc_node * const aggre1_noc_nodes[] = { + [MASTER_QSPI_0] = &qhm_qspi, + [MASTER_QUP_1] = &qhm_qup1, + [MASTER_SDCC_4] = &xm_sdc4, + [MASTER_UFS_MEM] = &xm_ufs_mem, + [MASTER_USB3_0] = &xm_usb3_0, + [SLAVE_A1NOC_SNOC] = &qns_a1noc_snoc, +}; + +static const struct qcom_icc_desc sm8550_aggre1_noc = { + .nodes = aggre1_noc_nodes, + .num_nodes = ARRAY_SIZE(aggre1_noc_nodes), + .bcms = aggre1_noc_bcms, + .num_bcms = ARRAY_SIZE(aggre1_noc_bcms), +}; + +static struct qcom_icc_bcm * const aggre2_noc_bcms[] = { + &bcm_ce0, +}; + +static struct qcom_icc_node * const aggre2_noc_nodes[] = { + [MASTER_QDSS_BAM] = &qhm_qdss_bam, + [MASTER_QUP_2] = &qhm_qup2, + [MASTER_CRYPTO] = &qxm_crypto, + [MASTER_IPA] = &qxm_ipa, + [MASTER_SP] = &qxm_sp, + [MASTER_QDSS_ETR] = &xm_qdss_etr_0, + [MASTER_QDSS_ETR_1] = &xm_qdss_etr_1, + [MASTER_SDCC_2] = &xm_sdc2, + [SLAVE_A2NOC_SNOC] = &qns_a2noc_snoc, +}; + +static const struct qcom_icc_desc sm8550_aggre2_noc = { + .nodes = aggre2_noc_nodes, + .num_nodes = ARRAY_SIZE(aggre2_noc_nodes), + .bcms = aggre2_noc_bcms, + .num_bcms = ARRAY_SIZE(aggre2_noc_bcms), +}; + +static struct qcom_icc_bcm * const clk_virt_bcms[] = { + &bcm_qup0, + &bcm_qup1, + &bcm_qup2, +}; + +static struct qcom_icc_node * const clk_virt_nodes[] = { + [MASTER_QUP_CORE_0] = &qup0_core_master, + [MASTER_QUP_CORE_1] = &qup1_core_master, + [MASTER_QUP_CORE_2] = &qup2_core_master, + [SLAVE_QUP_CORE_0] = &qup0_core_slave, + [SLAVE_QUP_CORE_1] = &qup1_core_slave, + [SLAVE_QUP_CORE_2] = &qup2_core_slave, +}; + +static const struct qcom_icc_desc sm8550_clk_virt = { + .nodes = clk_virt_nodes, + .num_nodes = ARRAY_SIZE(clk_virt_nodes), + .bcms = clk_virt_bcms, + .num_bcms = ARRAY_SIZE(clk_virt_bcms), +}; + +static struct qcom_icc_bcm * const config_noc_bcms[] = { + &bcm_cn0, + &bcm_cn1, +}; + +static struct qcom_icc_node * const config_noc_nodes[] = { + [MASTER_CNOC_CFG] = &qsm_cfg, + [SLAVE_AHB2PHY_SOUTH] = &qhs_ahb2phy0, + [SLAVE_AHB2PHY_NORTH] = &qhs_ahb2phy1, + [SLAVE_APPSS] = &qhs_apss, + [SLAVE_CAMERA_CFG] = &qhs_camera_cfg, + [SLAVE_CLK_CTL] = &qhs_clk_ctl, + [SLAVE_RBCPR_CX_CFG] = &qhs_cpr_cx, + [SLAVE_RBCPR_MMCX_CFG] = &qhs_cpr_mmcx, + [SLAVE_RBCPR_MXA_CFG] = &qhs_cpr_mxa, + [SLAVE_RBCPR_MXC_CFG] = &qhs_cpr_mxc, + [SLAVE_CPR_NSPCX] = &qhs_cpr_nspcx, + [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg, + [SLAVE_CX_RDPM] = &qhs_cx_rdpm, + [SLAVE_DISPLAY_CFG] = &qhs_display_cfg, + [SLAVE_GFX3D_CFG] = &qhs_gpuss_cfg, + [SLAVE_I2C] = &qhs_i2c, + [SLAVE_IMEM_CFG] = &qhs_imem_cfg, + [SLAVE_IPA_CFG] = &qhs_ipa, + [SLAVE_IPC_ROUTER_CFG] = &qhs_ipc_router, + [SLAVE_CNOC_MSS] = &qhs_mss_cfg, + [SLAVE_MX_RDPM] = &qhs_mx_rdpm, + [SLAVE_PCIE_0_CFG] = &qhs_pcie0_cfg, + [SLAVE_PCIE_1_CFG] = &qhs_pcie1_cfg, + [SLAVE_PDM] = &qhs_pdm, + [SLAVE_PIMEM_CFG] = &qhs_pimem_cfg, + [SLAVE_PRNG] = &qhs_prng, + [SLAVE_QDSS_CFG] = &qhs_qdss_cfg, + [SLAVE_QSPI_0] = &qhs_qspi, + [SLAVE_QUP_1] = &qhs_qup1, + [SLAVE_QUP_2] = &qhs_qup2, + [SLAVE_SDCC_2] = &qhs_sdc2, + [SLAVE_SDCC_4] = &qhs_sdc4, + [SLAVE_SPSS_CFG] = &qhs_spss_cfg, + [SLAVE_TCSR] = &qhs_tcsr, + [SLAVE_TLMM] = &qhs_tlmm, + [SLAVE_UFS_MEM_CFG] = &qhs_ufs_mem_cfg, + [SLAVE_USB3_0] = &qhs_usb3_0, + [SLAVE_VENUS_CFG] = &qhs_venus_cfg, + [SLAVE_VSENSE_CTRL_CFG] = &qhs_vsense_ctrl_cfg, + [SLAVE_LPASS_QTB_CFG] = &qss_lpass_qtb_cfg, + [SLAVE_CNOC_MNOC_CFG] = &qss_mnoc_cfg, + [SLAVE_NSP_QTB_CFG] = &qss_nsp_qtb_cfg, + [SLAVE_PCIE_ANOC_CFG] = &qss_pcie_anoc_cfg, + [SLAVE_QDSS_STM] = &xs_qdss_stm, + [SLAVE_TCU] = &xs_sys_tcu_cfg, +}; + +static const struct qcom_icc_desc sm8550_config_noc = { + .nodes = config_noc_nodes, + .num_nodes = ARRAY_SIZE(config_noc_nodes), + .bcms = config_noc_bcms, + .num_bcms = ARRAY_SIZE(config_noc_bcms), +}; + +static struct qcom_icc_bcm * const cnoc_main_bcms[] = { + &bcm_cn0, +}; + +static struct qcom_icc_node * const cnoc_main_nodes[] = { + [MASTER_GEM_NOC_CNOC] = &qnm_gemnoc_cnoc, + [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie, + [SLAVE_AOSS] = &qhs_aoss, + [SLAVE_TME_CFG] = &qhs_tme_cfg, + [SLAVE_CNOC_CFG] = &qss_cfg, + [SLAVE_DDRSS_CFG] = &qss_ddrss_cfg, + [SLAVE_BOOT_IMEM] = &qxs_boot_imem, + [SLAVE_IMEM] = &qxs_imem, + [SLAVE_PCIE_0] = &xs_pcie_0, + [SLAVE_PCIE_1] = &xs_pcie_1, +}; + +static const struct qcom_icc_desc sm8550_cnoc_main = { + .nodes = cnoc_main_nodes, + .num_nodes = ARRAY_SIZE(cnoc_main_nodes), + .bcms = cnoc_main_bcms, + .num_bcms = ARRAY_SIZE(cnoc_main_bcms), +}; + +static struct qcom_icc_bcm * const gem_noc_bcms[] = { + &bcm_sh0, + &bcm_sh1, + &bcm_sh0_disp, + &bcm_sh1_disp, + &bcm_sh0_cam_ife_0, + &bcm_sh1_cam_ife_0, + &bcm_sh0_cam_ife_1, + &bcm_sh1_cam_ife_1, + &bcm_sh0_cam_ife_2, + &bcm_sh1_cam_ife_2, +}; + +static struct qcom_icc_node * const gem_noc_nodes[] = { + [MASTER_GPU_TCU] = &alm_gpu_tcu, + [MASTER_SYS_TCU] = &alm_sys_tcu, + [MASTER_APPSS_PROC] = &chm_apps, + [MASTER_GFX3D] = &qnm_gpu, + [MASTER_LPASS_GEM_NOC] = &qnm_lpass_gemnoc, + [MASTER_MSS_PROC] = &qnm_mdsp, + [MASTER_MNOC_HF_MEM_NOC] = &qnm_mnoc_hf, + [MASTER_MNOC_SF_MEM_NOC] = &qnm_mnoc_sf, + [MASTER_COMPUTE_NOC] = &qnm_nsp_gemnoc, + [MASTER_ANOC_PCIE_GEM_NOC] = &qnm_pcie, + [MASTER_SNOC_GC_MEM_NOC] = &qnm_snoc_gc, + [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf, + [SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc, + [SLAVE_LLCC] = &qns_llcc, + [SLAVE_MEM_NOC_PCIE_SNOC] = &qns_pcie, + [MASTER_MNOC_HF_MEM_NOC_DISP] = &qnm_mnoc_hf_disp, + [MASTER_ANOC_PCIE_GEM_NOC_DISP] = &qnm_pcie_disp, + [SLAVE_LLCC_DISP] = &qns_llcc_disp, + [MASTER_MNOC_HF_MEM_NOC_CAM_IFE_0] = &qnm_mnoc_hf_cam_ife_0, + [MASTER_MNOC_SF_MEM_NOC_CAM_IFE_0] = &qnm_mnoc_sf_cam_ife_0, + [MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_0] = &qnm_pcie_cam_ife_0, + [SLAVE_LLCC_CAM_IFE_0] = &qns_llcc_cam_ife_0, + [MASTER_MNOC_HF_MEM_NOC_CAM_IFE_1] = &qnm_mnoc_hf_cam_ife_1, + [MASTER_MNOC_SF_MEM_NOC_CAM_IFE_1] = &qnm_mnoc_sf_cam_ife_1, + [MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_1] = &qnm_pcie_cam_ife_1, + [SLAVE_LLCC_CAM_IFE_1] = &qns_llcc_cam_ife_1, + [MASTER_MNOC_HF_MEM_NOC_CAM_IFE_2] = &qnm_mnoc_hf_cam_ife_2, + [MASTER_MNOC_SF_MEM_NOC_CAM_IFE_2] = &qnm_mnoc_sf_cam_ife_2, + [MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_2] = &qnm_pcie_cam_ife_2, + [SLAVE_LLCC_CAM_IFE_2] = &qns_llcc_cam_ife_2, +}; + +static const struct qcom_icc_desc sm8550_gem_noc = { + .nodes = gem_noc_nodes, + .num_nodes = ARRAY_SIZE(gem_noc_nodes), + .bcms = gem_noc_bcms, + .num_bcms = ARRAY_SIZE(gem_noc_bcms), +}; + +static struct qcom_icc_bcm * const lpass_ag_noc_bcms[] = { +}; + +static struct qcom_icc_node * const lpass_ag_noc_nodes[] = { + [MASTER_LPIAON_NOC] = &qnm_lpiaon_noc, + [SLAVE_LPASS_GEM_NOC] = &qns_lpass_ag_noc_gemnoc, +}; + +static const struct qcom_icc_desc sm8550_lpass_ag_noc = { + .nodes = lpass_ag_noc_nodes, + .num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes), + .bcms = lpass_ag_noc_bcms, + .num_bcms = ARRAY_SIZE(lpass_ag_noc_bcms), +}; + +static struct qcom_icc_bcm * const lpass_lpiaon_noc_bcms[] = { + &bcm_lp0, +}; + +static struct qcom_icc_node * const lpass_lpiaon_noc_nodes[] = { + [MASTER_LPASS_LPINOC] = &qnm_lpass_lpinoc, + [SLAVE_LPIAON_NOC_LPASS_AG_NOC] = &qns_lpass_aggnoc, +}; + +static const struct qcom_icc_desc sm8550_lpass_lpiaon_noc = { + .nodes = lpass_lpiaon_noc_nodes, + .num_nodes = ARRAY_SIZE(lpass_lpiaon_noc_nodes), + .bcms = lpass_lpiaon_noc_bcms, + .num_bcms = ARRAY_SIZE(lpass_lpiaon_noc_bcms), +}; + +static struct qcom_icc_bcm * const lpass_lpicx_noc_bcms[] = { +}; + +static struct qcom_icc_node * const lpass_lpicx_noc_nodes[] = { + [MASTER_LPASS_PROC] = &qxm_lpinoc_dsp_axim, + [SLAVE_LPICX_NOC_LPIAON_NOC] = &qns_lpi_aon_noc, +}; + +static const struct qcom_icc_desc sm8550_lpass_lpicx_noc = { + .nodes = lpass_lpicx_noc_nodes, + .num_nodes = ARRAY_SIZE(lpass_lpicx_noc_nodes), + .bcms = lpass_lpicx_noc_bcms, + .num_bcms = ARRAY_SIZE(lpass_lpicx_noc_bcms), +}; + +static struct qcom_icc_bcm * const mc_virt_bcms[] = { + &bcm_acv, + &bcm_mc0, + &bcm_acv_disp, + &bcm_mc0_disp, + &bcm_acv_cam_ife_0, + &bcm_mc0_cam_ife_0, + &bcm_acv_cam_ife_1, + &bcm_mc0_cam_ife_1, + &bcm_acv_cam_ife_2, + &bcm_mc0_cam_ife_2, +}; + +static struct qcom_icc_node * const mc_virt_nodes[] = { + [MASTER_LLCC] = &llcc_mc, + [SLAVE_EBI1] = &ebi, + [MASTER_LLCC_DISP] = &llcc_mc_disp, + [SLAVE_EBI1_DISP] = &ebi_disp, + [MASTER_LLCC_CAM_IFE_0] = &llcc_mc_cam_ife_0, + [SLAVE_EBI1_CAM_IFE_0] = &ebi_cam_ife_0, + [MASTER_LLCC_CAM_IFE_1] = &llcc_mc_cam_ife_1, + [SLAVE_EBI1_CAM_IFE_1] = &ebi_cam_ife_1, + [MASTER_LLCC_CAM_IFE_2] = &llcc_mc_cam_ife_2, + [SLAVE_EBI1_CAM_IFE_2] = &ebi_cam_ife_2, +}; + +static const struct qcom_icc_desc sm8550_mc_virt = { + .nodes = mc_virt_nodes, + .num_nodes = ARRAY_SIZE(mc_virt_nodes), + .bcms = mc_virt_bcms, + .num_bcms = ARRAY_SIZE(mc_virt_bcms), +}; + +static struct qcom_icc_bcm * const mmss_noc_bcms[] = { + &bcm_mm0, + &bcm_mm1, + &bcm_mm0_disp, + &bcm_mm0_cam_ife_0, + &bcm_mm1_cam_ife_0, + &bcm_mm0_cam_ife_1, + &bcm_mm1_cam_ife_1, + &bcm_mm0_cam_ife_2, + &bcm_mm1_cam_ife_2, +}; + +static struct qcom_icc_node * const mmss_noc_nodes[] = { + [MASTER_CAMNOC_HF] = &qnm_camnoc_hf, + [MASTER_CAMNOC_ICP] = &qnm_camnoc_icp, + [MASTER_CAMNOC_SF] = &qnm_camnoc_sf, + [MASTER_MDP] = &qnm_mdp, + [MASTER_CDSP_HCP] = &qnm_vapss_hcp, + [MASTER_VIDEO] = &qnm_video, + [MASTER_VIDEO_CV_PROC] = &qnm_video_cv_cpu, + [MASTER_VIDEO_PROC] = &qnm_video_cvp, + [MASTER_VIDEO_V_PROC] = &qnm_video_v_cpu, + [MASTER_CNOC_MNOC_CFG] = &qsm_mnoc_cfg, + [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf, + [SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf, + [SLAVE_SERVICE_MNOC] = &srvc_mnoc, + [MASTER_MDP_DISP] = &qnm_mdp_disp, + [SLAVE_MNOC_HF_MEM_NOC_DISP] = &qns_mem_noc_hf_disp, + [MASTER_CAMNOC_HF_CAM_IFE_0] = &qnm_camnoc_hf_cam_ife_0, + [MASTER_CAMNOC_ICP_CAM_IFE_0] = &qnm_camnoc_icp_cam_ife_0, + [MASTER_CAMNOC_SF_CAM_IFE_0] = &qnm_camnoc_sf_cam_ife_0, + [SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_0] = &qns_mem_noc_hf_cam_ife_0, + [SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0] = &qns_mem_noc_sf_cam_ife_0, + [MASTER_CAMNOC_HF_CAM_IFE_1] = &qnm_camnoc_hf_cam_ife_1, + [MASTER_CAMNOC_ICP_CAM_IFE_1] = &qnm_camnoc_icp_cam_ife_1, + [MASTER_CAMNOC_SF_CAM_IFE_1] = &qnm_camnoc_sf_cam_ife_1, + [SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_1] = &qns_mem_noc_hf_cam_ife_1, + [SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1] = &qns_mem_noc_sf_cam_ife_1, + [MASTER_CAMNOC_HF_CAM_IFE_2] = &qnm_camnoc_hf_cam_ife_2, + [MASTER_CAMNOC_ICP_CAM_IFE_2] = &qnm_camnoc_icp_cam_ife_2, + [MASTER_CAMNOC_SF_CAM_IFE_2] = &qnm_camnoc_sf_cam_ife_2, + [SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_2] = &qns_mem_noc_hf_cam_ife_2, + [SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2] = &qns_mem_noc_sf_cam_ife_2, +}; + +static const struct qcom_icc_desc sm8550_mmss_noc = { + .nodes = mmss_noc_nodes, + .num_nodes = ARRAY_SIZE(mmss_noc_nodes), + .bcms = mmss_noc_bcms, + .num_bcms = ARRAY_SIZE(mmss_noc_bcms), +}; + +static struct qcom_icc_bcm * const nsp_noc_bcms[] = { + &bcm_co0, +}; + +static struct qcom_icc_node * const nsp_noc_nodes[] = { + [MASTER_CDSP_PROC] = &qxm_nsp, + [SLAVE_CDSP_MEM_NOC] = &qns_nsp_gemnoc, +}; + +static const struct qcom_icc_desc sm8550_nsp_noc = { + .nodes = nsp_noc_nodes, + .num_nodes = ARRAY_SIZE(nsp_noc_nodes), + .bcms = nsp_noc_bcms, + .num_bcms = ARRAY_SIZE(nsp_noc_bcms), +}; + +static struct qcom_icc_bcm * const pcie_anoc_bcms[] = { + &bcm_sn7, +}; + +static struct qcom_icc_node * const pcie_anoc_nodes[] = { + [MASTER_PCIE_ANOC_CFG] = &qsm_pcie_anoc_cfg, + [MASTER_PCIE_0] = &xm_pcie3_0, + [MASTER_PCIE_1] = &xm_pcie3_1, + [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc, + [SLAVE_SERVICE_PCIE_ANOC] = &srvc_pcie_aggre_noc, +}; + +static const struct qcom_icc_desc sm8550_pcie_anoc = { + .nodes = pcie_anoc_nodes, + .num_nodes = ARRAY_SIZE(pcie_anoc_nodes), + .bcms = pcie_anoc_bcms, + .num_bcms = ARRAY_SIZE(pcie_anoc_bcms), +}; + +static struct qcom_icc_bcm * const system_noc_bcms[] = { + &bcm_sn0, + &bcm_sn1, + &bcm_sn2, + &bcm_sn3, +}; + +static struct qcom_icc_node * const system_noc_nodes[] = { + [MASTER_GIC_AHB] = &qhm_gic, + [MASTER_A1NOC_SNOC] = &qnm_aggre1_noc, + [MASTER_A2NOC_SNOC] = &qnm_aggre2_noc, + [MASTER_GIC] = &xm_gic, + [SLAVE_SNOC_GEM_NOC_GC] = &qns_gemnoc_gc, + [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf, +}; + +static const struct qcom_icc_desc sm8550_system_noc = { + .nodes = system_noc_nodes, + .num_nodes = ARRAY_SIZE(system_noc_nodes), + .bcms = system_noc_bcms, + .num_bcms = ARRAY_SIZE(system_noc_bcms), +}; + +static int qnoc_probe(struct platform_device *pdev) +{ + const struct qcom_icc_desc *desc; + struct icc_onecell_data *data; + struct icc_provider *provider; + struct qcom_icc_node * const *qnodes; + struct qcom_icc_provider *qp; + struct icc_node *node; + size_t num_nodes, i; + int ret; + + desc = device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + qnodes = desc->nodes; + num_nodes = desc->num_nodes; + + qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL); + if (!qp) + return -ENOMEM; + + data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL); + if (!data) + return -ENOMEM; + + provider = &qp->provider; + provider->dev = &pdev->dev; + provider->set = qcom_icc_set; + provider->pre_aggregate = qcom_icc_pre_aggregate; + provider->aggregate = qcom_icc_aggregate; + provider->xlate_extended = qcom_icc_xlate_extended; + INIT_LIST_HEAD(&provider->nodes); + provider->data = data; + + qp->dev = &pdev->dev; + qp->bcms = desc->bcms; + qp->num_bcms = desc->num_bcms; + + qp->voter = of_bcm_voter_get(qp->dev, NULL); + if (IS_ERR(qp->voter)) + return PTR_ERR(qp->voter); + + ret = icc_provider_add(provider); + if (ret) { + dev_err_probe(&pdev->dev, ret, + "error adding interconnect provider\n"); + return ret; + } + + for (i = 0; i < qp->num_bcms; i++) + qcom_icc_bcm_init(qp->bcms[i], &pdev->dev); + + for (i = 0; i < num_nodes; i++) { + size_t j; + + if (!qnodes[i]) + continue; + + node = icc_node_create(qnodes[i]->id); + if (IS_ERR(node)) { + ret = PTR_ERR(node); + goto err; + } + + node->name = qnodes[i]->name; + node->data = qnodes[i]; + icc_node_add(node, provider); + + for (j = 0; j < qnodes[i]->num_links; j++) + icc_link_create(node, qnodes[i]->links[j]); + + data->nodes[i] = node; + } + data->num_nodes = num_nodes; + + platform_set_drvdata(pdev, qp); + + return 0; +err: + icc_nodes_remove(provider); + icc_provider_del(provider); + return ret; +} + +static int qnoc_remove(struct platform_device *pdev) +{ + struct qcom_icc_provider *qp = platform_get_drvdata(pdev); + + icc_nodes_remove(&qp->provider); + icc_provider_del(&qp->provider); + + return 0; +} + +static const struct of_device_id qnoc_of_match[] = { + { .compatible = "qcom,sm8550-aggre1-noc", + .data = &sm8550_aggre1_noc}, + { .compatible = "qcom,sm8550-aggre2-noc", + .data = &sm8550_aggre2_noc}, + { .compatible = "qcom,sm8550-clk-virt", + .data = &sm8550_clk_virt}, + { .compatible = "qcom,sm8550-config-noc", + .data = &sm8550_config_noc}, + { .compatible = "qcom,sm8550-cnoc-main", + .data = &sm8550_cnoc_main}, + { .compatible = "qcom,sm8550-gem-noc", + .data = &sm8550_gem_noc}, + { .compatible = "qcom,sm8550-lpass-ag-noc", + .data = &sm8550_lpass_ag_noc}, + { .compatible = "qcom,sm8550-lpass-lpiaon-noc", + .data = &sm8550_lpass_lpiaon_noc}, + { .compatible = "qcom,sm8550-lpass-lpicx-noc", + .data = &sm8550_lpass_lpicx_noc}, + { .compatible = "qcom,sm8550-mc-virt", + .data = &sm8550_mc_virt}, + { .compatible = "qcom,sm8550-mmss-noc", + .data = &sm8550_mmss_noc}, + { .compatible = "qcom,sm8550-nsp-noc", + .data = &sm8550_nsp_noc}, + { .compatible = "qcom,sm8550-pcie-anoc", + .data = &sm8550_pcie_anoc}, + { .compatible = "qcom,sm8550-system-noc", + .data = &sm8550_system_noc}, + { } +}; +MODULE_DEVICE_TABLE(of, qnoc_of_match); + +static struct platform_driver qnoc_driver = { + .probe = qnoc_probe, + .remove = qnoc_remove, + .driver = { + .name = "qnoc-sm8550", + .of_match_table = qnoc_of_match, + }, +}; + +static int __init qnoc_driver_init(void) +{ + return platform_driver_register(&qnoc_driver); +} +core_initcall(qnoc_driver_init); + +static void __exit qnoc_driver_exit(void) +{ + platform_driver_unregister(&qnoc_driver); +} +module_exit(qnoc_driver_exit); + +MODULE_DESCRIPTION("sm8550 NoC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/interconnect/qcom/sm8550.h b/drivers/interconnect/qcom/sm8550.h new file mode 100644 index 000000000000..8d5862c04bca --- /dev/null +++ b/drivers/interconnect/qcom/sm8550.h @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * SM8450 interconnect IDs + * + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, Linaro Limited + */ + +#ifndef __DRIVERS_INTERCONNECT_QCOM_SM8450_H +#define __DRIVERS_INTERCONNECT_QCOM_SM8450_H + +#define SM8550_MASTER_A1NOC_SNOC 0 +#define SM8550_MASTER_A2NOC_SNOC 1 +#define SM8550_MASTER_ANOC_PCIE_GEM_NOC 2 +#define SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_0 3 +#define SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_1 4 +#define SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_2 5 +#define SM8550_MASTER_ANOC_PCIE_GEM_NOC_DISP 6 +#define SM8550_MASTER_APPSS_PROC 7 +#define SM8550_MASTER_CAMNOC_HF 8 +#define SM8550_MASTER_CAMNOC_HF_CAM_IFE_0 9 +#define SM8550_MASTER_CAMNOC_HF_CAM_IFE_1 10 +#define SM8550_MASTER_CAMNOC_HF_CAM_IFE_2 11 +#define SM8550_MASTER_CAMNOC_ICP 12 +#define SM8550_MASTER_CAMNOC_ICP_CAM_IFE_0 13 +#define SM8550_MASTER_CAMNOC_ICP_CAM_IFE_1 14 +#define SM8550_MASTER_CAMNOC_ICP_CAM_IFE_2 15 +#define SM8550_MASTER_CAMNOC_SF 16 +#define SM8550_MASTER_CAMNOC_SF_CAM_IFE_0 17 +#define SM8550_MASTER_CAMNOC_SF_CAM_IFE_1 18 +#define SM8550_MASTER_CAMNOC_SF_CAM_IFE_2 19 +#define SM8550_MASTER_CDSP_HCP 20 +#define SM8550_MASTER_CDSP_PROC 21 +#define SM8550_MASTER_CNOC_CFG 22 +#define SM8550_MASTER_CNOC_MNOC_CFG 23 +#define SM8550_MASTER_COMPUTE_NOC 24 +#define SM8550_MASTER_CRYPTO 25 +#define SM8550_MASTER_GEM_NOC_CNOC 26 +#define SM8550_MASTER_GEM_NOC_PCIE_SNOC 27 +#define SM8550_MASTER_GFX3D 28 +#define SM8550_MASTER_GIC 29 +#define SM8550_MASTER_GIC_AHB 30 +#define SM8550_MASTER_GPU_TCU 31 +#define SM8550_MASTER_IPA 32 +#define SM8550_MASTER_LLCC 33 +#define SM8550_MASTER_LLCC_CAM_IFE_0 34 +#define SM8550_MASTER_LLCC_CAM_IFE_1 35 +#define SM8550_MASTER_LLCC_CAM_IFE_2 36 +#define SM8550_MASTER_LLCC_DISP 37 +#define SM8550_MASTER_LPASS_GEM_NOC 38 +#define SM8550_MASTER_LPASS_LPINOC 39 +#define SM8550_MASTER_LPASS_PROC 40 +#define SM8550_MASTER_LPIAON_NOC 41 +#define SM8550_MASTER_MDP 42 +#define SM8550_MASTER_MDP_DISP 43 +#define SM8550_MASTER_MNOC_HF_MEM_NOC 44 +#define SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_0 45 +#define SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_1 46 +#define SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_2 47 +#define SM8550_MASTER_MNOC_HF_MEM_NOC_DISP 48 +#define SM8550_MASTER_MNOC_SF_MEM_NOC 49 +#define SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_0 50 +#define SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_1 51 +#define SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_2 52 +#define SM8550_MASTER_MSS_PROC 53 +#define SM8550_MASTER_PCIE_0 54 +#define SM8550_MASTER_PCIE_1 55 +#define SM8550_MASTER_PCIE_ANOC_CFG 56 +#define SM8550_MASTER_QDSS_BAM 57 +#define SM8550_MASTER_QDSS_ETR 58 +#define SM8550_MASTER_QDSS_ETR_1 59 +#define SM8550_MASTER_QSPI_0 60 +#define SM8550_MASTER_QUP_1 61 +#define SM8550_MASTER_QUP_2 62 +#define SM8550_MASTER_QUP_CORE_0 63 +#define SM8550_MASTER_QUP_CORE_1 64 +#define SM8550_MASTER_QUP_CORE_2 65 +#define SM8550_MASTER_SDCC_2 66 +#define SM8550_MASTER_SDCC_4 67 +#define SM8550_MASTER_SNOC_GC_MEM_NOC 68 +#define SM8550_MASTER_SNOC_SF_MEM_NOC 69 +#define SM8550_MASTER_SP 70 +#define SM8550_MASTER_SYS_TCU 71 +#define SM8550_MASTER_UFS_MEM 72 +#define SM8550_MASTER_USB3_0 73 +#define SM8550_MASTER_VIDEO 74 +#define SM8550_MASTER_VIDEO_CV_PROC 75 +#define SM8550_MASTER_VIDEO_PROC 76 +#define SM8550_MASTER_VIDEO_V_PROC 77 +#define SM8550_SLAVE_A1NOC_SNOC 78 +#define SM8550_SLAVE_A2NOC_SNOC 79 +#define SM8550_SLAVE_AHB2PHY_NORTH 80 +#define SM8550_SLAVE_AHB2PHY_SOUTH 81 +#define SM8550_SLAVE_ANOC_PCIE_GEM_NOC 82 +#define SM8550_SLAVE_AOSS 83 +#define SM8550_SLAVE_APPSS 84 +#define SM8550_SLAVE_BOOT_IMEM 85 +#define SM8550_SLAVE_CAMERA_CFG 86 +#define SM8550_SLAVE_CDSP_MEM_NOC 87 +#define SM8550_SLAVE_CLK_CTL 88 +#define SM8550_SLAVE_CNOC_CFG 89 +#define SM8550_SLAVE_CNOC_MNOC_CFG 90 +#define SM8550_SLAVE_CNOC_MSS 91 +#define SM8550_SLAVE_CPR_NSPCX 92 +#define SM8550_SLAVE_CRYPTO_0_CFG 93 +#define SM8550_SLAVE_CX_RDPM 94 +#define SM8550_SLAVE_DDRSS_CFG 95 +#define SM8550_SLAVE_DISPLAY_CFG 96 +#define SM8550_SLAVE_EBI1 97 +#define SM8550_SLAVE_EBI1_CAM_IFE_0 98 +#define SM8550_SLAVE_EBI1_CAM_IFE_1 99 +#define SM8550_SLAVE_EBI1_CAM_IFE_2 100 +#define SM8550_SLAVE_EBI1_DISP 101 +#define SM8550_SLAVE_GEM_NOC_CNOC 102 +#define SM8550_SLAVE_GFX3D_CFG 103 +#define SM8550_SLAVE_I2C 104 +#define SM8550_SLAVE_IMEM 105 +#define SM8550_SLAVE_IMEM_CFG 106 +#define SM8550_SLAVE_IPA_CFG 107 +#define SM8550_SLAVE_IPC_ROUTER_CFG 108 +#define SM8550_SLAVE_LLCC 109 +#define SM8550_SLAVE_LLCC_CAM_IFE_0 110 +#define SM8550_SLAVE_LLCC_CAM_IFE_1 111 +#define SM8550_SLAVE_LLCC_CAM_IFE_2 112 +#define SM8550_SLAVE_LLCC_DISP 113 +#define SM8550_SLAVE_LPASS_GEM_NOC 114 +#define SM8550_SLAVE_LPASS_QTB_CFG 115 +#define SM8550_SLAVE_LPIAON_NOC_LPASS_AG_NOC 116 +#define SM8550_SLAVE_LPICX_NOC_LPIAON_NOC 117 +#define SM8550_SLAVE_MEM_NOC_PCIE_SNOC 118 +#define SM8550_SLAVE_MNOC_HF_MEM_NOC 119 +#define SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_0 120 +#define SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_1 121 +#define SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_2 122 +#define SM8550_SLAVE_MNOC_HF_MEM_NOC_DISP 123 +#define SM8550_SLAVE_MNOC_SF_MEM_NOC 124 +#define SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0 125 +#define SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1 126 +#define SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2 127 +#define SM8550_SLAVE_MX_RDPM 128 +#define SM8550_SLAVE_NSP_QTB_CFG 129 +#define SM8550_SLAVE_PCIE_0 130 +#define SM8550_SLAVE_PCIE_0_CFG 131 +#define SM8550_SLAVE_PCIE_1 132 +#define SM8550_SLAVE_PCIE_1_CFG 133 +#define SM8550_SLAVE_PCIE_ANOC_CFG 134 +#define SM8550_SLAVE_PDM 135 +#define SM8550_SLAVE_PIMEM_CFG 136 +#define SM8550_SLAVE_PRNG 137 +#define SM8550_SLAVE_QDSS_CFG 138 +#define SM8550_SLAVE_QDSS_STM 139 +#define SM8550_SLAVE_QSPI_0 140 +#define SM8550_SLAVE_QUP_1 141 +#define SM8550_SLAVE_QUP_2 142 +#define SM8550_SLAVE_QUP_CORE_0 143 +#define SM8550_SLAVE_QUP_CORE_1 144 +#define SM8550_SLAVE_QUP_CORE_2 145 +#define SM8550_SLAVE_RBCPR_CX_CFG 146 +#define SM8550_SLAVE_RBCPR_MMCX_CFG 147 +#define SM8550_SLAVE_RBCPR_MXA_CFG 148 +#define SM8550_SLAVE_RBCPR_MXC_CFG 149 +#define SM8550_SLAVE_SDCC_2 150 +#define SM8550_SLAVE_SDCC_4 151 +#define SM8550_SLAVE_SERVICE_MNOC 152 +#define SM8550_SLAVE_SERVICE_PCIE_ANOC 153 +#define SM8550_SLAVE_SNOC_GEM_NOC_GC 154 +#define SM8550_SLAVE_SNOC_GEM_NOC_SF 155 +#define SM8550_SLAVE_SPSS_CFG 156 +#define SM8550_SLAVE_TCSR 157 +#define SM8550_SLAVE_TCU 158 +#define SM8550_SLAVE_TLMM 159 +#define SM8550_SLAVE_TME_CFG 160 +#define SM8550_SLAVE_UFS_MEM_CFG 161 +#define SM8550_SLAVE_USB3_0 162 +#define SM8550_SLAVE_VENUS_CFG 163 +#define SM8550_SLAVE_VSENSE_CTRL_CFG 164 + +#endif diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index ab160198edd6..f2425b0f0cd6 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -3858,7 +3858,9 @@ static int arm_smmu_device_remove(struct platform_device *pdev) static void arm_smmu_device_shutdown(struct platform_device *pdev) { - arm_smmu_device_remove(pdev); + struct arm_smmu_device *smmu = platform_get_drvdata(pdev); + + arm_smmu_device_disable(smmu); } static const struct of_device_id arm_smmu_of_match[] = { diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c index 719fbca1fe52..2ff7a72cf377 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c @@ -1316,8 +1316,14 @@ static bool arm_smmu_capable(struct device *dev, enum iommu_cap cap) switch (cap) { case IOMMU_CAP_CACHE_COHERENCY: - /* Assume that a coherent TCU implies coherent TBUs */ - return cfg->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK; + /* + * It's overwhelmingly the case in practice that when the pagetable + * walk interface is connected to a coherent interconnect, all the + * translation interfaces are too. Furthermore if the device is + * natively coherent, then its translation interface must also be. + */ + return cfg->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK || + device_get_dma_attr(dev) == DEV_DMA_COHERENT; case IOMMU_CAP_NOEXEC: return true; default: @@ -2185,19 +2191,16 @@ static int arm_smmu_device_probe(struct platform_device *pdev) return 0; } -static int arm_smmu_device_remove(struct platform_device *pdev) +static void arm_smmu_device_shutdown(struct platform_device *pdev) { struct arm_smmu_device *smmu = platform_get_drvdata(pdev); if (!smmu) - return -ENODEV; + return; if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS)) dev_notice(&pdev->dev, "disabling translation\n"); - iommu_device_unregister(&smmu->iommu); - iommu_device_sysfs_remove(&smmu->iommu); - arm_smmu_rpm_get(smmu); /* Turn the thing off */ arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, ARM_SMMU_sCR0_CLIENTPD); @@ -2209,12 +2212,21 @@ static int arm_smmu_device_remove(struct platform_device *pdev) clk_bulk_disable(smmu->num_clks, smmu->clks); clk_bulk_unprepare(smmu->num_clks, smmu->clks); - return 0; } -static void arm_smmu_device_shutdown(struct platform_device *pdev) +static int arm_smmu_device_remove(struct platform_device *pdev) { - arm_smmu_device_remove(pdev); + struct arm_smmu_device *smmu = platform_get_drvdata(pdev); + + if (!smmu) + return -ENODEV; + + iommu_device_unregister(&smmu->iommu); + iommu_device_sysfs_remove(&smmu->iommu); + + arm_smmu_device_shutdown(pdev); + + return 0; } static int __maybe_unused arm_smmu_runtime_resume(struct device *dev) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index de91dd88705b..5f6a85aea501 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -3185,14 +3185,16 @@ EXPORT_SYMBOL_GPL(iommu_group_claim_dma_owner); */ int iommu_device_claim_dma_owner(struct device *dev, void *owner) { - struct iommu_group *group = iommu_group_get(dev); + struct iommu_group *group; int ret = 0; - if (!group) - return -ENODEV; if (WARN_ON(!owner)) return -EINVAL; + group = iommu_group_get(dev); + if (!group) + return -ENODEV; + mutex_lock(&group->mutex); if (group->owner_cnt) { if (group->owner != owner) { diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index a44ad92fc5eb..fe452ce46642 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -197,7 +197,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, curr = __get_cached_rbnode(iovad, limit_pfn); curr_iova = to_iova(curr); - retry_pfn = curr_iova->pfn_hi + 1; + retry_pfn = curr_iova->pfn_hi; retry: do { @@ -211,7 +211,7 @@ retry: if (high_pfn < size || new_pfn < low_pfn) { if (low_pfn == iovad->start_pfn && retry_pfn < limit_pfn) { high_pfn = limit_pfn; - low_pfn = retry_pfn; + low_pfn = retry_pfn + 1; curr = iova_find_limit(iovad, limit_pfn); curr_iova = to_iova(curr); goto retry; diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index 69682ee068d2..ca581ff1c769 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -683,7 +683,7 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev) ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL, dev_name(&pdev->dev)); if (ret) - return ret; + goto out_clk_unprepare; ret = iommu_device_register(&data->iommu, &mtk_iommu_v1_ops, dev); if (ret) @@ -698,6 +698,8 @@ out_dev_unreg: iommu_device_unregister(&data->iommu); out_sysfs_remove: iommu_device_sysfs_remove(&data->iommu); +out_clk_unprepare: + clk_disable_unprepare(data->bclk); return ret; } diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index caa952c40ff9..d79683154f7f 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -136,11 +136,6 @@ config BRCMSTB_L2_IRQ select GENERIC_IRQ_CHIP select IRQ_DOMAIN -config DAVINCI_AINTC - bool - select GENERIC_IRQ_CHIP - select IRQ_DOMAIN - config DAVINCI_CP_INTC bool select GENERIC_IRQ_CHIP diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 87b49a10962c..ffd945fe71aa 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -8,7 +8,6 @@ obj-$(CONFIG_ATH79) += irq-ath79-misc.o obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o obj-$(CONFIG_ARCH_ACTIONS) += irq-owl-sirq.o -obj-$(CONFIG_DAVINCI_AINTC) += irq-davinci-aintc.o obj-$(CONFIG_DAVINCI_CP_INTC) += irq-davinci-cp-intc.o obj-$(CONFIG_EXYNOS_IRQ_COMBINER) += exynos-combiner.o obj-$(CONFIG_FARADAY_FTINTC010) += irq-ftintc010.o diff --git a/drivers/irqchip/irq-davinci-aintc.c b/drivers/irqchip/irq-davinci-aintc.c deleted file mode 100644 index 123eb7bfc117..000000000000 --- a/drivers/irqchip/irq-davinci-aintc.c +++ /dev/null @@ -1,163 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// -// Copyright (C) 2006, 2019 Texas Instruments. -// -// Interrupt handler for DaVinci boards. - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/irqchip/irq-davinci-aintc.h> -#include <linux/io.h> -#include <linux/irqdomain.h> - -#include <asm/exception.h> - -#define DAVINCI_AINTC_FIQ_REG0 0x00 -#define DAVINCI_AINTC_FIQ_REG1 0x04 -#define DAVINCI_AINTC_IRQ_REG0 0x08 -#define DAVINCI_AINTC_IRQ_REG1 0x0c -#define DAVINCI_AINTC_IRQ_IRQENTRY 0x14 -#define DAVINCI_AINTC_IRQ_ENT_REG0 0x18 -#define DAVINCI_AINTC_IRQ_ENT_REG1 0x1c -#define DAVINCI_AINTC_IRQ_INCTL_REG 0x20 -#define DAVINCI_AINTC_IRQ_EABASE_REG 0x24 -#define DAVINCI_AINTC_IRQ_INTPRI0_REG 0x30 -#define DAVINCI_AINTC_IRQ_INTPRI7_REG 0x4c - -static void __iomem *davinci_aintc_base; -static struct irq_domain *davinci_aintc_irq_domain; - -static inline void davinci_aintc_writel(unsigned long value, int offset) -{ - writel_relaxed(value, davinci_aintc_base + offset); -} - -static inline unsigned long davinci_aintc_readl(int offset) -{ - return readl_relaxed(davinci_aintc_base + offset); -} - -static __init void -davinci_aintc_setup_gc(void __iomem *base, - unsigned int irq_start, unsigned int num) -{ - struct irq_chip_generic *gc; - struct irq_chip_type *ct; - - gc = irq_get_domain_generic_chip(davinci_aintc_irq_domain, irq_start); - gc->reg_base = base; - gc->irq_base = irq_start; - - ct = gc->chip_types; - ct->chip.irq_ack = irq_gc_ack_set_bit; - ct->chip.irq_mask = irq_gc_mask_clr_bit; - ct->chip.irq_unmask = irq_gc_mask_set_bit; - - ct->regs.ack = DAVINCI_AINTC_IRQ_REG0; - ct->regs.mask = DAVINCI_AINTC_IRQ_ENT_REG0; - irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, - IRQ_NOREQUEST | IRQ_NOPROBE, 0); -} - -static asmlinkage void __exception_irq_entry -davinci_aintc_handle_irq(struct pt_regs *regs) -{ - int irqnr = davinci_aintc_readl(DAVINCI_AINTC_IRQ_IRQENTRY); - - /* - * Use the formula for entry vector index generation from section - * 8.3.3 of the manual. - */ - irqnr >>= 2; - irqnr -= 1; - - generic_handle_domain_irq(davinci_aintc_irq_domain, irqnr); -} - -/* ARM Interrupt Controller Initialization */ -void __init davinci_aintc_init(const struct davinci_aintc_config *config) -{ - unsigned int irq_off, reg_off, prio, shift; - void __iomem *req; - int ret, irq_base; - const u8 *prios; - - req = request_mem_region(config->reg.start, - resource_size(&config->reg), - "davinci-cp-intc"); - if (!req) { - pr_err("%s: register range busy\n", __func__); - return; - } - - davinci_aintc_base = ioremap(config->reg.start, - resource_size(&config->reg)); - if (!davinci_aintc_base) { - pr_err("%s: unable to ioremap register range\n", __func__); - return; - } - - /* Clear all interrupt requests */ - davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG0); - davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG1); - davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG0); - davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG1); - - /* Disable all interrupts */ - davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_ENT_REG0); - davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_ENT_REG1); - - /* Interrupts disabled immediately, IRQ entry reflects all */ - davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_INCTL_REG); - - /* we don't use the hardware vector table, just its entry addresses */ - davinci_aintc_writel(0, DAVINCI_AINTC_IRQ_EABASE_REG); - - /* Clear all interrupt requests */ - davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG0); - davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG1); - davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG0); - davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG1); - - prios = config->prios; - for (reg_off = DAVINCI_AINTC_IRQ_INTPRI0_REG; - reg_off <= DAVINCI_AINTC_IRQ_INTPRI7_REG; reg_off += 4) { - for (shift = 0, prio = 0; shift < 32; shift += 4, prios++) - prio |= (*prios & 0x07) << shift; - davinci_aintc_writel(prio, reg_off); - } - - irq_base = irq_alloc_descs(-1, 0, config->num_irqs, 0); - if (irq_base < 0) { - pr_err("%s: unable to allocate interrupt descriptors: %d\n", - __func__, irq_base); - return; - } - - davinci_aintc_irq_domain = irq_domain_add_legacy(NULL, - config->num_irqs, irq_base, 0, - &irq_domain_simple_ops, NULL); - if (!davinci_aintc_irq_domain) { - pr_err("%s: unable to create interrupt domain\n", __func__); - return; - } - - ret = irq_alloc_domain_generic_chips(davinci_aintc_irq_domain, 32, 1, - "AINTC", handle_edge_irq, - IRQ_NOREQUEST | IRQ_NOPROBE, 0, 0); - if (ret) { - pr_err("%s: unable to allocate generic irq chips for domain\n", - __func__); - return; - } - - for (irq_off = 0, reg_off = 0; - irq_off < config->num_irqs; - irq_off += 32, reg_off += 0x04) - davinci_aintc_setup_gc(davinci_aintc_base + reg_off, - irq_base + irq_off, 32); - - set_handle_irq(davinci_aintc_handle_irq); -} diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 499d0f215a8b..be2eeb3d6fd3 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -244,14 +244,6 @@ config LEDS_MT6323 This option enables support for on-chip LED drivers found on Mediatek MT6323 PMIC. -config LEDS_S3C24XX - tristate "LED Support for Samsung S3C24XX GPIO LEDs" - depends on LEDS_CLASS - depends on ARCH_S3C24XX || COMPILE_TEST - help - This option enables support for LEDs connected to GPIO lines - on Samsung S3C24XX series CPUs, such as the S3C2410 and S3C2440. - config LEDS_NET48XX tristate "LED Support for Soekris net48xx series Error LED" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 4fd2f92cd198..a790c967fce9 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -74,7 +74,6 @@ obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o obj-$(CONFIG_LEDS_PWM) += leds-pwm.o obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o -obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c deleted file mode 100644 index 3c0c7aa63b8c..000000000000 --- a/drivers/leds/leds-s3c24xx.c +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* drivers/leds/leds-s3c24xx.c - * - * (c) 2006 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks <ben@simtec.co.uk> - * - * S3C24XX - LEDs GPIO driver -*/ - -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/leds.h> -#include <linux/gpio/consumer.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/platform_data/leds-s3c24xx.h> - -/* our context */ - -struct s3c24xx_gpio_led { - struct led_classdev cdev; - struct s3c24xx_led_platdata *pdata; - struct gpio_desc *gpiod; -}; - -static inline struct s3c24xx_gpio_led *to_gpio(struct led_classdev *led_cdev) -{ - return container_of(led_cdev, struct s3c24xx_gpio_led, cdev); -} - -static void s3c24xx_led_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - struct s3c24xx_gpio_led *led = to_gpio(led_cdev); - - gpiod_set_value(led->gpiod, !!value); -} - -static int s3c24xx_led_probe(struct platform_device *dev) -{ - struct s3c24xx_led_platdata *pdata = dev_get_platdata(&dev->dev); - struct s3c24xx_gpio_led *led; - int ret; - - led = devm_kzalloc(&dev->dev, sizeof(struct s3c24xx_gpio_led), - GFP_KERNEL); - if (!led) - return -ENOMEM; - - led->cdev.brightness_set = s3c24xx_led_set; - led->cdev.default_trigger = pdata->def_trigger; - led->cdev.name = pdata->name; - led->cdev.flags |= LED_CORE_SUSPENDRESUME; - - led->pdata = pdata; - - /* Default to off */ - led->gpiod = devm_gpiod_get(&dev->dev, NULL, GPIOD_OUT_LOW); - if (IS_ERR(led->gpiod)) - return PTR_ERR(led->gpiod); - - /* register our new led device */ - ret = devm_led_classdev_register(&dev->dev, &led->cdev); - if (ret < 0) - dev_err(&dev->dev, "led_classdev_register failed\n"); - - return ret; -} - -static struct platform_driver s3c24xx_led_driver = { - .probe = s3c24xx_led_probe, - .driver = { - .name = "s3c24xx_led", - }, -}; - -module_platform_driver(s3c24xx_led_driver); - -MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); -MODULE_DESCRIPTION("S3C24XX LED driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c24xx_led"); diff --git a/drivers/md/bcache/bcache_ondisk.h b/drivers/md/bcache/bcache_ondisk.h index 97413586195b..f96034e0ba4f 100644 --- a/drivers/md/bcache/bcache_ondisk.h +++ b/drivers/md/bcache/bcache_ondisk.h @@ -106,7 +106,8 @@ static inline unsigned long bkey_bytes(const struct bkey *k) return bkey_u64s(k) * sizeof(__u64); } -#define bkey_copy(_dest, _src) memcpy(_dest, _src, bkey_bytes(_src)) +#define bkey_copy(_dest, _src) unsafe_memcpy(_dest, _src, bkey_bytes(_src), \ + /* bkey is always padded */) static inline void bkey_copy_key(struct bkey *dest, const struct bkey *src) { diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c index e5da469a4235..c182c21de2e8 100644 --- a/drivers/md/bcache/journal.c +++ b/drivers/md/bcache/journal.c @@ -149,7 +149,8 @@ add: bytes, GFP_KERNEL); if (!i) return -ENOMEM; - memcpy(&i->j, j, bytes); + unsafe_memcpy(&i->j, j, bytes, + /* "bytes" was calculated by set_bytes() above */); /* Add to the location after 'where' points to */ list_add(&i->list, where); ret = 1; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index e1ea3a7bd9d9..b424a6ee27ba 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1742,6 +1742,8 @@ static void dm_split_and_process_bio(struct mapped_device *md, * otherwise associated queue_limits won't be imposed. */ bio = bio_split_to_limits(bio); + if (!bio) + return; } init_clone_info(&ci, md, map, bio, is_abnormal); diff --git a/drivers/md/md.c b/drivers/md/md.c index 775f1dde190a..927a43db5dfb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -380,6 +380,10 @@ EXPORT_SYMBOL_GPL(md_new_event); static LIST_HEAD(all_mddevs); static DEFINE_SPINLOCK(all_mddevs_lock); +static bool is_md_suspended(struct mddev *mddev) +{ + return percpu_ref_is_dying(&mddev->active_io); +} /* Rather than calling directly into the personality make_request function, * IO requests come here first so that we can check if the device is * being suspended pending a reconfiguration. @@ -389,7 +393,7 @@ static DEFINE_SPINLOCK(all_mddevs_lock); */ static bool is_suspended(struct mddev *mddev, struct bio *bio) { - if (mddev->suspended) + if (is_md_suspended(mddev)) return true; if (bio_data_dir(bio) != WRITE) return false; @@ -405,12 +409,10 @@ static bool is_suspended(struct mddev *mddev, struct bio *bio) void md_handle_request(struct mddev *mddev, struct bio *bio) { check_suspended: - rcu_read_lock(); if (is_suspended(mddev, bio)) { DEFINE_WAIT(__wait); /* Bail out if REQ_NOWAIT is set for the bio */ if (bio->bi_opf & REQ_NOWAIT) { - rcu_read_unlock(); bio_wouldblock_error(bio); return; } @@ -419,23 +421,19 @@ check_suspended: TASK_UNINTERRUPTIBLE); if (!is_suspended(mddev, bio)) break; - rcu_read_unlock(); schedule(); - rcu_read_lock(); } finish_wait(&mddev->sb_wait, &__wait); } - atomic_inc(&mddev->active_io); - rcu_read_unlock(); + if (!percpu_ref_tryget_live(&mddev->active_io)) + goto check_suspended; if (!mddev->pers->make_request(mddev, bio)) { - atomic_dec(&mddev->active_io); - wake_up(&mddev->sb_wait); + percpu_ref_put(&mddev->active_io); goto check_suspended; } - if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended) - wake_up(&mddev->sb_wait); + percpu_ref_put(&mddev->active_io); } EXPORT_SYMBOL(md_handle_request); @@ -455,6 +453,8 @@ static void md_submit_bio(struct bio *bio) } bio = bio_split_to_limits(bio); + if (!bio) + return; if (mddev->ro == MD_RDONLY && unlikely(rw == WRITE)) { if (bio_sectors(bio) != 0) @@ -481,11 +481,10 @@ void mddev_suspend(struct mddev *mddev) lockdep_assert_held(&mddev->reconfig_mutex); if (mddev->suspended++) return; - synchronize_rcu(); wake_up(&mddev->sb_wait); set_bit(MD_ALLOW_SB_UPDATE, &mddev->flags); - smp_mb__after_atomic(); - wait_event(mddev->sb_wait, atomic_read(&mddev->active_io) == 0); + percpu_ref_kill(&mddev->active_io); + wait_event(mddev->sb_wait, percpu_ref_is_zero(&mddev->active_io)); mddev->pers->quiesce(mddev, 1); clear_bit_unlock(MD_ALLOW_SB_UPDATE, &mddev->flags); wait_event(mddev->sb_wait, !test_bit(MD_UPDATING_SB, &mddev->flags)); @@ -503,6 +502,7 @@ void mddev_resume(struct mddev *mddev) lockdep_assert_held(&mddev->reconfig_mutex); if (--mddev->suspended) return; + percpu_ref_resurrect(&mddev->active_io); wake_up(&mddev->sb_wait); mddev->pers->quiesce(mddev, 0); @@ -681,7 +681,6 @@ void mddev_init(struct mddev *mddev) timer_setup(&mddev->safemode_timer, md_safemode_timeout, 0); atomic_set(&mddev->active, 1); atomic_set(&mddev->openers, 0); - atomic_set(&mddev->active_io, 0); spin_lock_init(&mddev->lock); atomic_set(&mddev->flush_pending, 0); init_waitqueue_head(&mddev->sb_wait); @@ -3642,7 +3641,7 @@ EXPORT_SYMBOL_GPL(md_rdev_init); */ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int super_minor) { - static struct md_rdev *claim_rdev; /* just for claiming the bdev */ + static struct md_rdev claim_rdev; /* just for claiming the bdev */ struct md_rdev *rdev; sector_t size; int err; @@ -3660,7 +3659,7 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe rdev->bdev = blkdev_get_by_dev(newdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL, - super_format == -2 ? claim_rdev : rdev); + super_format == -2 ? &claim_rdev : rdev); if (IS_ERR(rdev->bdev)) { pr_warn("md: could not open device unknown-block(%u,%u).\n", MAJOR(newdev), MINOR(newdev)); @@ -5758,6 +5757,12 @@ static void md_safemode_timeout(struct timer_list *t) } static int start_dirty_degraded; +static void active_io_release(struct percpu_ref *ref) +{ + struct mddev *mddev = container_of(ref, struct mddev, active_io); + + wake_up(&mddev->sb_wait); +} int md_run(struct mddev *mddev) { @@ -5838,10 +5843,15 @@ int md_run(struct mddev *mddev) nowait = nowait && bdev_nowait(rdev->bdev); } + err = percpu_ref_init(&mddev->active_io, active_io_release, + PERCPU_REF_ALLOW_REINIT, GFP_KERNEL); + if (err) + return err; + if (!bioset_initialized(&mddev->bio_set)) { err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); if (err) - return err; + goto exit_active_io; } if (!bioset_initialized(&mddev->sync_set)) { err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); @@ -6029,6 +6039,8 @@ abort: bioset_exit(&mddev->sync_set); exit_bio_set: bioset_exit(&mddev->bio_set); +exit_active_io: + percpu_ref_exit(&mddev->active_io); return err; } EXPORT_SYMBOL_GPL(md_run); @@ -6154,7 +6166,7 @@ static void md_clean(struct mddev *mddev) mddev->new_level = LEVEL_NONE; mddev->new_layout = 0; mddev->new_chunk_sectors = 0; - mddev->curr_resync = 0; + mddev->curr_resync = MD_RESYNC_NONE; atomic64_set(&mddev->resync_mismatches, 0); mddev->suspend_lo = mddev->suspend_hi = 0; mddev->sync_speed_min = mddev->sync_speed_max = 0; @@ -6217,7 +6229,7 @@ EXPORT_SYMBOL_GPL(md_stop_writes); static void mddev_detach(struct mddev *mddev) { md_bitmap_wait_behind_writes(mddev); - if (mddev->pers && mddev->pers->quiesce && !mddev->suspended) { + if (mddev->pers && mddev->pers->quiesce && !is_md_suspended(mddev)) { mddev->pers->quiesce(mddev, 1); mddev->pers->quiesce(mddev, 0); } @@ -6253,6 +6265,8 @@ void md_stop(struct mddev *mddev) */ __md_stop_writes(mddev); __md_stop(mddev); + percpu_ref_exit(&mddev->writes_pending); + percpu_ref_exit(&mddev->active_io); bioset_exit(&mddev->bio_set); bioset_exit(&mddev->sync_set); } @@ -7826,6 +7840,7 @@ static void md_free_disk(struct gendisk *disk) struct mddev *mddev = disk->private_data; percpu_ref_exit(&mddev->writes_pending); + percpu_ref_exit(&mddev->active_io); bioset_exit(&mddev->bio_set); bioset_exit(&mddev->sync_set); @@ -8529,7 +8544,7 @@ bool md_write_start(struct mddev *mddev, struct bio *bi) return true; wait_event(mddev->sb_wait, !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags) || - mddev->suspended); + is_md_suspended(mddev)); if (test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags)) { percpu_ref_put(&mddev->writes_pending); return false; @@ -8613,12 +8628,15 @@ static void md_end_io_acct(struct bio *bio) { struct md_io_acct *md_io_acct = bio->bi_private; struct bio *orig_bio = md_io_acct->orig_bio; + struct mddev *mddev = md_io_acct->mddev; orig_bio->bi_status = bio->bi_status; bio_end_io_acct(orig_bio, md_io_acct->start_time); bio_put(bio); bio_endio(orig_bio); + + percpu_ref_put(&mddev->active_io); } /* @@ -8634,10 +8652,13 @@ void md_account_bio(struct mddev *mddev, struct bio **bio) if (!blk_queue_io_stat(bdev->bd_disk->queue)) return; + percpu_ref_get(&mddev->active_io); + clone = bio_alloc_clone(bdev, *bio, GFP_NOIO, &mddev->io_acct_set); md_io_acct = container_of(clone, struct md_io_acct, bio_clone); md_io_acct->orig_bio = *bio; md_io_acct->start_time = bio_start_io_acct(*bio); + md_io_acct->mddev = mddev; clone->bi_end_io = md_end_io_acct; clone->bi_private = md_io_acct; @@ -8881,7 +8902,7 @@ void md_do_sync(struct md_thread *thread) atomic_set(&mddev->recovery_active, 0); last_check = 0; - if (j>2) { + if (j >= MD_RESYNC_ACTIVE) { pr_debug("md: resuming %s of %s from checkpoint.\n", desc, mdname(mddev)); mddev->curr_resync = j; @@ -8953,7 +8974,7 @@ void md_do_sync(struct md_thread *thread) if (j > max_sectors) /* when skipping, extra large numbers can be returned. */ j = max_sectors; - if (j > 2) + if (j >= MD_RESYNC_ACTIVE) mddev->curr_resync = j; mddev->curr_mark_cnt = io_sectors; if (last_check == 0) @@ -9028,7 +9049,7 @@ void md_do_sync(struct md_thread *thread) mddev->pers->sync_request(mddev, max_sectors, &skipped); if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) && - mddev->curr_resync >= MD_RESYNC_ACTIVE) { + mddev->curr_resync > MD_RESYNC_ACTIVE) { if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { if (mddev->curr_resync >= mddev->recovery_cp) { @@ -9257,7 +9278,7 @@ void md_check_recovery(struct mddev *mddev) wake_up(&mddev->sb_wait); } - if (mddev->suspended) + if (is_md_suspended(mddev)) return; if (mddev->bitmap) diff --git a/drivers/md/md.h b/drivers/md/md.h index 554a9026669a..e148e3c83b0d 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -315,7 +315,7 @@ struct mddev { unsigned long sb_flags; int suspended; - atomic_t active_io; + struct percpu_ref active_io; int ro; int sysfs_active; /* set when sysfs deletes * are happening, so run/ @@ -710,9 +710,10 @@ struct md_thread { }; struct md_io_acct { - struct bio *orig_bio; - unsigned long start_time; - struct bio bio_clone; + struct mddev *mddev; + struct bio *orig_bio; + unsigned long start_time; + struct bio bio_clone; }; #define THREAD_WAKEUP 0 diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index fc3758a5bc1c..53e495223ea0 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -2149,8 +2149,6 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type) if (ret) return ret; - q->streaming = 1; - /* * Tell driver to start streaming provided sufficient buffers * are available. @@ -2161,12 +2159,13 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type) goto unprepare; } + q->streaming = 1; + dprintk(q, 3, "successful\n"); return 0; unprepare: call_void_qop(q, unprepare_streaming, q); - q->streaming = 0; return ret; } EXPORT_SYMBOL_GPL(vb2_core_streamon); diff --git a/drivers/media/platform/samsung/s3c-camif/Kconfig b/drivers/media/platform/samsung/s3c-camif/Kconfig index 8cb8d1ac3edc..f359f6382fff 100644 --- a/drivers/media/platform/samsung/s3c-camif/Kconfig +++ b/drivers/media/platform/samsung/s3c-camif/Kconfig @@ -1,15 +1,15 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_S3C_CAMIF - tristate "Samsung S3C24XX/S3C64XX SoC Camera Interface driver" + tristate "Samsung 3C64XX SoC Camera Interface driver" depends on V4L_PLATFORM_DRIVERS depends on VIDEO_DEV && I2C && PM - depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST + depends on ARCH_S3C64XX || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG help - This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera - host interface (CAMIF). + This is a v4l2 driver for s3c64xx SoC series camera host interface + (CAMIF). To compile this driver as a module, choose M here: the module will be called s3c-camif. diff --git a/drivers/media/platform/ti/davinci/Kconfig b/drivers/media/platform/ti/davinci/Kconfig index 96d4bed7fe9e..542a602e66be 100644 --- a/drivers/media/platform/ti/davinci/Kconfig +++ b/drivers/media/platform/ti/davinci/Kconfig @@ -31,19 +31,3 @@ config VIDEO_DAVINCI_VPIF_CAPTURE To compile this driver as a module, choose M here. There will be two modules called vpif.ko and vpif_capture.ko - -config VIDEO_DAVINCI_VPBE_DISPLAY - tristate "TI DaVinci VPBE V4L2-Display driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV - depends on ARCH_DAVINCI || COMPILE_TEST - depends on I2C - select VIDEOBUF2_DMA_CONTIG - help - Enables Davinci VPBE module used for display devices. - This module is used for display on TI DM644x/DM365/DM355 - based display devices. - - To compile this driver as a module, choose M here. There will - be five modules created called vpss.ko, vpbe.ko, vpbe_osd.ko, - vpbe_venc.ko and vpbe_display.ko diff --git a/drivers/media/platform/ti/davinci/Makefile b/drivers/media/platform/ti/davinci/Makefile index b20a91653162..512f03369bae 100644 --- a/drivers/media/platform/ti/davinci/Makefile +++ b/drivers/media/platform/ti/davinci/Makefile @@ -7,6 +7,3 @@ obj-$(CONFIG_VIDEO_DAVINCI_VPIF_DISPLAY) += vpif.o vpif_display.o #VPIF Capture driver obj-$(CONFIG_VIDEO_DAVINCI_VPIF_CAPTURE) += vpif.o vpif_capture.o - -obj-$(CONFIG_VIDEO_DAVINCI_VPBE_DISPLAY) += vpss.o vpbe.o vpbe_osd.o \ - vpbe_venc.o vpbe_display.o diff --git a/drivers/media/platform/ti/davinci/vpbe.c b/drivers/media/platform/ti/davinci/vpbe.c deleted file mode 100644 index 509ecc84624e..000000000000 --- a/drivers/media/platform/ti/davinci/vpbe.c +++ /dev/null @@ -1,840 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2010 Texas Instruments Inc - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/string.h> -#include <linux/wait.h> -#include <linux/time.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/clk.h> -#include <linux/err.h> - -#include <media/v4l2-device.h> -#include <media/davinci/vpbe_types.h> -#include <media/davinci/vpbe.h> -#include <media/davinci/vpss.h> -#include <media/davinci/vpbe_venc.h> - -#define VPBE_DEFAULT_OUTPUT "Composite" -#define VPBE_DEFAULT_MODE "ntsc" - -static char *def_output = VPBE_DEFAULT_OUTPUT; -static char *def_mode = VPBE_DEFAULT_MODE; -static int debug; - -module_param(def_output, charp, S_IRUGO); -module_param(def_mode, charp, S_IRUGO); -module_param(debug, int, 0644); - -MODULE_PARM_DESC(def_output, "vpbe output name (default:Composite)"); -MODULE_PARM_DESC(def_mode, "vpbe output mode name (default:ntsc"); -MODULE_PARM_DESC(debug, "Debug level 0-1"); - -MODULE_DESCRIPTION("TI DMXXX VPBE Display controller"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Texas Instruments"); - -/** - * vpbe_current_encoder_info - Get config info for current encoder - * @vpbe_dev: vpbe device ptr - * - * Return ptr to current encoder config info - */ -static struct encoder_config_info* -vpbe_current_encoder_info(struct vpbe_device *vpbe_dev) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - int index = vpbe_dev->current_sd_index; - - return ((index == 0) ? &cfg->venc : - &cfg->ext_encoders[index-1]); -} - -/** - * vpbe_find_encoder_sd_index - Given a name find encoder sd index - * - * @cfg: ptr to vpbe cfg - * @index: index used by application - * - * Return sd index of the encoder - */ -static int vpbe_find_encoder_sd_index(struct vpbe_config *cfg, - int index) -{ - char *encoder_name = cfg->outputs[index].subdev_name; - int i; - - /* Venc is always first */ - if (!strcmp(encoder_name, cfg->venc.module_name)) - return 0; - - for (i = 0; i < cfg->num_ext_encoders; i++) { - if (!strcmp(encoder_name, - cfg->ext_encoders[i].module_name)) - return i+1; - } - - return -EINVAL; -} - -/** - * vpbe_enum_outputs - enumerate outputs - * @vpbe_dev: vpbe device ptr - * @output: ptr to v4l2_output structure - * - * Enumerates the outputs available at the vpbe display - * returns the status, -EINVAL if end of output list - */ -static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev, - struct v4l2_output *output) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - unsigned int temp_index = output->index; - - if (temp_index >= cfg->num_outputs) - return -EINVAL; - - *output = cfg->outputs[temp_index].output; - output->index = temp_index; - - return 0; -} - -static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode, - int output_index) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - struct vpbe_enc_mode_info var; - int curr_output = output_index; - int i; - - if (!mode) - return -EINVAL; - - for (i = 0; i < cfg->outputs[curr_output].num_modes; i++) { - var = cfg->outputs[curr_output].modes[i]; - if (!strcmp(mode, var.name)) { - vpbe_dev->current_timings = var; - return 0; - } - } - - return -EINVAL; -} - -static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev, - struct vpbe_enc_mode_info *mode_info) -{ - if (!mode_info) - return -EINVAL; - - *mode_info = vpbe_dev->current_timings; - - return 0; -} - -/* Get std by std id */ -static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, - v4l2_std_id std_id) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - struct vpbe_enc_mode_info var; - int curr_output = vpbe_dev->current_out_index; - int i; - - for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { - var = cfg->outputs[curr_output].modes[i]; - if ((var.timings_type & VPBE_ENC_STD) && - (var.std_id & std_id)) { - vpbe_dev->current_timings = var; - return 0; - } - } - - return -EINVAL; -} - -static int vpbe_get_std_info_by_name(struct vpbe_device *vpbe_dev, - char *std_name) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - struct vpbe_enc_mode_info var; - int curr_output = vpbe_dev->current_out_index; - int i; - - for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { - var = cfg->outputs[curr_output].modes[i]; - if (!strcmp(var.name, std_name)) { - vpbe_dev->current_timings = var; - return 0; - } - } - - return -EINVAL; -} - -/** - * vpbe_set_output - Set output - * @vpbe_dev: vpbe device ptr - * @index: index of output - * - * Set vpbe output to the output specified by the index - */ -static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) -{ - struct encoder_config_info *curr_enc_info = - vpbe_current_encoder_info(vpbe_dev); - struct vpbe_config *cfg = vpbe_dev->cfg; - struct venc_platform_data *venc_device = vpbe_dev->venc_device; - int enc_out_index; - int sd_index; - int ret; - - if (index >= cfg->num_outputs) - return -EINVAL; - - mutex_lock(&vpbe_dev->lock); - - sd_index = vpbe_dev->current_sd_index; - enc_out_index = cfg->outputs[index].output.index; - /* - * Currently we switch the encoder based on output selected - * by the application. If media controller is implemented later - * there is will be an API added to setup_link between venc - * and external encoder. So in that case below comparison always - * match and encoder will not be switched. But if application - * chose not to use media controller, then this provides current - * way of switching encoder at the venc output. - */ - if (strcmp(curr_enc_info->module_name, - cfg->outputs[index].subdev_name)) { - /* Need to switch the encoder at the output */ - sd_index = vpbe_find_encoder_sd_index(cfg, index); - if (sd_index < 0) { - ret = -EINVAL; - goto unlock; - } - - ret = venc_device->setup_if_config(cfg->outputs[index].if_params); - if (ret) - goto unlock; - } - - /* Set output at the encoder */ - ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, - s_routing, 0, enc_out_index, 0); - if (ret) - goto unlock; - - /* - * It is assumed that venc or external encoder will set a default - * mode in the sub device. For external encoder or LCD pannel output, - * we also need to set up the lcd port for the required mode. So setup - * the lcd port for the default mode that is configured in the board - * arch/arm/mach-davinci/board-dm355-evm.setup file for the external - * encoder. - */ - ret = vpbe_get_mode_info(vpbe_dev, - cfg->outputs[index].default_mode, index); - if (!ret) { - struct osd_state *osd_device = vpbe_dev->osd_device; - - osd_device->ops.set_left_margin(osd_device, - vpbe_dev->current_timings.left_margin); - osd_device->ops.set_top_margin(osd_device, - vpbe_dev->current_timings.upper_margin); - vpbe_dev->current_sd_index = sd_index; - vpbe_dev->current_out_index = index; - } -unlock: - mutex_unlock(&vpbe_dev->lock); - return ret; -} - -static int vpbe_set_default_output(struct vpbe_device *vpbe_dev) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - int i; - - for (i = 0; i < cfg->num_outputs; i++) { - if (!strcmp(def_output, - cfg->outputs[i].output.name)) { - int ret = vpbe_set_output(vpbe_dev, i); - - if (!ret) - vpbe_dev->current_out_index = i; - return ret; - } - } - return 0; -} - -/** - * vpbe_get_output - Get output - * @vpbe_dev: vpbe device ptr - * - * return current vpbe output to the index - */ -static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev) -{ - return vpbe_dev->current_out_index; -} - -/* - * vpbe_s_dv_timings - Set the given preset timings in the encoder - * - * Sets the timings if supported by the current encoder. Return the status. - * 0 - success & -EINVAL on error - */ -static int vpbe_s_dv_timings(struct vpbe_device *vpbe_dev, - struct v4l2_dv_timings *dv_timings) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - int out_index = vpbe_dev->current_out_index; - struct vpbe_output *output = &cfg->outputs[out_index]; - int sd_index = vpbe_dev->current_sd_index; - int ret, i; - - - if (!(cfg->outputs[out_index].output.capabilities & - V4L2_OUT_CAP_DV_TIMINGS)) - return -ENODATA; - - for (i = 0; i < output->num_modes; i++) { - if (output->modes[i].timings_type == VPBE_ENC_DV_TIMINGS && - !memcmp(&output->modes[i].dv_timings, - dv_timings, sizeof(*dv_timings))) - break; - } - if (i >= output->num_modes) - return -EINVAL; - vpbe_dev->current_timings = output->modes[i]; - mutex_lock(&vpbe_dev->lock); - - ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, - s_dv_timings, dv_timings); - if (!ret && vpbe_dev->amp) { - /* Call amplifier subdevice */ - ret = v4l2_subdev_call(vpbe_dev->amp, video, - s_dv_timings, dv_timings); - } - /* set the lcd controller output for the given mode */ - if (!ret) { - struct osd_state *osd_device = vpbe_dev->osd_device; - - osd_device->ops.set_left_margin(osd_device, - vpbe_dev->current_timings.left_margin); - osd_device->ops.set_top_margin(osd_device, - vpbe_dev->current_timings.upper_margin); - } - mutex_unlock(&vpbe_dev->lock); - - return ret; -} - -/* - * vpbe_g_dv_timings - Get the timings in the current encoder - * - * Get the timings in the current encoder. Return the status. 0 - success - * -EINVAL on error - */ -static int vpbe_g_dv_timings(struct vpbe_device *vpbe_dev, - struct v4l2_dv_timings *dv_timings) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - int out_index = vpbe_dev->current_out_index; - - if (!(cfg->outputs[out_index].output.capabilities & - V4L2_OUT_CAP_DV_TIMINGS)) - return -ENODATA; - - if (vpbe_dev->current_timings.timings_type & - VPBE_ENC_DV_TIMINGS) { - *dv_timings = vpbe_dev->current_timings.dv_timings; - return 0; - } - - return -EINVAL; -} - -/* - * vpbe_enum_dv_timings - Enumerate the dv timings in the current encoder - * - * Get the timings in the current encoder. Return the status. 0 - success - * -EINVAL on error - */ -static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev, - struct v4l2_enum_dv_timings *timings) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - int out_index = vpbe_dev->current_out_index; - struct vpbe_output *output = &cfg->outputs[out_index]; - int j = 0; - int i; - - if (!(output->output.capabilities & V4L2_OUT_CAP_DV_TIMINGS)) - return -ENODATA; - - for (i = 0; i < output->num_modes; i++) { - if (output->modes[i].timings_type == VPBE_ENC_DV_TIMINGS) { - if (j == timings->index) - break; - j++; - } - } - - if (i == output->num_modes) - return -EINVAL; - timings->timings = output->modes[i].dv_timings; - return 0; -} - -/* - * vpbe_s_std - Set the given standard in the encoder - * - * Sets the standard if supported by the current encoder. Return the status. - * 0 - success & -EINVAL on error - */ -static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id std_id) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - int out_index = vpbe_dev->current_out_index; - int sd_index = vpbe_dev->current_sd_index; - int ret; - - if (!(cfg->outputs[out_index].output.capabilities & - V4L2_OUT_CAP_STD)) - return -ENODATA; - - ret = vpbe_get_std_info(vpbe_dev, std_id); - if (ret) - return ret; - - mutex_lock(&vpbe_dev->lock); - - ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, - s_std_output, std_id); - /* set the lcd controller output for the given mode */ - if (!ret) { - struct osd_state *osd_device = vpbe_dev->osd_device; - - osd_device->ops.set_left_margin(osd_device, - vpbe_dev->current_timings.left_margin); - osd_device->ops.set_top_margin(osd_device, - vpbe_dev->current_timings.upper_margin); - } - mutex_unlock(&vpbe_dev->lock); - - return ret; -} - -/* - * vpbe_g_std - Get the standard in the current encoder - * - * Get the standard in the current encoder. Return the status. 0 - success - * -EINVAL on error - */ -static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) -{ - struct vpbe_enc_mode_info *cur_timings = &vpbe_dev->current_timings; - struct vpbe_config *cfg = vpbe_dev->cfg; - int out_index = vpbe_dev->current_out_index; - - if (!(cfg->outputs[out_index].output.capabilities & V4L2_OUT_CAP_STD)) - return -ENODATA; - - if (cur_timings->timings_type & VPBE_ENC_STD) { - *std_id = cur_timings->std_id; - return 0; - } - - return -EINVAL; -} - -/* - * vpbe_set_mode - Set mode in the current encoder using mode info - * - * Use the mode string to decide what timings to set in the encoder - * This is typically useful when fbset command is used to change the current - * timings by specifying a string to indicate the timings. - */ -static int vpbe_set_mode(struct vpbe_device *vpbe_dev, - struct vpbe_enc_mode_info *mode_info) -{ - struct vpbe_enc_mode_info *preset_mode = NULL; - struct vpbe_config *cfg = vpbe_dev->cfg; - struct v4l2_dv_timings dv_timings; - struct osd_state *osd_device; - int out_index = vpbe_dev->current_out_index; - int i; - - if (!mode_info || !mode_info->name) - return -EINVAL; - - for (i = 0; i < cfg->outputs[out_index].num_modes; i++) { - if (!strcmp(mode_info->name, - cfg->outputs[out_index].modes[i].name)) { - preset_mode = &cfg->outputs[out_index].modes[i]; - /* - * it may be one of the 3 timings type. Check and - * invoke right API - */ - if (preset_mode->timings_type & VPBE_ENC_STD) - return vpbe_s_std(vpbe_dev, - preset_mode->std_id); - if (preset_mode->timings_type & - VPBE_ENC_DV_TIMINGS) { - dv_timings = - preset_mode->dv_timings; - return vpbe_s_dv_timings(vpbe_dev, &dv_timings); - } - } - } - - /* Only custom timing should reach here */ - if (!preset_mode) - return -EINVAL; - - mutex_lock(&vpbe_dev->lock); - - osd_device = vpbe_dev->osd_device; - vpbe_dev->current_timings = *preset_mode; - osd_device->ops.set_left_margin(osd_device, - vpbe_dev->current_timings.left_margin); - osd_device->ops.set_top_margin(osd_device, - vpbe_dev->current_timings.upper_margin); - - mutex_unlock(&vpbe_dev->lock); - return 0; -} - -static int vpbe_set_default_mode(struct vpbe_device *vpbe_dev) -{ - int ret; - - ret = vpbe_get_std_info_by_name(vpbe_dev, def_mode); - if (ret) - return ret; - - /* set the default mode in the encoder */ - return vpbe_set_mode(vpbe_dev, &vpbe_dev->current_timings); -} - -static int platform_device_get(struct device *dev, void *data) -{ - struct platform_device *pdev = to_platform_device(dev); - struct vpbe_device *vpbe_dev = data; - - if (strstr(pdev->name, "vpbe-osd")) - vpbe_dev->osd_device = platform_get_drvdata(pdev); - if (strstr(pdev->name, "vpbe-venc")) - vpbe_dev->venc_device = dev_get_platdata(&pdev->dev); - - return 0; -} - -/** - * vpbe_initialize() - Initialize the vpbe display controller - * @dev: Master and slave device ptr - * @vpbe_dev: vpbe device ptr - * - * Master frame buffer device drivers calls this to initialize vpbe - * display controller. This will then registers v4l2 device and the sub - * devices and sets a current encoder sub device for display. v4l2 display - * device driver is the master and frame buffer display device driver is - * the slave. Frame buffer display driver checks the initialized during - * probe and exit if not initialized. Returns status. - */ -static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) -{ - struct encoder_config_info *enc_info; - struct amp_config_info *amp_info; - struct v4l2_subdev **enc_subdev; - struct osd_state *osd_device; - struct i2c_adapter *i2c_adap; - int num_encoders; - int ret = 0; - int err; - int i; - - /* - * v4l2 abd FBDev frame buffer devices will get the vpbe_dev pointer - * from the platform device by iteration of platform drivers and - * matching with device name - */ - if (!vpbe_dev || !dev) { - printk(KERN_ERR "Null device pointers.\n"); - return -ENODEV; - } - - if (vpbe_dev->initialized) - return 0; - - mutex_lock(&vpbe_dev->lock); - - if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { - /* We have dac clock available for platform */ - vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac"); - if (IS_ERR(vpbe_dev->dac_clk)) { - ret = PTR_ERR(vpbe_dev->dac_clk); - goto fail_mutex_unlock; - } - if (clk_prepare_enable(vpbe_dev->dac_clk)) { - ret = -ENODEV; - clk_put(vpbe_dev->dac_clk); - goto fail_mutex_unlock; - } - } - - /* first enable vpss clocks */ - vpss_enable_clock(VPSS_VPBE_CLOCK, 1); - - /* First register a v4l2 device */ - ret = v4l2_device_register(dev, &vpbe_dev->v4l2_dev); - if (ret) { - v4l2_err(dev->driver, - "Unable to register v4l2 device.\n"); - goto fail_clk_put; - } - v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n"); - - err = bus_for_each_dev(&platform_bus_type, NULL, vpbe_dev, - platform_device_get); - if (err < 0) { - ret = err; - goto fail_dev_unregister; - } - - vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev, - vpbe_dev->cfg->venc.module_name); - /* register venc sub device */ - if (!vpbe_dev->venc) { - v4l2_err(&vpbe_dev->v4l2_dev, - "vpbe unable to init venc sub device\n"); - ret = -ENODEV; - goto fail_dev_unregister; - } - /* initialize osd device */ - osd_device = vpbe_dev->osd_device; - if (osd_device->ops.initialize) { - err = osd_device->ops.initialize(osd_device); - if (err) { - v4l2_err(&vpbe_dev->v4l2_dev, - "unable to initialize the OSD device"); - ret = -ENOMEM; - goto fail_dev_unregister; - } - } - - /* - * Register any external encoders that are configured. At index 0 we - * store venc sd index. - */ - num_encoders = vpbe_dev->cfg->num_ext_encoders + 1; - vpbe_dev->encoders = kmalloc_array(num_encoders, - sizeof(*vpbe_dev->encoders), - GFP_KERNEL); - if (!vpbe_dev->encoders) { - ret = -ENOMEM; - goto fail_dev_unregister; - } - - i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id); - for (i = 0; i < (vpbe_dev->cfg->num_ext_encoders + 1); i++) { - if (i == 0) { - /* venc is at index 0 */ - enc_subdev = &vpbe_dev->encoders[i]; - *enc_subdev = vpbe_dev->venc; - continue; - } - enc_info = &vpbe_dev->cfg->ext_encoders[i]; - if (enc_info->is_i2c) { - enc_subdev = &vpbe_dev->encoders[i]; - *enc_subdev = v4l2_i2c_new_subdev_board( - &vpbe_dev->v4l2_dev, i2c_adap, - &enc_info->board_info, NULL); - if (*enc_subdev) - v4l2_info(&vpbe_dev->v4l2_dev, - "v4l2 sub device %s registered\n", - enc_info->module_name); - else { - v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s failed to register", - enc_info->module_name); - ret = -ENODEV; - goto fail_kfree_encoders; - } - } else - v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders currently not supported"); - } - /* Add amplifier subdevice for dm365 */ - if ((strcmp(vpbe_dev->cfg->module_name, "dm365-vpbe-display") == 0) && - vpbe_dev->cfg->amp) { - amp_info = vpbe_dev->cfg->amp; - if (amp_info->is_i2c) { - vpbe_dev->amp = v4l2_i2c_new_subdev_board( - &vpbe_dev->v4l2_dev, i2c_adap, - &_info->board_info, NULL); - if (!vpbe_dev->amp) { - v4l2_err(&vpbe_dev->v4l2_dev, - "amplifier %s failed to register", - amp_info->module_name); - ret = -ENODEV; - goto fail_kfree_encoders; - } - v4l2_info(&vpbe_dev->v4l2_dev, - "v4l2 sub device %s registered\n", - amp_info->module_name); - } else { - vpbe_dev->amp = NULL; - v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c amplifiers currently not supported"); - } - } else { - vpbe_dev->amp = NULL; - } - - /* set the current encoder and output to that of venc by default */ - vpbe_dev->current_sd_index = 0; - vpbe_dev->current_out_index = 0; - - mutex_unlock(&vpbe_dev->lock); - - printk(KERN_NOTICE "Setting default output to %s\n", def_output); - ret = vpbe_set_default_output(vpbe_dev); - if (ret) { - v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s", - def_output); - goto fail_kfree_amp; - } - - printk(KERN_NOTICE "Setting default mode to %s\n", def_mode); - ret = vpbe_set_default_mode(vpbe_dev); - if (ret) { - v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s", - def_mode); - goto fail_kfree_amp; - } - vpbe_dev->initialized = 1; - /* TBD handling of bootargs for default output and mode */ - return 0; - -fail_kfree_amp: - mutex_lock(&vpbe_dev->lock); - kfree(vpbe_dev->amp); -fail_kfree_encoders: - kfree(vpbe_dev->encoders); -fail_dev_unregister: - v4l2_device_unregister(&vpbe_dev->v4l2_dev); -fail_clk_put: - if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { - clk_disable_unprepare(vpbe_dev->dac_clk); - clk_put(vpbe_dev->dac_clk); - } -fail_mutex_unlock: - mutex_unlock(&vpbe_dev->lock); - return ret; -} - -/** - * vpbe_deinitialize() - de-initialize the vpbe display controller - * @dev: Master and slave device ptr - * @vpbe_dev: vpbe device ptr - * - * vpbe_master and slave frame buffer devices calls this to de-initialize - * the display controller. It is called when master and slave device - * driver modules are removed and no longer requires the display controller. - */ -static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev) -{ - v4l2_device_unregister(&vpbe_dev->v4l2_dev); - if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { - clk_disable_unprepare(vpbe_dev->dac_clk); - clk_put(vpbe_dev->dac_clk); - } - - kfree(vpbe_dev->amp); - kfree(vpbe_dev->encoders); - vpbe_dev->initialized = 0; - /* disable vpss clocks */ - vpss_enable_clock(VPSS_VPBE_CLOCK, 0); -} - -static const struct vpbe_device_ops vpbe_dev_ops = { - .enum_outputs = vpbe_enum_outputs, - .set_output = vpbe_set_output, - .get_output = vpbe_get_output, - .s_dv_timings = vpbe_s_dv_timings, - .g_dv_timings = vpbe_g_dv_timings, - .enum_dv_timings = vpbe_enum_dv_timings, - .s_std = vpbe_s_std, - .g_std = vpbe_g_std, - .initialize = vpbe_initialize, - .deinitialize = vpbe_deinitialize, - .get_mode_info = vpbe_get_current_mode_info, - .set_mode = vpbe_set_mode, -}; - -static int vpbe_probe(struct platform_device *pdev) -{ - struct vpbe_device *vpbe_dev; - struct vpbe_config *cfg; - - if (!pdev->dev.platform_data) { - v4l2_err(pdev->dev.driver, "No platform data\n"); - return -ENODEV; - } - cfg = pdev->dev.platform_data; - - if (!cfg->module_name[0] || - !cfg->osd.module_name[0] || - !cfg->venc.module_name[0]) { - v4l2_err(pdev->dev.driver, "vpbe display module names not defined\n"); - return -EINVAL; - } - - vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL); - if (!vpbe_dev) - return -ENOMEM; - - vpbe_dev->cfg = cfg; - vpbe_dev->ops = vpbe_dev_ops; - vpbe_dev->pdev = &pdev->dev; - - if (cfg->outputs->num_modes > 0) - vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0]; - else { - kfree(vpbe_dev); - return -ENODEV; - } - - /* set the driver data in platform device */ - platform_set_drvdata(pdev, vpbe_dev); - mutex_init(&vpbe_dev->lock); - - return 0; -} - -static int vpbe_remove(struct platform_device *device) -{ - struct vpbe_device *vpbe_dev = platform_get_drvdata(device); - - kfree(vpbe_dev); - - return 0; -} - -static struct platform_driver vpbe_driver = { - .driver = { - .name = "vpbe_controller", - }, - .probe = vpbe_probe, - .remove = vpbe_remove, -}; - -module_platform_driver(vpbe_driver); diff --git a/drivers/media/platform/ti/davinci/vpbe_display.c b/drivers/media/platform/ti/davinci/vpbe_display.c deleted file mode 100644 index 9ea70817538e..000000000000 --- a/drivers/media/platform/ti/davinci/vpbe_display.c +++ /dev/null @@ -1,1510 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/ - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/string.h> -#include <linux/wait.h> -#include <linux/time.h> -#include <linux/platform_device.h> -#include <linux/irq.h> -#include <linux/mm.h> -#include <linux/mutex.h> -#include <linux/videodev2.h> -#include <linux/slab.h> - - -#include <media/v4l2-dev.h> -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-device.h> -#include <media/davinci/vpbe_display.h> -#include <media/davinci/vpbe_types.h> -#include <media/davinci/vpbe.h> -#include <media/davinci/vpbe_venc.h> -#include <media/davinci/vpbe_osd.h> -#include "vpbe_venc_regs.h" - -#define VPBE_DISPLAY_DRIVER "vpbe-v4l2" - -static int debug; - -#define VPBE_DEFAULT_NUM_BUFS 3 - -module_param(debug, int, 0644); - -static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev, - struct vpbe_layer *layer); - -static int venc_is_second_field(struct vpbe_display *disp_dev) -{ - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - int ret, val; - - ret = v4l2_subdev_call(vpbe_dev->venc, - core, - command, - VENC_GET_FLD, - &val); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Error in getting Field ID 0\n"); - return 1; - } - return val; -} - -static void vpbe_isr_even_field(struct vpbe_display *disp_obj, - struct vpbe_layer *layer) -{ - if (layer->cur_frm == layer->next_frm) - return; - - layer->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns(); - vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); - /* Make cur_frm pointing to next_frm */ - layer->cur_frm = layer->next_frm; -} - -static void vpbe_isr_odd_field(struct vpbe_display *disp_obj, - struct vpbe_layer *layer) -{ - struct osd_state *osd_device = disp_obj->osd_device; - unsigned long addr; - - spin_lock(&disp_obj->dma_queue_lock); - if (list_empty(&layer->dma_queue) || - (layer->cur_frm != layer->next_frm)) { - spin_unlock(&disp_obj->dma_queue_lock); - return; - } - /* - * one field is displayed configure - * the next frame if it is available - * otherwise hold on current frame - * Get next from the buffer queue - */ - layer->next_frm = list_entry(layer->dma_queue.next, - struct vpbe_disp_buffer, list); - /* Remove that from the buffer queue */ - list_del(&layer->next_frm->list); - spin_unlock(&disp_obj->dma_queue_lock); - /* Mark state of the frame to active */ - layer->next_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; - addr = vb2_dma_contig_plane_dma_addr(&layer->next_frm->vb.vb2_buf, 0); - osd_device->ops.start_layer(osd_device, - layer->layer_info.id, - addr, - disp_obj->cbcr_ofst); -} - -/* interrupt service routine */ -static irqreturn_t venc_isr(int irq, void *arg) -{ - struct vpbe_display *disp_dev = (struct vpbe_display *)arg; - struct vpbe_layer *layer; - static unsigned last_event; - unsigned event = 0; - int fid; - int i; - - if (!arg || !disp_dev->dev[0]) - return IRQ_HANDLED; - - if (venc_is_second_field(disp_dev)) - event |= VENC_SECOND_FIELD; - else - event |= VENC_FIRST_FIELD; - - if (event == (last_event & ~VENC_END_OF_FRAME)) { - /* - * If the display is non-interlaced, then we need to flag the - * end-of-frame event at every interrupt regardless of the - * value of the FIDST bit. We can conclude that the display is - * non-interlaced if the value of the FIDST bit is unchanged - * from the previous interrupt. - */ - event |= VENC_END_OF_FRAME; - } else if (event == VENC_SECOND_FIELD) { - /* end-of-frame for interlaced display */ - event |= VENC_END_OF_FRAME; - } - last_event = event; - - for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { - layer = disp_dev->dev[i]; - - if (!vb2_start_streaming_called(&layer->buffer_queue)) - continue; - - if (layer->layer_first_int) { - layer->layer_first_int = 0; - continue; - } - /* Check the field format */ - if ((V4L2_FIELD_NONE == layer->pix_fmt.field) && - (event & VENC_END_OF_FRAME)) { - /* Progressive mode */ - - vpbe_isr_even_field(disp_dev, layer); - vpbe_isr_odd_field(disp_dev, layer); - } else { - /* Interlaced mode */ - - layer->field_id ^= 1; - if (event & VENC_FIRST_FIELD) - fid = 0; - else - fid = 1; - - /* - * If field id does not match with store - * field id - */ - if (fid != layer->field_id) { - /* Make them in sync */ - layer->field_id = fid; - continue; - } - /* - * device field id and local field id are - * in sync. If this is even field - */ - if (0 == fid) - vpbe_isr_even_field(disp_dev, layer); - else /* odd field */ - vpbe_isr_odd_field(disp_dev, layer); - } - } - - return IRQ_HANDLED; -} - -/* - * vpbe_buffer_prepare() - * This is the callback function called from vb2_qbuf() function - * the buffer is prepared and user space virtual address is converted into - * physical address - */ -static int vpbe_buffer_prepare(struct vb2_buffer *vb) -{ - struct vb2_queue *q = vb->vb2_queue; - struct vpbe_layer *layer = vb2_get_drv_priv(q); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - unsigned long addr; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "vpbe_buffer_prepare\n"); - - vb2_set_plane_payload(vb, 0, layer->pix_fmt.sizeimage); - if (vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) - return -EINVAL; - - addr = vb2_dma_contig_plane_dma_addr(vb, 0); - if (!IS_ALIGNED(addr, 8)) { - v4l2_err(&vpbe_dev->v4l2_dev, - "buffer_prepare:offset is not aligned to 32 bytes\n"); - return -EINVAL; - } - return 0; -} - -/* - * vpbe_buffer_setup() - * This function allocates memory for the buffers - */ -static int -vpbe_buffer_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], struct device *alloc_devs[]) - -{ - /* Get the file handle object and layer object */ - struct vpbe_layer *layer = vb2_get_drv_priv(vq); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n"); - - /* Store number of buffers allocated in numbuffer member */ - if (vq->num_buffers + *nbuffers < VPBE_DEFAULT_NUM_BUFS) - *nbuffers = VPBE_DEFAULT_NUM_BUFS - vq->num_buffers; - - if (*nplanes) - return sizes[0] < layer->pix_fmt.sizeimage ? -EINVAL : 0; - - *nplanes = 1; - sizes[0] = layer->pix_fmt.sizeimage; - - return 0; -} - -/* - * vpbe_buffer_queue() - * This function adds the buffer to DMA queue - */ -static void vpbe_buffer_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - /* Get the file handle object and layer object */ - struct vpbe_disp_buffer *buf = container_of(vbuf, - struct vpbe_disp_buffer, vb); - struct vpbe_layer *layer = vb2_get_drv_priv(vb->vb2_queue); - struct vpbe_display *disp = layer->disp_dev; - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - unsigned long flags; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "vpbe_buffer_queue\n"); - - /* add the buffer to the DMA queue */ - spin_lock_irqsave(&disp->dma_queue_lock, flags); - list_add_tail(&buf->list, &layer->dma_queue); - spin_unlock_irqrestore(&disp->dma_queue_lock, flags); -} - -static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct vpbe_layer *layer = vb2_get_drv_priv(vq); - struct osd_state *osd_device = layer->disp_dev->osd_device; - int ret; - - osd_device->ops.disable_layer(osd_device, layer->layer_info.id); - - /* Get the next frame from the buffer queue */ - layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next, - struct vpbe_disp_buffer, list); - /* Remove buffer from the buffer queue */ - list_del(&layer->cur_frm->list); - /* Mark state of the current frame to active */ - layer->cur_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; - /* Initialize field_id and started member */ - layer->field_id = 0; - - /* Set parameters in OSD and VENC */ - ret = vpbe_set_osd_display_params(layer->disp_dev, layer); - if (ret < 0) { - struct vpbe_disp_buffer *buf, *tmp; - - vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - list_for_each_entry_safe(buf, tmp, &layer->dma_queue, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - } - - return ret; - } - - /* - * if request format is yuv420 semiplanar, need to - * enable both video windows - */ - layer->layer_first_int = 1; - - return ret; -} - -static void vpbe_stop_streaming(struct vb2_queue *vq) -{ - struct vpbe_layer *layer = vb2_get_drv_priv(vq); - struct osd_state *osd_device = layer->disp_dev->osd_device; - struct vpbe_display *disp = layer->disp_dev; - unsigned long flags; - - if (!vb2_is_streaming(vq)) - return; - - osd_device->ops.disable_layer(osd_device, layer->layer_info.id); - - /* release all active buffers */ - spin_lock_irqsave(&disp->dma_queue_lock, flags); - if (layer->cur_frm == layer->next_frm) { - vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } else { - if (layer->cur_frm) - vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - if (layer->next_frm) - vb2_buffer_done(&layer->next_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } - - while (!list_empty(&layer->dma_queue)) { - layer->next_frm = list_entry(layer->dma_queue.next, - struct vpbe_disp_buffer, list); - list_del(&layer->next_frm->list); - vb2_buffer_done(&layer->next_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } - spin_unlock_irqrestore(&disp->dma_queue_lock, flags); -} - -static const struct vb2_ops video_qops = { - .queue_setup = vpbe_buffer_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .buf_prepare = vpbe_buffer_prepare, - .start_streaming = vpbe_start_streaming, - .stop_streaming = vpbe_stop_streaming, - .buf_queue = vpbe_buffer_queue, -}; - -static -struct vpbe_layer* -_vpbe_display_get_other_win_layer(struct vpbe_display *disp_dev, - struct vpbe_layer *layer) -{ - enum vpbe_display_device_id thiswin, otherwin; - thiswin = layer->device_id; - - otherwin = (thiswin == VPBE_DISPLAY_DEVICE_0) ? - VPBE_DISPLAY_DEVICE_1 : VPBE_DISPLAY_DEVICE_0; - return disp_dev->dev[otherwin]; -} - -static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev, - struct vpbe_layer *layer) -{ - struct osd_layer_config *cfg = &layer->layer_info.config; - struct osd_state *osd_device = disp_dev->osd_device; - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - unsigned long addr; - int ret; - - addr = vb2_dma_contig_plane_dma_addr(&layer->cur_frm->vb.vb2_buf, 0); - /* Set address in the display registers */ - osd_device->ops.start_layer(osd_device, - layer->layer_info.id, - addr, - disp_dev->cbcr_ofst); - - ret = osd_device->ops.enable_layer(osd_device, - layer->layer_info.id, 0); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Error in enabling osd window layer 0\n"); - return -1; - } - - /* Enable the window */ - layer->layer_info.enable = 1; - if (cfg->pixfmt == PIXFMT_NV12) { - struct vpbe_layer *otherlayer = - _vpbe_display_get_other_win_layer(disp_dev, layer); - - ret = osd_device->ops.enable_layer(osd_device, - otherlayer->layer_info.id, 1); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Error in enabling osd window layer 1\n"); - return -1; - } - otherlayer->layer_info.enable = 1; - } - return 0; -} - -static void -vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev, - struct vpbe_layer *layer, - int expected_xsize, int expected_ysize) -{ - struct display_layer_info *layer_info = &layer->layer_info; - struct v4l2_pix_format *pixfmt = &layer->pix_fmt; - struct osd_layer_config *cfg = &layer->layer_info.config; - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - int calculated_xsize; - int h_exp = 0; - int v_exp = 0; - int h_scale; - int v_scale; - - v4l2_std_id standard_id = vpbe_dev->current_timings.std_id; - - /* - * Application initially set the image format. Current display - * size is obtained from the vpbe display controller. expected_xsize - * and expected_ysize are set through S_SELECTION ioctl. Based on this, - * driver will calculate the scale factors for vertical and - * horizontal direction so that the image is displayed scaled - * and expanded. Application uses expansion to display the image - * in a square pixel. Otherwise it is displayed using displays - * pixel aspect ratio.It is expected that application chooses - * the crop coordinates for cropped or scaled display. if crop - * size is less than the image size, it is displayed cropped or - * it is displayed scaled and/or expanded. - * - * to begin with, set the crop window same as expected. Later we - * will override with scaled window size - */ - - cfg->xsize = pixfmt->width; - cfg->ysize = pixfmt->height; - layer_info->h_zoom = ZOOM_X1; /* no horizontal zoom */ - layer_info->v_zoom = ZOOM_X1; /* no horizontal zoom */ - layer_info->h_exp = H_EXP_OFF; /* no horizontal zoom */ - layer_info->v_exp = V_EXP_OFF; /* no horizontal zoom */ - - if (pixfmt->width < expected_xsize) { - h_scale = vpbe_dev->current_timings.xres / pixfmt->width; - if (h_scale < 2) - h_scale = 1; - else if (h_scale >= 4) - h_scale = 4; - else - h_scale = 2; - cfg->xsize *= h_scale; - if (cfg->xsize < expected_xsize) { - if ((standard_id & V4L2_STD_525_60) || - (standard_id & V4L2_STD_625_50)) { - calculated_xsize = (cfg->xsize * - VPBE_DISPLAY_H_EXP_RATIO_N) / - VPBE_DISPLAY_H_EXP_RATIO_D; - if (calculated_xsize <= expected_xsize) { - h_exp = 1; - cfg->xsize = calculated_xsize; - } - } - } - if (h_scale == 2) - layer_info->h_zoom = ZOOM_X2; - else if (h_scale == 4) - layer_info->h_zoom = ZOOM_X4; - if (h_exp) - layer_info->h_exp = H_EXP_9_OVER_8; - } else { - /* no scaling, only cropping. Set display area to crop area */ - cfg->xsize = expected_xsize; - } - - if (pixfmt->height < expected_ysize) { - v_scale = expected_ysize / pixfmt->height; - if (v_scale < 2) - v_scale = 1; - else if (v_scale >= 4) - v_scale = 4; - else - v_scale = 2; - cfg->ysize *= v_scale; - if (cfg->ysize < expected_ysize) { - if ((standard_id & V4L2_STD_625_50)) { - calculated_xsize = (cfg->ysize * - VPBE_DISPLAY_V_EXP_RATIO_N) / - VPBE_DISPLAY_V_EXP_RATIO_D; - if (calculated_xsize <= expected_ysize) { - v_exp = 1; - cfg->ysize = calculated_xsize; - } - } - } - if (v_scale == 2) - layer_info->v_zoom = ZOOM_X2; - else if (v_scale == 4) - layer_info->v_zoom = ZOOM_X4; - if (v_exp) - layer_info->v_exp = V_EXP_6_OVER_5; - } else { - /* no scaling, only cropping. Set display area to crop area */ - cfg->ysize = expected_ysize; - } - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "crop display xsize = %d, ysize = %d\n", - cfg->xsize, cfg->ysize); -} - -static void vpbe_disp_adj_position(struct vpbe_display *disp_dev, - struct vpbe_layer *layer, - int top, int left) -{ - struct osd_layer_config *cfg = &layer->layer_info.config; - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - - cfg->xpos = min((unsigned int)left, - vpbe_dev->current_timings.xres - cfg->xsize); - cfg->ypos = min((unsigned int)top, - vpbe_dev->current_timings.yres - cfg->ysize); - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "new xpos = %d, ypos = %d\n", - cfg->xpos, cfg->ypos); -} - -static void vpbe_disp_check_window_params(struct vpbe_display *disp_dev, - struct v4l2_rect *c) -{ - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - - if ((c->width == 0) || - ((c->width + c->left) > vpbe_dev->current_timings.xres)) - c->width = vpbe_dev->current_timings.xres - c->left; - - if ((c->height == 0) || ((c->height + c->top) > - vpbe_dev->current_timings.yres)) - c->height = vpbe_dev->current_timings.yres - c->top; - - /* window height must be even for interlaced display */ - if (vpbe_dev->current_timings.interlaced) - c->height &= (~0x01); - -} - -/* - * vpbe_try_format() - * If user application provides width and height, and have bytesperline set - * to zero, driver calculates bytesperline and sizeimage based on hardware - * limits. - */ -static int vpbe_try_format(struct vpbe_display *disp_dev, - struct v4l2_pix_format *pixfmt, int check) -{ - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - int min_height = 1; - int min_width = 32; - int max_height; - int max_width; - int bpp; - - if ((pixfmt->pixelformat != V4L2_PIX_FMT_UYVY) && - (pixfmt->pixelformat != V4L2_PIX_FMT_NV12)) - /* choose default as V4L2_PIX_FMT_UYVY */ - pixfmt->pixelformat = V4L2_PIX_FMT_UYVY; - - /* Check the field format */ - if ((pixfmt->field != V4L2_FIELD_INTERLACED) && - (pixfmt->field != V4L2_FIELD_NONE)) { - if (vpbe_dev->current_timings.interlaced) - pixfmt->field = V4L2_FIELD_INTERLACED; - else - pixfmt->field = V4L2_FIELD_NONE; - } - - if (pixfmt->field == V4L2_FIELD_INTERLACED) - min_height = 2; - - if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) - bpp = 1; - else - bpp = 2; - - max_width = vpbe_dev->current_timings.xres; - max_height = vpbe_dev->current_timings.yres; - - min_width /= bpp; - - if (!pixfmt->width || (pixfmt->width < min_width) || - (pixfmt->width > max_width)) { - pixfmt->width = vpbe_dev->current_timings.xres; - } - - if (!pixfmt->height || (pixfmt->height < min_height) || - (pixfmt->height > max_height)) { - pixfmt->height = vpbe_dev->current_timings.yres; - } - - if (pixfmt->bytesperline < (pixfmt->width * bpp)) - pixfmt->bytesperline = pixfmt->width * bpp; - - /* Make the bytesperline 32 byte aligned */ - pixfmt->bytesperline = ((pixfmt->width * bpp + 31) & ~31); - - if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height + - (pixfmt->bytesperline * pixfmt->height >> 1); - else - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; - - return 0; -} - -static int vpbe_display_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - snprintf(cap->driver, sizeof(cap->driver), "%s", - dev_name(vpbe_dev->pdev)); - strscpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card)); - - return 0; -} - -static int vpbe_display_s_selection(struct file *file, void *priv, - struct v4l2_selection *sel) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_display *disp_dev = layer->disp_dev; - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - struct osd_layer_config *cfg = &layer->layer_info.config; - struct osd_state *osd_device = disp_dev->osd_device; - struct v4l2_rect rect = sel->r; - int ret; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "VIDIOC_S_SELECTION, layer id = %d\n", layer->device_id); - - if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || - sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - if (rect.top < 0) - rect.top = 0; - if (rect.left < 0) - rect.left = 0; - - vpbe_disp_check_window_params(disp_dev, &rect); - - osd_device->ops.get_layer_config(osd_device, - layer->layer_info.id, cfg); - - vpbe_disp_calculate_scale_factor(disp_dev, layer, - rect.width, - rect.height); - vpbe_disp_adj_position(disp_dev, layer, rect.top, - rect.left); - ret = osd_device->ops.set_layer_config(osd_device, - layer->layer_info.id, cfg); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Error in set layer config:\n"); - return -EINVAL; - } - - /* apply zooming and h or v expansion */ - osd_device->ops.set_zoom(osd_device, - layer->layer_info.id, - layer->layer_info.h_zoom, - layer->layer_info.v_zoom); - ret = osd_device->ops.set_vid_expansion(osd_device, - layer->layer_info.h_exp, - layer->layer_info.v_exp); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Error in set vid expansion:\n"); - return -EINVAL; - } - - if ((layer->layer_info.h_zoom != ZOOM_X1) || - (layer->layer_info.v_zoom != ZOOM_X1) || - (layer->layer_info.h_exp != H_EXP_OFF) || - (layer->layer_info.v_exp != V_EXP_OFF)) - /* Enable expansion filter */ - osd_device->ops.set_interpolation_filter(osd_device, 1); - else - osd_device->ops.set_interpolation_filter(osd_device, 0); - - sel->r = rect; - return 0; -} - -static int vpbe_display_g_selection(struct file *file, void *priv, - struct v4l2_selection *sel) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct osd_layer_config *cfg = &layer->layer_info.config; - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - struct osd_state *osd_device = layer->disp_dev->osd_device; - struct v4l2_rect *rect = &sel->r; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "VIDIOC_G_SELECTION, layer id = %d\n", - layer->device_id); - - if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - osd_device->ops.get_layer_config(osd_device, - layer->layer_info.id, cfg); - rect->top = cfg->ypos; - rect->left = cfg->xpos; - rect->width = cfg->xsize; - rect->height = cfg->ysize; - break; - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP_BOUNDS: - rect->left = 0; - rect->top = 0; - rect->width = vpbe_dev->current_timings.xres; - rect->height = vpbe_dev->current_timings.yres; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int vpbe_display_g_pixelaspect(struct file *file, void *priv, - int type, struct v4l2_fract *f) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n"); - - if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - *f = vpbe_dev->current_timings.aspect; - return 0; -} - -static int vpbe_display_g_fmt(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "VIDIOC_G_FMT, layer id = %d\n", - layer->device_id); - - /* If buffer type is video output */ - if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { - v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); - return -EINVAL; - } - /* Fill in the information about format */ - fmt->fmt.pix = layer->pix_fmt; - - return 0; -} - -static int vpbe_display_enum_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "VIDIOC_ENUM_FMT, layer id = %d\n", - layer->device_id); - if (fmt->index > 1) { - v4l2_err(&vpbe_dev->v4l2_dev, "Invalid format index\n"); - return -EINVAL; - } - - /* Fill in the information about format */ - if (fmt->index == 0) - fmt->pixelformat = V4L2_PIX_FMT_UYVY; - else - fmt->pixelformat = V4L2_PIX_FMT_NV12; - - return 0; -} - -static int vpbe_display_s_fmt(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_display *disp_dev = layer->disp_dev; - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - struct osd_layer_config *cfg = &layer->layer_info.config; - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - struct osd_state *osd_device = disp_dev->osd_device; - int ret; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "VIDIOC_S_FMT, layer id = %d\n", - layer->device_id); - - if (vb2_is_busy(&layer->buffer_queue)) - return -EBUSY; - - if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "invalid type\n"); - return -EINVAL; - } - /* Check for valid pixel format */ - ret = vpbe_try_format(disp_dev, pixfmt, 1); - if (ret) - return ret; - - /* YUV420 is requested, check availability of the - other video window */ - - layer->pix_fmt = *pixfmt; - if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) { - struct vpbe_layer *otherlayer; - - otherlayer = _vpbe_display_get_other_win_layer(disp_dev, layer); - /* if other layer is available, only - * claim it, do not configure it - */ - ret = osd_device->ops.request_layer(osd_device, - otherlayer->layer_info.id); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Display Manager failed to allocate layer\n"); - return -EBUSY; - } - } - - /* Get osd layer config */ - osd_device->ops.get_layer_config(osd_device, - layer->layer_info.id, cfg); - /* Store the pixel format in the layer object */ - cfg->xsize = pixfmt->width; - cfg->ysize = pixfmt->height; - cfg->line_length = pixfmt->bytesperline; - cfg->ypos = 0; - cfg->xpos = 0; - cfg->interlaced = vpbe_dev->current_timings.interlaced; - - if (V4L2_PIX_FMT_UYVY == pixfmt->pixelformat) - cfg->pixfmt = PIXFMT_YCBCRI; - - /* Change of the default pixel format for both video windows */ - if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) { - struct vpbe_layer *otherlayer; - cfg->pixfmt = PIXFMT_NV12; - otherlayer = _vpbe_display_get_other_win_layer(disp_dev, - layer); - otherlayer->layer_info.config.pixfmt = PIXFMT_NV12; - } - - /* Set the layer config in the osd window */ - ret = osd_device->ops.set_layer_config(osd_device, - layer->layer_info.id, cfg); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Error in S_FMT params:\n"); - return -EINVAL; - } - - /* Readback and fill the local copy of current pix format */ - osd_device->ops.get_layer_config(osd_device, - layer->layer_info.id, cfg); - - return 0; -} - -static int vpbe_display_try_fmt(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_display *disp_dev = layer->disp_dev; - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_TRY_FMT\n"); - - if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { - v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); - return -EINVAL; - } - - /* Check for valid field format */ - return vpbe_try_format(disp_dev, pixfmt, 0); - -} - -/* - * vpbe_display_s_std - Set the given standard in the encoder - * - * Sets the standard if supported by the current encoder. Return the status. - * 0 - success & -EINVAL on error - */ -static int vpbe_display_s_std(struct file *file, void *priv, - v4l2_std_id std_id) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - int ret; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_STD\n"); - - if (vb2_is_busy(&layer->buffer_queue)) - return -EBUSY; - - if (vpbe_dev->ops.s_std) { - ret = vpbe_dev->ops.s_std(vpbe_dev, std_id); - if (ret) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Failed to set standard for sub devices\n"); - return -EINVAL; - } - } else { - return -EINVAL; - } - - return 0; -} - -/* - * vpbe_display_g_std - Get the standard in the current encoder - * - * Get the standard in the current encoder. Return the status. 0 - success - * -EINVAL on error - */ -static int vpbe_display_g_std(struct file *file, void *priv, - v4l2_std_id *std_id) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_STD\n"); - - /* Get the standard from the current encoder */ - if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) { - *std_id = vpbe_dev->current_timings.std_id; - return 0; - } - - return -EINVAL; -} - -/* - * vpbe_display_enum_output - enumerate outputs - * - * Enumerates the outputs available at the vpbe display - * returns the status, -EINVAL if end of output list - */ -static int vpbe_display_enum_output(struct file *file, void *priv, - struct v4l2_output *output) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - int ret; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n"); - - /* Enumerate outputs */ - if (!vpbe_dev->ops.enum_outputs) - return -EINVAL; - - ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output); - if (ret) { - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "Failed to enumerate outputs\n"); - return -EINVAL; - } - - return 0; -} - -/* - * vpbe_display_s_output - Set output to - * the output specified by the index - */ -static int vpbe_display_s_output(struct file *file, void *priv, - unsigned int i) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - int ret; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_OUTPUT\n"); - - if (vb2_is_busy(&layer->buffer_queue)) - return -EBUSY; - - if (!vpbe_dev->ops.set_output) - return -EINVAL; - - ret = vpbe_dev->ops.set_output(vpbe_dev, i); - if (ret) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Failed to set output for sub devices\n"); - return -EINVAL; - } - - return 0; -} - -/* - * vpbe_display_g_output - Get output from subdevice - * for a given by the index - */ -static int vpbe_display_g_output(struct file *file, void *priv, - unsigned int *i) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_OUTPUT\n"); - /* Get the standard from the current encoder */ - *i = vpbe_dev->current_out_index; - - return 0; -} - -/* - * vpbe_display_enum_dv_timings - Enumerate the dv timings - * - * enum the timings in the current encoder. Return the status. 0 - success - * -EINVAL on error - */ -static int -vpbe_display_enum_dv_timings(struct file *file, void *priv, - struct v4l2_enum_dv_timings *timings) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - int ret; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_TIMINGS\n"); - - /* Enumerate outputs */ - if (!vpbe_dev->ops.enum_dv_timings) - return -EINVAL; - - ret = vpbe_dev->ops.enum_dv_timings(vpbe_dev, timings); - if (ret) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Failed to enumerate dv timings info\n"); - return -EINVAL; - } - - return 0; -} - -/* - * vpbe_display_s_dv_timings - Set the dv timings - * - * Set the timings in the current encoder. Return the status. 0 - success - * -EINVAL on error - */ -static int -vpbe_display_s_dv_timings(struct file *file, void *priv, - struct v4l2_dv_timings *timings) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - int ret; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_TIMINGS\n"); - - if (vb2_is_busy(&layer->buffer_queue)) - return -EBUSY; - - /* Set the given standard in the encoder */ - if (!vpbe_dev->ops.s_dv_timings) - return -EINVAL; - - ret = vpbe_dev->ops.s_dv_timings(vpbe_dev, timings); - if (ret) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Failed to set the dv timings info\n"); - return -EINVAL; - } - - return 0; -} - -/* - * vpbe_display_g_dv_timings - Set the dv timings - * - * Get the timings in the current encoder. Return the status. 0 - success - * -EINVAL on error - */ -static int -vpbe_display_g_dv_timings(struct file *file, void *priv, - struct v4l2_dv_timings *dv_timings) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_TIMINGS\n"); - - /* Get the given standard in the encoder */ - - if (vpbe_dev->current_timings.timings_type & - VPBE_ENC_DV_TIMINGS) { - *dv_timings = vpbe_dev->current_timings.dv_timings; - } else { - return -EINVAL; - } - - return 0; -} - -/* - * vpbe_display_open() - * It creates object of file handle structure and stores it in private_data - * member of filepointer - */ -static int vpbe_display_open(struct file *file) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_display *disp_dev = layer->disp_dev; - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - struct osd_state *osd_device = disp_dev->osd_device; - int err; - - /* creating context for file descriptor */ - err = v4l2_fh_open(file); - if (err) { - v4l2_err(&vpbe_dev->v4l2_dev, "v4l2_fh_open failed\n"); - return err; - } - - /* leaving if layer is already initialized */ - if (!v4l2_fh_is_singular_file(file)) - return err; - - if (!layer->usrs) { - if (mutex_lock_interruptible(&layer->opslock)) - return -ERESTARTSYS; - /* First claim the layer for this device */ - err = osd_device->ops.request_layer(osd_device, - layer->layer_info.id); - mutex_unlock(&layer->opslock); - if (err < 0) { - /* Couldn't get layer */ - v4l2_err(&vpbe_dev->v4l2_dev, - "Display Manager failed to allocate layer\n"); - v4l2_fh_release(file); - return -EINVAL; - } - } - /* Increment layer usrs counter */ - layer->usrs++; - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "vpbe display device opened successfully\n"); - return 0; -} - -/* - * vpbe_display_release() - * This function deletes buffer queue, frees the buffers and the davinci - * display file * handle - */ -static int vpbe_display_release(struct file *file) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct osd_layer_config *cfg = &layer->layer_info.config; - struct vpbe_display *disp_dev = layer->disp_dev; - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - struct osd_state *osd_device = disp_dev->osd_device; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n"); - - mutex_lock(&layer->opslock); - - osd_device->ops.disable_layer(osd_device, - layer->layer_info.id); - /* Decrement layer usrs counter */ - layer->usrs--; - /* If this file handle has initialize encoder device, reset it */ - if (!layer->usrs) { - if (cfg->pixfmt == PIXFMT_NV12) { - struct vpbe_layer *otherlayer; - otherlayer = - _vpbe_display_get_other_win_layer(disp_dev, layer); - osd_device->ops.disable_layer(osd_device, - otherlayer->layer_info.id); - osd_device->ops.release_layer(osd_device, - otherlayer->layer_info.id); - } - osd_device->ops.disable_layer(osd_device, - layer->layer_info.id); - osd_device->ops.release_layer(osd_device, - layer->layer_info.id); - } - - _vb2_fop_release(file, NULL); - mutex_unlock(&layer->opslock); - - disp_dev->cbcr_ofst = 0; - - return 0; -} - -/* vpbe capture ioctl operations */ -static const struct v4l2_ioctl_ops vpbe_ioctl_ops = { - .vidioc_querycap = vpbe_display_querycap, - .vidioc_g_fmt_vid_out = vpbe_display_g_fmt, - .vidioc_enum_fmt_vid_out = vpbe_display_enum_fmt, - .vidioc_s_fmt_vid_out = vpbe_display_s_fmt, - .vidioc_try_fmt_vid_out = vpbe_display_try_fmt, - - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - .vidioc_expbuf = vb2_ioctl_expbuf, - - .vidioc_g_pixelaspect = vpbe_display_g_pixelaspect, - .vidioc_g_selection = vpbe_display_g_selection, - .vidioc_s_selection = vpbe_display_s_selection, - - .vidioc_s_std = vpbe_display_s_std, - .vidioc_g_std = vpbe_display_g_std, - - .vidioc_enum_output = vpbe_display_enum_output, - .vidioc_s_output = vpbe_display_s_output, - .vidioc_g_output = vpbe_display_g_output, - - .vidioc_s_dv_timings = vpbe_display_s_dv_timings, - .vidioc_g_dv_timings = vpbe_display_g_dv_timings, - .vidioc_enum_dv_timings = vpbe_display_enum_dv_timings, -}; - -static const struct v4l2_file_operations vpbe_fops = { - .owner = THIS_MODULE, - .open = vpbe_display_open, - .release = vpbe_display_release, - .unlocked_ioctl = video_ioctl2, - .mmap = vb2_fop_mmap, - .poll = vb2_fop_poll, -}; - -static int vpbe_device_get(struct device *dev, void *data) -{ - struct platform_device *pdev = to_platform_device(dev); - struct vpbe_display *vpbe_disp = data; - - if (strcmp("vpbe_controller", pdev->name) == 0) - vpbe_disp->vpbe_dev = platform_get_drvdata(pdev); - - if (strstr(pdev->name, "vpbe-osd")) - vpbe_disp->osd_device = platform_get_drvdata(pdev); - - return 0; -} - -static int init_vpbe_layer(int i, struct vpbe_display *disp_dev, - struct platform_device *pdev) -{ - struct vpbe_layer *vpbe_display_layer = NULL; - struct video_device *vbd = NULL; - - /* Allocate memory for four plane display objects */ - disp_dev->dev[i] = kzalloc(sizeof(*disp_dev->dev[i]), GFP_KERNEL); - if (!disp_dev->dev[i]) - return -ENOMEM; - - spin_lock_init(&disp_dev->dev[i]->irqlock); - mutex_init(&disp_dev->dev[i]->opslock); - - /* Get the pointer to the layer object */ - vpbe_display_layer = disp_dev->dev[i]; - vbd = &vpbe_display_layer->video_dev; - /* Initialize field of video device */ - vbd->release = video_device_release_empty; - vbd->fops = &vpbe_fops; - vbd->ioctl_ops = &vpbe_ioctl_ops; - vbd->minor = -1; - vbd->v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev; - vbd->lock = &vpbe_display_layer->opslock; - vbd->vfl_dir = VFL_DIR_TX; - vbd->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - - if (disp_dev->vpbe_dev->current_timings.timings_type & - VPBE_ENC_STD) - vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50); - - snprintf(vbd->name, sizeof(vbd->name), - "DaVinci_VPBE Display_DRIVER_V%d.%d.%d", - (VPBE_DISPLAY_VERSION_CODE >> 16) & 0xff, - (VPBE_DISPLAY_VERSION_CODE >> 8) & 0xff, - (VPBE_DISPLAY_VERSION_CODE) & 0xff); - - vpbe_display_layer->device_id = i; - - vpbe_display_layer->layer_info.id = - ((i == VPBE_DISPLAY_DEVICE_0) ? WIN_VID0 : WIN_VID1); - - - return 0; -} - -static int register_device(struct vpbe_layer *vpbe_display_layer, - struct vpbe_display *disp_dev, - struct platform_device *pdev) -{ - int err; - - v4l2_info(&disp_dev->vpbe_dev->v4l2_dev, - "Trying to register VPBE display device.\n"); - v4l2_info(&disp_dev->vpbe_dev->v4l2_dev, - "layer=%p,layer->video_dev=%p\n", - vpbe_display_layer, - &vpbe_display_layer->video_dev); - - vpbe_display_layer->video_dev.queue = &vpbe_display_layer->buffer_queue; - err = video_register_device(&vpbe_display_layer->video_dev, - VFL_TYPE_VIDEO, - -1); - if (err) - return -ENODEV; - - vpbe_display_layer->disp_dev = disp_dev; - /* set the driver data in platform device */ - platform_set_drvdata(pdev, disp_dev); - video_set_drvdata(&vpbe_display_layer->video_dev, - vpbe_display_layer); - - return 0; -} - - - -/* - * vpbe_display_probe() - * This function creates device entries by register itself to the V4L2 driver - * and initializes fields of each layer objects - */ -static int vpbe_display_probe(struct platform_device *pdev) -{ - struct vpbe_display *disp_dev; - struct v4l2_device *v4l2_dev; - struct resource *res = NULL; - struct vb2_queue *q; - int k; - int i; - int err; - int irq; - - printk(KERN_DEBUG "vpbe_display_probe\n"); - /* Allocate memory for vpbe_display */ - disp_dev = devm_kzalloc(&pdev->dev, sizeof(*disp_dev), GFP_KERNEL); - if (!disp_dev) - return -ENOMEM; - - spin_lock_init(&disp_dev->dma_queue_lock); - /* - * Scan all the platform devices to find the vpbe - * controller device and get the vpbe_dev object - */ - err = bus_for_each_dev(&platform_bus_type, NULL, disp_dev, - vpbe_device_get); - if (err < 0) - return err; - - v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev; - /* Initialize the vpbe display controller */ - if (disp_dev->vpbe_dev->ops.initialize) { - err = disp_dev->vpbe_dev->ops.initialize(&pdev->dev, - disp_dev->vpbe_dev); - if (err) { - v4l2_err(v4l2_dev, "Error initing vpbe\n"); - err = -ENOMEM; - goto probe_out; - } - } - - for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { - if (init_vpbe_layer(i, disp_dev, pdev)) { - err = -ENODEV; - goto probe_out; - } - } - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - v4l2_err(v4l2_dev, "Unable to get VENC interrupt resource\n"); - err = -ENODEV; - goto probe_out; - } - - irq = res->start; - err = devm_request_irq(&pdev->dev, irq, venc_isr, 0, - VPBE_DISPLAY_DRIVER, disp_dev); - if (err) { - v4l2_err(v4l2_dev, "VPBE IRQ request failed\n"); - goto probe_out; - } - - for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { - /* initialize vb2 queue */ - q = &disp_dev->dev[i]->buffer_queue; - memset(q, 0, sizeof(*q)); - q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - q->drv_priv = disp_dev->dev[i]; - q->ops = &video_qops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct vpbe_disp_buffer); - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 1; - q->lock = &disp_dev->dev[i]->opslock; - q->dev = disp_dev->vpbe_dev->pdev; - err = vb2_queue_init(q); - if (err) { - v4l2_err(v4l2_dev, "vb2_queue_init() failed\n"); - goto probe_out; - } - - INIT_LIST_HEAD(&disp_dev->dev[i]->dma_queue); - - if (register_device(disp_dev->dev[i], disp_dev, pdev)) { - err = -ENODEV; - goto probe_out; - } - } - - v4l2_dbg(1, debug, v4l2_dev, - "Successfully completed the probing of vpbe v4l2 device\n"); - - return 0; - -probe_out: - for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) { - /* Unregister video device */ - if (disp_dev->dev[k]) { - video_unregister_device(&disp_dev->dev[k]->video_dev); - kfree(disp_dev->dev[k]); - } - } - return err; -} - -/* - * vpbe_display_remove() - * It un-register hardware layer from V4L2 driver - */ -static int vpbe_display_remove(struct platform_device *pdev) -{ - struct vpbe_layer *vpbe_display_layer; - struct vpbe_display *disp_dev = platform_get_drvdata(pdev); - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - int i; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n"); - - /* deinitialize the vpbe display controller */ - if (vpbe_dev->ops.deinitialize) - vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev); - /* un-register device */ - for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { - /* Get the pointer to the layer object */ - vpbe_display_layer = disp_dev->dev[i]; - /* Unregister video device */ - video_unregister_device(&vpbe_display_layer->video_dev); - - } - for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { - kfree(disp_dev->dev[i]); - disp_dev->dev[i] = NULL; - } - - return 0; -} - -static struct platform_driver vpbe_display_driver = { - .driver = { - .name = VPBE_DISPLAY_DRIVER, - .bus = &platform_bus_type, - }, - .probe = vpbe_display_probe, - .remove = vpbe_display_remove, -}; - -module_platform_driver(vpbe_display_driver); - -MODULE_DESCRIPTION("TI DM644x/DM355/DM365 VPBE Display controller"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/platform/ti/davinci/vpbe_osd.c b/drivers/media/platform/ti/davinci/vpbe_osd.c deleted file mode 100644 index 32f7ef547c82..000000000000 --- a/drivers/media/platform/ti/davinci/vpbe_osd.c +++ /dev/null @@ -1,1582 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2007-2010 Texas Instruments Inc - * Copyright (C) 2007 MontaVista Software, Inc. - * - * Andy Lowe (alowe@mvista.com), MontaVista Software - * - Initial version - * Murali Karicheri (mkaricheri@gmail.com), Texas Instruments Ltd. - * - ported to sub device interface - */ -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/kernel.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/slab.h> - -#include <media/davinci/vpss.h> -#include <media/v4l2-device.h> -#include <media/davinci/vpbe_types.h> -#include <media/davinci/vpbe_osd.h> - -#include <linux/io.h> -#include "vpbe_osd_regs.h" - -#define MODULE_NAME "davinci-vpbe-osd" - -static const struct platform_device_id vpbe_osd_devtype[] = { - { - .name = DM644X_VPBE_OSD_SUBDEV_NAME, - .driver_data = VPBE_VERSION_1, - }, { - .name = DM365_VPBE_OSD_SUBDEV_NAME, - .driver_data = VPBE_VERSION_2, - }, { - .name = DM355_VPBE_OSD_SUBDEV_NAME, - .driver_data = VPBE_VERSION_3, - }, - { - /* sentinel */ - } -}; - -MODULE_DEVICE_TABLE(platform, vpbe_osd_devtype); - -/* register access routines */ -static inline u32 __always_unused osd_read(struct osd_state *sd, u32 offset) -{ - struct osd_state *osd = sd; - - return readl(osd->osd_base + offset); -} - -static inline u32 osd_write(struct osd_state *sd, u32 val, u32 offset) -{ - struct osd_state *osd = sd; - - writel(val, osd->osd_base + offset); - - return val; -} - -static inline u32 osd_set(struct osd_state *sd, u32 mask, u32 offset) -{ - struct osd_state *osd = sd; - - void __iomem *addr = osd->osd_base + offset; - u32 val = readl(addr) | mask; - - writel(val, addr); - - return val; -} - -static inline u32 osd_clear(struct osd_state *sd, u32 mask, u32 offset) -{ - struct osd_state *osd = sd; - - void __iomem *addr = osd->osd_base + offset; - u32 val = readl(addr) & ~mask; - - writel(val, addr); - - return val; -} - -static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val, - u32 offset) -{ - struct osd_state *osd = sd; - - void __iomem *addr = osd->osd_base + offset; - u32 new_val = (readl(addr) & ~mask) | (val & mask); - - writel(new_val, addr); - - return new_val; -} - -/* define some macros for layer and pixfmt classification */ -#define is_osd_win(layer) (((layer) == WIN_OSD0) || ((layer) == WIN_OSD1)) -#define is_vid_win(layer) (((layer) == WIN_VID0) || ((layer) == WIN_VID1)) -#define is_rgb_pixfmt(pixfmt) \ - (((pixfmt) == PIXFMT_RGB565) || ((pixfmt) == PIXFMT_RGB888)) -#define is_yc_pixfmt(pixfmt) \ - (((pixfmt) == PIXFMT_YCBCRI) || ((pixfmt) == PIXFMT_YCRCBI) || \ - ((pixfmt) == PIXFMT_NV12)) -#define MAX_WIN_SIZE OSD_VIDWIN0XP_V0X -#define MAX_LINE_LENGTH (OSD_VIDWIN0OFST_V0LO << 5) - -/** - * _osd_dm6446_vid0_pingpong() - field inversion fix for DM6446 - * @sd: ptr to struct osd_state - * @field_inversion: inversion flag - * @fb_base_phys: frame buffer address - * @lconfig: ptr to layer config - * - * This routine implements a workaround for the field signal inversion silicon - * erratum described in Advisory 1.3.8 for the DM6446. The fb_base_phys and - * lconfig parameters apply to the vid0 window. This routine should be called - * whenever the vid0 layer configuration or start address is modified, or when - * the OSD field inversion setting is modified. - * Returns: 1 if the ping-pong buffers need to be toggled in the vsync isr, or - * 0 otherwise - */ -static int _osd_dm6446_vid0_pingpong(struct osd_state *sd, - int field_inversion, - unsigned long fb_base_phys, - const struct osd_layer_config *lconfig) -{ - struct osd_platform_data *pdata; - - pdata = (struct osd_platform_data *)sd->dev->platform_data; - if (pdata != NULL && pdata->field_inv_wa_enable) { - - if (!field_inversion || !lconfig->interlaced) { - osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); - osd_write(sd, fb_base_phys & ~0x1F, OSD_PPVWIN0ADR); - osd_modify(sd, OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, 0, - OSD_MISCCTL); - return 0; - } else { - unsigned miscctl = OSD_MISCCTL_PPRV; - - osd_write(sd, - (fb_base_phys & ~0x1F) - lconfig->line_length, - OSD_VIDWIN0ADR); - osd_write(sd, - (fb_base_phys & ~0x1F) + lconfig->line_length, - OSD_PPVWIN0ADR); - osd_modify(sd, - OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, miscctl, - OSD_MISCCTL); - - return 1; - } - } - - return 0; -} - -static void _osd_set_field_inversion(struct osd_state *sd, int enable) -{ - unsigned fsinv = 0; - - if (enable) - fsinv = OSD_MODE_FSINV; - - osd_modify(sd, OSD_MODE_FSINV, fsinv, OSD_MODE); -} - -static void _osd_set_blink_attribute(struct osd_state *sd, int enable, - enum osd_blink_interval blink) -{ - u32 osdatrmd = 0; - - if (enable) { - osdatrmd |= OSD_OSDATRMD_BLNK; - osdatrmd |= blink << OSD_OSDATRMD_BLNKINT_SHIFT; - } - /* caller must ensure that OSD1 is configured in attribute mode */ - osd_modify(sd, OSD_OSDATRMD_BLNKINT | OSD_OSDATRMD_BLNK, osdatrmd, - OSD_OSDATRMD); -} - -static void _osd_set_rom_clut(struct osd_state *sd, - enum osd_rom_clut rom_clut) -{ - if (rom_clut == ROM_CLUT0) - osd_clear(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL); - else - osd_set(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL); -} - -static void _osd_set_palette_map(struct osd_state *sd, - enum osd_win_layer osdwin, - unsigned char pixel_value, - unsigned char clut_index, - enum osd_pix_format pixfmt) -{ - static const int map_2bpp[] = { 0, 5, 10, 15 }; - static const int map_1bpp[] = { 0, 15 }; - int bmp_offset; - int bmp_shift; - int bmp_mask; - int bmp_reg; - - switch (pixfmt) { - case PIXFMT_1BPP: - bmp_reg = map_1bpp[pixel_value & 0x1]; - break; - case PIXFMT_2BPP: - bmp_reg = map_2bpp[pixel_value & 0x3]; - break; - case PIXFMT_4BPP: - bmp_reg = pixel_value & 0xf; - break; - default: - return; - } - - switch (osdwin) { - case OSDWIN_OSD0: - bmp_offset = OSD_W0BMP01 + (bmp_reg >> 1) * sizeof(u32); - break; - case OSDWIN_OSD1: - bmp_offset = OSD_W1BMP01 + (bmp_reg >> 1) * sizeof(u32); - break; - default: - return; - } - - if (bmp_reg & 1) { - bmp_shift = 8; - bmp_mask = 0xff << 8; - } else { - bmp_shift = 0; - bmp_mask = 0xff; - } - - osd_modify(sd, bmp_mask, clut_index << bmp_shift, bmp_offset); -} - -static void _osd_set_rec601_attenuation(struct osd_state *sd, - enum osd_win_layer osdwin, int enable) -{ - switch (osdwin) { - case OSDWIN_OSD0: - osd_modify(sd, OSD_OSDWIN0MD_ATN0E, - enable ? OSD_OSDWIN0MD_ATN0E : 0, - OSD_OSDWIN0MD); - if (sd->vpbe_type == VPBE_VERSION_1) - osd_modify(sd, OSD_OSDWIN0MD_ATN0E, - enable ? OSD_OSDWIN0MD_ATN0E : 0, - OSD_OSDWIN0MD); - else if ((sd->vpbe_type == VPBE_VERSION_3) || - (sd->vpbe_type == VPBE_VERSION_2)) - osd_modify(sd, OSD_EXTMODE_ATNOSD0EN, - enable ? OSD_EXTMODE_ATNOSD0EN : 0, - OSD_EXTMODE); - break; - case OSDWIN_OSD1: - osd_modify(sd, OSD_OSDWIN1MD_ATN1E, - enable ? OSD_OSDWIN1MD_ATN1E : 0, - OSD_OSDWIN1MD); - if (sd->vpbe_type == VPBE_VERSION_1) - osd_modify(sd, OSD_OSDWIN1MD_ATN1E, - enable ? OSD_OSDWIN1MD_ATN1E : 0, - OSD_OSDWIN1MD); - else if ((sd->vpbe_type == VPBE_VERSION_3) || - (sd->vpbe_type == VPBE_VERSION_2)) - osd_modify(sd, OSD_EXTMODE_ATNOSD1EN, - enable ? OSD_EXTMODE_ATNOSD1EN : 0, - OSD_EXTMODE); - break; - } -} - -static void _osd_set_blending_factor(struct osd_state *sd, - enum osd_win_layer osdwin, - enum osd_blending_factor blend) -{ - switch (osdwin) { - case OSDWIN_OSD0: - osd_modify(sd, OSD_OSDWIN0MD_BLND0, - blend << OSD_OSDWIN0MD_BLND0_SHIFT, OSD_OSDWIN0MD); - break; - case OSDWIN_OSD1: - osd_modify(sd, OSD_OSDWIN1MD_BLND1, - blend << OSD_OSDWIN1MD_BLND1_SHIFT, OSD_OSDWIN1MD); - break; - } -} - -static void _osd_enable_rgb888_pixblend(struct osd_state *sd, - enum osd_win_layer osdwin) -{ - - osd_modify(sd, OSD_MISCCTL_BLDSEL, 0, OSD_MISCCTL); - switch (osdwin) { - case OSDWIN_OSD0: - osd_modify(sd, OSD_EXTMODE_OSD0BLDCHR, - OSD_EXTMODE_OSD0BLDCHR, OSD_EXTMODE); - break; - case OSDWIN_OSD1: - osd_modify(sd, OSD_EXTMODE_OSD1BLDCHR, - OSD_EXTMODE_OSD1BLDCHR, OSD_EXTMODE); - break; - } -} - -static void _osd_enable_color_key(struct osd_state *sd, - enum osd_win_layer osdwin, - unsigned colorkey, - enum osd_pix_format pixfmt) -{ - switch (pixfmt) { - case PIXFMT_1BPP: - case PIXFMT_2BPP: - case PIXFMT_4BPP: - case PIXFMT_8BPP: - if (sd->vpbe_type == VPBE_VERSION_3) { - switch (osdwin) { - case OSDWIN_OSD0: - osd_modify(sd, OSD_TRANSPBMPIDX_BMP0, - colorkey << - OSD_TRANSPBMPIDX_BMP0_SHIFT, - OSD_TRANSPBMPIDX); - break; - case OSDWIN_OSD1: - osd_modify(sd, OSD_TRANSPBMPIDX_BMP1, - colorkey << - OSD_TRANSPBMPIDX_BMP1_SHIFT, - OSD_TRANSPBMPIDX); - break; - } - } - break; - case PIXFMT_RGB565: - if (sd->vpbe_type == VPBE_VERSION_1) - osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS, - OSD_TRANSPVAL); - else if (sd->vpbe_type == VPBE_VERSION_3) - osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL, - OSD_TRANSPVALL); - break; - case PIXFMT_YCBCRI: - case PIXFMT_YCRCBI: - if (sd->vpbe_type == VPBE_VERSION_3) - osd_modify(sd, OSD_TRANSPVALU_Y, colorkey, - OSD_TRANSPVALU); - break; - case PIXFMT_RGB888: - if (sd->vpbe_type == VPBE_VERSION_3) { - osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL, - OSD_TRANSPVALL); - osd_modify(sd, OSD_TRANSPVALU_RGBU, colorkey >> 16, - OSD_TRANSPVALU); - } - break; - default: - break; - } - - switch (osdwin) { - case OSDWIN_OSD0: - osd_set(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD); - break; - case OSDWIN_OSD1: - osd_set(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD); - break; - } -} - -static void _osd_disable_color_key(struct osd_state *sd, - enum osd_win_layer osdwin) -{ - switch (osdwin) { - case OSDWIN_OSD0: - osd_clear(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD); - break; - case OSDWIN_OSD1: - osd_clear(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD); - break; - } -} - -static void _osd_set_osd_clut(struct osd_state *sd, - enum osd_win_layer osdwin, - enum osd_clut clut) -{ - u32 winmd = 0; - - switch (osdwin) { - case OSDWIN_OSD0: - if (clut == RAM_CLUT) - winmd |= OSD_OSDWIN0MD_CLUTS0; - osd_modify(sd, OSD_OSDWIN0MD_CLUTS0, winmd, OSD_OSDWIN0MD); - break; - case OSDWIN_OSD1: - if (clut == RAM_CLUT) - winmd |= OSD_OSDWIN1MD_CLUTS1; - osd_modify(sd, OSD_OSDWIN1MD_CLUTS1, winmd, OSD_OSDWIN1MD); - break; - } -} - -static void _osd_set_zoom(struct osd_state *sd, enum osd_layer layer, - enum osd_zoom_factor h_zoom, - enum osd_zoom_factor v_zoom) -{ - u32 winmd = 0; - - switch (layer) { - case WIN_OSD0: - winmd |= (h_zoom << OSD_OSDWIN0MD_OHZ0_SHIFT); - winmd |= (v_zoom << OSD_OSDWIN0MD_OVZ0_SHIFT); - osd_modify(sd, OSD_OSDWIN0MD_OHZ0 | OSD_OSDWIN0MD_OVZ0, winmd, - OSD_OSDWIN0MD); - break; - case WIN_VID0: - winmd |= (h_zoom << OSD_VIDWINMD_VHZ0_SHIFT); - winmd |= (v_zoom << OSD_VIDWINMD_VVZ0_SHIFT); - osd_modify(sd, OSD_VIDWINMD_VHZ0 | OSD_VIDWINMD_VVZ0, winmd, - OSD_VIDWINMD); - break; - case WIN_OSD1: - winmd |= (h_zoom << OSD_OSDWIN1MD_OHZ1_SHIFT); - winmd |= (v_zoom << OSD_OSDWIN1MD_OVZ1_SHIFT); - osd_modify(sd, OSD_OSDWIN1MD_OHZ1 | OSD_OSDWIN1MD_OVZ1, winmd, - OSD_OSDWIN1MD); - break; - case WIN_VID1: - winmd |= (h_zoom << OSD_VIDWINMD_VHZ1_SHIFT); - winmd |= (v_zoom << OSD_VIDWINMD_VVZ1_SHIFT); - osd_modify(sd, OSD_VIDWINMD_VHZ1 | OSD_VIDWINMD_VVZ1, winmd, - OSD_VIDWINMD); - break; - } -} - -static void _osd_disable_layer(struct osd_state *sd, enum osd_layer layer) -{ - switch (layer) { - case WIN_OSD0: - osd_clear(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD); - break; - case WIN_VID0: - osd_clear(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD); - break; - case WIN_OSD1: - /* disable attribute mode as well as disabling the window */ - osd_clear(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, - OSD_OSDWIN1MD); - break; - case WIN_VID1: - osd_clear(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD); - break; - } -} - -static void osd_disable_layer(struct osd_state *sd, enum osd_layer layer) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - unsigned long flags; - - spin_lock_irqsave(&osd->lock, flags); - - if (!win->is_enabled) { - spin_unlock_irqrestore(&osd->lock, flags); - return; - } - win->is_enabled = 0; - - _osd_disable_layer(sd, layer); - - spin_unlock_irqrestore(&osd->lock, flags); -} - -static void _osd_enable_attribute_mode(struct osd_state *sd) -{ - /* enable attribute mode for OSD1 */ - osd_set(sd, OSD_OSDWIN1MD_OASW, OSD_OSDWIN1MD); -} - -static void _osd_enable_layer(struct osd_state *sd, enum osd_layer layer) -{ - switch (layer) { - case WIN_OSD0: - osd_set(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD); - break; - case WIN_VID0: - osd_set(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD); - break; - case WIN_OSD1: - /* enable OSD1 and disable attribute mode */ - osd_modify(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, - OSD_OSDWIN1MD_OACT1, OSD_OSDWIN1MD); - break; - case WIN_VID1: - osd_set(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD); - break; - } -} - -static int osd_enable_layer(struct osd_state *sd, enum osd_layer layer, - int otherwin) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - struct osd_layer_config *cfg = &win->lconfig; - unsigned long flags; - - spin_lock_irqsave(&osd->lock, flags); - - /* - * use otherwin flag to know this is the other vid window - * in YUV420 mode, if is, skip this check - */ - if (!otherwin && (!win->is_allocated || - !win->fb_base_phys || - !cfg->line_length || - !cfg->xsize || - !cfg->ysize)) { - spin_unlock_irqrestore(&osd->lock, flags); - return -1; - } - - if (win->is_enabled) { - spin_unlock_irqrestore(&osd->lock, flags); - return 0; - } - win->is_enabled = 1; - - if (cfg->pixfmt != PIXFMT_OSD_ATTR) - _osd_enable_layer(sd, layer); - else { - _osd_enable_attribute_mode(sd); - _osd_set_blink_attribute(sd, osd->is_blinking, osd->blink); - } - - spin_unlock_irqrestore(&osd->lock, flags); - - return 0; -} - -#define OSD_SRC_ADDR_HIGH4 0x7800000 -#define OSD_SRC_ADDR_HIGH7 0x7F0000 -#define OSD_SRCADD_OFSET_SFT 23 -#define OSD_SRCADD_ADD_SFT 16 -#define OSD_WINADL_MASK 0xFFFF -#define OSD_WINOFST_MASK 0x1000 -#define VPBE_REG_BASE 0x80000000 - -static void _osd_start_layer(struct osd_state *sd, enum osd_layer layer, - unsigned long fb_base_phys, - unsigned long cbcr_ofst) -{ - - if (sd->vpbe_type == VPBE_VERSION_1) { - switch (layer) { - case WIN_OSD0: - osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR); - break; - case WIN_VID0: - osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); - break; - case WIN_OSD1: - osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR); - break; - case WIN_VID1: - osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR); - break; - } - } else if (sd->vpbe_type == VPBE_VERSION_3) { - unsigned long fb_offset_32 = - (fb_base_phys - VPBE_REG_BASE) >> 5; - - switch (layer) { - case WIN_OSD0: - osd_modify(sd, OSD_OSDWINADH_O0AH, - fb_offset_32 >> (OSD_SRCADD_ADD_SFT - - OSD_OSDWINADH_O0AH_SHIFT), - OSD_OSDWINADH); - osd_write(sd, fb_offset_32 & OSD_OSDWIN0ADL_O0AL, - OSD_OSDWIN0ADL); - break; - case WIN_VID0: - osd_modify(sd, OSD_VIDWINADH_V0AH, - fb_offset_32 >> (OSD_SRCADD_ADD_SFT - - OSD_VIDWINADH_V0AH_SHIFT), - OSD_VIDWINADH); - osd_write(sd, fb_offset_32 & OSD_VIDWIN0ADL_V0AL, - OSD_VIDWIN0ADL); - break; - case WIN_OSD1: - osd_modify(sd, OSD_OSDWINADH_O1AH, - fb_offset_32 >> (OSD_SRCADD_ADD_SFT - - OSD_OSDWINADH_O1AH_SHIFT), - OSD_OSDWINADH); - osd_write(sd, fb_offset_32 & OSD_OSDWIN1ADL_O1AL, - OSD_OSDWIN1ADL); - break; - case WIN_VID1: - osd_modify(sd, OSD_VIDWINADH_V1AH, - fb_offset_32 >> (OSD_SRCADD_ADD_SFT - - OSD_VIDWINADH_V1AH_SHIFT), - OSD_VIDWINADH); - osd_write(sd, fb_offset_32 & OSD_VIDWIN1ADL_V1AL, - OSD_VIDWIN1ADL); - break; - } - } else if (sd->vpbe_type == VPBE_VERSION_2) { - struct osd_window_state *win = &sd->win[layer]; - unsigned long fb_offset_32, cbcr_offset_32; - - fb_offset_32 = fb_base_phys - VPBE_REG_BASE; - if (cbcr_ofst) - cbcr_offset_32 = cbcr_ofst; - else - cbcr_offset_32 = win->lconfig.line_length * - win->lconfig.ysize; - cbcr_offset_32 += fb_offset_32; - fb_offset_32 = fb_offset_32 >> 5; - cbcr_offset_32 = cbcr_offset_32 >> 5; - /* - * DM365: start address is 27-bit long address b26 - b23 are - * in offset register b12 - b9, and * bit 26 has to be '1' - */ - if (win->lconfig.pixfmt == PIXFMT_NV12) { - switch (layer) { - case WIN_VID0: - case WIN_VID1: - /* Y is in VID0 */ - osd_modify(sd, OSD_VIDWIN0OFST_V0AH, - ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> - (OSD_SRCADD_OFSET_SFT - - OSD_WINOFST_AH_SHIFT)) | - OSD_WINOFST_MASK, OSD_VIDWIN0OFST); - osd_modify(sd, OSD_VIDWINADH_V0AH, - (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> - (OSD_SRCADD_ADD_SFT - - OSD_VIDWINADH_V0AH_SHIFT), - OSD_VIDWINADH); - osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, - OSD_VIDWIN0ADL); - /* CbCr is in VID1 */ - osd_modify(sd, OSD_VIDWIN1OFST_V1AH, - ((cbcr_offset_32 & - OSD_SRC_ADDR_HIGH4) >> - (OSD_SRCADD_OFSET_SFT - - OSD_WINOFST_AH_SHIFT)) | - OSD_WINOFST_MASK, OSD_VIDWIN1OFST); - osd_modify(sd, OSD_VIDWINADH_V1AH, - (cbcr_offset_32 & - OSD_SRC_ADDR_HIGH7) >> - (OSD_SRCADD_ADD_SFT - - OSD_VIDWINADH_V1AH_SHIFT), - OSD_VIDWINADH); - osd_write(sd, cbcr_offset_32 & OSD_WINADL_MASK, - OSD_VIDWIN1ADL); - break; - default: - break; - } - } - - switch (layer) { - case WIN_OSD0: - osd_modify(sd, OSD_OSDWIN0OFST_O0AH, - ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> - (OSD_SRCADD_OFSET_SFT - - OSD_WINOFST_AH_SHIFT)) | OSD_WINOFST_MASK, - OSD_OSDWIN0OFST); - osd_modify(sd, OSD_OSDWINADH_O0AH, - (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> - (OSD_SRCADD_ADD_SFT - - OSD_OSDWINADH_O0AH_SHIFT), OSD_OSDWINADH); - osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, - OSD_OSDWIN0ADL); - break; - case WIN_VID0: - if (win->lconfig.pixfmt != PIXFMT_NV12) { - osd_modify(sd, OSD_VIDWIN0OFST_V0AH, - ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> - (OSD_SRCADD_OFSET_SFT - - OSD_WINOFST_AH_SHIFT)) | - OSD_WINOFST_MASK, OSD_VIDWIN0OFST); - osd_modify(sd, OSD_VIDWINADH_V0AH, - (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> - (OSD_SRCADD_ADD_SFT - - OSD_VIDWINADH_V0AH_SHIFT), - OSD_VIDWINADH); - osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, - OSD_VIDWIN0ADL); - } - break; - case WIN_OSD1: - osd_modify(sd, OSD_OSDWIN1OFST_O1AH, - ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> - (OSD_SRCADD_OFSET_SFT - - OSD_WINOFST_AH_SHIFT)) | OSD_WINOFST_MASK, - OSD_OSDWIN1OFST); - osd_modify(sd, OSD_OSDWINADH_O1AH, - (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> - (OSD_SRCADD_ADD_SFT - - OSD_OSDWINADH_O1AH_SHIFT), - OSD_OSDWINADH); - osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, - OSD_OSDWIN1ADL); - break; - case WIN_VID1: - if (win->lconfig.pixfmt != PIXFMT_NV12) { - osd_modify(sd, OSD_VIDWIN1OFST_V1AH, - ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> - (OSD_SRCADD_OFSET_SFT - - OSD_WINOFST_AH_SHIFT)) | - OSD_WINOFST_MASK, OSD_VIDWIN1OFST); - osd_modify(sd, OSD_VIDWINADH_V1AH, - (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> - (OSD_SRCADD_ADD_SFT - - OSD_VIDWINADH_V1AH_SHIFT), - OSD_VIDWINADH); - osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, - OSD_VIDWIN1ADL); - } - break; - } - } -} - -static void osd_start_layer(struct osd_state *sd, enum osd_layer layer, - unsigned long fb_base_phys, - unsigned long cbcr_ofst) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - struct osd_layer_config *cfg = &win->lconfig; - unsigned long flags; - - spin_lock_irqsave(&osd->lock, flags); - - win->fb_base_phys = fb_base_phys & ~0x1F; - _osd_start_layer(sd, layer, fb_base_phys, cbcr_ofst); - - if (layer == WIN_VID0) { - osd->pingpong = - _osd_dm6446_vid0_pingpong(sd, osd->field_inversion, - win->fb_base_phys, - cfg); - } - - spin_unlock_irqrestore(&osd->lock, flags); -} - -static void osd_get_layer_config(struct osd_state *sd, enum osd_layer layer, - struct osd_layer_config *lconfig) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - unsigned long flags; - - spin_lock_irqsave(&osd->lock, flags); - - *lconfig = win->lconfig; - - spin_unlock_irqrestore(&osd->lock, flags); -} - -/** - * try_layer_config() - Try a specific configuration for the layer - * @sd: ptr to struct osd_state - * @layer: layer to configure - * @lconfig: layer configuration to try - * - * If the requested lconfig is completely rejected and the value of lconfig on - * exit is the current lconfig, then try_layer_config() returns 1. Otherwise, - * try_layer_config() returns 0. A return value of 0 does not necessarily mean - * that the value of lconfig on exit is identical to the value of lconfig on - * entry, but merely that it represents a change from the current lconfig. - */ -static int try_layer_config(struct osd_state *sd, enum osd_layer layer, - struct osd_layer_config *lconfig) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - int bad_config = 0; - - /* verify that the pixel format is compatible with the layer */ - switch (lconfig->pixfmt) { - case PIXFMT_1BPP: - case PIXFMT_2BPP: - case PIXFMT_4BPP: - case PIXFMT_8BPP: - case PIXFMT_RGB565: - if (osd->vpbe_type == VPBE_VERSION_1) - bad_config = !is_vid_win(layer); - break; - case PIXFMT_YCBCRI: - case PIXFMT_YCRCBI: - bad_config = !is_vid_win(layer); - break; - case PIXFMT_RGB888: - if (osd->vpbe_type == VPBE_VERSION_1) - bad_config = !is_vid_win(layer); - else if ((osd->vpbe_type == VPBE_VERSION_3) || - (osd->vpbe_type == VPBE_VERSION_2)) - bad_config = !is_osd_win(layer); - break; - case PIXFMT_NV12: - if (osd->vpbe_type != VPBE_VERSION_2) - bad_config = 1; - else - bad_config = is_osd_win(layer); - break; - case PIXFMT_OSD_ATTR: - bad_config = (layer != WIN_OSD1); - break; - default: - bad_config = 1; - break; - } - if (bad_config) { - /* - * The requested pixel format is incompatible with the layer, - * so keep the current layer configuration. - */ - *lconfig = win->lconfig; - return bad_config; - } - - /* DM6446: */ - /* only one OSD window at a time can use RGB pixel formats */ - if ((osd->vpbe_type == VPBE_VERSION_1) && - is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) { - enum osd_pix_format pixfmt; - - if (layer == WIN_OSD0) - pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt; - else - pixfmt = osd->win[WIN_OSD0].lconfig.pixfmt; - - if (is_rgb_pixfmt(pixfmt)) { - /* - * The other OSD window is already configured for an - * RGB, so keep the current layer configuration. - */ - *lconfig = win->lconfig; - return 1; - } - } - - /* DM6446: only one video window at a time can use RGB888 */ - if ((osd->vpbe_type == VPBE_VERSION_1) && is_vid_win(layer) && - lconfig->pixfmt == PIXFMT_RGB888) { - enum osd_pix_format pixfmt; - - if (layer == WIN_VID0) - pixfmt = osd->win[WIN_VID1].lconfig.pixfmt; - else - pixfmt = osd->win[WIN_VID0].lconfig.pixfmt; - - if (pixfmt == PIXFMT_RGB888) { - /* - * The other video window is already configured for - * RGB888, so keep the current layer configuration. - */ - *lconfig = win->lconfig; - return 1; - } - } - - /* window dimensions must be non-zero */ - if (!lconfig->line_length || !lconfig->xsize || !lconfig->ysize) { - *lconfig = win->lconfig; - return 1; - } - - /* round line_length up to a multiple of 32 */ - lconfig->line_length = ((lconfig->line_length + 31) / 32) * 32; - lconfig->line_length = - min(lconfig->line_length, (unsigned)MAX_LINE_LENGTH); - lconfig->xsize = min(lconfig->xsize, (unsigned)MAX_WIN_SIZE); - lconfig->ysize = min(lconfig->ysize, (unsigned)MAX_WIN_SIZE); - lconfig->xpos = min(lconfig->xpos, (unsigned)MAX_WIN_SIZE); - lconfig->ypos = min(lconfig->ypos, (unsigned)MAX_WIN_SIZE); - lconfig->interlaced = (lconfig->interlaced != 0); - if (lconfig->interlaced) { - /* ysize and ypos must be even for interlaced displays */ - lconfig->ysize &= ~1; - lconfig->ypos &= ~1; - } - - return 0; -} - -static void _osd_disable_vid_rgb888(struct osd_state *sd) -{ - /* - * The DM6446 supports RGB888 pixel format in a single video window. - * This routine disables RGB888 pixel format for both video windows. - * The caller must ensure that neither video window is currently - * configured for RGB888 pixel format. - */ - if (sd->vpbe_type == VPBE_VERSION_1) - osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL); -} - -static void _osd_enable_vid_rgb888(struct osd_state *sd, - enum osd_layer layer) -{ - /* - * The DM6446 supports RGB888 pixel format in a single video window. - * This routine enables RGB888 pixel format for the specified video - * window. The caller must ensure that the other video window is not - * currently configured for RGB888 pixel format, as this routine will - * disable RGB888 pixel format for the other window. - */ - if (sd->vpbe_type == VPBE_VERSION_1) { - if (layer == WIN_VID0) - osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, - OSD_MISCCTL_RGBEN, OSD_MISCCTL); - else if (layer == WIN_VID1) - osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, - OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, - OSD_MISCCTL); - } -} - -static void _osd_set_cbcr_order(struct osd_state *sd, - enum osd_pix_format pixfmt) -{ - /* - * The caller must ensure that all windows using YC pixfmt use the same - * Cb/Cr order. - */ - if (pixfmt == PIXFMT_YCBCRI) - osd_clear(sd, OSD_MODE_CS, OSD_MODE); - else if (pixfmt == PIXFMT_YCRCBI) - osd_set(sd, OSD_MODE_CS, OSD_MODE); -} - -static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, - const struct osd_layer_config *lconfig) -{ - u32 winmd = 0, winmd_mask = 0, bmw = 0; - - _osd_set_cbcr_order(sd, lconfig->pixfmt); - - switch (layer) { - case WIN_OSD0: - if (sd->vpbe_type == VPBE_VERSION_1) { - winmd_mask |= OSD_OSDWIN0MD_RGB0E; - if (lconfig->pixfmt == PIXFMT_RGB565) - winmd |= OSD_OSDWIN0MD_RGB0E; - } else if ((sd->vpbe_type == VPBE_VERSION_3) || - (sd->vpbe_type == VPBE_VERSION_2)) { - winmd_mask |= OSD_OSDWIN0MD_BMP0MD; - switch (lconfig->pixfmt) { - case PIXFMT_RGB565: - winmd |= (1 << - OSD_OSDWIN0MD_BMP0MD_SHIFT); - break; - case PIXFMT_RGB888: - winmd |= (2 << OSD_OSDWIN0MD_BMP0MD_SHIFT); - _osd_enable_rgb888_pixblend(sd, OSDWIN_OSD0); - break; - case PIXFMT_YCBCRI: - case PIXFMT_YCRCBI: - winmd |= (3 << OSD_OSDWIN0MD_BMP0MD_SHIFT); - break; - default: - break; - } - } - - winmd_mask |= OSD_OSDWIN0MD_BMW0 | OSD_OSDWIN0MD_OFF0; - - switch (lconfig->pixfmt) { - case PIXFMT_1BPP: - bmw = 0; - break; - case PIXFMT_2BPP: - bmw = 1; - break; - case PIXFMT_4BPP: - bmw = 2; - break; - case PIXFMT_8BPP: - bmw = 3; - break; - default: - break; - } - winmd |= (bmw << OSD_OSDWIN0MD_BMW0_SHIFT); - - if (lconfig->interlaced) - winmd |= OSD_OSDWIN0MD_OFF0; - - osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN0MD); - osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN0OFST); - osd_write(sd, lconfig->xpos, OSD_OSDWIN0XP); - osd_write(sd, lconfig->xsize, OSD_OSDWIN0XL); - if (lconfig->interlaced) { - osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN0YP); - osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN0YL); - } else { - osd_write(sd, lconfig->ypos, OSD_OSDWIN0YP); - osd_write(sd, lconfig->ysize, OSD_OSDWIN0YL); - } - break; - case WIN_VID0: - winmd_mask |= OSD_VIDWINMD_VFF0; - if (lconfig->interlaced) - winmd |= OSD_VIDWINMD_VFF0; - - osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD); - osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN0OFST); - osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP); - osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL); - /* - * For YUV420P format the register contents are - * duplicated in both VID registers - */ - if ((sd->vpbe_type == VPBE_VERSION_2) && - (lconfig->pixfmt == PIXFMT_NV12)) { - /* other window also */ - if (lconfig->interlaced) { - winmd_mask |= OSD_VIDWINMD_VFF1; - winmd |= OSD_VIDWINMD_VFF1; - osd_modify(sd, winmd_mask, winmd, - OSD_VIDWINMD); - } - - osd_modify(sd, OSD_MISCCTL_S420D, - OSD_MISCCTL_S420D, OSD_MISCCTL); - osd_write(sd, lconfig->line_length >> 5, - OSD_VIDWIN1OFST); - osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP); - osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL); - /* - * if NV21 pixfmt and line length not 32B - * aligned (e.g. NTSC), Need to set window - * X pixel size to be 32B aligned as well - */ - if (lconfig->xsize % 32) { - osd_write(sd, - ((lconfig->xsize + 31) & ~31), - OSD_VIDWIN1XL); - osd_write(sd, - ((lconfig->xsize + 31) & ~31), - OSD_VIDWIN0XL); - } - } else if ((sd->vpbe_type == VPBE_VERSION_2) && - (lconfig->pixfmt != PIXFMT_NV12)) { - osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D, - OSD_MISCCTL); - } - - if (lconfig->interlaced) { - osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN0YP); - osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN0YL); - if ((sd->vpbe_type == VPBE_VERSION_2) && - lconfig->pixfmt == PIXFMT_NV12) { - osd_write(sd, lconfig->ypos >> 1, - OSD_VIDWIN1YP); - osd_write(sd, lconfig->ysize >> 1, - OSD_VIDWIN1YL); - } - } else { - osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP); - osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL); - if ((sd->vpbe_type == VPBE_VERSION_2) && - lconfig->pixfmt == PIXFMT_NV12) { - osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP); - osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL); - } - } - break; - case WIN_OSD1: - /* - * The caller must ensure that OSD1 is disabled prior to - * switching from a normal mode to attribute mode or from - * attribute mode to a normal mode. - */ - if (lconfig->pixfmt == PIXFMT_OSD_ATTR) { - if (sd->vpbe_type == VPBE_VERSION_1) { - winmd_mask |= OSD_OSDWIN1MD_ATN1E | - OSD_OSDWIN1MD_RGB1E | OSD_OSDWIN1MD_CLUTS1 | - OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1; - } else { - winmd_mask |= OSD_OSDWIN1MD_BMP1MD | - OSD_OSDWIN1MD_CLUTS1 | OSD_OSDWIN1MD_BLND1 | - OSD_OSDWIN1MD_TE1; - } - } else { - if (sd->vpbe_type == VPBE_VERSION_1) { - winmd_mask |= OSD_OSDWIN1MD_RGB1E; - if (lconfig->pixfmt == PIXFMT_RGB565) - winmd |= OSD_OSDWIN1MD_RGB1E; - } else if ((sd->vpbe_type == VPBE_VERSION_3) - || (sd->vpbe_type == VPBE_VERSION_2)) { - winmd_mask |= OSD_OSDWIN1MD_BMP1MD; - switch (lconfig->pixfmt) { - case PIXFMT_RGB565: - winmd |= - (1 << OSD_OSDWIN1MD_BMP1MD_SHIFT); - break; - case PIXFMT_RGB888: - winmd |= - (2 << OSD_OSDWIN1MD_BMP1MD_SHIFT); - _osd_enable_rgb888_pixblend(sd, - OSDWIN_OSD1); - break; - case PIXFMT_YCBCRI: - case PIXFMT_YCRCBI: - winmd |= - (3 << OSD_OSDWIN1MD_BMP1MD_SHIFT); - break; - default: - break; - } - } - - winmd_mask |= OSD_OSDWIN1MD_BMW1; - switch (lconfig->pixfmt) { - case PIXFMT_1BPP: - bmw = 0; - break; - case PIXFMT_2BPP: - bmw = 1; - break; - case PIXFMT_4BPP: - bmw = 2; - break; - case PIXFMT_8BPP: - bmw = 3; - break; - default: - break; - } - winmd |= (bmw << OSD_OSDWIN1MD_BMW1_SHIFT); - } - - winmd_mask |= OSD_OSDWIN1MD_OFF1; - if (lconfig->interlaced) - winmd |= OSD_OSDWIN1MD_OFF1; - - osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN1MD); - osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN1OFST); - osd_write(sd, lconfig->xpos, OSD_OSDWIN1XP); - osd_write(sd, lconfig->xsize, OSD_OSDWIN1XL); - if (lconfig->interlaced) { - osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN1YP); - osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN1YL); - } else { - osd_write(sd, lconfig->ypos, OSD_OSDWIN1YP); - osd_write(sd, lconfig->ysize, OSD_OSDWIN1YL); - } - break; - case WIN_VID1: - winmd_mask |= OSD_VIDWINMD_VFF1; - if (lconfig->interlaced) - winmd |= OSD_VIDWINMD_VFF1; - - osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD); - osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN1OFST); - osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP); - osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL); - /* - * For YUV420P format the register contents are - * duplicated in both VID registers - */ - if (sd->vpbe_type == VPBE_VERSION_2) { - if (lconfig->pixfmt == PIXFMT_NV12) { - /* other window also */ - if (lconfig->interlaced) { - winmd_mask |= OSD_VIDWINMD_VFF0; - winmd |= OSD_VIDWINMD_VFF0; - osd_modify(sd, winmd_mask, winmd, - OSD_VIDWINMD); - } - osd_modify(sd, OSD_MISCCTL_S420D, - OSD_MISCCTL_S420D, OSD_MISCCTL); - osd_write(sd, lconfig->line_length >> 5, - OSD_VIDWIN0OFST); - osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP); - osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL); - } else { - osd_modify(sd, OSD_MISCCTL_S420D, - ~OSD_MISCCTL_S420D, OSD_MISCCTL); - } - } - - if (lconfig->interlaced) { - osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN1YP); - osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN1YL); - if ((sd->vpbe_type == VPBE_VERSION_2) && - lconfig->pixfmt == PIXFMT_NV12) { - osd_write(sd, lconfig->ypos >> 1, - OSD_VIDWIN0YP); - osd_write(sd, lconfig->ysize >> 1, - OSD_VIDWIN0YL); - } - } else { - osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP); - osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL); - if ((sd->vpbe_type == VPBE_VERSION_2) && - lconfig->pixfmt == PIXFMT_NV12) { - osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP); - osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL); - } - } - break; - } -} - -static int osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, - struct osd_layer_config *lconfig) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - struct osd_layer_config *cfg = &win->lconfig; - unsigned long flags; - int reject_config; - - spin_lock_irqsave(&osd->lock, flags); - - reject_config = try_layer_config(sd, layer, lconfig); - if (reject_config) { - spin_unlock_irqrestore(&osd->lock, flags); - return reject_config; - } - - /* update the current Cb/Cr order */ - if (is_yc_pixfmt(lconfig->pixfmt)) - osd->yc_pixfmt = lconfig->pixfmt; - - /* - * If we are switching OSD1 from normal mode to attribute mode or from - * attribute mode to normal mode, then we must disable the window. - */ - if (layer == WIN_OSD1) { - if (((lconfig->pixfmt == PIXFMT_OSD_ATTR) && - (cfg->pixfmt != PIXFMT_OSD_ATTR)) || - ((lconfig->pixfmt != PIXFMT_OSD_ATTR) && - (cfg->pixfmt == PIXFMT_OSD_ATTR))) { - win->is_enabled = 0; - _osd_disable_layer(sd, layer); - } - } - - _osd_set_layer_config(sd, layer, lconfig); - - if (layer == WIN_OSD1) { - struct osd_osdwin_state *osdwin_state = - &osd->osdwin[OSDWIN_OSD1]; - - if ((lconfig->pixfmt != PIXFMT_OSD_ATTR) && - (cfg->pixfmt == PIXFMT_OSD_ATTR)) { - /* - * We just switched OSD1 from attribute mode to normal - * mode, so we must initialize the CLUT select, the - * blend factor, transparency colorkey enable, and - * attenuation enable (DM6446 only) bits in the - * OSDWIN1MD register. - */ - _osd_set_osd_clut(sd, OSDWIN_OSD1, - osdwin_state->clut); - _osd_set_blending_factor(sd, OSDWIN_OSD1, - osdwin_state->blend); - if (osdwin_state->colorkey_blending) { - _osd_enable_color_key(sd, OSDWIN_OSD1, - osdwin_state-> - colorkey, - lconfig->pixfmt); - } else - _osd_disable_color_key(sd, OSDWIN_OSD1); - _osd_set_rec601_attenuation(sd, OSDWIN_OSD1, - osdwin_state-> - rec601_attenuation); - } else if ((lconfig->pixfmt == PIXFMT_OSD_ATTR) && - (cfg->pixfmt != PIXFMT_OSD_ATTR)) { - /* - * We just switched OSD1 from normal mode to attribute - * mode, so we must initialize the blink enable and - * blink interval bits in the OSDATRMD register. - */ - _osd_set_blink_attribute(sd, osd->is_blinking, - osd->blink); - } - } - - /* - * If we just switched to a 1-, 2-, or 4-bits-per-pixel bitmap format - * then configure a default palette map. - */ - if ((lconfig->pixfmt != cfg->pixfmt) && - ((lconfig->pixfmt == PIXFMT_1BPP) || - (lconfig->pixfmt == PIXFMT_2BPP) || - (lconfig->pixfmt == PIXFMT_4BPP))) { - enum osd_win_layer osdwin = - ((layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1); - struct osd_osdwin_state *osdwin_state = - &osd->osdwin[osdwin]; - unsigned char clut_index; - unsigned char clut_entries = 0; - - switch (lconfig->pixfmt) { - case PIXFMT_1BPP: - clut_entries = 2; - break; - case PIXFMT_2BPP: - clut_entries = 4; - break; - case PIXFMT_4BPP: - clut_entries = 16; - break; - default: - break; - } - /* - * The default palette map maps the pixel value to the clut - * index, i.e. pixel value 0 maps to clut entry 0, pixel value - * 1 maps to clut entry 1, etc. - */ - for (clut_index = 0; clut_index < 16; clut_index++) { - osdwin_state->palette_map[clut_index] = clut_index; - if (clut_index < clut_entries) { - _osd_set_palette_map(sd, osdwin, clut_index, - clut_index, - lconfig->pixfmt); - } - } - } - - *cfg = *lconfig; - /* DM6446: configure the RGB888 enable and window selection */ - if (osd->win[WIN_VID0].lconfig.pixfmt == PIXFMT_RGB888) - _osd_enable_vid_rgb888(sd, WIN_VID0); - else if (osd->win[WIN_VID1].lconfig.pixfmt == PIXFMT_RGB888) - _osd_enable_vid_rgb888(sd, WIN_VID1); - else - _osd_disable_vid_rgb888(sd); - - if (layer == WIN_VID0) { - osd->pingpong = - _osd_dm6446_vid0_pingpong(sd, osd->field_inversion, - win->fb_base_phys, - cfg); - } - - spin_unlock_irqrestore(&osd->lock, flags); - - return 0; -} - -static void osd_init_layer(struct osd_state *sd, enum osd_layer layer) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - enum osd_win_layer osdwin; - struct osd_osdwin_state *osdwin_state; - struct osd_layer_config *cfg = &win->lconfig; - unsigned long flags; - - spin_lock_irqsave(&osd->lock, flags); - - win->is_enabled = 0; - _osd_disable_layer(sd, layer); - - win->h_zoom = ZOOM_X1; - win->v_zoom = ZOOM_X1; - _osd_set_zoom(sd, layer, win->h_zoom, win->v_zoom); - - win->fb_base_phys = 0; - _osd_start_layer(sd, layer, win->fb_base_phys, 0); - - cfg->line_length = 0; - cfg->xsize = 0; - cfg->ysize = 0; - cfg->xpos = 0; - cfg->ypos = 0; - cfg->interlaced = 0; - switch (layer) { - case WIN_OSD0: - case WIN_OSD1: - osdwin = (layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1; - osdwin_state = &osd->osdwin[osdwin]; - /* - * Other code relies on the fact that OSD windows default to a - * bitmap pixel format when they are deallocated, so don't - * change this default pixel format. - */ - cfg->pixfmt = PIXFMT_8BPP; - _osd_set_layer_config(sd, layer, cfg); - osdwin_state->clut = RAM_CLUT; - _osd_set_osd_clut(sd, osdwin, osdwin_state->clut); - osdwin_state->colorkey_blending = 0; - _osd_disable_color_key(sd, osdwin); - osdwin_state->blend = OSD_8_VID_0; - _osd_set_blending_factor(sd, osdwin, osdwin_state->blend); - osdwin_state->rec601_attenuation = 0; - _osd_set_rec601_attenuation(sd, osdwin, - osdwin_state-> - rec601_attenuation); - if (osdwin == OSDWIN_OSD1) { - osd->is_blinking = 0; - osd->blink = BLINK_X1; - } - break; - case WIN_VID0: - case WIN_VID1: - cfg->pixfmt = osd->yc_pixfmt; - _osd_set_layer_config(sd, layer, cfg); - break; - } - - spin_unlock_irqrestore(&osd->lock, flags); -} - -static void osd_release_layer(struct osd_state *sd, enum osd_layer layer) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - unsigned long flags; - - spin_lock_irqsave(&osd->lock, flags); - - if (!win->is_allocated) { - spin_unlock_irqrestore(&osd->lock, flags); - return; - } - - spin_unlock_irqrestore(&osd->lock, flags); - osd_init_layer(sd, layer); - spin_lock_irqsave(&osd->lock, flags); - - win->is_allocated = 0; - - spin_unlock_irqrestore(&osd->lock, flags); -} - -static int osd_request_layer(struct osd_state *sd, enum osd_layer layer) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - unsigned long flags; - - spin_lock_irqsave(&osd->lock, flags); - - if (win->is_allocated) { - spin_unlock_irqrestore(&osd->lock, flags); - return -1; - } - win->is_allocated = 1; - - spin_unlock_irqrestore(&osd->lock, flags); - - return 0; -} - -static void _osd_init(struct osd_state *sd) -{ - osd_write(sd, 0, OSD_MODE); - osd_write(sd, 0, OSD_VIDWINMD); - osd_write(sd, 0, OSD_OSDWIN0MD); - osd_write(sd, 0, OSD_OSDWIN1MD); - osd_write(sd, 0, OSD_RECTCUR); - osd_write(sd, 0, OSD_MISCCTL); - if (sd->vpbe_type == VPBE_VERSION_3) { - osd_write(sd, 0, OSD_VBNDRY); - osd_write(sd, 0, OSD_EXTMODE); - osd_write(sd, OSD_MISCCTL_DMANG, OSD_MISCCTL); - } -} - -static void osd_set_left_margin(struct osd_state *sd, u32 val) -{ - osd_write(sd, val, OSD_BASEPX); -} - -static void osd_set_top_margin(struct osd_state *sd, u32 val) -{ - osd_write(sd, val, OSD_BASEPY); -} - -static int osd_initialize(struct osd_state *osd) -{ - if (osd == NULL) - return -ENODEV; - _osd_init(osd); - - /* set default Cb/Cr order */ - osd->yc_pixfmt = PIXFMT_YCBCRI; - - if (osd->vpbe_type == VPBE_VERSION_3) { - /* - * ROM CLUT1 on the DM355 is similar (identical?) to ROM CLUT0 - * on the DM6446, so make ROM_CLUT1 the default on the DM355. - */ - osd->rom_clut = ROM_CLUT1; - } - - _osd_set_field_inversion(osd, osd->field_inversion); - _osd_set_rom_clut(osd, osd->rom_clut); - - osd_init_layer(osd, WIN_OSD0); - osd_init_layer(osd, WIN_VID0); - osd_init_layer(osd, WIN_OSD1); - osd_init_layer(osd, WIN_VID1); - - return 0; -} - -static const struct vpbe_osd_ops osd_ops = { - .initialize = osd_initialize, - .request_layer = osd_request_layer, - .release_layer = osd_release_layer, - .enable_layer = osd_enable_layer, - .disable_layer = osd_disable_layer, - .set_layer_config = osd_set_layer_config, - .get_layer_config = osd_get_layer_config, - .start_layer = osd_start_layer, - .set_left_margin = osd_set_left_margin, - .set_top_margin = osd_set_top_margin, -}; - -static int osd_probe(struct platform_device *pdev) -{ - const struct platform_device_id *pdev_id; - struct osd_state *osd; - struct resource *res; - - pdev_id = platform_get_device_id(pdev); - if (!pdev_id) - return -EINVAL; - - osd = devm_kzalloc(&pdev->dev, sizeof(struct osd_state), GFP_KERNEL); - if (osd == NULL) - return -ENOMEM; - - - osd->dev = &pdev->dev; - osd->vpbe_type = pdev_id->driver_data; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - osd->osd_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(osd->osd_base)) - return PTR_ERR(osd->osd_base); - - osd->osd_base_phys = res->start; - osd->osd_size = resource_size(res); - spin_lock_init(&osd->lock); - osd->ops = osd_ops; - platform_set_drvdata(pdev, osd); - dev_notice(osd->dev, "OSD sub device probe success\n"); - - return 0; -} - -static int osd_remove(struct platform_device *pdev) -{ - return 0; -} - -static struct platform_driver osd_driver = { - .probe = osd_probe, - .remove = osd_remove, - .driver = { - .name = MODULE_NAME, - }, - .id_table = vpbe_osd_devtype -}; - -module_platform_driver(osd_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("DaVinci OSD Manager Driver"); -MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/platform/ti/davinci/vpbe_osd_regs.h b/drivers/media/platform/ti/davinci/vpbe_osd_regs.h deleted file mode 100644 index cecd5991d4c5..000000000000 --- a/drivers/media/platform/ti/davinci/vpbe_osd_regs.h +++ /dev/null @@ -1,352 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2006-2010 Texas Instruments Inc - */ -#ifndef _VPBE_OSD_REGS_H -#define _VPBE_OSD_REGS_H - -/* VPBE Global Registers */ -#define VPBE_PID 0x0 -#define VPBE_PCR 0x4 - -/* VPSS CLock Registers */ -#define VPSSCLK_PID 0x00 -#define VPSSCLK_CLKCTRL 0x04 - -/* VPSS Buffer Logic Registers */ -#define VPSSBL_PID 0x00 -#define VPSSBL_PCR 0x04 -#define VPSSBL_BCR 0x08 -#define VPSSBL_INTSTAT 0x0C -#define VPSSBL_INTSEL 0x10 -#define VPSSBL_EVTSEL 0x14 -#define VPSSBL_MEMCTRL 0x18 -#define VPSSBL_CCDCMUX 0x1C - -/* DM365 ISP5 system configuration */ -#define ISP5_PID 0x0 -#define ISP5_PCCR 0x4 -#define ISP5_BCR 0x8 -#define ISP5_INTSTAT 0xC -#define ISP5_INTSEL1 0x10 -#define ISP5_INTSEL2 0x14 -#define ISP5_INTSEL3 0x18 -#define ISP5_EVTSEL 0x1c -#define ISP5_CCDCMUX 0x20 - -/* VPBE On-Screen Display Subsystem Registers (OSD) */ -#define OSD_MODE 0x00 -#define OSD_VIDWINMD 0x04 -#define OSD_OSDWIN0MD 0x08 -#define OSD_OSDWIN1MD 0x0C -#define OSD_OSDATRMD 0x0C -#define OSD_RECTCUR 0x10 -#define OSD_VIDWIN0OFST 0x18 -#define OSD_VIDWIN1OFST 0x1C -#define OSD_OSDWIN0OFST 0x20 -#define OSD_OSDWIN1OFST 0x24 -#define OSD_VIDWINADH 0x28 -#define OSD_VIDWIN0ADL 0x2C -#define OSD_VIDWIN0ADR 0x2C -#define OSD_VIDWIN1ADL 0x30 -#define OSD_VIDWIN1ADR 0x30 -#define OSD_OSDWINADH 0x34 -#define OSD_OSDWIN0ADL 0x38 -#define OSD_OSDWIN0ADR 0x38 -#define OSD_OSDWIN1ADL 0x3C -#define OSD_OSDWIN1ADR 0x3C -#define OSD_BASEPX 0x40 -#define OSD_BASEPY 0x44 -#define OSD_VIDWIN0XP 0x48 -#define OSD_VIDWIN0YP 0x4C -#define OSD_VIDWIN0XL 0x50 -#define OSD_VIDWIN0YL 0x54 -#define OSD_VIDWIN1XP 0x58 -#define OSD_VIDWIN1YP 0x5C -#define OSD_VIDWIN1XL 0x60 -#define OSD_VIDWIN1YL 0x64 -#define OSD_OSDWIN0XP 0x68 -#define OSD_OSDWIN0YP 0x6C -#define OSD_OSDWIN0XL 0x70 -#define OSD_OSDWIN0YL 0x74 -#define OSD_OSDWIN1XP 0x78 -#define OSD_OSDWIN1YP 0x7C -#define OSD_OSDWIN1XL 0x80 -#define OSD_OSDWIN1YL 0x84 -#define OSD_CURXP 0x88 -#define OSD_CURYP 0x8C -#define OSD_CURXL 0x90 -#define OSD_CURYL 0x94 -#define OSD_W0BMP01 0xA0 -#define OSD_W0BMP23 0xA4 -#define OSD_W0BMP45 0xA8 -#define OSD_W0BMP67 0xAC -#define OSD_W0BMP89 0xB0 -#define OSD_W0BMPAB 0xB4 -#define OSD_W0BMPCD 0xB8 -#define OSD_W0BMPEF 0xBC -#define OSD_W1BMP01 0xC0 -#define OSD_W1BMP23 0xC4 -#define OSD_W1BMP45 0xC8 -#define OSD_W1BMP67 0xCC -#define OSD_W1BMP89 0xD0 -#define OSD_W1BMPAB 0xD4 -#define OSD_W1BMPCD 0xD8 -#define OSD_W1BMPEF 0xDC -#define OSD_VBNDRY 0xE0 -#define OSD_EXTMODE 0xE4 -#define OSD_MISCCTL 0xE8 -#define OSD_CLUTRAMYCB 0xEC -#define OSD_CLUTRAMCR 0xF0 -#define OSD_TRANSPVAL 0xF4 -#define OSD_TRANSPVALL 0xF4 -#define OSD_TRANSPVALU 0xF8 -#define OSD_TRANSPBMPIDX 0xFC -#define OSD_PPVWIN0ADR 0xFC - -/* bit definitions */ -#define VPBE_PCR_VENC_DIV (1 << 1) -#define VPBE_PCR_CLK_OFF (1 << 0) - -#define VPSSBL_INTSTAT_HSSIINT (1 << 14) -#define VPSSBL_INTSTAT_CFALDINT (1 << 13) -#define VPSSBL_INTSTAT_IPIPE_INT5 (1 << 12) -#define VPSSBL_INTSTAT_IPIPE_INT4 (1 << 11) -#define VPSSBL_INTSTAT_IPIPE_INT3 (1 << 10) -#define VPSSBL_INTSTAT_IPIPE_INT2 (1 << 9) -#define VPSSBL_INTSTAT_IPIPE_INT1 (1 << 8) -#define VPSSBL_INTSTAT_IPIPE_INT0 (1 << 7) -#define VPSSBL_INTSTAT_IPIPEIFINT (1 << 6) -#define VPSSBL_INTSTAT_OSDINT (1 << 5) -#define VPSSBL_INTSTAT_VENCINT (1 << 4) -#define VPSSBL_INTSTAT_H3AINT (1 << 3) -#define VPSSBL_INTSTAT_CCDC_VDINT2 (1 << 2) -#define VPSSBL_INTSTAT_CCDC_VDINT1 (1 << 1) -#define VPSSBL_INTSTAT_CCDC_VDINT0 (1 << 0) - -/* DM365 ISP5 bit definitions */ -#define ISP5_INTSTAT_VENCINT (1 << 21) -#define ISP5_INTSTAT_OSDINT (1 << 20) - -/* VMOD TVTYP options for HDMD=0 */ -#define SDTV_NTSC 0 -#define SDTV_PAL 1 -/* VMOD TVTYP options for HDMD=1 */ -#define HDTV_525P 0 -#define HDTV_625P 1 -#define HDTV_1080I 2 -#define HDTV_720P 3 - -#define OSD_MODE_CS (1 << 15) -#define OSD_MODE_OVRSZ (1 << 14) -#define OSD_MODE_OHRSZ (1 << 13) -#define OSD_MODE_EF (1 << 12) -#define OSD_MODE_VVRSZ (1 << 11) -#define OSD_MODE_VHRSZ (1 << 10) -#define OSD_MODE_FSINV (1 << 9) -#define OSD_MODE_BCLUT (1 << 8) -#define OSD_MODE_CABG_SHIFT 0 -#define OSD_MODE_CABG (0xff << 0) - -#define OSD_VIDWINMD_VFINV (1 << 15) -#define OSD_VIDWINMD_V1EFC (1 << 14) -#define OSD_VIDWINMD_VHZ1_SHIFT 12 -#define OSD_VIDWINMD_VHZ1 (3 << 12) -#define OSD_VIDWINMD_VVZ1_SHIFT 10 -#define OSD_VIDWINMD_VVZ1 (3 << 10) -#define OSD_VIDWINMD_VFF1 (1 << 9) -#define OSD_VIDWINMD_ACT1 (1 << 8) -#define OSD_VIDWINMD_V0EFC (1 << 6) -#define OSD_VIDWINMD_VHZ0_SHIFT 4 -#define OSD_VIDWINMD_VHZ0 (3 << 4) -#define OSD_VIDWINMD_VVZ0_SHIFT 2 -#define OSD_VIDWINMD_VVZ0 (3 << 2) -#define OSD_VIDWINMD_VFF0 (1 << 1) -#define OSD_VIDWINMD_ACT0 (1 << 0) - -#define OSD_OSDWIN0MD_ATN0E (1 << 14) -#define OSD_OSDWIN0MD_RGB0E (1 << 13) -#define OSD_OSDWIN0MD_BMP0MD_SHIFT 13 -#define OSD_OSDWIN0MD_BMP0MD (3 << 13) -#define OSD_OSDWIN0MD_CLUTS0 (1 << 12) -#define OSD_OSDWIN0MD_OHZ0_SHIFT 10 -#define OSD_OSDWIN0MD_OHZ0 (3 << 10) -#define OSD_OSDWIN0MD_OVZ0_SHIFT 8 -#define OSD_OSDWIN0MD_OVZ0 (3 << 8) -#define OSD_OSDWIN0MD_BMW0_SHIFT 6 -#define OSD_OSDWIN0MD_BMW0 (3 << 6) -#define OSD_OSDWIN0MD_BLND0_SHIFT 3 -#define OSD_OSDWIN0MD_BLND0 (7 << 3) -#define OSD_OSDWIN0MD_TE0 (1 << 2) -#define OSD_OSDWIN0MD_OFF0 (1 << 1) -#define OSD_OSDWIN0MD_OACT0 (1 << 0) - -#define OSD_OSDWIN1MD_OASW (1 << 15) -#define OSD_OSDWIN1MD_ATN1E (1 << 14) -#define OSD_OSDWIN1MD_RGB1E (1 << 13) -#define OSD_OSDWIN1MD_BMP1MD_SHIFT 13 -#define OSD_OSDWIN1MD_BMP1MD (3 << 13) -#define OSD_OSDWIN1MD_CLUTS1 (1 << 12) -#define OSD_OSDWIN1MD_OHZ1_SHIFT 10 -#define OSD_OSDWIN1MD_OHZ1 (3 << 10) -#define OSD_OSDWIN1MD_OVZ1_SHIFT 8 -#define OSD_OSDWIN1MD_OVZ1 (3 << 8) -#define OSD_OSDWIN1MD_BMW1_SHIFT 6 -#define OSD_OSDWIN1MD_BMW1 (3 << 6) -#define OSD_OSDWIN1MD_BLND1_SHIFT 3 -#define OSD_OSDWIN1MD_BLND1 (7 << 3) -#define OSD_OSDWIN1MD_TE1 (1 << 2) -#define OSD_OSDWIN1MD_OFF1 (1 << 1) -#define OSD_OSDWIN1MD_OACT1 (1 << 0) - -#define OSD_OSDATRMD_OASW (1 << 15) -#define OSD_OSDATRMD_OHZA_SHIFT 10 -#define OSD_OSDATRMD_OHZA (3 << 10) -#define OSD_OSDATRMD_OVZA_SHIFT 8 -#define OSD_OSDATRMD_OVZA (3 << 8) -#define OSD_OSDATRMD_BLNKINT_SHIFT 6 -#define OSD_OSDATRMD_BLNKINT (3 << 6) -#define OSD_OSDATRMD_OFFA (1 << 1) -#define OSD_OSDATRMD_BLNK (1 << 0) - -#define OSD_RECTCUR_RCAD_SHIFT 8 -#define OSD_RECTCUR_RCAD (0xff << 8) -#define OSD_RECTCUR_CLUTSR (1 << 7) -#define OSD_RECTCUR_RCHW_SHIFT 4 -#define OSD_RECTCUR_RCHW (7 << 4) -#define OSD_RECTCUR_RCVW_SHIFT 1 -#define OSD_RECTCUR_RCVW (7 << 1) -#define OSD_RECTCUR_RCACT (1 << 0) - -#define OSD_VIDWIN0OFST_V0LO (0x1ff << 0) - -#define OSD_VIDWIN1OFST_V1LO (0x1ff << 0) - -#define OSD_OSDWIN0OFST_O0LO (0x1ff << 0) - -#define OSD_OSDWIN1OFST_O1LO (0x1ff << 0) - -#define OSD_WINOFST_AH_SHIFT 9 - -#define OSD_VIDWIN0OFST_V0AH (0xf << 9) -#define OSD_VIDWIN1OFST_V1AH (0xf << 9) -#define OSD_OSDWIN0OFST_O0AH (0xf << 9) -#define OSD_OSDWIN1OFST_O1AH (0xf << 9) - -#define OSD_VIDWINADH_V1AH_SHIFT 8 -#define OSD_VIDWINADH_V1AH (0x7f << 8) -#define OSD_VIDWINADH_V0AH_SHIFT 0 -#define OSD_VIDWINADH_V0AH (0x7f << 0) - -#define OSD_VIDWIN0ADL_V0AL (0xffff << 0) - -#define OSD_VIDWIN1ADL_V1AL (0xffff << 0) - -#define OSD_OSDWINADH_O1AH_SHIFT 8 -#define OSD_OSDWINADH_O1AH (0x7f << 8) -#define OSD_OSDWINADH_O0AH_SHIFT 0 -#define OSD_OSDWINADH_O0AH (0x7f << 0) - -#define OSD_OSDWIN0ADL_O0AL (0xffff << 0) - -#define OSD_OSDWIN1ADL_O1AL (0xffff << 0) - -#define OSD_BASEPX_BPX (0x3ff << 0) - -#define OSD_BASEPY_BPY (0x1ff << 0) - -#define OSD_VIDWIN0XP_V0X (0x7ff << 0) - -#define OSD_VIDWIN0YP_V0Y (0x7ff << 0) - -#define OSD_VIDWIN0XL_V0W (0x7ff << 0) - -#define OSD_VIDWIN0YL_V0H (0x7ff << 0) - -#define OSD_VIDWIN1XP_V1X (0x7ff << 0) - -#define OSD_VIDWIN1YP_V1Y (0x7ff << 0) - -#define OSD_VIDWIN1XL_V1W (0x7ff << 0) - -#define OSD_VIDWIN1YL_V1H (0x7ff << 0) - -#define OSD_OSDWIN0XP_W0X (0x7ff << 0) - -#define OSD_OSDWIN0YP_W0Y (0x7ff << 0) - -#define OSD_OSDWIN0XL_W0W (0x7ff << 0) - -#define OSD_OSDWIN0YL_W0H (0x7ff << 0) - -#define OSD_OSDWIN1XP_W1X (0x7ff << 0) - -#define OSD_OSDWIN1YP_W1Y (0x7ff << 0) - -#define OSD_OSDWIN1XL_W1W (0x7ff << 0) - -#define OSD_OSDWIN1YL_W1H (0x7ff << 0) - -#define OSD_CURXP_RCSX (0x7ff << 0) - -#define OSD_CURYP_RCSY (0x7ff << 0) - -#define OSD_CURXL_RCSW (0x7ff << 0) - -#define OSD_CURYL_RCSH (0x7ff << 0) - -#define OSD_EXTMODE_EXPMDSEL (1 << 15) -#define OSD_EXTMODE_SCRNHEXP_SHIFT 13 -#define OSD_EXTMODE_SCRNHEXP (3 << 13) -#define OSD_EXTMODE_SCRNVEXP (1 << 12) -#define OSD_EXTMODE_OSD1BLDCHR (1 << 11) -#define OSD_EXTMODE_OSD0BLDCHR (1 << 10) -#define OSD_EXTMODE_ATNOSD1EN (1 << 9) -#define OSD_EXTMODE_ATNOSD0EN (1 << 8) -#define OSD_EXTMODE_OSDHRSZ15 (1 << 7) -#define OSD_EXTMODE_VIDHRSZ15 (1 << 6) -#define OSD_EXTMODE_ZMFILV1HEN (1 << 5) -#define OSD_EXTMODE_ZMFILV1VEN (1 << 4) -#define OSD_EXTMODE_ZMFILV0HEN (1 << 3) -#define OSD_EXTMODE_ZMFILV0VEN (1 << 2) -#define OSD_EXTMODE_EXPFILHEN (1 << 1) -#define OSD_EXTMODE_EXPFILVEN (1 << 0) - -#define OSD_MISCCTL_BLDSEL (1 << 15) -#define OSD_MISCCTL_S420D (1 << 14) -#define OSD_MISCCTL_BMAPT (1 << 13) -#define OSD_MISCCTL_DM365M (1 << 12) -#define OSD_MISCCTL_RGBEN (1 << 7) -#define OSD_MISCCTL_RGBWIN (1 << 6) -#define OSD_MISCCTL_DMANG (1 << 6) -#define OSD_MISCCTL_TMON (1 << 5) -#define OSD_MISCCTL_RSEL (1 << 4) -#define OSD_MISCCTL_CPBSY (1 << 3) -#define OSD_MISCCTL_PPSW (1 << 2) -#define OSD_MISCCTL_PPRV (1 << 1) - -#define OSD_CLUTRAMYCB_Y_SHIFT 8 -#define OSD_CLUTRAMYCB_Y (0xff << 8) -#define OSD_CLUTRAMYCB_CB_SHIFT 0 -#define OSD_CLUTRAMYCB_CB (0xff << 0) - -#define OSD_CLUTRAMCR_CR_SHIFT 8 -#define OSD_CLUTRAMCR_CR (0xff << 8) -#define OSD_CLUTRAMCR_CADDR_SHIFT 0 -#define OSD_CLUTRAMCR_CADDR (0xff << 0) - -#define OSD_TRANSPVAL_RGBTRANS (0xffff << 0) - -#define OSD_TRANSPVALL_RGBL (0xffff << 0) - -#define OSD_TRANSPVALU_Y_SHIFT 8 -#define OSD_TRANSPVALU_Y (0xff << 8) -#define OSD_TRANSPVALU_RGBU_SHIFT 0 -#define OSD_TRANSPVALU_RGBU (0xff << 0) - -#define OSD_TRANSPBMPIDX_BMP1_SHIFT 8 -#define OSD_TRANSPBMPIDX_BMP1 (0xff << 8) -#define OSD_TRANSPBMPIDX_BMP0_SHIFT 0 -#define OSD_TRANSPBMPIDX_BMP0 0xff - -#endif /* _DAVINCI_VPBE_H_ */ diff --git a/drivers/media/platform/ti/davinci/vpbe_venc.c b/drivers/media/platform/ti/davinci/vpbe_venc.c deleted file mode 100644 index 4c8e31de12b1..000000000000 --- a/drivers/media/platform/ti/davinci/vpbe_venc.c +++ /dev/null @@ -1,676 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2010 Texas Instruments Inc - */ -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/ctype.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/videodev2.h> -#include <linux/slab.h> - -#include <linux/platform_data/i2c-davinci.h> - -#include <linux/io.h> - -#include <media/davinci/vpbe_types.h> -#include <media/davinci/vpbe_venc.h> -#include <media/davinci/vpss.h> -#include <media/v4l2-device.h> - -#include "vpbe_venc_regs.h" - -#define MODULE_NAME "davinci-vpbe-venc" - -static const struct platform_device_id vpbe_venc_devtype[] = { - { - .name = DM644X_VPBE_VENC_SUBDEV_NAME, - .driver_data = VPBE_VERSION_1, - }, { - .name = DM365_VPBE_VENC_SUBDEV_NAME, - .driver_data = VPBE_VERSION_2, - }, { - .name = DM355_VPBE_VENC_SUBDEV_NAME, - .driver_data = VPBE_VERSION_3, - }, - { - /* sentinel */ - } -}; - -MODULE_DEVICE_TABLE(platform, vpbe_venc_devtype); - -static int debug = 2; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level 0-2"); - -struct venc_state { - struct v4l2_subdev sd; - struct venc_callback *callback; - struct venc_platform_data *pdata; - struct device *pdev; - u32 output; - v4l2_std_id std; - spinlock_t lock; - void __iomem *venc_base; - void __iomem *vdaccfg_reg; - enum vpbe_version venc_type; -}; - -static inline struct venc_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct venc_state, sd); -} - -static inline u32 venc_read(struct v4l2_subdev *sd, u32 offset) -{ - struct venc_state *venc = to_state(sd); - - return readl(venc->venc_base + offset); -} - -static inline u32 venc_write(struct v4l2_subdev *sd, u32 offset, u32 val) -{ - struct venc_state *venc = to_state(sd); - - writel(val, (venc->venc_base + offset)); - - return val; -} - -static inline u32 venc_modify(struct v4l2_subdev *sd, u32 offset, - u32 val, u32 mask) -{ - u32 new_val = (venc_read(sd, offset) & ~mask) | (val & mask); - - venc_write(sd, offset, new_val); - - return new_val; -} - -static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val) -{ - struct venc_state *venc = to_state(sd); - - writel(val, venc->vdaccfg_reg); - - val = readl(venc->vdaccfg_reg); - - return val; -} - -#define VDAC_COMPONENT 0x543 -#define VDAC_S_VIDEO 0x210 -/* This function sets the dac of the VPBE for various outputs - */ -static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) -{ - switch (out_index) { - case 0: - v4l2_dbg(debug, 1, sd, "Setting output to Composite\n"); - venc_write(sd, VENC_DACSEL, 0); - break; - case 1: - v4l2_dbg(debug, 1, sd, "Setting output to Component\n"); - venc_write(sd, VENC_DACSEL, VDAC_COMPONENT); - break; - case 2: - v4l2_dbg(debug, 1, sd, "Setting output to S-video\n"); - venc_write(sd, VENC_DACSEL, VDAC_S_VIDEO); - break; - default: - return -EINVAL; - } - - return 0; -} - -static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) -{ - struct venc_state *venc = to_state(sd); - - v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n"); - - if (benable) { - venc_write(sd, VENC_VMOD, 0); - venc_write(sd, VENC_CVBS, 0); - venc_write(sd, VENC_LCDOUT, 0); - venc_write(sd, VENC_HSPLS, 0); - venc_write(sd, VENC_HSTART, 0); - venc_write(sd, VENC_HVALID, 0); - venc_write(sd, VENC_HINT, 0); - venc_write(sd, VENC_VSPLS, 0); - venc_write(sd, VENC_VSTART, 0); - venc_write(sd, VENC_VVALID, 0); - venc_write(sd, VENC_VINT, 0); - venc_write(sd, VENC_YCCCTL, 0); - venc_write(sd, VENC_DACSEL, 0); - - } else { - venc_write(sd, VENC_VMOD, 0); - /* disable VCLK output pin enable */ - venc_write(sd, VENC_VIDCTL, 0x141); - - /* Disable output sync pins */ - venc_write(sd, VENC_SYNCCTL, 0); - - /* Disable DCLOCK */ - venc_write(sd, VENC_DCLKCTL, 0); - venc_write(sd, VENC_DRGBX1, 0x0000057C); - - /* Disable LCD output control (accepting default polarity) */ - venc_write(sd, VENC_LCDOUT, 0); - if (venc->venc_type != VPBE_VERSION_3) - venc_write(sd, VENC_CMPNT, 0x100); - venc_write(sd, VENC_HSPLS, 0); - venc_write(sd, VENC_HINT, 0); - venc_write(sd, VENC_HSTART, 0); - venc_write(sd, VENC_HVALID, 0); - - venc_write(sd, VENC_VSPLS, 0); - venc_write(sd, VENC_VINT, 0); - venc_write(sd, VENC_VSTART, 0); - venc_write(sd, VENC_VVALID, 0); - - venc_write(sd, VENC_HSDLY, 0); - venc_write(sd, VENC_VSDLY, 0); - - venc_write(sd, VENC_YCCCTL, 0); - venc_write(sd, VENC_VSTARTA, 0); - - /* Set OSD clock and OSD Sync Adavance registers */ - venc_write(sd, VENC_OSDCLK0, 1); - venc_write(sd, VENC_OSDCLK1, 2); - } -} - -static void -venc_enable_vpss_clock(int venc_type, - enum vpbe_enc_timings_type type, - unsigned int pclock) -{ - if (venc_type == VPBE_VERSION_1) - return; - - if (venc_type == VPBE_VERSION_2 && (type == VPBE_ENC_STD || (type == - VPBE_ENC_DV_TIMINGS && pclock <= 27000000))) { - vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); - vpss_enable_clock(VPSS_VPBE_CLOCK, 1); - return; - } - - if (venc_type == VPBE_VERSION_3 && type == VPBE_ENC_STD) - vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 0); -} - -#define VDAC_CONFIG_SD_V3 0x0E21A6B6 -#define VDAC_CONFIG_SD_V2 0x081141CF -/* - * setting NTSC mode - */ -static int venc_set_ntsc(struct v4l2_subdev *sd) -{ - struct venc_state *venc = to_state(sd); - struct venc_platform_data *pdata = venc->pdata; - - v4l2_dbg(debug, 2, sd, "venc_set_ntsc\n"); - - /* Setup clock at VPSS & VENC for SD */ - vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); - if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0) - return -EINVAL; - - venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_STD, V4L2_STD_525_60); - venc_enabledigitaloutput(sd, 0); - - if (venc->venc_type == VPBE_VERSION_3) { - venc_write(sd, VENC_CLKCTL, 0x01); - venc_write(sd, VENC_VIDCTL, 0); - vdaccfg_write(sd, VDAC_CONFIG_SD_V3); - } else if (venc->venc_type == VPBE_VERSION_2) { - venc_write(sd, VENC_CLKCTL, 0x01); - venc_write(sd, VENC_VIDCTL, 0); - vdaccfg_write(sd, VDAC_CONFIG_SD_V2); - } else { - /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ - venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); - /* Set REC656 Mode */ - venc_write(sd, VENC_YCCCTL, 0x1); - venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ); - venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS); - } - - venc_write(sd, VENC_VMOD, 0); - venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), - VENC_VMOD_VIE); - venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); - venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_TVTYP_SHIFT), - VENC_VMOD_TVTYP); - venc_write(sd, VENC_DACTST, 0x0); - venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); - - return 0; -} - -/* - * setting PAL mode - */ -static int venc_set_pal(struct v4l2_subdev *sd) -{ - struct venc_state *venc = to_state(sd); - - v4l2_dbg(debug, 2, sd, "venc_set_pal\n"); - - /* Setup clock at VPSS & VENC for SD */ - vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); - if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0) - return -EINVAL; - - venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_STD, V4L2_STD_625_50); - venc_enabledigitaloutput(sd, 0); - - if (venc->venc_type == VPBE_VERSION_3) { - venc_write(sd, VENC_CLKCTL, 0x1); - venc_write(sd, VENC_VIDCTL, 0); - vdaccfg_write(sd, VDAC_CONFIG_SD_V3); - } else if (venc->venc_type == VPBE_VERSION_2) { - venc_write(sd, VENC_CLKCTL, 0x1); - venc_write(sd, VENC_VIDCTL, 0); - vdaccfg_write(sd, VDAC_CONFIG_SD_V2); - } else { - /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ - venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); - /* Set REC656 Mode */ - venc_write(sd, VENC_YCCCTL, 0x1); - } - - venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT, - VENC_SYNCCTL_OVD); - venc_write(sd, VENC_VMOD, 0); - venc_modify(sd, VENC_VMOD, - (1 << VENC_VMOD_VIE_SHIFT), - VENC_VMOD_VIE); - venc_modify(sd, VENC_VMOD, - (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); - venc_modify(sd, VENC_VMOD, - (1 << VENC_VMOD_TVTYP_SHIFT), - VENC_VMOD_TVTYP); - venc_write(sd, VENC_DACTST, 0x0); - venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); - - return 0; -} - -#define VDAC_CONFIG_HD_V2 0x081141EF -/* - * venc_set_480p59_94 - * - * This function configures the video encoder to EDTV(525p) component setting. - */ -static int venc_set_480p59_94(struct v4l2_subdev *sd) -{ - struct venc_state *venc = to_state(sd); - struct venc_platform_data *pdata = venc->pdata; - - v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n"); - if (venc->venc_type != VPBE_VERSION_1 && - venc->venc_type != VPBE_VERSION_2) - return -EINVAL; - - /* Setup clock at VPSS & VENC for SD */ - if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0) - return -EINVAL; - - venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 27000000); - venc_enabledigitaloutput(sd, 0); - - if (venc->venc_type == VPBE_VERSION_2) - vdaccfg_write(sd, VDAC_CONFIG_HD_V2); - venc_write(sd, VENC_OSDCLK0, 0); - venc_write(sd, VENC_OSDCLK1, 1); - - if (venc->venc_type == VPBE_VERSION_1) { - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, - VENC_VDPRO_DAFRQ); - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, - VENC_VDPRO_DAUPS); - } - - venc_write(sd, VENC_VMOD, 0); - venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), - VENC_VMOD_VIE); - venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); - venc_modify(sd, VENC_VMOD, (HDTV_525P << VENC_VMOD_TVTYP_SHIFT), - VENC_VMOD_TVTYP); - venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << - VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); - - venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); - - return 0; -} - -/* - * venc_set_625p - * - * This function configures the video encoder to HDTV(625p) component setting - */ -static int venc_set_576p50(struct v4l2_subdev *sd) -{ - struct venc_state *venc = to_state(sd); - struct venc_platform_data *pdata = venc->pdata; - - v4l2_dbg(debug, 2, sd, "venc_set_576p50\n"); - - if (venc->venc_type != VPBE_VERSION_1 && - venc->venc_type != VPBE_VERSION_2) - return -EINVAL; - /* Setup clock at VPSS & VENC for SD */ - if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0) - return -EINVAL; - - venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 27000000); - venc_enabledigitaloutput(sd, 0); - - if (venc->venc_type == VPBE_VERSION_2) - vdaccfg_write(sd, VDAC_CONFIG_HD_V2); - - venc_write(sd, VENC_OSDCLK0, 0); - venc_write(sd, VENC_OSDCLK1, 1); - - if (venc->venc_type == VPBE_VERSION_1) { - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, - VENC_VDPRO_DAFRQ); - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, - VENC_VDPRO_DAUPS); - } - - venc_write(sd, VENC_VMOD, 0); - venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), - VENC_VMOD_VIE); - venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); - venc_modify(sd, VENC_VMOD, (HDTV_625P << VENC_VMOD_TVTYP_SHIFT), - VENC_VMOD_TVTYP); - - venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << - VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); - venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); - - return 0; -} - -/* - * venc_set_720p60_internal - Setup 720p60 in venc for dm365 only - */ -static int venc_set_720p60_internal(struct v4l2_subdev *sd) -{ - struct venc_state *venc = to_state(sd); - struct venc_platform_data *pdata = venc->pdata; - - if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0) - return -EINVAL; - - venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 74250000); - venc_enabledigitaloutput(sd, 0); - - venc_write(sd, VENC_OSDCLK0, 0); - venc_write(sd, VENC_OSDCLK1, 1); - - venc_write(sd, VENC_VMOD, 0); - /* DM365 component HD mode */ - venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), - VENC_VMOD_VIE); - venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); - venc_modify(sd, VENC_VMOD, (HDTV_720P << VENC_VMOD_TVTYP_SHIFT), - VENC_VMOD_TVTYP); - venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); - venc_write(sd, VENC_XHINTVL, 0); - return 0; -} - -/* - * venc_set_1080i30_internal - Setup 1080i30 in venc for dm365 only - */ -static int venc_set_1080i30_internal(struct v4l2_subdev *sd) -{ - struct venc_state *venc = to_state(sd); - struct venc_platform_data *pdata = venc->pdata; - - if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0) - return -EINVAL; - - venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 74250000); - venc_enabledigitaloutput(sd, 0); - - venc_write(sd, VENC_OSDCLK0, 0); - venc_write(sd, VENC_OSDCLK1, 1); - - - venc_write(sd, VENC_VMOD, 0); - /* DM365 component HD mode */ - venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), - VENC_VMOD_VIE); - venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); - venc_modify(sd, VENC_VMOD, (HDTV_1080I << VENC_VMOD_TVTYP_SHIFT), - VENC_VMOD_TVTYP); - venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); - venc_write(sd, VENC_XHINTVL, 0); - return 0; -} - -static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) -{ - v4l2_dbg(debug, 1, sd, "venc_s_std_output\n"); - - if (norm & V4L2_STD_525_60) - return venc_set_ntsc(sd); - else if (norm & V4L2_STD_625_50) - return venc_set_pal(sd); - - return -EINVAL; -} - -static int venc_s_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *dv_timings) -{ - struct venc_state *venc = to_state(sd); - u32 height = dv_timings->bt.height; - int ret; - - v4l2_dbg(debug, 1, sd, "venc_s_dv_timings\n"); - - if (height == 576) - return venc_set_576p50(sd); - else if (height == 480) - return venc_set_480p59_94(sd); - else if ((height == 720) && - (venc->venc_type == VPBE_VERSION_2)) { - /* TBD setup internal 720p mode here */ - ret = venc_set_720p60_internal(sd); - /* for DM365 VPBE, there is DAC inside */ - vdaccfg_write(sd, VDAC_CONFIG_HD_V2); - return ret; - } else if ((height == 1080) && - (venc->venc_type == VPBE_VERSION_2)) { - /* TBD setup internal 1080i mode here */ - ret = venc_set_1080i30_internal(sd); - /* for DM365 VPBE, there is DAC inside */ - vdaccfg_write(sd, VDAC_CONFIG_HD_V2); - return ret; - } - return -EINVAL; -} - -static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, - u32 config) -{ - struct venc_state *venc = to_state(sd); - int ret; - - v4l2_dbg(debug, 1, sd, "venc_s_routing\n"); - - ret = venc_set_dac(sd, output); - if (!ret) - venc->output = output; - - return ret; -} - -static long venc_command(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - u32 val; - - switch (cmd) { - case VENC_GET_FLD: - val = venc_read(sd, VENC_VSTAT); - *((int *)arg) = ((val & VENC_VSTAT_FIDST) == - VENC_VSTAT_FIDST); - break; - default: - v4l2_err(sd, "Wrong IOCTL cmd\n"); - break; - } - - return 0; -} - -static const struct v4l2_subdev_core_ops venc_core_ops = { - .command = venc_command, -}; - -static const struct v4l2_subdev_video_ops venc_video_ops = { - .s_routing = venc_s_routing, - .s_std_output = venc_s_std_output, - .s_dv_timings = venc_s_dv_timings, -}; - -static const struct v4l2_subdev_ops venc_ops = { - .core = &venc_core_ops, - .video = &venc_video_ops, -}; - -static int venc_initialize(struct v4l2_subdev *sd) -{ - struct venc_state *venc = to_state(sd); - int ret; - - /* Set default to output to composite and std to NTSC */ - venc->output = 0; - venc->std = V4L2_STD_525_60; - - ret = venc_s_routing(sd, 0, venc->output, 0); - if (ret < 0) { - v4l2_err(sd, "Error setting output during init\n"); - return -EINVAL; - } - - ret = venc_s_std_output(sd, venc->std); - if (ret < 0) { - v4l2_err(sd, "Error setting std during init\n"); - return -EINVAL; - } - - return ret; -} - -static int venc_device_get(struct device *dev, void *data) -{ - struct platform_device *pdev = to_platform_device(dev); - struct venc_state **venc = data; - - if (strstr(pdev->name, "vpbe-venc") != NULL) - *venc = platform_get_drvdata(pdev); - - return 0; -} - -struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, - const char *venc_name) -{ - struct venc_state *venc = NULL; - - bus_for_each_dev(&platform_bus_type, NULL, &venc, - venc_device_get); - if (venc == NULL) - return NULL; - - v4l2_subdev_init(&venc->sd, &venc_ops); - - strscpy(venc->sd.name, venc_name, sizeof(venc->sd.name)); - if (v4l2_device_register_subdev(v4l2_dev, &venc->sd) < 0) { - v4l2_err(v4l2_dev, - "vpbe unable to register venc sub device\n"); - return NULL; - } - if (venc_initialize(&venc->sd)) { - v4l2_err(v4l2_dev, - "vpbe venc initialization failed\n"); - return NULL; - } - - return &venc->sd; -} -EXPORT_SYMBOL(venc_sub_dev_init); - -static int venc_probe(struct platform_device *pdev) -{ - const struct platform_device_id *pdev_id; - struct venc_state *venc; - - if (!pdev->dev.platform_data) { - dev_err(&pdev->dev, "No platform data for VENC sub device"); - return -EINVAL; - } - - pdev_id = platform_get_device_id(pdev); - if (!pdev_id) - return -EINVAL; - - venc = devm_kzalloc(&pdev->dev, sizeof(struct venc_state), GFP_KERNEL); - if (venc == NULL) - return -ENOMEM; - - venc->venc_type = pdev_id->driver_data; - venc->pdev = &pdev->dev; - venc->pdata = pdev->dev.platform_data; - - venc->venc_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(venc->venc_base)) - return PTR_ERR(venc->venc_base); - - if (venc->venc_type != VPBE_VERSION_1) { - venc->vdaccfg_reg = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(venc->vdaccfg_reg)) - return PTR_ERR(venc->vdaccfg_reg); - } - spin_lock_init(&venc->lock); - platform_set_drvdata(pdev, venc); - dev_notice(venc->pdev, "VENC sub device probe success\n"); - - return 0; -} - -static int venc_remove(struct platform_device *pdev) -{ - return 0; -} - -static struct platform_driver venc_driver = { - .probe = venc_probe, - .remove = venc_remove, - .driver = { - .name = MODULE_NAME, - }, - .id_table = vpbe_venc_devtype -}; - -module_platform_driver(venc_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("VPBE VENC Driver"); -MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/platform/ti/davinci/vpbe_venc_regs.h b/drivers/media/platform/ti/davinci/vpbe_venc_regs.h deleted file mode 100644 index 29d8fc3af662..000000000000 --- a/drivers/media/platform/ti/davinci/vpbe_venc_regs.h +++ /dev/null @@ -1,165 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2006-2010 Texas Instruments Inc - */ -#ifndef _VPBE_VENC_REGS_H -#define _VPBE_VENC_REGS_H - -/* VPBE Video Encoder / Digital LCD Subsystem Registers (VENC) */ -#define VENC_VMOD 0x00 -#define VENC_VIDCTL 0x04 -#define VENC_VDPRO 0x08 -#define VENC_SYNCCTL 0x0C -#define VENC_HSPLS 0x10 -#define VENC_VSPLS 0x14 -#define VENC_HINT 0x18 -#define VENC_HSTART 0x1C -#define VENC_HVALID 0x20 -#define VENC_VINT 0x24 -#define VENC_VSTART 0x28 -#define VENC_VVALID 0x2C -#define VENC_HSDLY 0x30 -#define VENC_VSDLY 0x34 -#define VENC_YCCCTL 0x38 -#define VENC_RGBCTL 0x3C -#define VENC_RGBCLP 0x40 -#define VENC_LINECTL 0x44 -#define VENC_CULLLINE 0x48 -#define VENC_LCDOUT 0x4C -#define VENC_BRTS 0x50 -#define VENC_BRTW 0x54 -#define VENC_ACCTL 0x58 -#define VENC_PWMP 0x5C -#define VENC_PWMW 0x60 -#define VENC_DCLKCTL 0x64 -#define VENC_DCLKPTN0 0x68 -#define VENC_DCLKPTN1 0x6C -#define VENC_DCLKPTN2 0x70 -#define VENC_DCLKPTN3 0x74 -#define VENC_DCLKPTN0A 0x78 -#define VENC_DCLKPTN1A 0x7C -#define VENC_DCLKPTN2A 0x80 -#define VENC_DCLKPTN3A 0x84 -#define VENC_DCLKHS 0x88 -#define VENC_DCLKHSA 0x8C -#define VENC_DCLKHR 0x90 -#define VENC_DCLKVS 0x94 -#define VENC_DCLKVR 0x98 -#define VENC_CAPCTL 0x9C -#define VENC_CAPDO 0xA0 -#define VENC_CAPDE 0xA4 -#define VENC_ATR0 0xA8 -#define VENC_ATR1 0xAC -#define VENC_ATR2 0xB0 -#define VENC_VSTAT 0xB8 -#define VENC_RAMADR 0xBC -#define VENC_RAMPORT 0xC0 -#define VENC_DACTST 0xC4 -#define VENC_YCOLVL 0xC8 -#define VENC_SCPROG 0xCC -#define VENC_CVBS 0xDC -#define VENC_CMPNT 0xE0 -#define VENC_ETMG0 0xE4 -#define VENC_ETMG1 0xE8 -#define VENC_ETMG2 0xEC -#define VENC_ETMG3 0xF0 -#define VENC_DACSEL 0xF4 -#define VENC_ARGBX0 0x100 -#define VENC_ARGBX1 0x104 -#define VENC_ARGBX2 0x108 -#define VENC_ARGBX3 0x10C -#define VENC_ARGBX4 0x110 -#define VENC_DRGBX0 0x114 -#define VENC_DRGBX1 0x118 -#define VENC_DRGBX2 0x11C -#define VENC_DRGBX3 0x120 -#define VENC_DRGBX4 0x124 -#define VENC_VSTARTA 0x128 -#define VENC_OSDCLK0 0x12C -#define VENC_OSDCLK1 0x130 -#define VENC_HVLDCL0 0x134 -#define VENC_HVLDCL1 0x138 -#define VENC_OSDHADV 0x13C -#define VENC_CLKCTL 0x140 -#define VENC_GAMCTL 0x144 -#define VENC_XHINTVL 0x174 - -/* bit definitions */ -#define VPBE_PCR_VENC_DIV (1 << 1) -#define VPBE_PCR_CLK_OFF (1 << 0) - -#define VENC_VMOD_VDMD_SHIFT 12 -#define VENC_VMOD_VDMD_YCBCR16 0 -#define VENC_VMOD_VDMD_YCBCR8 1 -#define VENC_VMOD_VDMD_RGB666 2 -#define VENC_VMOD_VDMD_RGB8 3 -#define VENC_VMOD_VDMD_EPSON 4 -#define VENC_VMOD_VDMD_CASIO 5 -#define VENC_VMOD_VDMD_UDISPQVGA 6 -#define VENC_VMOD_VDMD_STNLCD 7 -#define VENC_VMOD_VIE_SHIFT 1 -#define VENC_VMOD_VDMD (7 << 12) -#define VENC_VMOD_ITLCL (1 << 11) -#define VENC_VMOD_ITLC (1 << 10) -#define VENC_VMOD_NSIT (1 << 9) -#define VENC_VMOD_HDMD (1 << 8) -#define VENC_VMOD_TVTYP_SHIFT 6 -#define VENC_VMOD_TVTYP (3 << 6) -#define VENC_VMOD_SLAVE (1 << 5) -#define VENC_VMOD_VMD (1 << 4) -#define VENC_VMOD_BLNK (1 << 3) -#define VENC_VMOD_VIE (1 << 1) -#define VENC_VMOD_VENC (1 << 0) - -/* VMOD TVTYP options for HDMD=0 */ -#define SDTV_NTSC 0 -#define SDTV_PAL 1 -/* VMOD TVTYP options for HDMD=1 */ -#define HDTV_525P 0 -#define HDTV_625P 1 -#define HDTV_1080I 2 -#define HDTV_720P 3 - -#define VENC_VIDCTL_VCLKP (1 << 14) -#define VENC_VIDCTL_VCLKE_SHIFT 13 -#define VENC_VIDCTL_VCLKE (1 << 13) -#define VENC_VIDCTL_VCLKZ_SHIFT 12 -#define VENC_VIDCTL_VCLKZ (1 << 12) -#define VENC_VIDCTL_SYDIR_SHIFT 8 -#define VENC_VIDCTL_SYDIR (1 << 8) -#define VENC_VIDCTL_DOMD_SHIFT 4 -#define VENC_VIDCTL_DOMD (3 << 4) -#define VENC_VIDCTL_YCDIR_SHIFT 0 -#define VENC_VIDCTL_YCDIR (1 << 0) - -#define VENC_VDPRO_ATYCC_SHIFT 5 -#define VENC_VDPRO_ATYCC (1 << 5) -#define VENC_VDPRO_ATCOM_SHIFT 4 -#define VENC_VDPRO_ATCOM (1 << 4) -#define VENC_VDPRO_DAFRQ (1 << 3) -#define VENC_VDPRO_DAUPS (1 << 2) -#define VENC_VDPRO_CUPS (1 << 1) -#define VENC_VDPRO_YUPS (1 << 0) - -#define VENC_SYNCCTL_VPL_SHIFT 3 -#define VENC_SYNCCTL_VPL (1 << 3) -#define VENC_SYNCCTL_HPL_SHIFT 2 -#define VENC_SYNCCTL_HPL (1 << 2) -#define VENC_SYNCCTL_SYEV_SHIFT 1 -#define VENC_SYNCCTL_SYEV (1 << 1) -#define VENC_SYNCCTL_SYEH_SHIFT 0 -#define VENC_SYNCCTL_SYEH (1 << 0) -#define VENC_SYNCCTL_OVD_SHIFT 14 -#define VENC_SYNCCTL_OVD (1 << 14) - -#define VENC_DCLKCTL_DCKEC_SHIFT 11 -#define VENC_DCLKCTL_DCKEC (1 << 11) -#define VENC_DCLKCTL_DCKPW_SHIFT 0 -#define VENC_DCLKCTL_DCKPW (0x3f << 0) - -#define VENC_VSTAT_FIDST (1 << 4) - -#define VENC_CMPNT_MRGB_SHIFT 14 -#define VENC_CMPNT_MRGB (1 << 14) - -#endif /* _VPBE_VENC_REGS_H */ diff --git a/drivers/media/platform/ti/davinci/vpss.c b/drivers/media/platform/ti/davinci/vpss.c deleted file mode 100644 index d15b991ab17c..000000000000 --- a/drivers/media/platform/ti/davinci/vpss.c +++ /dev/null @@ -1,529 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2009 Texas Instruments. - * - * common vpss system module platform driver for all video drivers. - */ -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/pm_runtime.h> -#include <linux/err.h> - -#include <media/davinci/vpss.h> - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("VPSS Driver"); -MODULE_AUTHOR("Texas Instruments"); - -/* DM644x defines */ -#define DM644X_SBL_PCR_VPSS (4) - -#define DM355_VPSSBL_INTSEL 0x10 -#define DM355_VPSSBL_EVTSEL 0x14 -/* vpss BL register offsets */ -#define DM355_VPSSBL_CCDCMUX 0x1c -/* vpss CLK register offsets */ -#define DM355_VPSSCLK_CLKCTRL 0x04 -/* masks and shifts */ -#define VPSS_HSSISEL_SHIFT 4 -/* - * VDINT0 - vpss_int0, VDINT1 - vpss_int1, H3A - vpss_int4, - * IPIPE_INT1_SDR - vpss_int5 - */ -#define DM355_VPSSBL_INTSEL_DEFAULT 0xff83ff10 -/* VENCINT - vpss_int8 */ -#define DM355_VPSSBL_EVTSEL_DEFAULT 0x4 - -#define DM365_ISP5_PCCR 0x04 -#define DM365_ISP5_PCCR_BL_CLK_ENABLE BIT(0) -#define DM365_ISP5_PCCR_ISIF_CLK_ENABLE BIT(1) -#define DM365_ISP5_PCCR_H3A_CLK_ENABLE BIT(2) -#define DM365_ISP5_PCCR_RSZ_CLK_ENABLE BIT(3) -#define DM365_ISP5_PCCR_IPIPE_CLK_ENABLE BIT(4) -#define DM365_ISP5_PCCR_IPIPEIF_CLK_ENABLE BIT(5) -#define DM365_ISP5_PCCR_RSV BIT(6) - -#define DM365_ISP5_BCR 0x08 -#define DM365_ISP5_BCR_ISIF_OUT_ENABLE BIT(1) - -#define DM365_ISP5_INTSEL1 0x10 -#define DM365_ISP5_INTSEL2 0x14 -#define DM365_ISP5_INTSEL3 0x18 -#define DM365_ISP5_CCDCMUX 0x20 -#define DM365_ISP5_PG_FRAME_SIZE 0x28 -#define DM365_VPBE_CLK_CTRL 0x00 - -#define VPSS_CLK_CTRL 0x01c40044 -#define VPSS_CLK_CTRL_VENCCLKEN BIT(3) -#define VPSS_CLK_CTRL_DACCLKEN BIT(4) - -/* - * vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1, - * AF - vpss_int3 - */ -#define DM365_ISP5_INTSEL1_DEFAULT 0x0b1f0100 -/* AEW - vpss_int6, RSZ_INT_DMA - vpss_int5 */ -#define DM365_ISP5_INTSEL2_DEFAULT 0x1f0a0f1f -/* VENC - vpss_int8 */ -#define DM365_ISP5_INTSEL3_DEFAULT 0x00000015 - -/* masks and shifts for DM365*/ -#define DM365_CCDC_PG_VD_POL_SHIFT 0 -#define DM365_CCDC_PG_HD_POL_SHIFT 1 - -#define CCD_SRC_SEL_MASK (BIT_MASK(5) | BIT_MASK(4)) -#define CCD_SRC_SEL_SHIFT 4 - -/* Different SoC platforms supported by this driver */ -enum vpss_platform_type { - DM644X, - DM355, - DM365, -}; - -/* - * vpss operations. Depends on platform. Not all functions are available - * on all platforms. The api, first check if a function is available before - * invoking it. In the probe, the function ptrs are initialized based on - * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc. - */ -struct vpss_hw_ops { - /* enable clock */ - int (*enable_clock)(enum vpss_clock_sel clock_sel, int en); - /* select input to ccdc */ - void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel); - /* clear wbl overflow bit */ - int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel); - /* set sync polarity */ - void (*set_sync_pol)(struct vpss_sync_pol); - /* set the PG_FRAME_SIZE register*/ - void (*set_pg_frame_size)(struct vpss_pg_frame_size); - /* check and clear interrupt if occurred */ - int (*dma_complete_interrupt)(void); -}; - -/* vpss configuration */ -struct vpss_oper_config { - __iomem void *vpss_regs_base0; - __iomem void *vpss_regs_base1; - __iomem void *vpss_regs_base2; - enum vpss_platform_type platform; - spinlock_t vpss_lock; - struct vpss_hw_ops hw_ops; -}; - -static struct vpss_oper_config oper_cfg; - -/* register access routines */ -static inline u32 bl_regr(u32 offset) -{ - return __raw_readl(oper_cfg.vpss_regs_base0 + offset); -} - -static inline void bl_regw(u32 val, u32 offset) -{ - __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); -} - -static inline u32 vpss_regr(u32 offset) -{ - return __raw_readl(oper_cfg.vpss_regs_base1 + offset); -} - -static inline void vpss_regw(u32 val, u32 offset) -{ - __raw_writel(val, oper_cfg.vpss_regs_base1 + offset); -} - -/* For DM365 only */ -static inline u32 isp5_read(u32 offset) -{ - return __raw_readl(oper_cfg.vpss_regs_base0 + offset); -} - -/* For DM365 only */ -static inline void isp5_write(u32 val, u32 offset) -{ - __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); -} - -static void dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) -{ - u32 temp = isp5_read(DM365_ISP5_CCDCMUX) & ~CCD_SRC_SEL_MASK; - - /* if we are using pattern generator, enable it */ - if (src_sel == VPSS_PGLPBK || src_sel == VPSS_CCDCPG) - temp |= 0x08; - - temp |= (src_sel << CCD_SRC_SEL_SHIFT); - isp5_write(temp, DM365_ISP5_CCDCMUX); -} - -static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) -{ - bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX); -} - -int vpss_dma_complete_interrupt(void) -{ - if (!oper_cfg.hw_ops.dma_complete_interrupt) - return 2; - return oper_cfg.hw_ops.dma_complete_interrupt(); -} -EXPORT_SYMBOL(vpss_dma_complete_interrupt); - -int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) -{ - if (!oper_cfg.hw_ops.select_ccdc_source) - return -EINVAL; - - oper_cfg.hw_ops.select_ccdc_source(src_sel); - return 0; -} -EXPORT_SYMBOL(vpss_select_ccdc_source); - -static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) -{ - u32 mask = 1, val; - - if (wbl_sel < VPSS_PCR_AEW_WBL_0 || - wbl_sel > VPSS_PCR_CCDC_WBL_O) - return -EINVAL; - - /* writing a 0 clear the overflow */ - mask = ~(mask << wbl_sel); - val = bl_regr(DM644X_SBL_PCR_VPSS) & mask; - bl_regw(val, DM644X_SBL_PCR_VPSS); - return 0; -} - -void vpss_set_sync_pol(struct vpss_sync_pol sync) -{ - if (!oper_cfg.hw_ops.set_sync_pol) - return; - - oper_cfg.hw_ops.set_sync_pol(sync); -} -EXPORT_SYMBOL(vpss_set_sync_pol); - -int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) -{ - if (!oper_cfg.hw_ops.clear_wbl_overflow) - return -EINVAL; - - return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel); -} -EXPORT_SYMBOL(vpss_clear_wbl_overflow); - -/* - * dm355_enable_clock - Enable VPSS Clock - * @clock_sel: Clock to be enabled/disabled - * @en: enable/disable flag - * - * This is called to enable or disable a vpss clock - */ -static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en) -{ - unsigned long flags; - u32 utemp, mask = 0x1, shift = 0; - - switch (clock_sel) { - case VPSS_VPBE_CLOCK: - /* nothing since lsb */ - break; - case VPSS_VENC_CLOCK_SEL: - shift = 2; - break; - case VPSS_CFALD_CLOCK: - shift = 3; - break; - case VPSS_H3A_CLOCK: - shift = 4; - break; - case VPSS_IPIPE_CLOCK: - shift = 5; - break; - case VPSS_CCDC_CLOCK: - shift = 6; - break; - default: - printk(KERN_ERR "dm355_enable_clock: Invalid selector: %d\n", - clock_sel); - return -EINVAL; - } - - spin_lock_irqsave(&oper_cfg.vpss_lock, flags); - utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL); - if (!en) - utemp &= ~(mask << shift); - else - utemp |= (mask << shift); - - vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL); - spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); - return 0; -} - -static int dm365_enable_clock(enum vpss_clock_sel clock_sel, int en) -{ - unsigned long flags; - u32 utemp, mask = 0x1, shift = 0, offset = DM365_ISP5_PCCR; - u32 (*read)(u32 offset) = isp5_read; - void(*write)(u32 val, u32 offset) = isp5_write; - - switch (clock_sel) { - case VPSS_BL_CLOCK: - break; - case VPSS_CCDC_CLOCK: - shift = 1; - break; - case VPSS_H3A_CLOCK: - shift = 2; - break; - case VPSS_RSZ_CLOCK: - shift = 3; - break; - case VPSS_IPIPE_CLOCK: - shift = 4; - break; - case VPSS_IPIPEIF_CLOCK: - shift = 5; - break; - case VPSS_PCLK_INTERNAL: - shift = 6; - break; - case VPSS_PSYNC_CLOCK_SEL: - shift = 7; - break; - case VPSS_VPBE_CLOCK: - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_VENC_CLOCK_SEL: - shift = 2; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_LDC_CLOCK: - shift = 3; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_FDIF_CLOCK: - shift = 4; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_OSD_CLOCK_SEL: - shift = 6; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_LDC_CLOCK_SEL: - shift = 7; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - default: - printk(KERN_ERR "dm365_enable_clock: Invalid selector: %d\n", - clock_sel); - return -1; - } - - spin_lock_irqsave(&oper_cfg.vpss_lock, flags); - utemp = read(offset); - if (!en) { - mask = ~mask; - utemp &= (mask << shift); - } else - utemp |= (mask << shift); - - write(utemp, offset); - spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); - - return 0; -} - -int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en) -{ - if (!oper_cfg.hw_ops.enable_clock) - return -EINVAL; - - return oper_cfg.hw_ops.enable_clock(clock_sel, en); -} -EXPORT_SYMBOL(vpss_enable_clock); - -void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync) -{ - int val = 0; - val = isp5_read(DM365_ISP5_CCDCMUX); - - val |= (sync.ccdpg_hdpol << DM365_CCDC_PG_HD_POL_SHIFT); - val |= (sync.ccdpg_vdpol << DM365_CCDC_PG_VD_POL_SHIFT); - - isp5_write(val, DM365_ISP5_CCDCMUX); -} -EXPORT_SYMBOL(dm365_vpss_set_sync_pol); - -void vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size) -{ - if (!oper_cfg.hw_ops.set_pg_frame_size) - return; - - oper_cfg.hw_ops.set_pg_frame_size(frame_size); -} -EXPORT_SYMBOL(vpss_set_pg_frame_size); - -void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size) -{ - int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16; - - current_reg |= (frame_size.pplen - 1); - isp5_write(current_reg, DM365_ISP5_PG_FRAME_SIZE); -} -EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size); - -static int vpss_probe(struct platform_device *pdev) -{ - char *platform_name; - - if (!pdev->dev.platform_data) { - dev_err(&pdev->dev, "no platform data\n"); - return -ENOENT; - } - - platform_name = pdev->dev.platform_data; - if (!strcmp(platform_name, "dm355_vpss")) - oper_cfg.platform = DM355; - else if (!strcmp(platform_name, "dm365_vpss")) - oper_cfg.platform = DM365; - else if (!strcmp(platform_name, "dm644x_vpss")) - oper_cfg.platform = DM644X; - else { - dev_err(&pdev->dev, "vpss driver not supported on this platform\n"); - return -ENODEV; - } - - dev_info(&pdev->dev, "%s vpss probed\n", platform_name); - oper_cfg.vpss_regs_base0 = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(oper_cfg.vpss_regs_base0)) - return PTR_ERR(oper_cfg.vpss_regs_base0); - - if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { - oper_cfg.vpss_regs_base1 = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(oper_cfg.vpss_regs_base1)) - return PTR_ERR(oper_cfg.vpss_regs_base1); - } - - if (oper_cfg.platform == DM355) { - oper_cfg.hw_ops.enable_clock = dm355_enable_clock; - oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source; - /* Setup vpss interrupts */ - bl_regw(DM355_VPSSBL_INTSEL_DEFAULT, DM355_VPSSBL_INTSEL); - bl_regw(DM355_VPSSBL_EVTSEL_DEFAULT, DM355_VPSSBL_EVTSEL); - } else if (oper_cfg.platform == DM365) { - oper_cfg.hw_ops.enable_clock = dm365_enable_clock; - oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source; - /* Setup vpss interrupts */ - isp5_write((isp5_read(DM365_ISP5_PCCR) | - DM365_ISP5_PCCR_BL_CLK_ENABLE | - DM365_ISP5_PCCR_ISIF_CLK_ENABLE | - DM365_ISP5_PCCR_H3A_CLK_ENABLE | - DM365_ISP5_PCCR_RSZ_CLK_ENABLE | - DM365_ISP5_PCCR_IPIPE_CLK_ENABLE | - DM365_ISP5_PCCR_IPIPEIF_CLK_ENABLE | - DM365_ISP5_PCCR_RSV), DM365_ISP5_PCCR); - isp5_write((isp5_read(DM365_ISP5_BCR) | - DM365_ISP5_BCR_ISIF_OUT_ENABLE), DM365_ISP5_BCR); - isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1); - isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2); - isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3); - } else - oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow; - - pm_runtime_enable(&pdev->dev); - - pm_runtime_get(&pdev->dev); - - spin_lock_init(&oper_cfg.vpss_lock); - dev_info(&pdev->dev, "%s vpss probe success\n", platform_name); - - return 0; -} - -static int vpss_remove(struct platform_device *pdev) -{ - pm_runtime_disable(&pdev->dev); - return 0; -} - -static int vpss_suspend(struct device *dev) -{ - pm_runtime_put(dev); - return 0; -} - -static int vpss_resume(struct device *dev) -{ - pm_runtime_get(dev); - return 0; -} - -static const struct dev_pm_ops vpss_pm_ops = { - .suspend = vpss_suspend, - .resume = vpss_resume, -}; - -static struct platform_driver vpss_driver = { - .driver = { - .name = "vpss", - .pm = &vpss_pm_ops, - }, - .remove = vpss_remove, - .probe = vpss_probe, -}; - -static void vpss_exit(void) -{ - platform_driver_unregister(&vpss_driver); - iounmap(oper_cfg.vpss_regs_base2); - release_mem_region(VPSS_CLK_CTRL, 4); -} - -static int __init vpss_init(void) -{ - int ret; - - if (!request_mem_region(VPSS_CLK_CTRL, 4, "vpss_clock_control")) - return -EBUSY; - - oper_cfg.vpss_regs_base2 = ioremap(VPSS_CLK_CTRL, 4); - if (unlikely(!oper_cfg.vpss_regs_base2)) { - ret = -ENOMEM; - goto err_ioremap; - } - - writel(VPSS_CLK_CTRL_VENCCLKEN | - VPSS_CLK_CTRL_DACCLKEN, oper_cfg.vpss_regs_base2); - - ret = platform_driver_register(&vpss_driver); - if (ret) - goto err_pd_register; - - return 0; - -err_pd_register: - iounmap(oper_cfg.vpss_regs_base2); -err_ioremap: - release_mem_region(VPSS_CLK_CTRL, 4); - return ret; -} -subsys_initcall(vpss_init); -module_exit(vpss_exit); diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c index 3d3b6dc24ca6..002ea6588edf 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-api.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c @@ -150,8 +150,8 @@ static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) * then return an error. */ if (strlen(ctrl->p_new.p_char) == ctrl->maximum && last) - ctrl->is_new = 1; return -ERANGE; + ctrl->is_new = 1; } return ret; default: diff --git a/drivers/memory/atmel-sdramc.c b/drivers/memory/atmel-sdramc.c index 9c49d00c2a96..ea6e9e1eaf04 100644 --- a/drivers/memory/atmel-sdramc.c +++ b/drivers/memory/atmel-sdramc.c @@ -47,19 +47,17 @@ static int atmel_ramc_probe(struct platform_device *pdev) caps = of_device_get_match_data(&pdev->dev); if (caps->has_ddrck) { - clk = devm_clk_get(&pdev->dev, "ddrck"); + clk = devm_clk_get_enabled(&pdev->dev, "ddrck"); if (IS_ERR(clk)) return PTR_ERR(clk); - clk_prepare_enable(clk); } if (caps->has_mpddr_clk) { - clk = devm_clk_get(&pdev->dev, "mpddr"); + clk = devm_clk_get_enabled(&pdev->dev, "mpddr"); if (IS_ERR(clk)) { pr_err("AT91 RAMC: couldn't get mpddr clock\n"); return PTR_ERR(clk); } - clk_prepare_enable(clk); } return 0; diff --git a/drivers/memory/mvebu-devbus.c b/drivers/memory/mvebu-devbus.c index 8450638e8670..efc6c08db2b7 100644 --- a/drivers/memory/mvebu-devbus.c +++ b/drivers/memory/mvebu-devbus.c @@ -280,10 +280,9 @@ static int mvebu_devbus_probe(struct platform_device *pdev) if (IS_ERR(devbus->base)) return PTR_ERR(devbus->base); - clk = devm_clk_get(&pdev->dev, NULL); + clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(clk)) return PTR_ERR(clk); - clk_prepare_enable(clk); /* * Obtain clock period in picoseconds, diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index 57d9f91fe89b..d78f73db37c8 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c @@ -1918,7 +1918,8 @@ int gpmc_cs_program_settings(int cs, struct gpmc_settings *p) } } - if (p->wait_pin > gpmc_nr_waitpins) { + if (p->wait_pin != GPMC_WAITPIN_INVALID && + p->wait_pin > gpmc_nr_waitpins) { pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin); return -EINVAL; } diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c index 62477e592bf5..7bb73f06fad3 100644 --- a/drivers/memory/tegra/tegra186.c +++ b/drivers/memory/tegra/tegra186.c @@ -22,32 +22,6 @@ #define MC_SID_STREAMID_SECURITY_WRITE_ACCESS_DISABLED BIT(16) #define MC_SID_STREAMID_SECURITY_OVERRIDE BIT(8) -static void tegra186_mc_program_sid(struct tegra_mc *mc) -{ - unsigned int i; - - for (i = 0; i < mc->soc->num_clients; i++) { - const struct tegra_mc_client *client = &mc->soc->clients[i]; - u32 override, security; - - override = readl(mc->regs + client->regs.sid.override); - security = readl(mc->regs + client->regs.sid.security); - - dev_dbg(mc->dev, "client %s: override: %x security: %x\n", - client->name, override, security); - - dev_dbg(mc->dev, "setting SID %u for %s\n", client->sid, - client->name); - writel(client->sid, mc->regs + client->regs.sid.override); - - override = readl(mc->regs + client->regs.sid.override); - security = readl(mc->regs + client->regs.sid.security); - - dev_dbg(mc->dev, "client %s: override: %x security: %x\n", - client->name, override, security); - } -} - static int tegra186_mc_probe(struct tegra_mc *mc) { struct platform_device *pdev = to_platform_device(mc->dev); @@ -85,8 +59,6 @@ populate: if (err < 0) return err; - tegra186_mc_program_sid(mc); - return 0; } @@ -95,13 +67,6 @@ static void tegra186_mc_remove(struct tegra_mc *mc) of_platform_depopulate(mc->dev); } -static int tegra186_mc_resume(struct tegra_mc *mc) -{ - tegra186_mc_program_sid(mc); - - return 0; -} - #if IS_ENABLED(CONFIG_IOMMU_API) static void tegra186_mc_client_sid_override(struct tegra_mc *mc, const struct tegra_mc_client *client, @@ -173,7 +138,6 @@ static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev) const struct tegra_mc_ops tegra186_mc_ops = { .probe = tegra186_mc_probe, .remove = tegra186_mc_remove, - .resume = tegra186_mc_resume, .probe_device = tegra186_mc_probe_device, .handle_irq = tegra30_mc_handle_irq, }; diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 30db49f31866..5c24841e5699 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -300,15 +300,6 @@ config MFD_CS47L92 help Support for Cirrus Logic CS42L92, CS47L92 and CS47L93 Smart Codecs -config MFD_ASIC3 - bool "Compaq ASIC3" - depends on GPIOLIB - depends on ARM || COMPILE_TEST - select MFD_CORE - help - This driver supports the ASIC3 multifunction chip found on many - PDAs (mainly iPAQ and HTC based ones) - config PMIC_DA903X bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" depends on I2C=y @@ -550,15 +541,6 @@ config MFD_HI655X_PMIC help Select this option to enable Hisilicon hi655x series pmic driver. -config HTC_PASIC3 - tristate "HTC PASIC3 LED/DS1WM chip support" - select MFD_CORE - help - This core driver provides register access for the LED/DS1WM - chips labeled "AIC2" and "AIC3", found on HTC Blueangel and - HTC Magician devices, respectively. Actual functionality is - handled by the leds-pasic3 and ds1wm drivers. - config MFD_INTEL_QUARK_I2C_GPIO tristate "Intel Quark MFD I2C GPIO" depends on PCI @@ -702,7 +684,7 @@ config MFD_INTEL_PMC_BXT config MFD_IPAQ_MICRO bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" - depends on SA1100_H3100 || SA1100_H3600 + depends on SA1100_H3600 select MFD_CORE help Select this to get support for the Microcontroller found in @@ -1080,17 +1062,6 @@ config PCF50633_GPIO Say yes here if you want to include support GPIO for pins on the PCF50633 chip. -config UCB1400_CORE - tristate "Philips UCB1400 Core driver" - depends on AC97_BUS - depends on GPIOLIB - help - This enables support for the Philips UCB1400 core functions. - The UCB1400 is an AC97 audio codec. - - To compile this driver as a module, choose M here: the - module will be called ucb1400_core. - config MFD_PM8XXX tristate "Qualcomm PM8xxx PMIC chips driver" depends on (ARM || HEXAGON || COMPILE_TEST) @@ -1514,7 +1485,7 @@ config TPS6105X config TPS65010 tristate "TI TPS6501x Power Management chips" depends on I2C && GPIOLIB - default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK + default MACH_OMAP_OSK help If you say yes here you get support for the TPS6501x series of Power Management chips. These include voltage regulators, @@ -1795,35 +1766,6 @@ config MFD_TC3589X additional drivers must be enabled in order to use the functionality of the device. -config MFD_TMIO - bool - default n - -config MFD_T7L66XB - bool "Toshiba T7L66XB" - depends on ARM && HAVE_CLK - select MFD_CORE - select MFD_TMIO - help - Support for Toshiba Mobile IO Controller T7L66XB - -config MFD_TC6387XB - bool "Toshiba TC6387XB" - depends on ARM && HAVE_CLK - select MFD_CORE - select MFD_TMIO - help - Support for Toshiba Mobile IO Controller TC6387XB - -config MFD_TC6393XB - bool "Toshiba TC6393XB" - depends on ARM && HAVE_CLK - select GPIOLIB - select MFD_CORE - select MFD_TMIO - help - Support for Toshiba Mobile IO Controller TC6393XB - config MFD_TQMX86 tristate "TQ-Systems IO controller TQMX86" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 457471478a93..09712495f4f4 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o obj-$(CONFIG_MFD_ACT8945A) += act8945a.o obj-$(CONFIG_MFD_SM501) += sm501.o -obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o @@ -18,8 +17,6 @@ obj-$(CONFIG_MFD_ENE_KB3930) += ene-kb3930.o obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o obj-$(CONFIG_MFD_GATEWORKS_GSC) += gateworks-gsc.o -obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o - obj-$(CONFIG_MFD_TI_LP873X) += lp873x.o obj-$(CONFIG_MFD_TI_LP87565) += lp87565.o obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o @@ -30,9 +27,6 @@ obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o obj-$(CONFIG_MFD_SUN6I_PRCM) += sun6i-prcm.o obj-$(CONFIG_MFD_TC3589X) += tc3589x.o -obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o -obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o -obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o obj-$(CONFIG_MFD_TQMX86) += tqmx86.o obj-$(CONFIG_MFD_LOCHNAGAR) += lochnagar-i2c.o @@ -131,7 +125,6 @@ obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o ifeq ($(CONFIG_SA1100_ASSABET),y) obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o endif -obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o obj-$(CONFIG_PMIC_DA903X) += da903x.o diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c deleted file mode 100644 index 4fb7e35eb5ed..000000000000 --- a/drivers/mfd/asic3.c +++ /dev/null @@ -1,1071 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * driver/mfd/asic3.c - * - * Compaq ASIC3 support. - * - * 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> -#include <linux/delay.h> -#include <linux/irq.h> -#include <linux/gpio/driver.h> -#include <linux/export.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/platform_device.h> - -#include <linux/mfd/asic3.h> -#include <linux/mfd/core.h> -#include <linux/mfd/ds1wm.h> -#include <linux/mfd/tmio.h> - -#include <linux/mmc/host.h> - -enum { - ASIC3_CLOCK_SPI, - ASIC3_CLOCK_OWM, - ASIC3_CLOCK_PWM0, - ASIC3_CLOCK_PWM1, - ASIC3_CLOCK_LED0, - ASIC3_CLOCK_LED1, - ASIC3_CLOCK_LED2, - ASIC3_CLOCK_SD_HOST, - ASIC3_CLOCK_SD_BUS, - ASIC3_CLOCK_SMBUS, - ASIC3_CLOCK_EX0, - ASIC3_CLOCK_EX1, -}; - -struct asic3_clk { - int enabled; - unsigned int cdex; - unsigned long rate; -}; - -#define INIT_CDEX(_name, _rate) \ - [ASIC3_CLOCK_##_name] = { \ - .cdex = CLOCK_CDEX_##_name, \ - .rate = _rate, \ - } - -static struct asic3_clk asic3_clk_init[] __initdata = { - INIT_CDEX(SPI, 0), - INIT_CDEX(OWM, 5000000), - INIT_CDEX(PWM0, 0), - INIT_CDEX(PWM1, 0), - INIT_CDEX(LED0, 0), - INIT_CDEX(LED1, 0), - INIT_CDEX(LED2, 0), - INIT_CDEX(SD_HOST, 24576000), - INIT_CDEX(SD_BUS, 12288000), - INIT_CDEX(SMBUS, 0), - INIT_CDEX(EX0, 32768), - INIT_CDEX(EX1, 24576000), -}; - -struct asic3 { - void __iomem *mapping; - unsigned int bus_shift; - unsigned int irq_nr; - unsigned int irq_base; - raw_spinlock_t lock; - u16 irq_bothedge[4]; - struct gpio_chip gpio; - struct device *dev; - void __iomem *tmio_cnf; - - struct asic3_clk clocks[ARRAY_SIZE(asic3_clk_init)]; -}; - -static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset); - -void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 value) -{ - iowrite16(value, asic->mapping + - (reg >> asic->bus_shift)); -} -EXPORT_SYMBOL_GPL(asic3_write_register); - -u32 asic3_read_register(struct asic3 *asic, unsigned int reg) -{ - return ioread16(asic->mapping + - (reg >> asic->bus_shift)); -} -EXPORT_SYMBOL_GPL(asic3_read_register); - -static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set) -{ - unsigned long flags; - u32 val; - - raw_spin_lock_irqsave(&asic->lock, flags); - val = asic3_read_register(asic, reg); - if (set) - val |= bits; - else - val &= ~bits; - asic3_write_register(asic, reg, val); - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -/* IRQs */ -#define MAX_ASIC_ISR_LOOPS 20 -#define ASIC3_GPIO_BASE_INCR \ - (ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE) - -static void asic3_irq_flip_edge(struct asic3 *asic, - u32 base, int bit) -{ - u16 edge; - unsigned long flags; - - raw_spin_lock_irqsave(&asic->lock, flags); - edge = asic3_read_register(asic, - base + ASIC3_GPIO_EDGE_TRIGGER); - edge ^= bit; - asic3_write_register(asic, - base + ASIC3_GPIO_EDGE_TRIGGER, edge); - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -static void asic3_irq_demux(struct irq_desc *desc) -{ - struct asic3 *asic = irq_desc_get_handler_data(desc); - struct irq_data *data = irq_desc_get_irq_data(desc); - int iter, i; - unsigned long flags; - - data->chip->irq_ack(data); - - for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) { - u32 status; - int bank; - - raw_spin_lock_irqsave(&asic->lock, flags); - status = asic3_read_register(asic, - ASIC3_OFFSET(INTR, P_INT_STAT)); - raw_spin_unlock_irqrestore(&asic->lock, flags); - - /* Check all ten register bits */ - if ((status & 0x3ff) == 0) - break; - - /* Handle GPIO IRQs */ - for (bank = 0; bank < ASIC3_NUM_GPIO_BANKS; bank++) { - if (status & (1 << bank)) { - unsigned long base, istat; - - base = ASIC3_GPIO_A_BASE - + bank * ASIC3_GPIO_BASE_INCR; - raw_spin_lock_irqsave(&asic->lock, flags); - istat = asic3_read_register(asic, - base + - ASIC3_GPIO_INT_STATUS); - /* Clearing IntStatus */ - asic3_write_register(asic, - base + - ASIC3_GPIO_INT_STATUS, 0); - raw_spin_unlock_irqrestore(&asic->lock, flags); - - for (i = 0; i < ASIC3_GPIOS_PER_BANK; i++) { - int bit = (1 << i); - unsigned int irqnr; - - if (!(istat & bit)) - continue; - - irqnr = asic->irq_base + - (ASIC3_GPIOS_PER_BANK * bank) - + i; - generic_handle_irq(irqnr); - if (asic->irq_bothedge[bank] & bit) - asic3_irq_flip_edge(asic, base, - bit); - } - } - } - - /* Handle remaining IRQs in the status register */ - for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) { - /* They start at bit 4 and go up */ - if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) - generic_handle_irq(asic->irq_base + i); - } - } - - if (iter >= MAX_ASIC_ISR_LOOPS) - dev_err(asic->dev, "interrupt processing overrun\n"); -} - -static inline int asic3_irq_to_bank(struct asic3 *asic, int irq) -{ - int n; - - n = (irq - asic->irq_base) >> 4; - - return (n * (ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE)); -} - -static inline int asic3_irq_to_index(struct asic3 *asic, int irq) -{ - return (irq - asic->irq_base) & 0xf; -} - -static void asic3_mask_gpio_irq(struct irq_data *data) -{ - struct asic3 *asic = irq_data_get_irq_chip_data(data); - u32 val, bank, index; - unsigned long flags; - - bank = asic3_irq_to_bank(asic, data->irq); - index = asic3_irq_to_index(asic, data->irq); - - raw_spin_lock_irqsave(&asic->lock, flags); - val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); - val |= 1 << index; - asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val); - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -static void asic3_mask_irq(struct irq_data *data) -{ - struct asic3 *asic = irq_data_get_irq_chip_data(data); - int regval; - unsigned long flags; - - raw_spin_lock_irqsave(&asic->lock, flags); - regval = asic3_read_register(asic, - ASIC3_INTR_BASE + - ASIC3_INTR_INT_MASK); - - regval &= ~(ASIC3_INTMASK_MASK0 << - (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS))); - - asic3_write_register(asic, - ASIC3_INTR_BASE + - ASIC3_INTR_INT_MASK, - regval); - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -static void asic3_unmask_gpio_irq(struct irq_data *data) -{ - struct asic3 *asic = irq_data_get_irq_chip_data(data); - u32 val, bank, index; - unsigned long flags; - - bank = asic3_irq_to_bank(asic, data->irq); - index = asic3_irq_to_index(asic, data->irq); - - raw_spin_lock_irqsave(&asic->lock, flags); - val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); - val &= ~(1 << index); - asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val); - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -static void asic3_unmask_irq(struct irq_data *data) -{ - struct asic3 *asic = irq_data_get_irq_chip_data(data); - int regval; - unsigned long flags; - - raw_spin_lock_irqsave(&asic->lock, flags); - regval = asic3_read_register(asic, - ASIC3_INTR_BASE + - ASIC3_INTR_INT_MASK); - - regval |= (ASIC3_INTMASK_MASK0 << - (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS))); - - asic3_write_register(asic, - ASIC3_INTR_BASE + - ASIC3_INTR_INT_MASK, - regval); - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type) -{ - struct asic3 *asic = irq_data_get_irq_chip_data(data); - u32 bank, index; - u16 trigger, level, edge, bit; - unsigned long flags; - - bank = asic3_irq_to_bank(asic, data->irq); - index = asic3_irq_to_index(asic, data->irq); - bit = 1<<index; - - raw_spin_lock_irqsave(&asic->lock, flags); - level = asic3_read_register(asic, - bank + ASIC3_GPIO_LEVEL_TRIGGER); - edge = asic3_read_register(asic, - bank + ASIC3_GPIO_EDGE_TRIGGER); - trigger = asic3_read_register(asic, - bank + ASIC3_GPIO_TRIGGER_TYPE); - asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] &= ~bit; - - if (type == IRQ_TYPE_EDGE_RISING) { - trigger |= bit; - edge |= bit; - } else if (type == IRQ_TYPE_EDGE_FALLING) { - trigger |= bit; - edge &= ~bit; - } else if (type == IRQ_TYPE_EDGE_BOTH) { - trigger |= bit; - if (asic3_gpio_get(&asic->gpio, data->irq - asic->irq_base)) - edge &= ~bit; - else - edge |= bit; - asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] |= bit; - } else if (type == IRQ_TYPE_LEVEL_LOW) { - trigger &= ~bit; - level &= ~bit; - } else if (type == IRQ_TYPE_LEVEL_HIGH) { - trigger &= ~bit; - level |= bit; - } else { - /* - * if type == IRQ_TYPE_NONE, we should mask interrupts, but - * be careful to not unmask them if mask was also called. - * Probably need internal state for mask. - */ - dev_notice(asic->dev, "irq type not changed\n"); - } - asic3_write_register(asic, bank + ASIC3_GPIO_LEVEL_TRIGGER, - level); - asic3_write_register(asic, bank + ASIC3_GPIO_EDGE_TRIGGER, - edge); - asic3_write_register(asic, bank + ASIC3_GPIO_TRIGGER_TYPE, - trigger); - raw_spin_unlock_irqrestore(&asic->lock, flags); - return 0; -} - -static int asic3_gpio_irq_set_wake(struct irq_data *data, unsigned int on) -{ - struct asic3 *asic = irq_data_get_irq_chip_data(data); - u32 bank, index; - u16 bit; - - bank = asic3_irq_to_bank(asic, data->irq); - index = asic3_irq_to_index(asic, data->irq); - bit = 1<<index; - - asic3_set_register(asic, bank + ASIC3_GPIO_SLEEP_MASK, bit, !on); - - return 0; -} - -static struct irq_chip asic3_gpio_irq_chip = { - .name = "ASIC3-GPIO", - .irq_ack = asic3_mask_gpio_irq, - .irq_mask = asic3_mask_gpio_irq, - .irq_unmask = asic3_unmask_gpio_irq, - .irq_set_type = asic3_gpio_irq_type, - .irq_set_wake = asic3_gpio_irq_set_wake, -}; - -static struct irq_chip asic3_irq_chip = { - .name = "ASIC3", - .irq_ack = asic3_mask_irq, - .irq_mask = asic3_mask_irq, - .irq_unmask = asic3_unmask_irq, -}; - -static int __init asic3_irq_probe(struct platform_device *pdev) -{ - struct asic3 *asic = platform_get_drvdata(pdev); - unsigned long clksel = 0; - unsigned int irq, irq_base; - int ret; - - ret = platform_get_irq(pdev, 0); - if (ret < 0) - return ret; - asic->irq_nr = ret; - - /* turn on clock to IRQ controller */ - clksel |= CLOCK_SEL_CX; - asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), - clksel); - - irq_base = asic->irq_base; - - for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { - if (irq < asic->irq_base + ASIC3_NUM_GPIOS) - irq_set_chip(irq, &asic3_gpio_irq_chip); - else - irq_set_chip(irq, &asic3_irq_chip); - - irq_set_chip_data(irq, asic); - irq_set_handler(irq, handle_level_irq); - irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); - } - - asic3_write_register(asic, ASIC3_OFFSET(INTR, INT_MASK), - ASIC3_INTMASK_GINTMASK); - - irq_set_chained_handler_and_data(asic->irq_nr, asic3_irq_demux, asic); - irq_set_irq_type(asic->irq_nr, IRQ_TYPE_EDGE_RISING); - - return 0; -} - -static void asic3_irq_remove(struct platform_device *pdev) -{ - struct asic3 *asic = platform_get_drvdata(pdev); - unsigned int irq, irq_base; - - irq_base = asic->irq_base; - - for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { - irq_set_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); - } - irq_set_chained_handler(asic->irq_nr, NULL); -} - -/* GPIOs */ -static int asic3_gpio_direction(struct gpio_chip *chip, - unsigned offset, int out) -{ - u32 mask = ASIC3_GPIO_TO_MASK(offset), out_reg; - unsigned int gpio_base; - unsigned long flags; - struct asic3 *asic; - - asic = gpiochip_get_data(chip); - gpio_base = ASIC3_GPIO_TO_BASE(offset); - - if (gpio_base > ASIC3_GPIO_D_BASE) { - dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n", - gpio_base, offset); - return -EINVAL; - } - - raw_spin_lock_irqsave(&asic->lock, flags); - - out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_DIRECTION); - - /* Input is 0, Output is 1 */ - if (out) - out_reg |= mask; - else - out_reg &= ~mask; - - asic3_write_register(asic, gpio_base + ASIC3_GPIO_DIRECTION, out_reg); - - raw_spin_unlock_irqrestore(&asic->lock, flags); - - return 0; - -} - -static int asic3_gpio_direction_input(struct gpio_chip *chip, - unsigned offset) -{ - return asic3_gpio_direction(chip, offset, 0); -} - -static int asic3_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - return asic3_gpio_direction(chip, offset, 1); -} - -static int asic3_gpio_get(struct gpio_chip *chip, - unsigned offset) -{ - unsigned int gpio_base; - u32 mask = ASIC3_GPIO_TO_MASK(offset); - struct asic3 *asic; - - asic = gpiochip_get_data(chip); - gpio_base = ASIC3_GPIO_TO_BASE(offset); - - if (gpio_base > ASIC3_GPIO_D_BASE) { - dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n", - gpio_base, offset); - return -EINVAL; - } - - return !!(asic3_read_register(asic, - gpio_base + ASIC3_GPIO_STATUS) & mask); -} - -static void asic3_gpio_set(struct gpio_chip *chip, - unsigned offset, int value) -{ - u32 mask, out_reg; - unsigned int gpio_base; - unsigned long flags; - struct asic3 *asic; - - asic = gpiochip_get_data(chip); - gpio_base = ASIC3_GPIO_TO_BASE(offset); - - if (gpio_base > ASIC3_GPIO_D_BASE) { - dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n", - gpio_base, offset); - return; - } - - mask = ASIC3_GPIO_TO_MASK(offset); - - raw_spin_lock_irqsave(&asic->lock, flags); - - out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_OUT); - - if (value) - out_reg |= mask; - else - out_reg &= ~mask; - - asic3_write_register(asic, gpio_base + ASIC3_GPIO_OUT, out_reg); - - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct asic3 *asic = gpiochip_get_data(chip); - - return asic->irq_base + offset; -} - -static __init int asic3_gpio_probe(struct platform_device *pdev, - u16 *gpio_config, int num) -{ - struct asic3 *asic = platform_get_drvdata(pdev); - u16 alt_reg[ASIC3_NUM_GPIO_BANKS]; - u16 out_reg[ASIC3_NUM_GPIO_BANKS]; - u16 dir_reg[ASIC3_NUM_GPIO_BANKS]; - int i; - - memset(alt_reg, 0, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); - memset(out_reg, 0, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); - memset(dir_reg, 0, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); - - /* Enable all GPIOs */ - asic3_write_register(asic, ASIC3_GPIO_OFFSET(A, MASK), 0xffff); - asic3_write_register(asic, ASIC3_GPIO_OFFSET(B, MASK), 0xffff); - asic3_write_register(asic, ASIC3_GPIO_OFFSET(C, MASK), 0xffff); - asic3_write_register(asic, ASIC3_GPIO_OFFSET(D, MASK), 0xffff); - - for (i = 0; i < num; i++) { - u8 alt, pin, dir, init, bank_num, bit_num; - u16 config = gpio_config[i]; - - pin = ASIC3_CONFIG_GPIO_PIN(config); - alt = ASIC3_CONFIG_GPIO_ALT(config); - dir = ASIC3_CONFIG_GPIO_DIR(config); - init = ASIC3_CONFIG_GPIO_INIT(config); - - bank_num = ASIC3_GPIO_TO_BANK(pin); - bit_num = ASIC3_GPIO_TO_BIT(pin); - - alt_reg[bank_num] |= (alt << bit_num); - out_reg[bank_num] |= (init << bit_num); - dir_reg[bank_num] |= (dir << bit_num); - } - - for (i = 0; i < ASIC3_NUM_GPIO_BANKS; i++) { - asic3_write_register(asic, - ASIC3_BANK_TO_BASE(i) + - ASIC3_GPIO_DIRECTION, - dir_reg[i]); - asic3_write_register(asic, - ASIC3_BANK_TO_BASE(i) + ASIC3_GPIO_OUT, - out_reg[i]); - asic3_write_register(asic, - ASIC3_BANK_TO_BASE(i) + - ASIC3_GPIO_ALT_FUNCTION, - alt_reg[i]); - } - - return gpiochip_add_data(&asic->gpio, asic); -} - -static void asic3_gpio_remove(struct platform_device *pdev) -{ - struct asic3 *asic = platform_get_drvdata(pdev); - - gpiochip_remove(&asic->gpio); -} - -static void asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk) -{ - unsigned long flags; - u32 cdex; - - raw_spin_lock_irqsave(&asic->lock, flags); - if (clk->enabled++ == 0) { - cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX)); - cdex |= clk->cdex; - asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex); - } - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk) -{ - unsigned long flags; - u32 cdex; - - WARN_ON(clk->enabled == 0); - - raw_spin_lock_irqsave(&asic->lock, flags); - if (--clk->enabled == 0) { - cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX)); - cdex &= ~clk->cdex; - asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex); - } - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -/* MFD cells (SPI, PWM, LED, DS1WM, MMC) */ -static struct ds1wm_driver_data ds1wm_pdata = { - .active_high = 1, - .reset_recover_delay = 1, -}; - -static struct resource ds1wm_resources[] = { - { - .start = ASIC3_OWM_BASE, - .end = ASIC3_OWM_BASE + 0x13, - .flags = IORESOURCE_MEM, - }, - { - .start = ASIC3_IRQ_OWM, - .end = ASIC3_IRQ_OWM, - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, - }, -}; - -static int ds1wm_enable(struct platform_device *pdev) -{ - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - /* Turn on external clocks and the OWM clock */ - asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); - asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); - asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_OWM]); - usleep_range(1000, 5000); - - /* Reset and enable DS1WM */ - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, RESET), - ASIC3_EXTCF_OWM_RESET, 1); - usleep_range(1000, 5000); - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, RESET), - ASIC3_EXTCF_OWM_RESET, 0); - usleep_range(1000, 5000); - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), - ASIC3_EXTCF_OWM_EN, 1); - usleep_range(1000, 5000); - - return 0; -} - -static int ds1wm_disable(struct platform_device *pdev) -{ - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), - ASIC3_EXTCF_OWM_EN, 0); - - asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_OWM]); - asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); - asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); - - return 0; -} - -static const struct mfd_cell asic3_cell_ds1wm = { - .name = "ds1wm", - .enable = ds1wm_enable, - .disable = ds1wm_disable, - .platform_data = &ds1wm_pdata, - .pdata_size = sizeof(ds1wm_pdata), - .num_resources = ARRAY_SIZE(ds1wm_resources), - .resources = ds1wm_resources, -}; - -static void asic3_mmc_pwr(struct platform_device *pdev, int state) -{ - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - tmio_core_mmc_pwr(asic->tmio_cnf, 1 - asic->bus_shift, state); -} - -static void asic3_mmc_clk_div(struct platform_device *pdev, int state) -{ - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - tmio_core_mmc_clk_div(asic->tmio_cnf, 1 - asic->bus_shift, state); -} - -static struct tmio_mmc_data asic3_mmc_data = { - .hclk = 24576000, - .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, - .set_pwr = asic3_mmc_pwr, - .set_clk_div = asic3_mmc_clk_div, -}; - -static struct resource asic3_mmc_resources[] = { - DEFINE_RES_MEM(ASIC3_SD_CTRL_BASE, 0x400), - DEFINE_RES_IRQ(0) -}; - -static int asic3_mmc_enable(struct platform_device *pdev) -{ - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - /* Not sure if it must be done bit by bit, but leaving as-is */ - asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), - ASIC3_SDHWCTRL_LEVCD, 1); - asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), - ASIC3_SDHWCTRL_LEVWP, 1); - asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), - ASIC3_SDHWCTRL_SUSPEND, 0); - asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), - ASIC3_SDHWCTRL_PCLR, 0); - - asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); - /* CLK32 used for card detection and for interruption detection - * when HCLK is stopped. - */ - asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); - usleep_range(1000, 5000); - - /* HCLK 24.576 MHz, BCLK 12.288 MHz: */ - asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), - CLOCK_SEL_CX | CLOCK_SEL_SD_HCLK_SEL); - - asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_SD_HOST]); - asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_SD_BUS]); - usleep_range(1000, 5000); - - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), - ASIC3_EXTCF_SD_MEM_ENABLE, 1); - - /* Enable SD card slot 3.3V power supply */ - asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), - ASIC3_SDHWCTRL_SDPWR, 1); - - /* ASIC3_SD_CTRL_BASE assumes 32-bit addressing, TMIO is 16-bit */ - tmio_core_mmc_enable(asic->tmio_cnf, 1 - asic->bus_shift, - ASIC3_SD_CTRL_BASE >> 1); - - return 0; -} - -static int asic3_mmc_disable(struct platform_device *pdev) -{ - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - /* Put in suspend mode */ - asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), - ASIC3_SDHWCTRL_SUSPEND, 1); - - /* Disable clocks */ - asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_SD_HOST]); - asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_SD_BUS]); - asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); - asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); - return 0; -} - -static const struct mfd_cell asic3_cell_mmc = { - .name = "tmio-mmc", - .enable = asic3_mmc_enable, - .disable = asic3_mmc_disable, - .suspend = asic3_mmc_disable, - .resume = asic3_mmc_enable, - .platform_data = &asic3_mmc_data, - .pdata_size = sizeof(asic3_mmc_data), - .num_resources = ARRAY_SIZE(asic3_mmc_resources), - .resources = asic3_mmc_resources, -}; - -static const int clock_ledn[ASIC3_NUM_LEDS] = { - [0] = ASIC3_CLOCK_LED0, - [1] = ASIC3_CLOCK_LED1, - [2] = ASIC3_CLOCK_LED2, -}; - -static int asic3_leds_enable(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - asic3_clk_enable(asic, &asic->clocks[clock_ledn[cell->id]]); - - return 0; -} - -static int asic3_leds_disable(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - asic3_clk_disable(asic, &asic->clocks[clock_ledn[cell->id]]); - - return 0; -} - -static int asic3_leds_suspend(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - while (asic3_gpio_get(&asic->gpio, ASIC3_GPIO(C, cell->id)) != 0) - usleep_range(1000, 5000); - - asic3_clk_disable(asic, &asic->clocks[clock_ledn[cell->id]]); - - return 0; -} - -static struct mfd_cell asic3_cell_leds[ASIC3_NUM_LEDS] = { - [0] = { - .name = "leds-asic3", - .id = 0, - .enable = asic3_leds_enable, - .disable = asic3_leds_disable, - .suspend = asic3_leds_suspend, - .resume = asic3_leds_enable, - }, - [1] = { - .name = "leds-asic3", - .id = 1, - .enable = asic3_leds_enable, - .disable = asic3_leds_disable, - .suspend = asic3_leds_suspend, - .resume = asic3_leds_enable, - }, - [2] = { - .name = "leds-asic3", - .id = 2, - .enable = asic3_leds_enable, - .disable = asic3_leds_disable, - .suspend = asic3_leds_suspend, - .resume = asic3_leds_enable, - }, -}; - -static int __init asic3_mfd_probe(struct platform_device *pdev, - struct asic3_platform_data *pdata, - struct resource *mem) -{ - struct asic3 *asic = platform_get_drvdata(pdev); - struct resource *mem_sdio; - int irq, ret; - - mem_sdio = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!mem_sdio) - dev_dbg(asic->dev, "no SDIO MEM resource\n"); - - irq = platform_get_irq(pdev, 1); - if (irq < 0) - dev_dbg(asic->dev, "no SDIO IRQ resource\n"); - - /* DS1WM */ - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), - ASIC3_EXTCF_OWM_SMB, 0); - - ds1wm_resources[0].start >>= asic->bus_shift; - ds1wm_resources[0].end >>= asic->bus_shift; - - /* MMC */ - if (mem_sdio) { - asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> - asic->bus_shift) + mem_sdio->start, - ASIC3_SD_CONFIG_SIZE >> asic->bus_shift); - if (!asic->tmio_cnf) { - ret = -ENOMEM; - dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n"); - goto out; - } - } - asic3_mmc_resources[0].start >>= asic->bus_shift; - asic3_mmc_resources[0].end >>= asic->bus_shift; - - if (pdata->clock_rate) { - ds1wm_pdata.clock_rate = pdata->clock_rate; - ret = mfd_add_devices(&pdev->dev, pdev->id, - &asic3_cell_ds1wm, 1, mem, asic->irq_base, NULL); - if (ret < 0) - goto out_unmap; - } - - if (mem_sdio && (irq >= 0)) { - ret = mfd_add_devices(&pdev->dev, pdev->id, - &asic3_cell_mmc, 1, mem_sdio, irq, NULL); - if (ret < 0) - goto out_unmap; - } - - ret = 0; - if (pdata->leds) { - int i; - - for (i = 0; i < ASIC3_NUM_LEDS; ++i) { - asic3_cell_leds[i].platform_data = &pdata->leds[i]; - asic3_cell_leds[i].pdata_size = sizeof(pdata->leds[i]); - } - ret = mfd_add_devices(&pdev->dev, 0, - asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0, NULL); - } - return ret; - -out_unmap: - if (asic->tmio_cnf) - iounmap(asic->tmio_cnf); -out: - return ret; -} - -static void asic3_mfd_remove(struct platform_device *pdev) -{ - struct asic3 *asic = platform_get_drvdata(pdev); - - mfd_remove_devices(&pdev->dev); - iounmap(asic->tmio_cnf); -} - -/* Core */ -static int __init asic3_probe(struct platform_device *pdev) -{ - struct asic3_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct asic3 *asic; - struct resource *mem; - unsigned long clksel; - int ret = 0; - - asic = devm_kzalloc(&pdev->dev, - sizeof(struct asic3), GFP_KERNEL); - if (!asic) - return -ENOMEM; - - raw_spin_lock_init(&asic->lock); - platform_set_drvdata(pdev, asic); - asic->dev = &pdev->dev; - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(asic->dev, "no MEM resource\n"); - return -ENOMEM; - } - - asic->mapping = ioremap(mem->start, resource_size(mem)); - if (!asic->mapping) { - dev_err(asic->dev, "Couldn't ioremap\n"); - return -ENOMEM; - } - - asic->irq_base = pdata->irq_base; - - /* calculate bus shift from mem resource */ - asic->bus_shift = 2 - (resource_size(mem) >> 12); - - clksel = 0; - asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), clksel); - - ret = asic3_irq_probe(pdev); - if (ret < 0) { - dev_err(asic->dev, "Couldn't probe IRQs\n"); - goto out_unmap; - } - - asic->gpio.label = "asic3"; - asic->gpio.base = pdata->gpio_base; - asic->gpio.ngpio = ASIC3_NUM_GPIOS; - asic->gpio.get = asic3_gpio_get; - asic->gpio.set = asic3_gpio_set; - asic->gpio.direction_input = asic3_gpio_direction_input; - asic->gpio.direction_output = asic3_gpio_direction_output; - asic->gpio.to_irq = asic3_gpio_to_irq; - - ret = asic3_gpio_probe(pdev, - pdata->gpio_config, - pdata->gpio_config_num); - if (ret < 0) { - dev_err(asic->dev, "GPIO probe failed\n"); - goto out_irq; - } - - /* Making a per-device copy is only needed for the - * theoretical case of multiple ASIC3s on one board: - */ - memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init)); - - asic3_mfd_probe(pdev, pdata, mem); - - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), - (ASIC3_EXTCF_CF0_BUF_EN|ASIC3_EXTCF_CF0_PWAIT_EN), 1); - - dev_info(asic->dev, "ASIC3 Core driver\n"); - - return 0; - - out_irq: - asic3_irq_remove(pdev); - - out_unmap: - iounmap(asic->mapping); - - return ret; -} - -static int asic3_remove(struct platform_device *pdev) -{ - struct asic3 *asic = platform_get_drvdata(pdev); - - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), - (ASIC3_EXTCF_CF0_BUF_EN|ASIC3_EXTCF_CF0_PWAIT_EN), 0); - - asic3_mfd_remove(pdev); - - asic3_gpio_remove(pdev); - - asic3_irq_remove(pdev); - - asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), 0); - - iounmap(asic->mapping); - - return 0; -} - -static void asic3_shutdown(struct platform_device *pdev) -{ -} - -static struct platform_driver asic3_device_driver = { - .driver = { - .name = "asic3", - }, - .remove = asic3_remove, - .shutdown = asic3_shutdown, -}; - -static int __init asic3_init(void) -{ - int retval = 0; - - retval = platform_driver_probe(&asic3_device_driver, asic3_probe); - - return retval; -} - -subsys_initcall(asic3_init); diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c deleted file mode 100644 index 0c46b7e64b2d..000000000000 --- a/drivers/mfd/htc-pasic3.c +++ /dev/null @@ -1,210 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Core driver for HTC PASIC3 LED/DS1WM chip. - * - * Copyright (C) 2006 Philipp Zabel <philipp.zabel@gmail.com> - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/platform_device.h> - -#include <linux/gpio.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/mfd/core.h> -#include <linux/mfd/ds1wm.h> -#include <linux/mfd/htc-pasic3.h> -#include <linux/slab.h> - -struct pasic3_data { - void __iomem *mapping; - unsigned int bus_shift; -}; - -#define REG_ADDR 5 -#define REG_DATA 6 - -#define READ_MODE 0x80 - -/* - * write to a secondary register on the PASIC3 - */ -void pasic3_write_register(struct device *dev, u32 reg, u8 val) -{ - struct pasic3_data *asic = dev_get_drvdata(dev); - int bus_shift = asic->bus_shift; - void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift); - void __iomem *data = asic->mapping + (REG_DATA << bus_shift); - - __raw_writeb(~READ_MODE & reg, addr); - __raw_writeb(val, data); -} -EXPORT_SYMBOL(pasic3_write_register); /* for leds-pasic3 */ - -/* - * read from a secondary register on the PASIC3 - */ -u8 pasic3_read_register(struct device *dev, u32 reg) -{ - struct pasic3_data *asic = dev_get_drvdata(dev); - int bus_shift = asic->bus_shift; - void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift); - void __iomem *data = asic->mapping + (REG_DATA << bus_shift); - - __raw_writeb(READ_MODE | reg, addr); - return __raw_readb(data); -} -EXPORT_SYMBOL(pasic3_read_register); /* for leds-pasic3 */ - -/* - * LEDs - */ - -static struct mfd_cell led_cell __initdata = { - .name = "leds-pasic3", -}; - -/* - * DS1WM - */ - -static int ds1wm_enable(struct platform_device *pdev) -{ - struct device *dev = pdev->dev.parent; - int c; - - c = pasic3_read_register(dev, 0x28); - pasic3_write_register(dev, 0x28, c & 0x7f); - - dev_dbg(dev, "DS1WM OWM_EN low (active) %02x\n", c & 0x7f); - return 0; -} - -static int ds1wm_disable(struct platform_device *pdev) -{ - struct device *dev = pdev->dev.parent; - int c; - - c = pasic3_read_register(dev, 0x28); - pasic3_write_register(dev, 0x28, c | 0x80); - - dev_dbg(dev, "DS1WM OWM_EN high (inactive) %02x\n", c | 0x80); - return 0; -} - -static struct ds1wm_driver_data ds1wm_pdata = { - .active_high = 0, - .reset_recover_delay = 1, -}; - -static struct resource ds1wm_resources[] __initdata = { - [0] = { - .start = 0, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = 0, - .end = 0, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct mfd_cell ds1wm_cell __initconst = { - .name = "ds1wm", - .enable = ds1wm_enable, - .disable = ds1wm_disable, - .platform_data = &ds1wm_pdata, - .pdata_size = sizeof(ds1wm_pdata), - .num_resources = 2, - .resources = ds1wm_resources, -}; - -static int __init pasic3_probe(struct platform_device *pdev) -{ - struct pasic3_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct device *dev = &pdev->dev; - struct pasic3_data *asic; - struct resource *r; - int ret; - int irq = 0; - - r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (r) { - ds1wm_resources[1].flags = IORESOURCE_IRQ | (r->flags & - (IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE)); - irq = r->start; - } - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) - return -ENXIO; - - if (!request_mem_region(r->start, resource_size(r), "pasic3")) - return -EBUSY; - - asic = devm_kzalloc(dev, sizeof(struct pasic3_data), GFP_KERNEL); - if (!asic) - return -ENOMEM; - - platform_set_drvdata(pdev, asic); - - asic->mapping = ioremap(r->start, resource_size(r)); - if (!asic->mapping) { - dev_err(dev, "couldn't ioremap PASIC3\n"); - return -ENOMEM; - } - - /* calculate bus shift from mem resource */ - asic->bus_shift = (resource_size(r) - 5) >> 3; - - if (pdata && pdata->clock_rate) { - ds1wm_pdata.clock_rate = pdata->clock_rate; - /* the first 5 PASIC3 registers control the DS1WM */ - ds1wm_resources[0].end = (5 << asic->bus_shift) - 1; - ret = mfd_add_devices(&pdev->dev, pdev->id, - &ds1wm_cell, 1, r, irq, NULL); - if (ret < 0) - dev_warn(dev, "failed to register DS1WM\n"); - } - - if (pdata && pdata->led_pdata) { - led_cell.platform_data = pdata->led_pdata; - led_cell.pdata_size = sizeof(struct pasic3_leds_machinfo); - ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, - 0, NULL); - if (ret < 0) - dev_warn(dev, "failed to register LED device\n"); - } - - return 0; -} - -static int pasic3_remove(struct platform_device *pdev) -{ - struct pasic3_data *asic = platform_get_drvdata(pdev); - struct resource *r; - - mfd_remove_devices(&pdev->dev); - - iounmap(asic->mapping); - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(r->start, resource_size(r)); - return 0; -} - -MODULE_ALIAS("platform:pasic3"); - -static struct platform_driver pasic3_driver = { - .driver = { - .name = "pasic3", - }, - .remove = pasic3_remove, -}; - -module_platform_driver_probe(pasic3_driver, pasic3_probe); - -MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>"); -MODULE_DESCRIPTION("Core driver for HTC PASIC3"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c deleted file mode 100644 index 1d9d1d38d068..000000000000 --- a/drivers/mfd/t7l66xb.c +++ /dev/null @@ -1,427 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * - * Toshiba T7L66XB core mfd support - * - * Copyright (c) 2005, 2007, 2008 Ian Molton - * Copyright (c) 2008 Dmitry Baryshkov - * - * T7L66 features: - * - * Supported in this driver: - * SD/MMC - * SM/NAND flash controller - * - * As yet not supported - * GPIO interface (on NAND pins) - * Serial interface - * TFT 'interface converter' - * PCMCIA interface logic - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/irq.h> -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/mfd/core.h> -#include <linux/mfd/tmio.h> -#include <linux/mfd/t7l66xb.h> - -enum { - T7L66XB_CELL_NAND, - T7L66XB_CELL_MMC, -}; - -static const struct resource t7l66xb_mmc_resources[] = { - DEFINE_RES_MEM(0x800, 0x200), - DEFINE_RES_IRQ(IRQ_T7L66XB_MMC) -}; - -#define SCR_REVID 0x08 /* b Revision ID */ -#define SCR_IMR 0x42 /* b Interrupt Mask */ -#define SCR_DEV_CTL 0xe0 /* b Device control */ -#define SCR_ISR 0xe1 /* b Interrupt Status */ -#define SCR_GPO_OC 0xf0 /* b GPO output control */ -#define SCR_GPO_OS 0xf1 /* b GPO output enable */ -#define SCR_GPI_S 0xf2 /* w GPI status */ -#define SCR_APDC 0xf8 /* b Active pullup down ctrl */ - -#define SCR_DEV_CTL_USB BIT(0) /* USB enable */ -#define SCR_DEV_CTL_MMC BIT(1) /* MMC enable */ - -/*--------------------------------------------------------------------------*/ - -struct t7l66xb { - void __iomem *scr; - /* Lock to protect registers requiring read/modify/write ops. */ - raw_spinlock_t lock; - - struct resource rscr; - struct clk *clk48m; - struct clk *clk32k; - int irq; - int irq_base; -}; - -/*--------------------------------------------------------------------------*/ - -static int t7l66xb_mmc_enable(struct platform_device *mmc) -{ - struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent); - unsigned long flags; - u8 dev_ctl; - int ret; - - ret = clk_prepare_enable(t7l66xb->clk32k); - if (ret) - return ret; - - raw_spin_lock_irqsave(&t7l66xb->lock, flags); - - dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL); - dev_ctl |= SCR_DEV_CTL_MMC; - tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL); - - raw_spin_unlock_irqrestore(&t7l66xb->lock, flags); - - tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0, - t7l66xb_mmc_resources[0].start & 0xfffe); - - return 0; -} - -static int t7l66xb_mmc_disable(struct platform_device *mmc) -{ - struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent); - unsigned long flags; - u8 dev_ctl; - - raw_spin_lock_irqsave(&t7l66xb->lock, flags); - - dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL); - dev_ctl &= ~SCR_DEV_CTL_MMC; - tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL); - - raw_spin_unlock_irqrestore(&t7l66xb->lock, flags); - - clk_disable_unprepare(t7l66xb->clk32k); - - return 0; -} - -static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state) -{ - struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_pwr(t7l66xb->scr + 0x200, 0, state); -} - -static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state) -{ - struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, 0, state); -} - -/*--------------------------------------------------------------------------*/ - -static struct tmio_mmc_data t7166xb_mmc_data = { - .hclk = 24000000, - .set_pwr = t7l66xb_mmc_pwr, - .set_clk_div = t7l66xb_mmc_clk_div, -}; - -static const struct resource t7l66xb_nand_resources[] = { - { - .start = 0xc00, - .end = 0xc07, - .flags = IORESOURCE_MEM, - }, - { - .start = 0x0100, - .end = 0x01ff, - .flags = IORESOURCE_MEM, - }, - { - .start = IRQ_T7L66XB_NAND, - .end = IRQ_T7L66XB_NAND, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct mfd_cell t7l66xb_cells[] = { - [T7L66XB_CELL_MMC] = { - .name = "tmio-mmc", - .enable = t7l66xb_mmc_enable, - .disable = t7l66xb_mmc_disable, - .platform_data = &t7166xb_mmc_data, - .pdata_size = sizeof(t7166xb_mmc_data), - .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources), - .resources = t7l66xb_mmc_resources, - }, - [T7L66XB_CELL_NAND] = { - .name = "tmio-nand", - .num_resources = ARRAY_SIZE(t7l66xb_nand_resources), - .resources = t7l66xb_nand_resources, - }, -}; - -/*--------------------------------------------------------------------------*/ - -/* Handle the T7L66XB interrupt mux */ -static void t7l66xb_irq(struct irq_desc *desc) -{ - struct t7l66xb *t7l66xb = irq_desc_get_handler_data(desc); - unsigned int isr; - unsigned int i, irq_base; - - irq_base = t7l66xb->irq_base; - - while ((isr = tmio_ioread8(t7l66xb->scr + SCR_ISR) & - ~tmio_ioread8(t7l66xb->scr + SCR_IMR))) - for (i = 0; i < T7L66XB_NR_IRQS; i++) - if (isr & (1 << i)) - generic_handle_irq(irq_base + i); -} - -static void t7l66xb_irq_mask(struct irq_data *data) -{ - struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data); - unsigned long flags; - u8 imr; - - raw_spin_lock_irqsave(&t7l66xb->lock, flags); - imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); - imr |= 1 << (data->irq - t7l66xb->irq_base); - tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); - raw_spin_unlock_irqrestore(&t7l66xb->lock, flags); -} - -static void t7l66xb_irq_unmask(struct irq_data *data) -{ - struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data); - unsigned long flags; - u8 imr; - - raw_spin_lock_irqsave(&t7l66xb->lock, flags); - imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); - imr &= ~(1 << (data->irq - t7l66xb->irq_base)); - tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); - raw_spin_unlock_irqrestore(&t7l66xb->lock, flags); -} - -static struct irq_chip t7l66xb_chip = { - .name = "t7l66xb", - .irq_ack = t7l66xb_irq_mask, - .irq_mask = t7l66xb_irq_mask, - .irq_unmask = t7l66xb_irq_unmask, -}; - -/*--------------------------------------------------------------------------*/ - -/* Install the IRQ handler */ -static void t7l66xb_attach_irq(struct platform_device *dev) -{ - struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - unsigned int irq, irq_base; - - irq_base = t7l66xb->irq_base; - - for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { - irq_set_chip_and_handler(irq, &t7l66xb_chip, handle_level_irq); - irq_set_chip_data(irq, t7l66xb); - } - - irq_set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING); - irq_set_chained_handler_and_data(t7l66xb->irq, t7l66xb_irq, t7l66xb); -} - -static void t7l66xb_detach_irq(struct platform_device *dev) -{ - struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - unsigned int irq, irq_base; - - irq_base = t7l66xb->irq_base; - - irq_set_chained_handler_and_data(t7l66xb->irq, NULL, NULL); - - for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { - irq_set_chip(irq, NULL); - irq_set_chip_data(irq, NULL); - } -} - -/*--------------------------------------------------------------------------*/ - -static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state) -{ - struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); - - if (pdata && pdata->suspend) - pdata->suspend(dev); - clk_disable_unprepare(t7l66xb->clk48m); - - return 0; -} - -static int t7l66xb_resume(struct platform_device *dev) -{ - struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); - int ret; - - ret = clk_prepare_enable(t7l66xb->clk48m); - if (ret) - return ret; - - if (pdata && pdata->resume) - pdata->resume(dev); - - tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0, - t7l66xb_mmc_resources[0].start & 0xfffe); - - return 0; -} - -/*--------------------------------------------------------------------------*/ - -static int t7l66xb_probe(struct platform_device *dev) -{ - struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); - struct t7l66xb *t7l66xb; - struct resource *iomem, *rscr; - int ret; - - if (!pdata) - return -EINVAL; - - iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!iomem) - return -EINVAL; - - t7l66xb = kzalloc(sizeof *t7l66xb, GFP_KERNEL); - if (!t7l66xb) - return -ENOMEM; - - raw_spin_lock_init(&t7l66xb->lock); - - platform_set_drvdata(dev, t7l66xb); - - ret = platform_get_irq(dev, 0); - if (ret >= 0) - t7l66xb->irq = ret; - else - goto err_noirq; - - t7l66xb->irq_base = pdata->irq_base; - - t7l66xb->clk32k = clk_get(&dev->dev, "CLK_CK32K"); - if (IS_ERR(t7l66xb->clk32k)) { - ret = PTR_ERR(t7l66xb->clk32k); - goto err_clk32k_get; - } - - t7l66xb->clk48m = clk_get(&dev->dev, "CLK_CK48M"); - if (IS_ERR(t7l66xb->clk48m)) { - ret = PTR_ERR(t7l66xb->clk48m); - goto err_clk48m_get; - } - - rscr = &t7l66xb->rscr; - rscr->name = "t7l66xb-core"; - rscr->start = iomem->start; - rscr->end = iomem->start + 0xff; - rscr->flags = IORESOURCE_MEM; - - ret = request_resource(iomem, rscr); - if (ret) - goto err_request_scr; - - t7l66xb->scr = ioremap(rscr->start, resource_size(rscr)); - if (!t7l66xb->scr) { - ret = -ENOMEM; - goto err_ioremap; - } - - ret = clk_prepare_enable(t7l66xb->clk48m); - if (ret) - goto err_clk_enable; - - if (pdata->enable) - pdata->enable(dev); - - /* Mask all interrupts */ - tmio_iowrite8(0xbf, t7l66xb->scr + SCR_IMR); - - printk(KERN_INFO "%s rev %d @ 0x%08lx, irq %d\n", - dev->name, tmio_ioread8(t7l66xb->scr + SCR_REVID), - (unsigned long)iomem->start, t7l66xb->irq); - - t7l66xb_attach_irq(dev); - - t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = pdata->nand_data; - t7l66xb_cells[T7L66XB_CELL_NAND].pdata_size = sizeof(*pdata->nand_data); - - ret = mfd_add_devices(&dev->dev, dev->id, - t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), - iomem, t7l66xb->irq_base, NULL); - - if (!ret) - return 0; - - t7l66xb_detach_irq(dev); - clk_disable_unprepare(t7l66xb->clk48m); -err_clk_enable: - iounmap(t7l66xb->scr); -err_ioremap: - release_resource(&t7l66xb->rscr); -err_request_scr: - clk_put(t7l66xb->clk48m); -err_clk48m_get: - clk_put(t7l66xb->clk32k); -err_clk32k_get: -err_noirq: - kfree(t7l66xb); - return ret; -} - -static int t7l66xb_remove(struct platform_device *dev) -{ - struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - - clk_disable_unprepare(t7l66xb->clk48m); - clk_put(t7l66xb->clk48m); - clk_disable_unprepare(t7l66xb->clk32k); - clk_put(t7l66xb->clk32k); - t7l66xb_detach_irq(dev); - iounmap(t7l66xb->scr); - release_resource(&t7l66xb->rscr); - mfd_remove_devices(&dev->dev); - kfree(t7l66xb); - - return 0; -} - -static struct platform_driver t7l66xb_platform_driver = { - .driver = { - .name = "t7l66xb", - }, - .suspend = pm_sleep_ptr(t7l66xb_suspend), - .resume = pm_sleep_ptr(t7l66xb_resume), - .probe = t7l66xb_probe, - .remove = t7l66xb_remove, -}; - -/*--------------------------------------------------------------------------*/ - -module_platform_driver(t7l66xb_platform_driver); - -MODULE_DESCRIPTION("Toshiba T7L66XB core driver"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Ian Molton"); -MODULE_ALIAS("platform:t7l66xb"); diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c deleted file mode 100644 index 5392da6ba7b0..000000000000 --- a/drivers/mfd/tc6387xb.c +++ /dev/null @@ -1,228 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Toshiba TC6387XB support - * Copyright (c) 2005 Ian Molton - * - * This file contains TC6387XB base support. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/mfd/core.h> -#include <linux/mfd/tmio.h> -#include <linux/mfd/tc6387xb.h> -#include <linux/slab.h> - -enum { - TC6387XB_CELL_MMC, -}; - -struct tc6387xb { - void __iomem *scr; - struct clk *clk32k; - struct resource rscr; -}; - -static const struct resource tc6387xb_mmc_resources[] = { - { - .start = 0x800, - .end = 0x9ff, - .flags = IORESOURCE_MEM, - }, - { - .start = 0, - .end = 0, - .flags = IORESOURCE_IRQ, - }, -}; - -/*--------------------------------------------------------------------------*/ - -static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state) -{ - struct tc6387xb *tc6387xb = platform_get_drvdata(dev); - struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev); - - if (pdata && pdata->suspend) - pdata->suspend(dev); - clk_disable_unprepare(tc6387xb->clk32k); - - return 0; -} - -static int tc6387xb_resume(struct platform_device *dev) -{ - struct tc6387xb *tc6387xb = platform_get_drvdata(dev); - struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev); - - clk_prepare_enable(tc6387xb->clk32k); - if (pdata && pdata->resume) - pdata->resume(dev); - - tmio_core_mmc_resume(tc6387xb->scr + 0x200, 0, - tc6387xb_mmc_resources[0].start & 0xfffe); - - return 0; -} - -/*--------------------------------------------------------------------------*/ - -static void tc6387xb_mmc_pwr(struct platform_device *mmc, int state) -{ - struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_pwr(tc6387xb->scr + 0x200, 0, state); -} - -static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state) -{ - struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_clk_div(tc6387xb->scr + 0x200, 0, state); -} - - -static int tc6387xb_mmc_enable(struct platform_device *mmc) -{ - struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent); - - clk_prepare_enable(tc6387xb->clk32k); - - tmio_core_mmc_enable(tc6387xb->scr + 0x200, 0, - tc6387xb_mmc_resources[0].start & 0xfffe); - - return 0; -} - -static int tc6387xb_mmc_disable(struct platform_device *mmc) -{ - struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent); - - clk_disable_unprepare(tc6387xb->clk32k); - - return 0; -} - -static struct tmio_mmc_data tc6387xb_mmc_data = { - .hclk = 24000000, - .set_pwr = tc6387xb_mmc_pwr, - .set_clk_div = tc6387xb_mmc_clk_div, -}; - -/*--------------------------------------------------------------------------*/ - -static const struct mfd_cell tc6387xb_cells[] = { - [TC6387XB_CELL_MMC] = { - .name = "tmio-mmc", - .enable = tc6387xb_mmc_enable, - .disable = tc6387xb_mmc_disable, - .platform_data = &tc6387xb_mmc_data, - .pdata_size = sizeof(tc6387xb_mmc_data), - .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources), - .resources = tc6387xb_mmc_resources, - }, -}; - -static int tc6387xb_probe(struct platform_device *dev) -{ - struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev); - struct resource *iomem, *rscr; - struct clk *clk32k; - struct tc6387xb *tc6387xb; - int irq, ret; - - iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!iomem) - return -EINVAL; - - tc6387xb = kzalloc(sizeof(*tc6387xb), GFP_KERNEL); - if (!tc6387xb) - return -ENOMEM; - - ret = platform_get_irq(dev, 0); - if (ret >= 0) - irq = ret; - else - goto err_no_irq; - - clk32k = clk_get(&dev->dev, "CLK_CK32K"); - if (IS_ERR(clk32k)) { - ret = PTR_ERR(clk32k); - goto err_no_clk; - } - - rscr = &tc6387xb->rscr; - rscr->name = "tc6387xb-core"; - rscr->start = iomem->start; - rscr->end = iomem->start + 0xff; - rscr->flags = IORESOURCE_MEM; - - ret = request_resource(iomem, rscr); - if (ret) - goto err_resource; - - tc6387xb->scr = ioremap(rscr->start, resource_size(rscr)); - if (!tc6387xb->scr) { - ret = -ENOMEM; - goto err_ioremap; - } - - tc6387xb->clk32k = clk32k; - platform_set_drvdata(dev, tc6387xb); - - if (pdata && pdata->enable) - pdata->enable(dev); - - dev_info(&dev->dev, "Toshiba tc6387xb initialised\n"); - - ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells, - ARRAY_SIZE(tc6387xb_cells), iomem, irq, NULL); - - if (!ret) - return 0; - - iounmap(tc6387xb->scr); -err_ioremap: - release_resource(&tc6387xb->rscr); -err_resource: - clk_put(clk32k); -err_no_clk: -err_no_irq: - kfree(tc6387xb); - return ret; -} - -static int tc6387xb_remove(struct platform_device *dev) -{ - struct tc6387xb *tc6387xb = platform_get_drvdata(dev); - - mfd_remove_devices(&dev->dev); - iounmap(tc6387xb->scr); - release_resource(&tc6387xb->rscr); - clk_disable_unprepare(tc6387xb->clk32k); - clk_put(tc6387xb->clk32k); - kfree(tc6387xb); - - return 0; -} - - -static struct platform_driver tc6387xb_platform_driver = { - .driver = { - .name = "tc6387xb", - }, - .probe = tc6387xb_probe, - .remove = tc6387xb_remove, - .suspend = pm_sleep_ptr(tc6387xb_suspend), - .resume = pm_sleep_ptr(tc6387xb_resume), -}; - -module_platform_driver(tc6387xb_platform_driver); - -MODULE_DESCRIPTION("Toshiba TC6387XB core driver"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Ian Molton"); -MODULE_ALIAS("platform:tc6387xb"); - diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c deleted file mode 100644 index 997bb8b5881d..000000000000 --- a/drivers/mfd/tc6393xb.c +++ /dev/null @@ -1,907 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Toshiba TC6393XB SoC support - * - * Copyright(c) 2005-2006 Chris Humbert - * Copyright(c) 2005 Dirk Opfer - * Copyright(c) 2005 Ian Molton <spyro@f2s.com> - * Copyright(c) 2007 Dmitry Baryshkov - * - * Based on code written by Sharp/Lineo for 2.4 kernels - * Based on locomo.c - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/mfd/core.h> -#include <linux/mfd/tmio.h> -#include <linux/mfd/tc6393xb.h> -#include <linux/gpio/driver.h> -#include <linux/gpio/machine.h> -#include <linux/gpio/consumer.h> -#include <linux/slab.h> - -#define SCR_REVID 0x08 /* b Revision ID */ -#define SCR_ISR 0x50 /* b Interrupt Status */ -#define SCR_IMR 0x52 /* b Interrupt Mask */ -#define SCR_IRR 0x54 /* b Interrupt Routing */ -#define SCR_GPER 0x60 /* w GP Enable */ -#define SCR_GPI_SR(i) (0x64 + (i)) /* b3 GPI Status */ -#define SCR_GPI_IMR(i) (0x68 + (i)) /* b3 GPI INT Mask */ -#define SCR_GPI_EDER(i) (0x6c + (i)) /* b3 GPI Edge Detect Enable */ -#define SCR_GPI_LIR(i) (0x70 + (i)) /* b3 GPI Level Invert */ -#define SCR_GPO_DSR(i) (0x78 + (i)) /* b3 GPO Data Set */ -#define SCR_GPO_DOECR(i) (0x7c + (i)) /* b3 GPO Data OE Control */ -#define SCR_GP_IARCR(i) (0x80 + (i)) /* b3 GP Internal Active Register Control */ -#define SCR_GP_IARLCR(i) (0x84 + (i)) /* b3 GP INTERNAL Active Register Level Control */ -#define SCR_GPI_BCR(i) (0x88 + (i)) /* b3 GPI Buffer Control */ -#define SCR_GPA_IARCR 0x8c /* w GPa Internal Active Register Control */ -#define SCR_GPA_IARLCR 0x90 /* w GPa Internal Active Register Level Control */ -#define SCR_GPA_BCR 0x94 /* w GPa Buffer Control */ -#define SCR_CCR 0x98 /* w Clock Control */ -#define SCR_PLL2CR 0x9a /* w PLL2 Control */ -#define SCR_PLL1CR 0x9c /* l PLL1 Control */ -#define SCR_DIARCR 0xa0 /* b Device Internal Active Register Control */ -#define SCR_DBOCR 0xa1 /* b Device Buffer Off Control */ -#define SCR_FER 0xe0 /* b Function Enable */ -#define SCR_MCR 0xe4 /* w Mode Control */ -#define SCR_CONFIG 0xfc /* b Configuration Control */ -#define SCR_DEBUG 0xff /* b Debug */ - -#define SCR_CCR_CK32K BIT(0) -#define SCR_CCR_USBCK BIT(1) -#define SCR_CCR_UNK1 BIT(4) -#define SCR_CCR_MCLK_MASK (7 << 8) -#define SCR_CCR_MCLK_OFF (0 << 8) -#define SCR_CCR_MCLK_12 (1 << 8) -#define SCR_CCR_MCLK_24 (2 << 8) -#define SCR_CCR_MCLK_48 (3 << 8) -#define SCR_CCR_HCLK_MASK (3 << 12) -#define SCR_CCR_HCLK_24 (0 << 12) -#define SCR_CCR_HCLK_48 (1 << 12) - -#define SCR_FER_USBEN BIT(0) /* USB host enable */ -#define SCR_FER_LCDCVEN BIT(1) /* polysilicon TFT enable */ -#define SCR_FER_SLCDEN BIT(2) /* SLCD enable */ - -#define SCR_MCR_RDY_MASK (3 << 0) -#define SCR_MCR_RDY_OPENDRAIN (0 << 0) -#define SCR_MCR_RDY_TRISTATE (1 << 0) -#define SCR_MCR_RDY_PUSHPULL (2 << 0) -#define SCR_MCR_RDY_UNK BIT(2) -#define SCR_MCR_RDY_EN BIT(3) -#define SCR_MCR_INT_MASK (3 << 4) -#define SCR_MCR_INT_OPENDRAIN (0 << 4) -#define SCR_MCR_INT_TRISTATE (1 << 4) -#define SCR_MCR_INT_PUSHPULL (2 << 4) -#define SCR_MCR_INT_UNK BIT(6) -#define SCR_MCR_INT_EN BIT(7) -/* bits 8 - 16 are unknown */ - -#define TC_GPIO_BIT(i) (1 << (i & 0x7)) - -/*--------------------------------------------------------------------------*/ - -struct tc6393xb { - void __iomem *scr; - struct device *dev; - - struct gpio_chip gpio; - struct gpio_desc *vcc_on; - - struct clk *clk; /* 3,6 Mhz */ - - raw_spinlock_t lock; /* protects RMW cycles */ - - struct { - u8 fer; - u16 ccr; - u8 gpi_bcr[3]; - u8 gpo_dsr[3]; - u8 gpo_doecr[3]; - } suspend_state; - - struct resource rscr; - struct resource *iomem; - int irq; - int irq_base; -}; - -enum { - TC6393XB_CELL_NAND, - TC6393XB_CELL_MMC, - TC6393XB_CELL_OHCI, - TC6393XB_CELL_FB, -}; - -/*--------------------------------------------------------------------------*/ - -static int tc6393xb_nand_enable(struct platform_device *nand) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(nand->dev.parent); - unsigned long flags; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - /* SMD buffer on */ - dev_dbg(nand->dev.parent, "SMD buffer on\n"); - tmio_iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1)); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} - -static const struct resource tc6393xb_nand_resources[] = { - { - .start = 0x1000, - .end = 0x1007, - .flags = IORESOURCE_MEM, - }, - { - .start = 0x0100, - .end = 0x01ff, - .flags = IORESOURCE_MEM, - }, - { - .start = IRQ_TC6393_NAND, - .end = IRQ_TC6393_NAND, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct resource tc6393xb_mmc_resources[] = { - { - .start = 0x800, - .end = 0x9ff, - .flags = IORESOURCE_MEM, - }, - { - .start = IRQ_TC6393_MMC, - .end = IRQ_TC6393_MMC, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct resource tc6393xb_ohci_resources[] = { - { - .start = 0x3000, - .end = 0x31ff, - .flags = IORESOURCE_MEM, - }, - { - .start = 0x0300, - .end = 0x03ff, - .flags = IORESOURCE_MEM, - }, - { - .start = 0x010000, - .end = 0x017fff, - .flags = IORESOURCE_MEM, - }, - { - .start = 0x018000, - .end = 0x01ffff, - .flags = IORESOURCE_MEM, - }, - { - .start = IRQ_TC6393_OHCI, - .end = IRQ_TC6393_OHCI, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct resource tc6393xb_fb_resources[] = { - { - .start = 0x5000, - .end = 0x51ff, - .flags = IORESOURCE_MEM, - }, - { - .start = 0x0500, - .end = 0x05ff, - .flags = IORESOURCE_MEM, - }, - { - .start = 0x100000, - .end = 0x1fffff, - .flags = IORESOURCE_MEM, - }, - { - .start = IRQ_TC6393_FB, - .end = IRQ_TC6393_FB, - .flags = IORESOURCE_IRQ, - }, -}; - -static int tc6393xb_ohci_enable(struct platform_device *dev) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); - unsigned long flags; - u16 ccr; - u8 fer; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); - ccr |= SCR_CCR_USBCK; - tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); - - fer = tmio_ioread8(tc6393xb->scr + SCR_FER); - fer |= SCR_FER_USBEN; - tmio_iowrite8(fer, tc6393xb->scr + SCR_FER); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} - -static int tc6393xb_ohci_disable(struct platform_device *dev) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); - unsigned long flags; - u16 ccr; - u8 fer; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - fer = tmio_ioread8(tc6393xb->scr + SCR_FER); - fer &= ~SCR_FER_USBEN; - tmio_iowrite8(fer, tc6393xb->scr + SCR_FER); - - ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); - ccr &= ~SCR_CCR_USBCK; - tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} - -static int tc6393xb_ohci_suspend(struct platform_device *dev) -{ - struct tc6393xb_platform_data *tcpd = dev_get_platdata(dev->dev.parent); - - /* We can't properly store/restore OHCI state, so fail here */ - if (tcpd->resume_restore) - return -EBUSY; - - return tc6393xb_ohci_disable(dev); -} - -static int tc6393xb_fb_enable(struct platform_device *dev) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); - unsigned long flags; - u16 ccr; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); - ccr &= ~SCR_CCR_MCLK_MASK; - ccr |= SCR_CCR_MCLK_48; - tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} - -static int tc6393xb_fb_disable(struct platform_device *dev) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); - unsigned long flags; - u16 ccr; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); - ccr &= ~SCR_CCR_MCLK_MASK; - ccr |= SCR_CCR_MCLK_OFF; - tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} - -int tc6393xb_lcd_set_power(struct platform_device *fb, bool on) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(fb->dev.parent); - u8 fer; - unsigned long flags; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - fer = ioread8(tc6393xb->scr + SCR_FER); - if (on) - fer |= SCR_FER_SLCDEN; - else - fer &= ~SCR_FER_SLCDEN; - iowrite8(fer, tc6393xb->scr + SCR_FER); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} -EXPORT_SYMBOL(tc6393xb_lcd_set_power); - -int tc6393xb_lcd_mode(struct platform_device *fb, - const struct fb_videomode *mode) { - struct tc6393xb *tc6393xb = dev_get_drvdata(fb->dev.parent); - unsigned long flags; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - iowrite16(mode->pixclock, tc6393xb->scr + SCR_PLL1CR + 0); - iowrite16(mode->pixclock >> 16, tc6393xb->scr + SCR_PLL1CR + 2); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} -EXPORT_SYMBOL(tc6393xb_lcd_mode); - -static int tc6393xb_mmc_enable(struct platform_device *mmc) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_enable(tc6393xb->scr + 0x200, 0, - tc6393xb_mmc_resources[0].start & 0xfffe); - - return 0; -} - -static int tc6393xb_mmc_resume(struct platform_device *mmc) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_resume(tc6393xb->scr + 0x200, 0, - tc6393xb_mmc_resources[0].start & 0xfffe); - - return 0; -} - -static void tc6393xb_mmc_pwr(struct platform_device *mmc, int state) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_pwr(tc6393xb->scr + 0x200, 0, state); -} - -static void tc6393xb_mmc_clk_div(struct platform_device *mmc, int state) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_clk_div(tc6393xb->scr + 0x200, 0, state); -} - -static struct tmio_mmc_data tc6393xb_mmc_data = { - .hclk = 24000000, - .set_pwr = tc6393xb_mmc_pwr, - .set_clk_div = tc6393xb_mmc_clk_div, -}; - -static struct mfd_cell tc6393xb_cells[] = { - [TC6393XB_CELL_NAND] = { - .name = "tmio-nand", - .enable = tc6393xb_nand_enable, - .num_resources = ARRAY_SIZE(tc6393xb_nand_resources), - .resources = tc6393xb_nand_resources, - }, - [TC6393XB_CELL_MMC] = { - .name = "tmio-mmc", - .enable = tc6393xb_mmc_enable, - .resume = tc6393xb_mmc_resume, - .platform_data = &tc6393xb_mmc_data, - .pdata_size = sizeof(tc6393xb_mmc_data), - .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), - .resources = tc6393xb_mmc_resources, - }, - [TC6393XB_CELL_OHCI] = { - .name = "tmio-ohci", - .num_resources = ARRAY_SIZE(tc6393xb_ohci_resources), - .resources = tc6393xb_ohci_resources, - .enable = tc6393xb_ohci_enable, - .suspend = tc6393xb_ohci_suspend, - .resume = tc6393xb_ohci_enable, - .disable = tc6393xb_ohci_disable, - }, - [TC6393XB_CELL_FB] = { - .name = "tmio-fb", - .num_resources = ARRAY_SIZE(tc6393xb_fb_resources), - .resources = tc6393xb_fb_resources, - .enable = tc6393xb_fb_enable, - .suspend = tc6393xb_fb_disable, - .resume = tc6393xb_fb_enable, - .disable = tc6393xb_fb_disable, - }, -}; - -/*--------------------------------------------------------------------------*/ - -static int tc6393xb_gpio_get(struct gpio_chip *chip, - unsigned offset) -{ - struct tc6393xb *tc6393xb = gpiochip_get_data(chip); - - /* XXX: does dsr also represent inputs? */ - return !!(tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)) - & TC_GPIO_BIT(offset)); -} - -static void __tc6393xb_gpio_set(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct tc6393xb *tc6393xb = gpiochip_get_data(chip); - u8 dsr; - - dsr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)); - if (value) - dsr |= TC_GPIO_BIT(offset); - else - dsr &= ~TC_GPIO_BIT(offset); - - tmio_iowrite8(dsr, tc6393xb->scr + SCR_GPO_DSR(offset / 8)); -} - -static void tc6393xb_gpio_set(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct tc6393xb *tc6393xb = gpiochip_get_data(chip); - unsigned long flags; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - __tc6393xb_gpio_set(chip, offset, value); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); -} - -static int tc6393xb_gpio_direction_input(struct gpio_chip *chip, - unsigned offset) -{ - struct tc6393xb *tc6393xb = gpiochip_get_data(chip); - unsigned long flags; - u8 doecr; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); - doecr &= ~TC_GPIO_BIT(offset); - tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} - -static int tc6393xb_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct tc6393xb *tc6393xb = gpiochip_get_data(chip); - unsigned long flags; - u8 doecr; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - __tc6393xb_gpio_set(chip, offset, value); - - doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); - doecr |= TC_GPIO_BIT(offset); - tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} - -/* - * TC6393XB GPIOs as used on TOSA, are the only user of this chip. - * GPIOs 2, 5, 8 and 13 are not connected. - */ -#define TOSA_GPIO_TG_ON 0 -#define TOSA_GPIO_L_MUTE 1 -#define TOSA_GPIO_BL_C20MA 3 -#define TOSA_GPIO_CARD_VCC_ON 4 -#define TOSA_GPIO_CHARGE_OFF 6 -#define TOSA_GPIO_CHARGE_OFF_JC 7 -#define TOSA_GPIO_BAT0_V_ON 9 -#define TOSA_GPIO_BAT1_V_ON 10 -#define TOSA_GPIO_BU_CHRG_ON 11 -#define TOSA_GPIO_BAT_SW_ON 12 -#define TOSA_GPIO_BAT0_TH_ON 14 -#define TOSA_GPIO_BAT1_TH_ON 15 - - -GPIO_LOOKUP_SINGLE(tosa_lcd_gpio_lookup, "spi2.0", "tc6393xb", - TOSA_GPIO_TG_ON, "tg #pwr", GPIO_ACTIVE_HIGH); - -GPIO_LOOKUP_SINGLE(tosa_lcd_bl_gpio_lookup, "i2c-tos-bl", "tc6393xb", - TOSA_GPIO_BL_C20MA, "backlight", GPIO_ACTIVE_HIGH); - -GPIO_LOOKUP_SINGLE(tosa_audio_gpio_lookup, "tosa-audio", "tc6393xb", - TOSA_GPIO_L_MUTE, NULL, GPIO_ACTIVE_HIGH); - -static struct gpiod_lookup_table tosa_battery_gpio_lookup = { - .dev_id = "wm97xx-battery", - .table = { - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_CHARGE_OFF, - "main charge off", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_CHARGE_OFF_JC, - "jacket charge off", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT0_V_ON, - "main battery", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT1_V_ON, - "jacket battery", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BU_CHRG_ON, - "backup battery", GPIO_ACTIVE_HIGH), - /* BAT1 and BAT0 thermistors appear to be swapped */ - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT1_TH_ON, - "main battery temp", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT0_TH_ON, - "jacket battery temp", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT_SW_ON, - "battery switch", GPIO_ACTIVE_HIGH), - { }, - }, -}; - -static struct gpiod_lookup_table *tc6393xb_gpio_lookups[] = { - &tosa_lcd_gpio_lookup, - &tosa_lcd_bl_gpio_lookup, - &tosa_audio_gpio_lookup, - &tosa_battery_gpio_lookup, -}; - -static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb) -{ - struct gpio_chip *gc = &tc6393xb->gpio; - struct device *dev = tc6393xb->dev; - int ret; - - gc->label = "tc6393xb"; - gc->base = -1; /* Dynamic allocation */ - gc->ngpio = 16; - gc->set = tc6393xb_gpio_set; - gc->get = tc6393xb_gpio_get; - gc->direction_input = tc6393xb_gpio_direction_input; - gc->direction_output = tc6393xb_gpio_direction_output; - - ret = devm_gpiochip_add_data(dev, gc, tc6393xb); - if (ret) - return dev_err_probe(dev, ret, "failed to add GPIO chip\n"); - - /* Register descriptor look-ups for consumers */ - gpiod_add_lookup_tables(tc6393xb_gpio_lookups, ARRAY_SIZE(tc6393xb_gpio_lookups)); - - /* Request some of our own GPIOs */ - tc6393xb->vcc_on = gpiochip_request_own_desc(gc, TOSA_GPIO_CARD_VCC_ON, "VCC ON", - GPIO_ACTIVE_HIGH, GPIOD_OUT_HIGH); - if (IS_ERR(tc6393xb->vcc_on)) - return dev_err_probe(dev, PTR_ERR(tc6393xb->vcc_on), - "failed to request VCC ON GPIO\n"); - - return 0; -} - -/*--------------------------------------------------------------------------*/ - -static void tc6393xb_irq(struct irq_desc *desc) -{ - struct tc6393xb *tc6393xb = irq_desc_get_handler_data(desc); - unsigned int isr; - unsigned int i, irq_base; - - irq_base = tc6393xb->irq_base; - - while ((isr = tmio_ioread8(tc6393xb->scr + SCR_ISR) & - ~tmio_ioread8(tc6393xb->scr + SCR_IMR))) - for (i = 0; i < TC6393XB_NR_IRQS; i++) { - if (isr & (1 << i)) - generic_handle_irq(irq_base + i); - } -} - -static void tc6393xb_irq_ack(struct irq_data *data) -{ -} - -static void tc6393xb_irq_mask(struct irq_data *data) -{ - struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data); - unsigned long flags; - u8 imr; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); - imr |= 1 << (data->irq - tc6393xb->irq_base); - tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); -} - -static void tc6393xb_irq_unmask(struct irq_data *data) -{ - struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data); - unsigned long flags; - u8 imr; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); - imr &= ~(1 << (data->irq - tc6393xb->irq_base)); - tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); -} - -static struct irq_chip tc6393xb_chip = { - .name = "tc6393xb", - .irq_ack = tc6393xb_irq_ack, - .irq_mask = tc6393xb_irq_mask, - .irq_unmask = tc6393xb_irq_unmask, -}; - -static void tc6393xb_attach_irq(struct platform_device *dev) -{ - struct tc6393xb *tc6393xb = platform_get_drvdata(dev); - unsigned int irq, irq_base; - - irq_base = tc6393xb->irq_base; - - for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { - irq_set_chip_and_handler(irq, &tc6393xb_chip, handle_edge_irq); - irq_set_chip_data(irq, tc6393xb); - irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); - } - - irq_set_irq_type(tc6393xb->irq, IRQ_TYPE_EDGE_FALLING); - irq_set_chained_handler_and_data(tc6393xb->irq, tc6393xb_irq, - tc6393xb); -} - -static void tc6393xb_detach_irq(struct platform_device *dev) -{ - struct tc6393xb *tc6393xb = platform_get_drvdata(dev); - unsigned int irq, irq_base; - - irq_set_chained_handler_and_data(tc6393xb->irq, NULL, NULL); - - irq_base = tc6393xb->irq_base; - - for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { - irq_set_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); - irq_set_chip(irq, NULL); - irq_set_chip_data(irq, NULL); - } -} - -/*--------------------------------------------------------------------------*/ - -static int tc6393xb_probe(struct platform_device *dev) -{ - struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); - struct tc6393xb *tc6393xb; - struct resource *iomem, *rscr; - int ret; - - iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!iomem) - return -EINVAL; - - tc6393xb = kzalloc(sizeof *tc6393xb, GFP_KERNEL); - if (!tc6393xb) { - ret = -ENOMEM; - goto err_kzalloc; - } - tc6393xb->dev = &dev->dev; - - raw_spin_lock_init(&tc6393xb->lock); - - platform_set_drvdata(dev, tc6393xb); - - ret = platform_get_irq(dev, 0); - if (ret >= 0) - tc6393xb->irq = ret; - else - goto err_noirq; - - tc6393xb->iomem = iomem; - tc6393xb->irq_base = tcpd->irq_base; - - tc6393xb->clk = clk_get(&dev->dev, "CLK_CK3P6MI"); - if (IS_ERR(tc6393xb->clk)) { - ret = PTR_ERR(tc6393xb->clk); - goto err_clk_get; - } - - rscr = &tc6393xb->rscr; - rscr->name = "tc6393xb-core"; - rscr->start = iomem->start; - rscr->end = iomem->start + 0xff; - rscr->flags = IORESOURCE_MEM; - - ret = request_resource(iomem, rscr); - if (ret) - goto err_request_scr; - - tc6393xb->scr = ioremap(rscr->start, resource_size(rscr)); - if (!tc6393xb->scr) { - ret = -ENOMEM; - goto err_ioremap; - } - - ret = clk_prepare_enable(tc6393xb->clk); - if (ret) - goto err_clk_enable; - - ret = tcpd->enable(dev); - if (ret) - goto err_enable; - - iowrite8(0, tc6393xb->scr + SCR_FER); - iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR); - iowrite16(SCR_CCR_UNK1 | SCR_CCR_HCLK_48, - tc6393xb->scr + SCR_CCR); - iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN | - SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN | - BIT(15), tc6393xb->scr + SCR_MCR); - iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER); - iowrite8(0, tc6393xb->scr + SCR_IRR); - iowrite8(0xbf, tc6393xb->scr + SCR_IMR); - - printk(KERN_INFO "Toshiba tc6393xb revision %d at 0x%08lx, irq %d\n", - tmio_ioread8(tc6393xb->scr + SCR_REVID), - (unsigned long) iomem->start, tc6393xb->irq); - - ret = tc6393xb_register_gpio(tc6393xb); - if (ret) - goto err_gpio_add; - - tc6393xb_attach_irq(dev); - - tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = tcpd->nand_data; - tc6393xb_cells[TC6393XB_CELL_NAND].pdata_size = - sizeof(*tcpd->nand_data); - tc6393xb_cells[TC6393XB_CELL_FB].platform_data = tcpd->fb_data; - tc6393xb_cells[TC6393XB_CELL_FB].pdata_size = sizeof(*tcpd->fb_data); - - ret = mfd_add_devices(&dev->dev, dev->id, - tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), - iomem, tcpd->irq_base, NULL); - - if (!ret) - return 0; - - tc6393xb_detach_irq(dev); -err_gpio_add: - tcpd->disable(dev); -err_enable: - clk_disable_unprepare(tc6393xb->clk); -err_clk_enable: - iounmap(tc6393xb->scr); -err_ioremap: - release_resource(&tc6393xb->rscr); -err_request_scr: - clk_put(tc6393xb->clk); -err_noirq: -err_clk_get: - kfree(tc6393xb); -err_kzalloc: - return ret; -} - -static int tc6393xb_remove(struct platform_device *dev) -{ - struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); - struct tc6393xb *tc6393xb = platform_get_drvdata(dev); - - mfd_remove_devices(&dev->dev); - - tc6393xb_detach_irq(dev); - - tcpd->disable(dev); - clk_disable_unprepare(tc6393xb->clk); - iounmap(tc6393xb->scr); - release_resource(&tc6393xb->rscr); - clk_put(tc6393xb->clk); - kfree(tc6393xb); - - return 0; -} - -static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state) -{ - struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); - struct tc6393xb *tc6393xb = platform_get_drvdata(dev); - int i, ret; - - tc6393xb->suspend_state.ccr = ioread16(tc6393xb->scr + SCR_CCR); - tc6393xb->suspend_state.fer = ioread8(tc6393xb->scr + SCR_FER); - - for (i = 0; i < 3; i++) { - tc6393xb->suspend_state.gpo_dsr[i] = - ioread8(tc6393xb->scr + SCR_GPO_DSR(i)); - tc6393xb->suspend_state.gpo_doecr[i] = - ioread8(tc6393xb->scr + SCR_GPO_DOECR(i)); - tc6393xb->suspend_state.gpi_bcr[i] = - ioread8(tc6393xb->scr + SCR_GPI_BCR(i)); - } - ret = tcpd->suspend(dev); - clk_disable_unprepare(tc6393xb->clk); - - return ret; -} - -static int tc6393xb_resume(struct platform_device *dev) -{ - struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); - struct tc6393xb *tc6393xb = platform_get_drvdata(dev); - int ret; - int i; - - ret = clk_prepare_enable(tc6393xb->clk); - if (ret) - return ret; - - ret = tcpd->resume(dev); - if (ret) - return ret; - - if (!tcpd->resume_restore) - return 0; - - iowrite8(tc6393xb->suspend_state.fer, tc6393xb->scr + SCR_FER); - iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR); - iowrite16(tc6393xb->suspend_state.ccr, tc6393xb->scr + SCR_CCR); - iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN | - SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN | - BIT(15), tc6393xb->scr + SCR_MCR); - iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER); - iowrite8(0, tc6393xb->scr + SCR_IRR); - iowrite8(0xbf, tc6393xb->scr + SCR_IMR); - - for (i = 0; i < 3; i++) { - iowrite8(tc6393xb->suspend_state.gpo_dsr[i], - tc6393xb->scr + SCR_GPO_DSR(i)); - iowrite8(tc6393xb->suspend_state.gpo_doecr[i], - tc6393xb->scr + SCR_GPO_DOECR(i)); - iowrite8(tc6393xb->suspend_state.gpi_bcr[i], - tc6393xb->scr + SCR_GPI_BCR(i)); - } - - return 0; -} - -static struct platform_driver tc6393xb_driver = { - .probe = tc6393xb_probe, - .remove = tc6393xb_remove, - .suspend = pm_sleep_ptr(tc6393xb_suspend), - .resume = pm_sleep_ptr(tc6393xb_resume), - - .driver = { - .name = "tc6393xb", - }, -}; - -static int __init tc6393xb_init(void) -{ - return platform_driver_register(&tc6393xb_driver); -} - -static void __exit tc6393xb_exit(void) -{ - platform_driver_unregister(&tc6393xb_driver); -} - -subsys_initcall(tc6393xb_init); -module_exit(tc6393xb_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer"); -MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller"); -MODULE_ALIAS("platform:tc6393xb"); - diff --git a/drivers/mfd/tmio_core.c b/drivers/mfd/tmio_core.c deleted file mode 100644 index 7ee873551482..000000000000 --- a/drivers/mfd/tmio_core.c +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright(c) 2009 Ian Molton <spyro@f2s.com> - */ - -#include <linux/export.h> -#include <linux/mfd/tmio.h> - -#define CNF_CMD 0x04 -#define CNF_CTL_BASE 0x10 -#define CNF_INT_PIN 0x3d -#define CNF_STOP_CLK_CTL 0x40 -#define CNF_GCLK_CTL 0x41 -#define CNF_SD_CLK_MODE 0x42 -#define CNF_PIN_STATUS 0x44 -#define CNF_PWR_CTL_1 0x48 -#define CNF_PWR_CTL_2 0x49 -#define CNF_PWR_CTL_3 0x4a -#define CNF_CARD_DETECT_MODE 0x4c -#define CNF_SD_SLOT 0x50 -#define CNF_EXT_GCLK_CTL_1 0xf0 -#define CNF_EXT_GCLK_CTL_2 0xf1 -#define CNF_EXT_GCLK_CTL_3 0xf9 -#define CNF_SD_LED_EN_1 0xfa -#define CNF_SD_LED_EN_2 0xfe - -#define SDCREN 0x2 /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/ - -int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base) -{ - /* Enable the MMC/SD Control registers */ - sd_config_write16(cnf, shift, CNF_CMD, SDCREN); - sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe); - - /* Disable SD power during suspend */ - sd_config_write8(cnf, shift, CNF_PWR_CTL_3, 0x01); - - /* The below is required but why? FIXME */ - sd_config_write8(cnf, shift, CNF_STOP_CLK_CTL, 0x1f); - - /* Power down SD bus */ - sd_config_write8(cnf, shift, CNF_PWR_CTL_2, 0x00); - - return 0; -} -EXPORT_SYMBOL(tmio_core_mmc_enable); - -int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base) -{ - - /* Enable the MMC/SD Control registers */ - sd_config_write16(cnf, shift, CNF_CMD, SDCREN); - sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe); - - return 0; -} -EXPORT_SYMBOL(tmio_core_mmc_resume); - -void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state) -{ - sd_config_write8(cnf, shift, CNF_PWR_CTL_2, state ? 0x02 : 0x00); -} -EXPORT_SYMBOL(tmio_core_mmc_pwr); - -void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state) -{ - sd_config_write8(cnf, shift, CNF_SD_CLK_MODE, state ? 1 : 0); -} -EXPORT_SYMBOL(tmio_core_mmc_clk_div); - diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c deleted file mode 100644 index ac1d18039568..000000000000 --- a/drivers/mfd/ucb1400_core.c +++ /dev/null @@ -1,158 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Core functions for: - * Philips UCB1400 multifunction chip - * - * Based on ucb1400_ts.c: - * Author: Nicolas Pitre - * Created: September 25, 2006 - * Copyright: MontaVista Software, Inc. - * - * Spliting done by: Marek Vasut <marek.vasut@gmail.com> - * If something doesn't work and it worked before spliting, e-mail me, - * dont bother Nicolas please ;-) - * - * 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. - */ - -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/ucb1400.h> - -unsigned int ucb1400_adc_read(struct snd_ac97 *ac97, u16 adc_channel, - int adcsync) -{ - unsigned int val; - - if (adcsync) - adc_channel |= UCB_ADC_SYNC_ENA; - - ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel); - ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel | - UCB_ADC_START); - - while (!((val = ucb1400_reg_read(ac97, UCB_ADC_DATA)) - & UCB_ADC_DAT_VALID)) - schedule_timeout_uninterruptible(1); - - return val & UCB_ADC_DAT_MASK; -} -EXPORT_SYMBOL_GPL(ucb1400_adc_read); - -static int ucb1400_core_probe(struct device *dev) -{ - int err; - struct ucb1400 *ucb; - struct ucb1400_ts ucb_ts; - struct ucb1400_gpio ucb_gpio; - struct snd_ac97 *ac97; - struct ucb1400_pdata *pdata = dev_get_platdata(dev); - - memset(&ucb_ts, 0, sizeof(ucb_ts)); - memset(&ucb_gpio, 0, sizeof(ucb_gpio)); - - ucb = kzalloc(sizeof(struct ucb1400), GFP_KERNEL); - if (!ucb) { - err = -ENOMEM; - goto err; - } - - dev_set_drvdata(dev, ucb); - - ac97 = to_ac97_t(dev); - - ucb_ts.id = ucb1400_reg_read(ac97, UCB_ID); - if (ucb_ts.id != UCB_ID_1400) { - err = -ENODEV; - goto err0; - } - - /* GPIO */ - ucb_gpio.ac97 = ac97; - if (pdata) - ucb_gpio.gpio_offset = pdata->gpio_offset; - - ucb->ucb1400_gpio = platform_device_alloc("ucb1400_gpio", -1); - if (!ucb->ucb1400_gpio) { - err = -ENOMEM; - goto err0; - } - err = platform_device_add_data(ucb->ucb1400_gpio, &ucb_gpio, - sizeof(ucb_gpio)); - if (err) - goto err1; - err = platform_device_add(ucb->ucb1400_gpio); - if (err) - goto err1; - - /* TOUCHSCREEN */ - ucb_ts.ac97 = ac97; - - if (pdata != NULL && pdata->irq >= 0) - ucb_ts.irq = pdata->irq; - else - ucb_ts.irq = -1; - - ucb->ucb1400_ts = platform_device_alloc("ucb1400_ts", -1); - if (!ucb->ucb1400_ts) { - err = -ENOMEM; - goto err2; - } - err = platform_device_add_data(ucb->ucb1400_ts, &ucb_ts, - sizeof(ucb_ts)); - if (err) - goto err3; - err = platform_device_add(ucb->ucb1400_ts); - if (err) - goto err3; - - return 0; - -err3: - platform_device_put(ucb->ucb1400_ts); -err2: - platform_device_del(ucb->ucb1400_gpio); -err1: - platform_device_put(ucb->ucb1400_gpio); -err0: - kfree(ucb); -err: - return err; -} - -static int ucb1400_core_remove(struct device *dev) -{ - struct ucb1400 *ucb = dev_get_drvdata(dev); - - platform_device_unregister(ucb->ucb1400_ts); - platform_device_unregister(ucb->ucb1400_gpio); - - kfree(ucb); - return 0; -} - -static struct device_driver ucb1400_core_driver = { - .name = "ucb1400_core", - .bus = &ac97_bus_type, - .probe = ucb1400_core_probe, - .remove = ucb1400_core_remove, -}; - -static int __init ucb1400_core_init(void) -{ - return driver_register(&ucb1400_core_driver); -} - -static void __exit ucb1400_core_exit(void) -{ - driver_unregister(&ucb1400_core_driver); -} - -module_init(ucb1400_core_init); -module_exit(ucb1400_core_exit); - -MODULE_DESCRIPTION("Philips UCB1400 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index c9902a1dcf5d..5310606113fe 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -321,7 +321,7 @@ static void fastrpc_free_map(struct kref *ref) perm.vmid = QCOM_SCM_VMID_HLOS; perm.perm = QCOM_SCM_PERM_RWX; err = qcom_scm_assign_mem(map->phys, map->size, - &(map->fl->cctx->vmperms[0].vmid), &perm, 1); + &map->fl->cctx->perms, &perm, 1); if (err) { dev_err(map->fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d", map->phys, map->size, err); @@ -334,6 +334,13 @@ static void fastrpc_free_map(struct kref *ref) dma_buf_put(map->buf); } + if (map->fl) { + spin_lock(&map->fl->lock); + list_del(&map->node); + spin_unlock(&map->fl->lock); + map->fl = NULL; + } + kfree(map); } @@ -343,38 +350,41 @@ static void fastrpc_map_put(struct fastrpc_map *map) kref_put(&map->refcount, fastrpc_free_map); } -static void fastrpc_map_get(struct fastrpc_map *map) +static int fastrpc_map_get(struct fastrpc_map *map) { - if (map) - kref_get(&map->refcount); + if (!map) + return -ENOENT; + + return kref_get_unless_zero(&map->refcount) ? 0 : -ENOENT; } static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd, - struct fastrpc_map **ppmap) + struct fastrpc_map **ppmap, bool take_ref) { + struct fastrpc_session_ctx *sess = fl->sctx; struct fastrpc_map *map = NULL; + int ret = -ENOENT; - mutex_lock(&fl->mutex); + spin_lock(&fl->lock); list_for_each_entry(map, &fl->maps, node) { - if (map->fd == fd) { - *ppmap = map; - mutex_unlock(&fl->mutex); - return 0; - } - } - mutex_unlock(&fl->mutex); - - return -ENOENT; -} + if (map->fd != fd) + continue; -static int fastrpc_map_find(struct fastrpc_user *fl, int fd, - struct fastrpc_map **ppmap) -{ - int ret = fastrpc_map_lookup(fl, fd, ppmap); + if (take_ref) { + ret = fastrpc_map_get(map); + if (ret) { + dev_dbg(sess->dev, "%s: Failed to get map fd=%d ret=%d\n", + __func__, fd, ret); + break; + } + } - if (!ret) - fastrpc_map_get(*ppmap); + *ppmap = map; + ret = 0; + break; + } + spin_unlock(&fl->lock); return ret; } @@ -746,7 +756,7 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd, struct fastrpc_map *map = NULL; int err = 0; - if (!fastrpc_map_find(fl, fd, ppmap)) + if (!fastrpc_map_lookup(fl, fd, ppmap, true)) return 0; map = kzalloc(sizeof(*map), GFP_KERNEL); @@ -788,10 +798,8 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd, * If subsystem VMIDs are defined in DTSI, then do * hyp_assign from HLOS to those VM(s) */ - unsigned int perms = BIT(QCOM_SCM_VMID_HLOS); - map->attr = attr; - err = qcom_scm_assign_mem(map->phys, (u64)map->size, &perms, + err = qcom_scm_assign_mem(map->phys, (u64)map->size, &fl->cctx->perms, fl->cctx->vmperms, fl->cctx->vmcount); if (err) { dev_err(sess->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d", @@ -1070,7 +1078,7 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx, for (i = 0; i < FASTRPC_MAX_FDLIST; i++) { if (!fdlist[i]) break; - if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap)) + if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false)) fastrpc_map_put(mmap); } @@ -1258,10 +1266,9 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl, /* Map if we have any heap VMIDs associated with this ADSP Static Process. */ if (fl->cctx->vmcount) { - unsigned int perms = BIT(QCOM_SCM_VMID_HLOS); - err = qcom_scm_assign_mem(fl->cctx->remote_heap->phys, - (u64)fl->cctx->remote_heap->size, &perms, + (u64)fl->cctx->remote_heap->size, + &fl->cctx->perms, fl->cctx->vmperms, fl->cctx->vmcount); if (err) { dev_err(fl->sctx->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d", @@ -1309,7 +1316,7 @@ err_invoke: perm.perm = QCOM_SCM_PERM_RWX; err = qcom_scm_assign_mem(fl->cctx->remote_heap->phys, (u64)fl->cctx->remote_heap->size, - &(fl->cctx->vmperms[0].vmid), &perm, 1); + &fl->cctx->perms, &perm, 1); if (err) dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d", fl->cctx->remote_heap->phys, fl->cctx->remote_heap->size, err); @@ -1433,12 +1440,7 @@ err_invoke: fl->init_mem = NULL; fastrpc_buf_free(imem); err_alloc: - if (map) { - spin_lock(&fl->lock); - list_del(&map->node); - spin_unlock(&fl->lock); - fastrpc_map_put(map); - } + fastrpc_map_put(map); err: kfree(args); @@ -1514,10 +1516,8 @@ static int fastrpc_device_release(struct inode *inode, struct file *file) fastrpc_context_put(ctx); } - list_for_each_entry_safe(map, m, &fl->maps, node) { - list_del(&map->node); + list_for_each_entry_safe(map, m, &fl->maps, node) fastrpc_map_put(map); - } list_for_each_entry_safe(buf, b, &fl->mmaps, node) { list_del(&buf->node); @@ -1894,12 +1894,11 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp) /* Add memory to static PD pool, protection thru hypervisor */ if (req.flags != ADSP_MMAP_REMOTE_HEAP_ADDR && fl->cctx->vmcount) { struct qcom_scm_vmperm perm; - int err = 0; perm.vmid = QCOM_SCM_VMID_HLOS; perm.perm = QCOM_SCM_PERM_RWX; err = qcom_scm_assign_mem(buf->phys, buf->size, - &(fl->cctx->vmperms[0].vmid), &perm, 1); + &fl->cctx->perms, &perm, 1); if (err) { dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d", buf->phys, buf->size, err); diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 4a08b624910a..a81b890c7ee6 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -702,13 +702,15 @@ void *mei_cldev_dma_map(struct mei_cl_device *cldev, u8 buffer_id, size_t size) if (cl->state == MEI_FILE_UNINITIALIZED) { ret = mei_cl_link(cl); if (ret) - goto out; + goto notlinked; /* update pointers */ cl->cldev = cldev; } ret = mei_cl_dma_alloc_and_map(cl, NULL, buffer_id, size); -out: + if (ret) + mei_cl_unlink(cl); +notlinked: mutex_unlock(&bus->device_lock); if (ret) return ERR_PTR(ret); @@ -758,7 +760,7 @@ int mei_cldev_enable(struct mei_cl_device *cldev) if (cl->state == MEI_FILE_UNINITIALIZED) { ret = mei_cl_link(cl); if (ret) - goto out; + goto notlinked; /* update pointers */ cl->cldev = cldev; } @@ -785,6 +787,9 @@ int mei_cldev_enable(struct mei_cl_device *cldev) } out: + if (ret) + mei_cl_unlink(cl); +notlinked: mutex_unlock(&bus->device_lock); return ret; @@ -1277,7 +1282,6 @@ static void mei_cl_bus_dev_release(struct device *dev) mei_cl_flush_queues(cldev->cl, NULL); mei_me_cl_put(cldev->me_cl); mei_dev_bus_put(cldev->bus); - mei_cl_unlink(cldev->cl); kfree(cldev->cl); kfree(cldev); } diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index 99966cd3e7d8..bdc65d50b945 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -111,6 +111,8 @@ #define MEI_DEV_ID_RPL_S 0x7A68 /* Raptor Lake Point S */ +#define MEI_DEV_ID_MTL_M 0x7E70 /* Meteor Lake Point M */ + /* * MEI HW Section */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 704cd0caa172..5bf0d50d55a0 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -118,6 +118,8 @@ static const struct pci_device_id mei_me_pci_tbl[] = { {MEI_PCI_DEVICE(MEI_DEV_ID_RPL_S, MEI_ME_PCH15_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_MTL_M, MEI_ME_PCH15_CFG)}, + /* required last entry */ {0, } }; diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index aa7b05de97dd..4f8d962bb5b2 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -56,8 +56,6 @@ struct vmci_guest_device { bool exclusive_vectors; - struct tasklet_struct datagram_tasklet; - struct tasklet_struct bm_tasklet; struct wait_queue_head inout_wq; void *data_buffer; @@ -304,9 +302,8 @@ static int vmci_check_host_caps(struct pci_dev *pdev) * This function assumes that it has exclusive access to the data * in register(s) for the duration of the call. */ -static void vmci_dispatch_dgs(unsigned long data) +static void vmci_dispatch_dgs(struct vmci_guest_device *vmci_dev) { - struct vmci_guest_device *vmci_dev = (struct vmci_guest_device *)data; u8 *dg_in_buffer = vmci_dev->data_buffer; struct vmci_datagram *dg; size_t dg_in_buffer_size = VMCI_MAX_DG_SIZE; @@ -465,10 +462,8 @@ static void vmci_dispatch_dgs(unsigned long data) * Scans the notification bitmap for raised flags, clears them * and handles the notifications. */ -static void vmci_process_bitmap(unsigned long data) +static void vmci_process_bitmap(struct vmci_guest_device *dev) { - struct vmci_guest_device *dev = (struct vmci_guest_device *)data; - if (!dev->notification_bitmap) { dev_dbg(dev->dev, "No bitmap present in %s\n", __func__); return; @@ -486,13 +481,13 @@ static irqreturn_t vmci_interrupt(int irq, void *_dev) struct vmci_guest_device *dev = _dev; /* - * If we are using MSI-X with exclusive vectors then we simply schedule - * the datagram tasklet, since we know the interrupt was meant for us. + * If we are using MSI-X with exclusive vectors then we simply call + * vmci_dispatch_dgs(), since we know the interrupt was meant for us. * Otherwise we must read the ICR to determine what to do. */ if (dev->exclusive_vectors) { - tasklet_schedule(&dev->datagram_tasklet); + vmci_dispatch_dgs(dev); } else { unsigned int icr; @@ -502,12 +497,12 @@ static irqreturn_t vmci_interrupt(int irq, void *_dev) return IRQ_NONE; if (icr & VMCI_ICR_DATAGRAM) { - tasklet_schedule(&dev->datagram_tasklet); + vmci_dispatch_dgs(dev); icr &= ~VMCI_ICR_DATAGRAM; } if (icr & VMCI_ICR_NOTIFICATION) { - tasklet_schedule(&dev->bm_tasklet); + vmci_process_bitmap(dev); icr &= ~VMCI_ICR_NOTIFICATION; } @@ -536,7 +531,7 @@ static irqreturn_t vmci_interrupt_bm(int irq, void *_dev) struct vmci_guest_device *dev = _dev; /* For MSI-X we can just assume it was meant for us. */ - tasklet_schedule(&dev->bm_tasklet); + vmci_process_bitmap(dev); return IRQ_HANDLED; } @@ -638,10 +633,6 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, vmci_dev->iobase = iobase; vmci_dev->mmio_base = mmio_base; - tasklet_init(&vmci_dev->datagram_tasklet, - vmci_dispatch_dgs, (unsigned long)vmci_dev); - tasklet_init(&vmci_dev->bm_tasklet, - vmci_process_bitmap, (unsigned long)vmci_dev); init_waitqueue_head(&vmci_dev->inout_wq); if (mmio_base != NULL) { @@ -808,8 +799,9 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, * Request IRQ for legacy or MSI interrupts, or for first * MSI-X vector. */ - error = request_irq(pci_irq_vector(pdev, 0), vmci_interrupt, - IRQF_SHARED, KBUILD_MODNAME, vmci_dev); + error = request_threaded_irq(pci_irq_vector(pdev, 0), NULL, + vmci_interrupt, IRQF_SHARED, + KBUILD_MODNAME, vmci_dev); if (error) { dev_err(&pdev->dev, "Irq %u in use: %d\n", pci_irq_vector(pdev, 0), error); @@ -823,9 +815,9 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, * between the vectors. */ if (vmci_dev->exclusive_vectors) { - error = request_irq(pci_irq_vector(pdev, 1), - vmci_interrupt_bm, 0, KBUILD_MODNAME, - vmci_dev); + error = request_threaded_irq(pci_irq_vector(pdev, 1), NULL, + vmci_interrupt_bm, 0, + KBUILD_MODNAME, vmci_dev); if (error) { dev_err(&pdev->dev, "Failed to allocate irq %u: %d\n", @@ -833,9 +825,11 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, goto err_free_irq; } if (caps_in_use & VMCI_CAPS_DMA_DATAGRAM) { - error = request_irq(pci_irq_vector(pdev, 2), - vmci_interrupt_dma_datagram, - 0, KBUILD_MODNAME, vmci_dev); + error = request_threaded_irq(pci_irq_vector(pdev, 2), + NULL, + vmci_interrupt_dma_datagram, + 0, KBUILD_MODNAME, + vmci_dev); if (error) { dev_err(&pdev->dev, "Failed to allocate irq %u: %d\n", @@ -871,8 +865,6 @@ err_free_bm_irq: err_free_irq: free_irq(pci_irq_vector(pdev, 0), vmci_dev); - tasklet_kill(&vmci_dev->datagram_tasklet); - tasklet_kill(&vmci_dev->bm_tasklet); err_disable_msi: pci_free_irq_vectors(pdev); @@ -943,9 +935,6 @@ static void vmci_guest_remove_device(struct pci_dev *pdev) free_irq(pci_irq_vector(pdev, 0), vmci_dev); pci_free_irq_vectors(pdev); - tasklet_kill(&vmci_dev->datagram_tasklet); - tasklet_kill(&vmci_dev->bm_tasklet); - if (vmci_dev->notification_bitmap) { /* * The device reset above cleared the bitmap state of the diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index babf21a0adeb..f191a2a76f3b 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -294,6 +294,12 @@ static void sdio_release_func(struct device *dev) if (!(func->card->quirks & MMC_QUIRK_NONSTD_SDIO)) sdio_free_func_cis(func); + /* + * We have now removed the link to the tuples in the + * card structure, so remove the reference. + */ + put_device(&func->card->dev); + kfree(func->info); kfree(func->tmpbuf); kfree(func); @@ -324,6 +330,12 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card) device_initialize(&func->dev); + /* + * We may link to tuples in the card structure, + * we need make sure we have a reference to it. + */ + get_device(&func->card->dev); + func->dev.parent = &card->dev; func->dev.bus = &sdio_bus_type; func->dev.release = sdio_release_func; @@ -377,10 +389,9 @@ int sdio_add_func(struct sdio_func *func) */ void sdio_remove_func(struct sdio_func *func) { - if (!sdio_func_present(func)) - return; + if (sdio_func_present(func)) + device_del(&func->dev); - device_del(&func->dev); of_node_put(func->dev.of_node); put_device(&func->dev); } diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index a705ba6eff5b..afaa6cab1adc 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -404,12 +404,6 @@ int sdio_read_func_cis(struct sdio_func *func) return ret; /* - * Since we've linked to tuples in the card structure, - * we must make sure we have a reference to it. - */ - get_device(&func->card->dev); - - /* * Vendor/device id is optional for function CIS, so * copy it from the card structure as needed. */ @@ -434,11 +428,5 @@ void sdio_free_func_cis(struct sdio_func *func) } func->tuples = NULL; - - /* - * We have now removed the link to the tuples in the - * card structure, so remove the reference. - */ - put_device(&func->card->dev); } diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 5e19a961c34d..e13b0b0b8ebb 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -262,17 +262,6 @@ config MMC_SDHCI_CADENCE If unsure, say N. -config MMC_SDHCI_CNS3XXX - tristate "SDHCI support on the Cavium Networks CNS3xxx SoC" - depends on ARCH_CNS3XXX || COMPILE_TEST - depends on MMC_SDHCI_PLTFM - help - This selects the SDHCI support for CNS3xxx System-on-Chip devices. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - config MMC_SDHCI_ESDHC_MCF tristate "SDHCI support for the Freescale eSDHC ColdFire controller" depends on M5441x @@ -332,9 +321,8 @@ config MMC_SDHCI_S3C depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST help This selects the Secure Digital Host Controller Interface (SDHCI) - often referrered to as the HSMMC block in some of the Samsung S3C - (S3C2416, S3C2443, S3C6410), S5Pv210 and Exynos (Exynso4210, - Exynos4412) SoCs. + often referrered to as the HSMMC block in some of the Samsung + S3C6410, S5Pv210 and Exynos (Exynso4210, Exynos4412) SoCs. If you have a controller with this interface (thereforeyou build for such Samsung SoC), say Y or M here. @@ -500,7 +488,6 @@ config MMC_SDHCI_ST config MMC_OMAP tristate "TI OMAP Multimedia Card Interface support" depends on ARCH_OMAP - depends on TPS65010 || !MACH_OMAP_H2 help This selects the TI OMAP Multimedia card Interface. If you have an OMAP board with a Multimedia Card slot, @@ -640,49 +627,6 @@ config MMC_SPI If unsure, or if your system has no SPI master driver, say N. -config MMC_S3C - tristate "Samsung S3C SD/MMC Card Interface support" - depends on ARCH_S3C24XX || COMPILE_TEST - depends on S3C24XX_DMAC || COMPILE_TEST - help - This selects a driver for the MCI interface found in - Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs. - If you have a board based on one of those and a MMC/SD - slot, say Y or M here. - - If unsure, say N. - -config MMC_S3C_HW_SDIO_IRQ - bool "Hardware support for SDIO IRQ" - depends on MMC_S3C - help - Enable the hardware support for SDIO interrupts instead of using - the generic polling code. - -choice - prompt "Samsung S3C SD/MMC transfer code" - depends on MMC_S3C - -config MMC_S3C_PIO - bool "Use PIO transfers only" - help - Use PIO to transfer data between memory and the hardware. - - PIO is slower than DMA as it requires CPU instructions to - move the data. This has been the traditional default for - the S3C MCI driver. - -config MMC_S3C_DMA - bool "Use DMA transfers only" - help - Use DMA to transfer data between memory and the hardware. - - Currently, the DMA support in this driver seems to not be - working properly and needs to be debugged before this - option is useful. - -endchoice - config MMC_SDRICOH_CS tristate "MMC/SD driver for Ricoh Bay1Controllers" depends on PCI && PCMCIA @@ -710,14 +654,6 @@ config MMC_SDHCI_SPRD config MMC_TMIO_CORE tristate -config MMC_TMIO - tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" - depends on MFD_TMIO || MFD_ASIC3 || COMPILE_TEST - select MMC_TMIO_CORE - help - This provides support for the SD/MMC cell found in TC6393XB, - T7L66XB and also HTC ASIC3 - config MMC_SDHI tristate "Renesas SDHI SD/SDIO controller support" depends on SUPERH || ARCH_RENESAS || COMPILE_TEST diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index ba0c6d0cd85d..b498c17cd124 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -34,9 +34,7 @@ obj-$(CONFIG_MMC_MVSDIO) += mvsdio.o obj-$(CONFIG_MMC_DAVINCI) += davinci_mmc.o obj-$(CONFIG_MMC_SPI) += mmc_spi.o obj-$(CONFIG_MMC_SPI) += of_mmc_spi.o -obj-$(CONFIG_MMC_S3C) += s3cmci.o obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o -obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_core.o obj-$(CONFIG_MMC_SDHI_SYS_DMAC) += renesas_sdhi_sys_dmac.o @@ -77,7 +75,6 @@ obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence.o -obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o obj-$(CONFIG_MMC_SDHCI_ESDHC_MCF) += sdhci-esdhc-mcf.o obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index dc2db9c185ea..eda1e2ddcaca 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -1053,6 +1053,16 @@ static int jz4740_mmc_probe(struct platform_device* pdev) mmc->ops = &jz4740_mmc_ops; if (!mmc->f_max) mmc->f_max = JZ_MMC_CLK_RATE; + + /* + * There seems to be a problem with this driver on the JZ4760 and + * JZ4760B SoCs. There, when using the maximum rate supported (50 MHz), + * the communication fails with many SD cards. + * Until this bug is sorted out, limit the maximum rate to 24 MHz. + */ + if (host->version == JZ_MMC_JZ4760 && mmc->f_max > JZ_MMC_CLK_RATE) + mmc->f_max = JZ_MMC_CLK_RATE; + mmc->f_min = mmc->f_max / 128; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 6e5ea0213b47..5c94ad4661ce 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -435,7 +435,8 @@ static int meson_mmc_clk_init(struct meson_host *host) clk_reg |= FIELD_PREP(CLK_CORE_PHASE_MASK, CLK_PHASE_180); clk_reg |= FIELD_PREP(CLK_TX_PHASE_MASK, CLK_PHASE_0); clk_reg |= FIELD_PREP(CLK_RX_PHASE_MASK, CLK_PHASE_0); - clk_reg |= CLK_IRQ_SDIO_SLEEP(host); + if (host->mmc->caps & MMC_CAP_SDIO_IRQ) + clk_reg |= CLK_IRQ_SDIO_SLEEP(host); writel(clk_reg, host->regs + SD_EMMC_CLOCK); /* get the mux parents */ @@ -948,16 +949,18 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id) { struct meson_host *host = dev_id; struct mmc_command *cmd; - u32 status, raw_status; + u32 status, raw_status, irq_mask = IRQ_EN_MASK; irqreturn_t ret = IRQ_NONE; + if (host->mmc->caps & MMC_CAP_SDIO_IRQ) + irq_mask |= IRQ_SDIO; raw_status = readl(host->regs + SD_EMMC_STATUS); - status = raw_status & (IRQ_EN_MASK | IRQ_SDIO); + status = raw_status & irq_mask; if (!status) { dev_dbg(host->dev, - "Unexpected IRQ! irq_en 0x%08lx - status 0x%08x\n", - IRQ_EN_MASK | IRQ_SDIO, raw_status); + "Unexpected IRQ! irq_en 0x%08x - status 0x%08x\n", + irq_mask, raw_status); return IRQ_NONE; } @@ -1204,6 +1207,11 @@ static int meson_mmc_probe(struct platform_device *pdev) goto free_host; } + mmc->caps |= MMC_CAP_CMD23; + + if (mmc->caps & MMC_CAP_SDIO_IRQ) + mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; + host->data = (struct meson_mmc_data *) of_device_get_match_data(&pdev->dev); if (!host->data) { @@ -1277,11 +1285,6 @@ static int meson_mmc_probe(struct platform_device *pdev) spin_lock_init(&host->lock); - mmc->caps |= MMC_CAP_CMD23; - - if (mmc->caps & MMC_CAP_SDIO_IRQ) - mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; - if (host->dram_access_quirk) { /* Limit segments to 1 due to low available sram memory */ mmc->max_segs = 1; diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 106dd204b1a7..cc333ad67cac 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1437,7 +1437,7 @@ static int mmc_spi_probe(struct spi_device *spi) status = mmc_add_host(mmc); if (status != 0) - goto fail_add_host; + goto fail_glue_init; /* * Index 0 is card detect @@ -1445,7 +1445,7 @@ static int mmc_spi_probe(struct spi_device *spi) */ status = mmc_gpiod_request_cd(mmc, NULL, 0, false, 1000); if (status == -EPROBE_DEFER) - goto fail_add_host; + goto fail_gpiod_request; if (!status) { /* * The platform has a CD GPIO signal that may support @@ -1460,7 +1460,7 @@ static int mmc_spi_probe(struct spi_device *spi) /* Index 1 is write protect/read only */ status = mmc_gpiod_request_ro(mmc, NULL, 1, 0); if (status == -EPROBE_DEFER) - goto fail_add_host; + goto fail_gpiod_request; if (!status) has_ro = true; @@ -1474,7 +1474,7 @@ static int mmc_spi_probe(struct spi_device *spi) ? ", cd polling" : ""); return 0; -fail_add_host: +fail_gpiod_request: mmc_remove_host(mmc); fail_glue_init: mmc_spi_dma_free(host); diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c deleted file mode 100644 index 8d5929a32d34..000000000000 --- a/drivers/mmc/host/s3cmci.c +++ /dev/null @@ -1,1777 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver - * - * Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel <tk@maintech.de> - * - * Current driver maintained by Ben Dooks and Simtec Electronics - * Copyright (C) 2008 Simtec Electronics <ben-linux@fluff.org> - */ - -#include <linux/module.h> -#include <linux/dmaengine.h> -#include <linux/dma-mapping.h> -#include <linux/clk.h> -#include <linux/mmc/host.h> -#include <linux/platform_device.h> -#include <linux/cpufreq.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <linux/gpio/consumer.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/mmc/slot-gpio.h> -#include <linux/platform_data/mmc-s3cmci.h> - -#include "s3cmci.h" - -#define DRIVER_NAME "s3c-mci" - -#define S3C2410_SDICON (0x00) -#define S3C2410_SDIPRE (0x04) -#define S3C2410_SDICMDARG (0x08) -#define S3C2410_SDICMDCON (0x0C) -#define S3C2410_SDICMDSTAT (0x10) -#define S3C2410_SDIRSP0 (0x14) -#define S3C2410_SDIRSP1 (0x18) -#define S3C2410_SDIRSP2 (0x1C) -#define S3C2410_SDIRSP3 (0x20) -#define S3C2410_SDITIMER (0x24) -#define S3C2410_SDIBSIZE (0x28) -#define S3C2410_SDIDCON (0x2C) -#define S3C2410_SDIDCNT (0x30) -#define S3C2410_SDIDSTA (0x34) -#define S3C2410_SDIFSTA (0x38) - -#define S3C2410_SDIDATA (0x3C) -#define S3C2410_SDIIMSK (0x40) - -#define S3C2440_SDIDATA (0x40) -#define S3C2440_SDIIMSK (0x3C) - -#define S3C2440_SDICON_SDRESET (1 << 8) -#define S3C2410_SDICON_SDIOIRQ (1 << 3) -#define S3C2410_SDICON_FIFORESET (1 << 1) -#define S3C2410_SDICON_CLOCKTYPE (1 << 0) - -#define S3C2410_SDICMDCON_LONGRSP (1 << 10) -#define S3C2410_SDICMDCON_WAITRSP (1 << 9) -#define S3C2410_SDICMDCON_CMDSTART (1 << 8) -#define S3C2410_SDICMDCON_SENDERHOST (1 << 6) -#define S3C2410_SDICMDCON_INDEX (0x3f) - -#define S3C2410_SDICMDSTAT_CRCFAIL (1 << 12) -#define S3C2410_SDICMDSTAT_CMDSENT (1 << 11) -#define S3C2410_SDICMDSTAT_CMDTIMEOUT (1 << 10) -#define S3C2410_SDICMDSTAT_RSPFIN (1 << 9) - -#define S3C2440_SDIDCON_DS_WORD (2 << 22) -#define S3C2410_SDIDCON_TXAFTERRESP (1 << 20) -#define S3C2410_SDIDCON_RXAFTERCMD (1 << 19) -#define S3C2410_SDIDCON_BLOCKMODE (1 << 17) -#define S3C2410_SDIDCON_WIDEBUS (1 << 16) -#define S3C2410_SDIDCON_DMAEN (1 << 15) -#define S3C2410_SDIDCON_STOP (1 << 14) -#define S3C2440_SDIDCON_DATSTART (1 << 14) - -#define S3C2410_SDIDCON_XFER_RXSTART (2 << 12) -#define S3C2410_SDIDCON_XFER_TXSTART (3 << 12) - -#define S3C2410_SDIDCON_BLKNUM_MASK (0xFFF) - -#define S3C2410_SDIDSTA_SDIOIRQDETECT (1 << 9) -#define S3C2410_SDIDSTA_FIFOFAIL (1 << 8) -#define S3C2410_SDIDSTA_CRCFAIL (1 << 7) -#define S3C2410_SDIDSTA_RXCRCFAIL (1 << 6) -#define S3C2410_SDIDSTA_DATATIMEOUT (1 << 5) -#define S3C2410_SDIDSTA_XFERFINISH (1 << 4) -#define S3C2410_SDIDSTA_TXDATAON (1 << 1) -#define S3C2410_SDIDSTA_RXDATAON (1 << 0) - -#define S3C2440_SDIFSTA_FIFORESET (1 << 16) -#define S3C2440_SDIFSTA_FIFOFAIL (3 << 14) -#define S3C2410_SDIFSTA_TFDET (1 << 13) -#define S3C2410_SDIFSTA_RFDET (1 << 12) -#define S3C2410_SDIFSTA_COUNTMASK (0x7f) - -#define S3C2410_SDIIMSK_RESPONSECRC (1 << 17) -#define S3C2410_SDIIMSK_CMDSENT (1 << 16) -#define S3C2410_SDIIMSK_CMDTIMEOUT (1 << 15) -#define S3C2410_SDIIMSK_RESPONSEND (1 << 14) -#define S3C2410_SDIIMSK_SDIOIRQ (1 << 12) -#define S3C2410_SDIIMSK_FIFOFAIL (1 << 11) -#define S3C2410_SDIIMSK_CRCSTATUS (1 << 10) -#define S3C2410_SDIIMSK_DATACRC (1 << 9) -#define S3C2410_SDIIMSK_DATATIMEOUT (1 << 8) -#define S3C2410_SDIIMSK_DATAFINISH (1 << 7) -#define S3C2410_SDIIMSK_TXFIFOHALF (1 << 4) -#define S3C2410_SDIIMSK_RXFIFOLAST (1 << 2) -#define S3C2410_SDIIMSK_RXFIFOHALF (1 << 0) - -enum dbg_channels { - dbg_err = (1 << 0), - dbg_debug = (1 << 1), - dbg_info = (1 << 2), - dbg_irq = (1 << 3), - dbg_sg = (1 << 4), - dbg_dma = (1 << 5), - dbg_pio = (1 << 6), - dbg_fail = (1 << 7), - dbg_conf = (1 << 8), -}; - -static const int dbgmap_err = dbg_fail; -static const int dbgmap_info = dbg_info | dbg_conf; -static const int dbgmap_debug = dbg_err | dbg_debug; - -#define dbg(host, channels, args...) \ - do { \ - if (dbgmap_err & channels) \ - dev_err(&host->pdev->dev, args); \ - else if (dbgmap_info & channels) \ - dev_info(&host->pdev->dev, args); \ - else if (dbgmap_debug & channels) \ - dev_dbg(&host->pdev->dev, args); \ - } while (0) - -static void finalize_request(struct s3cmci_host *host); -static void s3cmci_send_request(struct mmc_host *mmc); -static void s3cmci_reset(struct s3cmci_host *host); - -#ifdef CONFIG_MMC_DEBUG - -static void dbg_dumpregs(struct s3cmci_host *host, char *prefix) -{ - u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer; - u32 datcon, datcnt, datsta, fsta; - - con = readl(host->base + S3C2410_SDICON); - pre = readl(host->base + S3C2410_SDIPRE); - cmdarg = readl(host->base + S3C2410_SDICMDARG); - cmdcon = readl(host->base + S3C2410_SDICMDCON); - cmdsta = readl(host->base + S3C2410_SDICMDSTAT); - r0 = readl(host->base + S3C2410_SDIRSP0); - r1 = readl(host->base + S3C2410_SDIRSP1); - r2 = readl(host->base + S3C2410_SDIRSP2); - r3 = readl(host->base + S3C2410_SDIRSP3); - timer = readl(host->base + S3C2410_SDITIMER); - datcon = readl(host->base + S3C2410_SDIDCON); - datcnt = readl(host->base + S3C2410_SDIDCNT); - datsta = readl(host->base + S3C2410_SDIDSTA); - fsta = readl(host->base + S3C2410_SDIFSTA); - - dbg(host, dbg_debug, "%s CON:[%08x] PRE:[%08x] TMR:[%08x]\n", - prefix, con, pre, timer); - - dbg(host, dbg_debug, "%s CCON:[%08x] CARG:[%08x] CSTA:[%08x]\n", - prefix, cmdcon, cmdarg, cmdsta); - - dbg(host, dbg_debug, "%s DCON:[%08x] FSTA:[%08x]" - " DSTA:[%08x] DCNT:[%08x]\n", - prefix, datcon, fsta, datsta, datcnt); - - dbg(host, dbg_debug, "%s R0:[%08x] R1:[%08x]" - " R2:[%08x] R3:[%08x]\n", - prefix, r0, r1, r2, r3); -} - -static void prepare_dbgmsg(struct s3cmci_host *host, struct mmc_command *cmd, - int stop) -{ - snprintf(host->dbgmsg_cmd, 300, - "#%u%s op:%i arg:0x%08x flags:0x08%x retries:%u", - host->ccnt, (stop ? " (STOP)" : ""), - cmd->opcode, cmd->arg, cmd->flags, cmd->retries); - - if (cmd->data) { - snprintf(host->dbgmsg_dat, 300, - "#%u bsize:%u blocks:%u bytes:%u", - host->dcnt, cmd->data->blksz, - cmd->data->blocks, - cmd->data->blocks * cmd->data->blksz); - } else { - host->dbgmsg_dat[0] = '\0'; - } -} - -static void dbg_dumpcmd(struct s3cmci_host *host, struct mmc_command *cmd, - int fail) -{ - unsigned int dbglvl = fail ? dbg_fail : dbg_debug; - - if (!cmd) - return; - - if (cmd->error == 0) { - dbg(host, dbglvl, "CMD[OK] %s R0:0x%08x\n", - host->dbgmsg_cmd, cmd->resp[0]); - } else { - dbg(host, dbglvl, "CMD[ERR %i] %s Status:%s\n", - cmd->error, host->dbgmsg_cmd, host->status); - } - - if (!cmd->data) - return; - - if (cmd->data->error == 0) { - dbg(host, dbglvl, "DAT[OK] %s\n", host->dbgmsg_dat); - } else { - dbg(host, dbglvl, "DAT[ERR %i] %s DCNT:0x%08x\n", - cmd->data->error, host->dbgmsg_dat, - readl(host->base + S3C2410_SDIDCNT)); - } -} -#else -static void dbg_dumpcmd(struct s3cmci_host *host, - struct mmc_command *cmd, int fail) { } - -static void prepare_dbgmsg(struct s3cmci_host *host, struct mmc_command *cmd, - int stop) { } - -static void dbg_dumpregs(struct s3cmci_host *host, char *prefix) { } - -#endif /* CONFIG_MMC_DEBUG */ - -/** - * s3cmci_host_usedma - return whether the host is using dma or pio - * @host: The host state - * - * Return true if the host is using DMA to transfer data, else false - * to use PIO mode. Will return static data depending on the driver - * configuration. - */ -static inline bool s3cmci_host_usedma(struct s3cmci_host *host) -{ -#ifdef CONFIG_MMC_S3C_PIO - return false; -#else /* CONFIG_MMC_S3C_DMA */ - return true; -#endif -} - -static inline u32 enable_imask(struct s3cmci_host *host, u32 imask) -{ - u32 newmask; - - newmask = readl(host->base + host->sdiimsk); - newmask |= imask; - - writel(newmask, host->base + host->sdiimsk); - - return newmask; -} - -static inline u32 disable_imask(struct s3cmci_host *host, u32 imask) -{ - u32 newmask; - - newmask = readl(host->base + host->sdiimsk); - newmask &= ~imask; - - writel(newmask, host->base + host->sdiimsk); - - return newmask; -} - -static inline void clear_imask(struct s3cmci_host *host) -{ - u32 mask = readl(host->base + host->sdiimsk); - - /* preserve the SDIO IRQ mask state */ - mask &= S3C2410_SDIIMSK_SDIOIRQ; - writel(mask, host->base + host->sdiimsk); -} - -/** - * s3cmci_check_sdio_irq - test whether the SDIO IRQ is being signalled - * @host: The host to check. - * - * Test to see if the SDIO interrupt is being signalled in case the - * controller has failed to re-detect a card interrupt. Read GPE8 and - * see if it is low and if so, signal a SDIO interrupt. - * - * This is currently called if a request is finished (we assume that the - * bus is now idle) and when the SDIO IRQ is enabled in case the IRQ is - * already being indicated. -*/ -static void s3cmci_check_sdio_irq(struct s3cmci_host *host) -{ - if (host->sdio_irqen) { - if (host->pdata->bus[3] && - gpiod_get_value(host->pdata->bus[3]) == 0) { - pr_debug("%s: signalling irq\n", __func__); - mmc_signal_sdio_irq(host->mmc); - } - } -} - -static inline int get_data_buffer(struct s3cmci_host *host, - u32 *bytes, u32 **pointer) -{ - struct scatterlist *sg; - - if (host->pio_active == XFER_NONE) - return -EINVAL; - - if ((!host->mrq) || (!host->mrq->data)) - return -EINVAL; - - if (host->pio_sgptr >= host->mrq->data->sg_len) { - dbg(host, dbg_debug, "no more buffers (%i/%i)\n", - host->pio_sgptr, host->mrq->data->sg_len); - return -EBUSY; - } - sg = &host->mrq->data->sg[host->pio_sgptr]; - - *bytes = sg->length; - *pointer = sg_virt(sg); - - host->pio_sgptr++; - - dbg(host, dbg_sg, "new buffer (%i/%i)\n", - host->pio_sgptr, host->mrq->data->sg_len); - - return 0; -} - -static inline u32 fifo_count(struct s3cmci_host *host) -{ - u32 fifostat = readl(host->base + S3C2410_SDIFSTA); - - fifostat &= S3C2410_SDIFSTA_COUNTMASK; - return fifostat; -} - -static inline u32 fifo_free(struct s3cmci_host *host) -{ - u32 fifostat = readl(host->base + S3C2410_SDIFSTA); - - fifostat &= S3C2410_SDIFSTA_COUNTMASK; - return 63 - fifostat; -} - -/** - * s3cmci_enable_irq - enable IRQ, after having disabled it. - * @host: The device state. - * @more: True if more IRQs are expected from transfer. - * - * Enable the main IRQ if needed after it has been disabled. - * - * The IRQ can be one of the following states: - * - disabled during IDLE - * - disabled whilst processing data - * - enabled during transfer - * - enabled whilst awaiting SDIO interrupt detection - */ -static void s3cmci_enable_irq(struct s3cmci_host *host, bool more) -{ - unsigned long flags; - bool enable = false; - - local_irq_save(flags); - - host->irq_enabled = more; - host->irq_disabled = false; - - enable = more | host->sdio_irqen; - - if (host->irq_state != enable) { - host->irq_state = enable; - - if (enable) - enable_irq(host->irq); - else - disable_irq(host->irq); - } - - local_irq_restore(flags); -} - -static void s3cmci_disable_irq(struct s3cmci_host *host, bool transfer) -{ - unsigned long flags; - - local_irq_save(flags); - - /* pr_debug("%s: transfer %d\n", __func__, transfer); */ - - host->irq_disabled = transfer; - - if (transfer && host->irq_state) { - host->irq_state = false; - disable_irq(host->irq); - } - - local_irq_restore(flags); -} - -static void do_pio_read(struct s3cmci_host *host) -{ - int res; - u32 fifo; - u32 *ptr; - u32 fifo_words; - void __iomem *from_ptr; - - /* write real prescaler to host, it might be set slow to fix */ - writel(host->prescaler, host->base + S3C2410_SDIPRE); - - from_ptr = host->base + host->sdidata; - - while ((fifo = fifo_count(host))) { - if (!host->pio_bytes) { - res = get_data_buffer(host, &host->pio_bytes, - &host->pio_ptr); - if (res) { - host->pio_active = XFER_NONE; - host->complete_what = COMPLETION_FINALIZE; - - dbg(host, dbg_pio, "pio_read(): " - "complete (no more data).\n"); - return; - } - - dbg(host, dbg_pio, - "pio_read(): new target: [%i]@[%p]\n", - host->pio_bytes, host->pio_ptr); - } - - dbg(host, dbg_pio, - "pio_read(): fifo:[%02i] buffer:[%03i] dcnt:[%08X]\n", - fifo, host->pio_bytes, - readl(host->base + S3C2410_SDIDCNT)); - - /* If we have reached the end of the block, we can - * read a word and get 1 to 3 bytes. If we in the - * middle of the block, we have to read full words, - * otherwise we will write garbage, so round down to - * an even multiple of 4. */ - if (fifo >= host->pio_bytes) - fifo = host->pio_bytes; - else - fifo -= fifo & 3; - - host->pio_bytes -= fifo; - host->pio_count += fifo; - - fifo_words = fifo >> 2; - ptr = host->pio_ptr; - while (fifo_words--) - *ptr++ = readl(from_ptr); - host->pio_ptr = ptr; - - if (fifo & 3) { - u32 n = fifo & 3; - u32 data = readl(from_ptr); - u8 *p = (u8 *)host->pio_ptr; - - while (n--) { - *p++ = data; - data >>= 8; - } - } - } - - if (!host->pio_bytes) { - res = get_data_buffer(host, &host->pio_bytes, &host->pio_ptr); - if (res) { - dbg(host, dbg_pio, - "pio_read(): complete (no more buffers).\n"); - host->pio_active = XFER_NONE; - host->complete_what = COMPLETION_FINALIZE; - - return; - } - } - - enable_imask(host, - S3C2410_SDIIMSK_RXFIFOHALF | S3C2410_SDIIMSK_RXFIFOLAST); -} - -static void do_pio_write(struct s3cmci_host *host) -{ - void __iomem *to_ptr; - int res; - u32 fifo; - u32 *ptr; - - to_ptr = host->base + host->sdidata; - - while ((fifo = fifo_free(host)) > 3) { - if (!host->pio_bytes) { - res = get_data_buffer(host, &host->pio_bytes, - &host->pio_ptr); - if (res) { - dbg(host, dbg_pio, - "pio_write(): complete (no more data).\n"); - host->pio_active = XFER_NONE; - - return; - } - - dbg(host, dbg_pio, - "pio_write(): new source: [%i]@[%p]\n", - host->pio_bytes, host->pio_ptr); - - } - - /* If we have reached the end of the block, we have to - * write exactly the remaining number of bytes. If we - * in the middle of the block, we have to write full - * words, so round down to an even multiple of 4. */ - if (fifo >= host->pio_bytes) - fifo = host->pio_bytes; - else - fifo -= fifo & 3; - - host->pio_bytes -= fifo; - host->pio_count += fifo; - - fifo = (fifo + 3) >> 2; - ptr = host->pio_ptr; - while (fifo--) - writel(*ptr++, to_ptr); - host->pio_ptr = ptr; - } - - enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF); -} - -static void pio_tasklet(struct tasklet_struct *t) -{ - struct s3cmci_host *host = from_tasklet(host, t, pio_tasklet); - - s3cmci_disable_irq(host, true); - - if (host->pio_active == XFER_WRITE) - do_pio_write(host); - - if (host->pio_active == XFER_READ) - do_pio_read(host); - - if (host->complete_what == COMPLETION_FINALIZE) { - clear_imask(host); - if (host->pio_active != XFER_NONE) { - dbg(host, dbg_err, "unfinished %s " - "- pio_count:[%u] pio_bytes:[%u]\n", - (host->pio_active == XFER_READ) ? "read" : "write", - host->pio_count, host->pio_bytes); - - if (host->mrq->data) - host->mrq->data->error = -EINVAL; - } - - s3cmci_enable_irq(host, false); - finalize_request(host); - } else - s3cmci_enable_irq(host, true); -} - -/* - * ISR for SDI Interface IRQ - * Communication between driver and ISR works as follows: - * host->mrq points to current request - * host->complete_what Indicates when the request is considered done - * COMPLETION_CMDSENT when the command was sent - * COMPLETION_RSPFIN when a response was received - * COMPLETION_XFERFINISH when the data transfer is finished - * COMPLETION_XFERFINISH_RSPFIN both of the above. - * host->complete_request is the completion-object the driver waits for - * - * 1) Driver sets up host->mrq and host->complete_what - * 2) Driver prepares the transfer - * 3) Driver enables interrupts - * 4) Driver starts transfer - * 5) Driver waits for host->complete_rquest - * 6) ISR checks for request status (errors and success) - * 6) ISR sets host->mrq->cmd->error and host->mrq->data->error - * 7) ISR completes host->complete_request - * 8) ISR disables interrupts - * 9) Driver wakes up and takes care of the request - * - * Note: "->error"-fields are expected to be set to 0 before the request - * was issued by mmc.c - therefore they are only set, when an error - * contition comes up - */ - -static irqreturn_t s3cmci_irq(int irq, void *dev_id) -{ - struct s3cmci_host *host = dev_id; - struct mmc_command *cmd; - u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk; - u32 mci_cclear = 0, mci_dclear; - unsigned long iflags; - - mci_dsta = readl(host->base + S3C2410_SDIDSTA); - mci_imsk = readl(host->base + host->sdiimsk); - - if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) { - if (mci_imsk & S3C2410_SDIIMSK_SDIOIRQ) { - mci_dclear = S3C2410_SDIDSTA_SDIOIRQDETECT; - writel(mci_dclear, host->base + S3C2410_SDIDSTA); - - mmc_signal_sdio_irq(host->mmc); - return IRQ_HANDLED; - } - } - - spin_lock_irqsave(&host->complete_lock, iflags); - - mci_csta = readl(host->base + S3C2410_SDICMDSTAT); - mci_dcnt = readl(host->base + S3C2410_SDIDCNT); - mci_fsta = readl(host->base + S3C2410_SDIFSTA); - mci_dclear = 0; - - if ((host->complete_what == COMPLETION_NONE) || - (host->complete_what == COMPLETION_FINALIZE)) { - host->status = "nothing to complete"; - clear_imask(host); - goto irq_out; - } - - if (!host->mrq) { - host->status = "no active mrq"; - clear_imask(host); - goto irq_out; - } - - cmd = host->cmd_is_stop ? host->mrq->stop : host->mrq->cmd; - - if (!cmd) { - host->status = "no active cmd"; - clear_imask(host); - goto irq_out; - } - - if (!s3cmci_host_usedma(host)) { - if ((host->pio_active == XFER_WRITE) && - (mci_fsta & S3C2410_SDIFSTA_TFDET)) { - - disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF); - tasklet_schedule(&host->pio_tasklet); - host->status = "pio tx"; - } - - if ((host->pio_active == XFER_READ) && - (mci_fsta & S3C2410_SDIFSTA_RFDET)) { - - disable_imask(host, - S3C2410_SDIIMSK_RXFIFOHALF | - S3C2410_SDIIMSK_RXFIFOLAST); - - tasklet_schedule(&host->pio_tasklet); - host->status = "pio rx"; - } - } - - if (mci_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) { - dbg(host, dbg_err, "CMDSTAT: error CMDTIMEOUT\n"); - cmd->error = -ETIMEDOUT; - host->status = "error: command timeout"; - goto fail_transfer; - } - - if (mci_csta & S3C2410_SDICMDSTAT_CMDSENT) { - if (host->complete_what == COMPLETION_CMDSENT) { - host->status = "ok: command sent"; - goto close_transfer; - } - - mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT; - } - - if (mci_csta & S3C2410_SDICMDSTAT_CRCFAIL) { - if (cmd->flags & MMC_RSP_CRC) { - if (host->mrq->cmd->flags & MMC_RSP_136) { - dbg(host, dbg_irq, - "fixup: ignore CRC fail with long rsp\n"); - } else { - /* note, we used to fail the transfer - * here, but it seems that this is just - * the hardware getting it wrong. - * - * cmd->error = -EILSEQ; - * host->status = "error: bad command crc"; - * goto fail_transfer; - */ - } - } - - mci_cclear |= S3C2410_SDICMDSTAT_CRCFAIL; - } - - if (mci_csta & S3C2410_SDICMDSTAT_RSPFIN) { - if (host->complete_what == COMPLETION_RSPFIN) { - host->status = "ok: command response received"; - goto close_transfer; - } - - if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN) - host->complete_what = COMPLETION_XFERFINISH; - - mci_cclear |= S3C2410_SDICMDSTAT_RSPFIN; - } - - /* errors handled after this point are only relevant - when a data transfer is in progress */ - - if (!cmd->data) - goto clear_status_bits; - - /* Check for FIFO failure */ - if (host->is2440) { - if (mci_fsta & S3C2440_SDIFSTA_FIFOFAIL) { - dbg(host, dbg_err, "FIFO failure\n"); - host->mrq->data->error = -EILSEQ; - host->status = "error: 2440 fifo failure"; - goto fail_transfer; - } - } else { - if (mci_dsta & S3C2410_SDIDSTA_FIFOFAIL) { - dbg(host, dbg_err, "FIFO failure\n"); - cmd->data->error = -EILSEQ; - host->status = "error: fifo failure"; - goto fail_transfer; - } - } - - if (mci_dsta & S3C2410_SDIDSTA_RXCRCFAIL) { - dbg(host, dbg_err, "bad data crc (outgoing)\n"); - cmd->data->error = -EILSEQ; - host->status = "error: bad data crc (outgoing)"; - goto fail_transfer; - } - - if (mci_dsta & S3C2410_SDIDSTA_CRCFAIL) { - dbg(host, dbg_err, "bad data crc (incoming)\n"); - cmd->data->error = -EILSEQ; - host->status = "error: bad data crc (incoming)"; - goto fail_transfer; - } - - if (mci_dsta & S3C2410_SDIDSTA_DATATIMEOUT) { - dbg(host, dbg_err, "data timeout\n"); - cmd->data->error = -ETIMEDOUT; - host->status = "error: data timeout"; - goto fail_transfer; - } - - if (mci_dsta & S3C2410_SDIDSTA_XFERFINISH) { - if (host->complete_what == COMPLETION_XFERFINISH) { - host->status = "ok: data transfer completed"; - goto close_transfer; - } - - if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN) - host->complete_what = COMPLETION_RSPFIN; - - mci_dclear |= S3C2410_SDIDSTA_XFERFINISH; - } - -clear_status_bits: - writel(mci_cclear, host->base + S3C2410_SDICMDSTAT); - writel(mci_dclear, host->base + S3C2410_SDIDSTA); - - goto irq_out; - -fail_transfer: - host->pio_active = XFER_NONE; - -close_transfer: - host->complete_what = COMPLETION_FINALIZE; - - clear_imask(host); - tasklet_schedule(&host->pio_tasklet); - - goto irq_out; - -irq_out: - dbg(host, dbg_irq, - "csta:0x%08x dsta:0x%08x fsta:0x%08x dcnt:0x%08x status:%s.\n", - mci_csta, mci_dsta, mci_fsta, mci_dcnt, host->status); - - spin_unlock_irqrestore(&host->complete_lock, iflags); - return IRQ_HANDLED; - -} - -static void s3cmci_dma_done_callback(void *arg) -{ - struct s3cmci_host *host = arg; - unsigned long iflags; - - BUG_ON(!host->mrq); - BUG_ON(!host->mrq->data); - - spin_lock_irqsave(&host->complete_lock, iflags); - - dbg(host, dbg_dma, "DMA FINISHED\n"); - - host->dma_complete = 1; - host->complete_what = COMPLETION_FINALIZE; - - tasklet_schedule(&host->pio_tasklet); - spin_unlock_irqrestore(&host->complete_lock, iflags); - -} - -static void finalize_request(struct s3cmci_host *host) -{ - struct mmc_request *mrq = host->mrq; - struct mmc_command *cmd; - int debug_as_failure = 0; - - if (host->complete_what != COMPLETION_FINALIZE) - return; - - if (!mrq) - return; - cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd; - - if (cmd->data && (cmd->error == 0) && - (cmd->data->error == 0)) { - if (s3cmci_host_usedma(host) && (!host->dma_complete)) { - dbg(host, dbg_dma, "DMA Missing (%d)!\n", - host->dma_complete); - return; - } - } - - /* Read response from controller. */ - cmd->resp[0] = readl(host->base + S3C2410_SDIRSP0); - cmd->resp[1] = readl(host->base + S3C2410_SDIRSP1); - cmd->resp[2] = readl(host->base + S3C2410_SDIRSP2); - cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3); - - writel(host->prescaler, host->base + S3C2410_SDIPRE); - - if (cmd->error) - debug_as_failure = 1; - - if (cmd->data && cmd->data->error) - debug_as_failure = 1; - - dbg_dumpcmd(host, cmd, debug_as_failure); - - /* Cleanup controller */ - writel(0, host->base + S3C2410_SDICMDARG); - writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON); - writel(0, host->base + S3C2410_SDICMDCON); - clear_imask(host); - - if (cmd->data && cmd->error) - cmd->data->error = cmd->error; - - if (cmd->data && cmd->data->stop && (!host->cmd_is_stop)) { - host->cmd_is_stop = 1; - s3cmci_send_request(host->mmc); - return; - } - - /* If we have no data transfer we are finished here */ - if (!mrq->data) - goto request_done; - - /* Calculate the amout of bytes transfer if there was no error */ - if (mrq->data->error == 0) { - mrq->data->bytes_xfered = - (mrq->data->blocks * mrq->data->blksz); - } else { - mrq->data->bytes_xfered = 0; - } - - /* If we had an error while transferring data we flush the - * DMA channel and the fifo to clear out any garbage. */ - if (mrq->data->error != 0) { - if (s3cmci_host_usedma(host)) - dmaengine_terminate_all(host->dma); - - if (host->is2440) { - /* Clear failure register and reset fifo. */ - writel(S3C2440_SDIFSTA_FIFORESET | - S3C2440_SDIFSTA_FIFOFAIL, - host->base + S3C2410_SDIFSTA); - } else { - u32 mci_con; - - /* reset fifo */ - mci_con = readl(host->base + S3C2410_SDICON); - mci_con |= S3C2410_SDICON_FIFORESET; - - writel(mci_con, host->base + S3C2410_SDICON); - } - } - -request_done: - host->complete_what = COMPLETION_NONE; - host->mrq = NULL; - - s3cmci_check_sdio_irq(host); - mmc_request_done(host->mmc, mrq); -} - -static void s3cmci_send_command(struct s3cmci_host *host, - struct mmc_command *cmd) -{ - u32 ccon, imsk; - - imsk = S3C2410_SDIIMSK_CRCSTATUS | S3C2410_SDIIMSK_CMDTIMEOUT | - S3C2410_SDIIMSK_RESPONSEND | S3C2410_SDIIMSK_CMDSENT | - S3C2410_SDIIMSK_RESPONSECRC; - - enable_imask(host, imsk); - - if (cmd->data) - host->complete_what = COMPLETION_XFERFINISH_RSPFIN; - else if (cmd->flags & MMC_RSP_PRESENT) - host->complete_what = COMPLETION_RSPFIN; - else - host->complete_what = COMPLETION_CMDSENT; - - writel(cmd->arg, host->base + S3C2410_SDICMDARG); - - ccon = cmd->opcode & S3C2410_SDICMDCON_INDEX; - ccon |= S3C2410_SDICMDCON_SENDERHOST | S3C2410_SDICMDCON_CMDSTART; - - if (cmd->flags & MMC_RSP_PRESENT) - ccon |= S3C2410_SDICMDCON_WAITRSP; - - if (cmd->flags & MMC_RSP_136) - ccon |= S3C2410_SDICMDCON_LONGRSP; - - writel(ccon, host->base + S3C2410_SDICMDCON); -} - -static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data) -{ - u32 dcon, imsk, stoptries = 3; - - if ((data->blksz & 3) != 0) { - /* We cannot deal with unaligned blocks with more than - * one block being transferred. */ - - if (data->blocks > 1) { - pr_warn("%s: can't do non-word sized block transfers (blksz %d)\n", - __func__, data->blksz); - return -EINVAL; - } - } - - while (readl(host->base + S3C2410_SDIDSTA) & - (S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) { - - dbg(host, dbg_err, - "mci_setup_data() transfer stillin progress.\n"); - - writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON); - s3cmci_reset(host); - - if ((stoptries--) == 0) { - dbg_dumpregs(host, "DRF"); - return -EINVAL; - } - } - - dcon = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK; - - if (s3cmci_host_usedma(host)) - dcon |= S3C2410_SDIDCON_DMAEN; - - if (host->bus_width == MMC_BUS_WIDTH_4) - dcon |= S3C2410_SDIDCON_WIDEBUS; - - dcon |= S3C2410_SDIDCON_BLOCKMODE; - - if (data->flags & MMC_DATA_WRITE) { - dcon |= S3C2410_SDIDCON_TXAFTERRESP; - dcon |= S3C2410_SDIDCON_XFER_TXSTART; - } - - if (data->flags & MMC_DATA_READ) { - dcon |= S3C2410_SDIDCON_RXAFTERCMD; - dcon |= S3C2410_SDIDCON_XFER_RXSTART; - } - - if (host->is2440) { - dcon |= S3C2440_SDIDCON_DS_WORD; - dcon |= S3C2440_SDIDCON_DATSTART; - } - - writel(dcon, host->base + S3C2410_SDIDCON); - - /* write BSIZE register */ - - writel(data->blksz, host->base + S3C2410_SDIBSIZE); - - /* add to IMASK register */ - imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC | - S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH; - - enable_imask(host, imsk); - - /* write TIMER register */ - - if (host->is2440) { - writel(0x007FFFFF, host->base + S3C2410_SDITIMER); - } else { - writel(0x0000FFFF, host->base + S3C2410_SDITIMER); - - /* FIX: set slow clock to prevent timeouts on read */ - if (data->flags & MMC_DATA_READ) - writel(0xFF, host->base + S3C2410_SDIPRE); - } - - return 0; -} - -#define BOTH_DIR (MMC_DATA_WRITE | MMC_DATA_READ) - -static int s3cmci_prepare_pio(struct s3cmci_host *host, struct mmc_data *data) -{ - int rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0; - - BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); - - host->pio_sgptr = 0; - host->pio_bytes = 0; - host->pio_count = 0; - host->pio_active = rw ? XFER_WRITE : XFER_READ; - - if (rw) { - do_pio_write(host); - enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF); - } else { - enable_imask(host, S3C2410_SDIIMSK_RXFIFOHALF - | S3C2410_SDIIMSK_RXFIFOLAST); - } - - return 0; -} - -static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) -{ - int rw = data->flags & MMC_DATA_WRITE; - struct dma_async_tx_descriptor *desc; - struct dma_slave_config conf = { - .src_addr = host->mem->start + host->sdidata, - .dst_addr = host->mem->start + host->sdidata, - .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, - .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, - }; - - BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); - - /* Restore prescaler value */ - writel(host->prescaler, host->base + S3C2410_SDIPRE); - - if (!rw) - conf.direction = DMA_DEV_TO_MEM; - else - conf.direction = DMA_MEM_TO_DEV; - - dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - mmc_get_dma_dir(data)); - - dmaengine_slave_config(host->dma, &conf); - desc = dmaengine_prep_slave_sg(host->dma, data->sg, data->sg_len, - conf.direction, - DMA_CTRL_ACK | DMA_PREP_INTERRUPT); - if (!desc) - goto unmap_exit; - desc->callback = s3cmci_dma_done_callback; - desc->callback_param = host; - dmaengine_submit(desc); - dma_async_issue_pending(host->dma); - - return 0; - -unmap_exit: - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - mmc_get_dma_dir(data)); - return -ENOMEM; -} - -static void s3cmci_send_request(struct mmc_host *mmc) -{ - struct s3cmci_host *host = mmc_priv(mmc); - struct mmc_request *mrq = host->mrq; - struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd; - - host->ccnt++; - prepare_dbgmsg(host, cmd, host->cmd_is_stop); - - /* Clear command, data and fifo status registers - Fifo clear only necessary on 2440, but doesn't hurt on 2410 - */ - writel(0xFFFFFFFF, host->base + S3C2410_SDICMDSTAT); - writel(0xFFFFFFFF, host->base + S3C2410_SDIDSTA); - writel(0xFFFFFFFF, host->base + S3C2410_SDIFSTA); - - if (cmd->data) { - int res = s3cmci_setup_data(host, cmd->data); - - host->dcnt++; - - if (res) { - dbg(host, dbg_err, "setup data error %d\n", res); - cmd->error = res; - cmd->data->error = res; - - mmc_request_done(mmc, mrq); - return; - } - - if (s3cmci_host_usedma(host)) - res = s3cmci_prepare_dma(host, cmd->data); - else - res = s3cmci_prepare_pio(host, cmd->data); - - if (res) { - dbg(host, dbg_err, "data prepare error %d\n", res); - cmd->error = res; - cmd->data->error = res; - - mmc_request_done(mmc, mrq); - return; - } - } - - /* Send command */ - s3cmci_send_command(host, cmd); - - /* Enable Interrupt */ - s3cmci_enable_irq(host, true); -} - -static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct s3cmci_host *host = mmc_priv(mmc); - - host->status = "mmc request"; - host->cmd_is_stop = 0; - host->mrq = mrq; - - if (mmc_gpio_get_cd(mmc) == 0) { - dbg(host, dbg_err, "%s: no medium present\n", __func__); - host->mrq->cmd->error = -ENOMEDIUM; - mmc_request_done(mmc, mrq); - } else - s3cmci_send_request(mmc); -} - -static void s3cmci_set_clk(struct s3cmci_host *host, struct mmc_ios *ios) -{ - u32 mci_psc; - - /* Set clock */ - for (mci_psc = 0; mci_psc < 255; mci_psc++) { - host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1)); - - if (host->real_rate <= ios->clock) - break; - } - - if (mci_psc > 255) - mci_psc = 255; - - host->prescaler = mci_psc; - writel(host->prescaler, host->base + S3C2410_SDIPRE); - - /* If requested clock is 0, real_rate will be 0, too */ - if (ios->clock == 0) - host->real_rate = 0; -} - -static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct s3cmci_host *host = mmc_priv(mmc); - u32 mci_con; - - /* Set the power state */ - - mci_con = readl(host->base + S3C2410_SDICON); - - switch (ios->power_mode) { - case MMC_POWER_ON: - case MMC_POWER_UP: - if (!host->is2440) - mci_con |= S3C2410_SDICON_FIFORESET; - break; - - case MMC_POWER_OFF: - default: - if (host->is2440) - mci_con |= S3C2440_SDICON_SDRESET; - break; - } - - if (host->pdata->set_power) - host->pdata->set_power(ios->power_mode, ios->vdd); - - s3cmci_set_clk(host, ios); - - /* Set CLOCK_ENABLE */ - if (ios->clock) - mci_con |= S3C2410_SDICON_CLOCKTYPE; - else - mci_con &= ~S3C2410_SDICON_CLOCKTYPE; - - writel(mci_con, host->base + S3C2410_SDICON); - - if ((ios->power_mode == MMC_POWER_ON) || - (ios->power_mode == MMC_POWER_UP)) { - dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n", - host->real_rate/1000, ios->clock/1000); - } else { - dbg(host, dbg_conf, "powered down.\n"); - } - - host->bus_width = ios->bus_width; -} - -static void s3cmci_reset(struct s3cmci_host *host) -{ - u32 con = readl(host->base + S3C2410_SDICON); - - con |= S3C2440_SDICON_SDRESET; - writel(con, host->base + S3C2410_SDICON); -} - -static void s3cmci_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct s3cmci_host *host = mmc_priv(mmc); - unsigned long flags; - u32 con; - - local_irq_save(flags); - - con = readl(host->base + S3C2410_SDICON); - host->sdio_irqen = enable; - - if (enable == host->sdio_irqen) - goto same_state; - - if (enable) { - con |= S3C2410_SDICON_SDIOIRQ; - enable_imask(host, S3C2410_SDIIMSK_SDIOIRQ); - - if (!host->irq_state && !host->irq_disabled) { - host->irq_state = true; - enable_irq(host->irq); - } - } else { - disable_imask(host, S3C2410_SDIIMSK_SDIOIRQ); - con &= ~S3C2410_SDICON_SDIOIRQ; - - if (!host->irq_enabled && host->irq_state) { - disable_irq_nosync(host->irq); - host->irq_state = false; - } - } - - writel(con, host->base + S3C2410_SDICON); - - same_state: - local_irq_restore(flags); - - s3cmci_check_sdio_irq(host); -} - -static const struct mmc_host_ops s3cmci_ops = { - .request = s3cmci_request, - .set_ios = s3cmci_set_ios, - .get_ro = mmc_gpio_get_ro, - .get_cd = mmc_gpio_get_cd, - .enable_sdio_irq = s3cmci_enable_sdio_irq, -}; - -#ifdef CONFIG_ARM_S3C24XX_CPUFREQ - -static int s3cmci_cpufreq_transition(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct s3cmci_host *host; - struct mmc_host *mmc; - unsigned long newclk; - unsigned long flags; - - host = container_of(nb, struct s3cmci_host, freq_transition); - newclk = clk_get_rate(host->clk); - mmc = host->mmc; - - if ((val == CPUFREQ_PRECHANGE && newclk > host->clk_rate) || - (val == CPUFREQ_POSTCHANGE && newclk < host->clk_rate)) { - spin_lock_irqsave(&mmc->lock, flags); - - host->clk_rate = newclk; - - if (mmc->ios.power_mode != MMC_POWER_OFF && - mmc->ios.clock != 0) - s3cmci_set_clk(host, &mmc->ios); - - spin_unlock_irqrestore(&mmc->lock, flags); - } - - return 0; -} - -static inline int s3cmci_cpufreq_register(struct s3cmci_host *host) -{ - host->freq_transition.notifier_call = s3cmci_cpufreq_transition; - - return cpufreq_register_notifier(&host->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host) -{ - cpufreq_unregister_notifier(&host->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -#else -static inline int s3cmci_cpufreq_register(struct s3cmci_host *host) -{ - return 0; -} - -static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host) -{ -} -#endif - - -#ifdef CONFIG_DEBUG_FS - -static int s3cmci_state_show(struct seq_file *seq, void *v) -{ - struct s3cmci_host *host = seq->private; - - seq_printf(seq, "Register base = 0x%p\n", host->base); - seq_printf(seq, "Clock rate = %ld\n", host->clk_rate); - seq_printf(seq, "Prescale = %d\n", host->prescaler); - seq_printf(seq, "is2440 = %d\n", host->is2440); - seq_printf(seq, "IRQ = %d\n", host->irq); - seq_printf(seq, "IRQ enabled = %d\n", host->irq_enabled); - seq_printf(seq, "IRQ disabled = %d\n", host->irq_disabled); - seq_printf(seq, "IRQ state = %d\n", host->irq_state); - seq_printf(seq, "CD IRQ = %d\n", host->irq_cd); - seq_printf(seq, "Do DMA = %d\n", s3cmci_host_usedma(host)); - seq_printf(seq, "SDIIMSK at %d\n", host->sdiimsk); - seq_printf(seq, "SDIDATA at %d\n", host->sdidata); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(s3cmci_state); - -#define DBG_REG(_r) { .addr = S3C2410_SDI##_r, .name = #_r } - -struct s3cmci_reg { - unsigned short addr; - unsigned char *name; -}; - -static const struct s3cmci_reg debug_regs[] = { - DBG_REG(CON), - DBG_REG(PRE), - DBG_REG(CMDARG), - DBG_REG(CMDCON), - DBG_REG(CMDSTAT), - DBG_REG(RSP0), - DBG_REG(RSP1), - DBG_REG(RSP2), - DBG_REG(RSP3), - DBG_REG(TIMER), - DBG_REG(BSIZE), - DBG_REG(DCON), - DBG_REG(DCNT), - DBG_REG(DSTA), - DBG_REG(FSTA), - {} -}; - -static int s3cmci_regs_show(struct seq_file *seq, void *v) -{ - struct s3cmci_host *host = seq->private; - const struct s3cmci_reg *rptr = debug_regs; - - for (; rptr->name; rptr++) - seq_printf(seq, "SDI%s\t=0x%08x\n", rptr->name, - readl(host->base + rptr->addr)); - - seq_printf(seq, "SDIIMSK\t=0x%08x\n", readl(host->base + host->sdiimsk)); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(s3cmci_regs); - -static void s3cmci_debugfs_attach(struct s3cmci_host *host) -{ - struct device *dev = &host->pdev->dev; - struct dentry *root; - - root = debugfs_create_dir(dev_name(dev), NULL); - host->debug_root = root; - - debugfs_create_file("state", 0444, root, host, &s3cmci_state_fops); - debugfs_create_file("regs", 0444, root, host, &s3cmci_regs_fops); -} - -static void s3cmci_debugfs_remove(struct s3cmci_host *host) -{ - debugfs_remove_recursive(host->debug_root); -} - -#else -static inline void s3cmci_debugfs_attach(struct s3cmci_host *host) { } -static inline void s3cmci_debugfs_remove(struct s3cmci_host *host) { } - -#endif /* CONFIG_DEBUG_FS */ - -static int s3cmci_probe_pdata(struct s3cmci_host *host) -{ - struct platform_device *pdev = host->pdev; - struct mmc_host *mmc = host->mmc; - struct s3c24xx_mci_pdata *pdata; - int i, ret; - - host->is2440 = platform_get_device_id(pdev)->driver_data; - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "need platform data"); - return -ENXIO; - } - - for (i = 0; i < 6; i++) { - pdata->bus[i] = devm_gpiod_get_index(&pdev->dev, "bus", i, - GPIOD_OUT_LOW); - if (IS_ERR(pdata->bus[i])) { - dev_err(&pdev->dev, "failed to get gpio %d\n", i); - return PTR_ERR(pdata->bus[i]); - } - } - - if (pdata->no_wprotect) - mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; - - if (pdata->no_detect) - mmc->caps |= MMC_CAP_NEEDS_POLL; - - if (pdata->wprotect_invert) - mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; - - /* If we get -ENOENT we have no card detect GPIO line */ - ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0); - if (ret != -ENOENT) { - dev_err(&pdev->dev, "error requesting GPIO for CD %d\n", - ret); - return ret; - } - - ret = mmc_gpiod_request_ro(host->mmc, "wp", 0, 0); - if (ret != -ENOENT) { - dev_err(&pdev->dev, "error requesting GPIO for WP %d\n", - ret); - return ret; - } - - return 0; -} - -static int s3cmci_probe_dt(struct s3cmci_host *host) -{ - struct platform_device *pdev = host->pdev; - struct s3c24xx_mci_pdata *pdata; - struct mmc_host *mmc = host->mmc; - int ret; - - host->is2440 = (long) of_device_get_match_data(&pdev->dev); - - ret = mmc_of_parse(mmc); - if (ret) - return ret; - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - pdev->dev.platform_data = pdata; - - return 0; -} - -static int s3cmci_probe(struct platform_device *pdev) -{ - struct s3cmci_host *host; - struct mmc_host *mmc; - int ret; - - mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto probe_out; - } - - host = mmc_priv(mmc); - host->mmc = mmc; - host->pdev = pdev; - - if (pdev->dev.of_node) - ret = s3cmci_probe_dt(host); - else - ret = s3cmci_probe_pdata(host); - - if (ret) - goto probe_free_host; - - host->pdata = pdev->dev.platform_data; - - spin_lock_init(&host->complete_lock); - tasklet_setup(&host->pio_tasklet, pio_tasklet); - - if (host->is2440) { - host->sdiimsk = S3C2440_SDIIMSK; - host->sdidata = S3C2440_SDIDATA; - host->clk_div = 1; - } else { - host->sdiimsk = S3C2410_SDIIMSK; - host->sdidata = S3C2410_SDIDATA; - host->clk_div = 2; - } - - host->complete_what = COMPLETION_NONE; - host->pio_active = XFER_NONE; - - host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!host->mem) { - dev_err(&pdev->dev, - "failed to get io memory region resource.\n"); - - ret = -ENOENT; - goto probe_free_host; - } - - host->mem = request_mem_region(host->mem->start, - resource_size(host->mem), pdev->name); - - if (!host->mem) { - dev_err(&pdev->dev, "failed to request io memory region.\n"); - ret = -ENOENT; - goto probe_free_host; - } - - host->base = ioremap(host->mem->start, resource_size(host->mem)); - if (!host->base) { - dev_err(&pdev->dev, "failed to ioremap() io memory region.\n"); - ret = -EINVAL; - goto probe_free_mem_region; - } - - host->irq = platform_get_irq(pdev, 0); - if (host->irq <= 0) { - ret = -EINVAL; - goto probe_iounmap; - } - - if (request_irq(host->irq, s3cmci_irq, IRQF_NO_AUTOEN, DRIVER_NAME, host)) { - dev_err(&pdev->dev, "failed to request mci interrupt.\n"); - ret = -ENOENT; - goto probe_iounmap; - } - - host->irq_state = false; - - /* Depending on the dma state, get a DMA channel to use. */ - - if (s3cmci_host_usedma(host)) { - host->dma = dma_request_chan(&pdev->dev, "rx-tx"); - ret = PTR_ERR_OR_ZERO(host->dma); - if (ret) { - dev_err(&pdev->dev, "cannot get DMA channel.\n"); - goto probe_free_irq; - } - } - - host->clk = clk_get(&pdev->dev, "sdi"); - if (IS_ERR(host->clk)) { - dev_err(&pdev->dev, "failed to find clock source.\n"); - ret = PTR_ERR(host->clk); - host->clk = NULL; - goto probe_free_dma; - } - - ret = clk_prepare_enable(host->clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable clock source.\n"); - goto clk_free; - } - - host->clk_rate = clk_get_rate(host->clk); - - mmc->ops = &s3cmci_ops; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; -#ifdef CONFIG_MMC_S3C_HW_SDIO_IRQ - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; -#else - mmc->caps = MMC_CAP_4_BIT_DATA; -#endif - mmc->f_min = host->clk_rate / (host->clk_div * 256); - mmc->f_max = host->clk_rate / host->clk_div; - - if (host->pdata->ocr_avail) - mmc->ocr_avail = host->pdata->ocr_avail; - - mmc->max_blk_count = 4095; - mmc->max_blk_size = 4095; - mmc->max_req_size = 4095 * 512; - mmc->max_seg_size = mmc->max_req_size; - - mmc->max_segs = 128; - - dbg(host, dbg_debug, - "probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%u dma:%p.\n", - (host->is2440?"2440":""), - host->base, host->irq, host->irq_cd, host->dma); - - ret = s3cmci_cpufreq_register(host); - if (ret) { - dev_err(&pdev->dev, "failed to register cpufreq\n"); - goto free_dmabuf; - } - - ret = mmc_add_host(mmc); - if (ret) { - dev_err(&pdev->dev, "failed to add mmc host.\n"); - goto free_cpufreq; - } - - s3cmci_debugfs_attach(host); - - platform_set_drvdata(pdev, mmc); - dev_info(&pdev->dev, "%s - using %s, %s SDIO IRQ\n", mmc_hostname(mmc), - s3cmci_host_usedma(host) ? "dma" : "pio", - mmc->caps & MMC_CAP_SDIO_IRQ ? "hw" : "sw"); - - return 0; - - free_cpufreq: - s3cmci_cpufreq_deregister(host); - - free_dmabuf: - clk_disable_unprepare(host->clk); - - clk_free: - clk_put(host->clk); - - probe_free_dma: - if (s3cmci_host_usedma(host)) - dma_release_channel(host->dma); - - probe_free_irq: - free_irq(host->irq, host); - - probe_iounmap: - iounmap(host->base); - - probe_free_mem_region: - release_mem_region(host->mem->start, resource_size(host->mem)); - - probe_free_host: - mmc_free_host(mmc); - - probe_out: - return ret; -} - -static void s3cmci_shutdown(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct s3cmci_host *host = mmc_priv(mmc); - - if (host->irq_cd >= 0) - free_irq(host->irq_cd, host); - - s3cmci_debugfs_remove(host); - s3cmci_cpufreq_deregister(host); - mmc_remove_host(mmc); - clk_disable_unprepare(host->clk); -} - -static int s3cmci_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct s3cmci_host *host = mmc_priv(mmc); - - s3cmci_shutdown(pdev); - - clk_put(host->clk); - - tasklet_disable(&host->pio_tasklet); - - if (s3cmci_host_usedma(host)) - dma_release_channel(host->dma); - - free_irq(host->irq, host); - - iounmap(host->base); - release_mem_region(host->mem->start, resource_size(host->mem)); - - mmc_free_host(mmc); - return 0; -} - -static const struct of_device_id s3cmci_dt_match[] = { - { - .compatible = "samsung,s3c2410-sdi", - .data = (void *)0, - }, - { - .compatible = "samsung,s3c2412-sdi", - .data = (void *)1, - }, - { - .compatible = "samsung,s3c2440-sdi", - .data = (void *)1, - }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, s3cmci_dt_match); - -static const struct platform_device_id s3cmci_driver_ids[] = { - { - .name = "s3c2410-sdi", - .driver_data = 0, - }, { - .name = "s3c2412-sdi", - .driver_data = 1, - }, { - .name = "s3c2440-sdi", - .driver_data = 1, - }, - { } -}; - -MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids); - -static struct platform_driver s3cmci_driver = { - .driver = { - .name = "s3c-sdi", - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .of_match_table = s3cmci_dt_match, - }, - .id_table = s3cmci_driver_ids, - .probe = s3cmci_probe, - .remove = s3cmci_remove, - .shutdown = s3cmci_shutdown, -}; - -module_platform_driver(s3cmci_driver); - -MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>, Ben Dooks <ben-linux@fluff.org>"); diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h deleted file mode 100644 index 8b65d7ad9f97..000000000000 --- a/drivers/mmc/host/s3cmci.h +++ /dev/null @@ -1,75 +0,0 @@ -/* 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. - */ - -enum s3cmci_waitfor { - COMPLETION_NONE, - COMPLETION_FINALIZE, - COMPLETION_CMDSENT, - COMPLETION_RSPFIN, - COMPLETION_XFERFINISH, - COMPLETION_XFERFINISH_RSPFIN, -}; - -struct s3cmci_host { - struct platform_device *pdev; - struct s3c24xx_mci_pdata *pdata; - struct mmc_host *mmc; - struct resource *mem; - struct clk *clk; - void __iomem *base; - int irq; - int irq_cd; - struct dma_chan *dma; - - unsigned long clk_rate; - unsigned long clk_div; - unsigned long real_rate; - u8 prescaler; - - int is2440; - unsigned sdiimsk; - unsigned sdidata; - - bool irq_disabled; - bool irq_enabled; - bool irq_state; - int sdio_irqen; - - struct mmc_request *mrq; - int cmd_is_stop; - - spinlock_t complete_lock; - enum s3cmci_waitfor complete_what; - - int dma_complete; - - u32 pio_sgptr; - u32 pio_bytes; - u32 pio_count; - u32 *pio_ptr; -#define XFER_NONE 0 -#define XFER_READ 1 -#define XFER_WRITE 2 - u32 pio_active; - - int bus_width; - - char dbgmsg_cmd[301]; - char dbgmsg_dat[301]; - char *status; - - unsigned int ccnt, dcnt; - struct tasklet_struct pio_tasklet; - -#ifdef CONFIG_DEBUG_FS - struct dentry *debug_root; -#endif - -#ifdef CONFIG_ARM_S3C24XX_CPUFREQ - struct notifier_block freq_transition; -#endif -}; diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c deleted file mode 100644 index 2a29c7a4f308..000000000000 --- a/drivers/mmc/host/sdhci-cns3xxx.c +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * SDHCI support for CNS3xxx SoC - * - * Copyright 2008 Cavium Networks - * Copyright 2010 MontaVista Software, LLC. - * - * Authors: Scott Shu - * Anton Vorontsov <avorontsov@mvista.com> - */ - -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/mmc/host.h> -#include <linux/module.h> -#include "sdhci-pltfm.h" - -static unsigned int sdhci_cns3xxx_get_max_clk(struct sdhci_host *host) -{ - return 150000000; -} - -static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock) -{ - struct device *dev = mmc_dev(host->mmc); - int div = 1; - u16 clk; - unsigned long timeout; - - host->mmc->actual_clock = 0; - - sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); - - if (clock == 0) - return; - - while (host->max_clk / div > clock) { - /* - * On CNS3xxx divider grows linearly up to 4, and then - * exponentially up to 256. - */ - if (div < 4) - div += 1; - else if (div < 256) - div *= 2; - else - break; - } - - dev_dbg(dev, "desired SD clock: %d, actual: %d\n", - clock, host->max_clk / div); - - /* Divide by 3 is special. */ - if (div != 3) - div >>= 1; - - clk = div << SDHCI_DIVIDER_SHIFT; - clk |= SDHCI_CLOCK_INT_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - - timeout = 20; - while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) - & SDHCI_CLOCK_INT_STABLE)) { - if (timeout == 0) { - dev_warn(dev, "clock is unstable"); - break; - } - timeout--; - mdelay(1); - } - - clk |= SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); -} - -static const struct sdhci_ops sdhci_cns3xxx_ops = { - .get_max_clock = sdhci_cns3xxx_get_max_clk, - .set_clock = sdhci_cns3xxx_set_clock, - .set_bus_width = sdhci_set_bus_width, - .reset = sdhci_reset, - .set_uhs_signaling = sdhci_set_uhs_signaling, -}; - -static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = { - .ops = &sdhci_cns3xxx_ops, - .quirks = SDHCI_QUIRK_BROKEN_DMA | - SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | - SDHCI_QUIRK_INVERTED_WRITE_PROTECT | - SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | - SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, -}; - -static int sdhci_cns3xxx_probe(struct platform_device *pdev) -{ - return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata, 0); -} - -static struct platform_driver sdhci_cns3xxx_driver = { - .driver = { - .name = "sdhci-cns3xxx", - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .pm = &sdhci_pltfm_pmops, - }, - .probe = sdhci_cns3xxx_probe, - .remove = sdhci_pltfm_unregister, -}; - -module_platform_driver(sdhci_cns3xxx_driver); - -MODULE_DESCRIPTION("SDHCI driver for CNS3xxx"); -MODULE_AUTHOR("Scott Shu, " - "Anton Vorontsov <avorontsov@mvista.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 89ef0c80ac37..9e73c34b6401 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -107,6 +107,7 @@ #define ESDHC_TUNING_START_TAP_DEFAULT 0x1 #define ESDHC_TUNING_START_TAP_MASK 0x7f #define ESDHC_TUNING_CMD_CRC_CHECK_DISABLE (1 << 7) +#define ESDHC_TUNING_STEP_DEFAULT 0x1 #define ESDHC_TUNING_STEP_MASK 0x00070000 #define ESDHC_TUNING_STEP_SHIFT 16 @@ -1368,7 +1369,7 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); struct cqhci_host *cq_host = host->mmc->cqe_private; - int tmp; + u32 tmp; if (esdhc_is_usdhc(imx_data)) { /* @@ -1423,17 +1424,24 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); - tmp |= ESDHC_STD_TUNING_EN | - ESDHC_TUNING_START_TAP_DEFAULT; - if (imx_data->boarddata.tuning_start_tap) { - tmp &= ~ESDHC_TUNING_START_TAP_MASK; + tmp |= ESDHC_STD_TUNING_EN; + + /* + * ROM code or bootloader may config the start tap + * and step, unmask them first. + */ + tmp &= ~(ESDHC_TUNING_START_TAP_MASK | ESDHC_TUNING_STEP_MASK); + if (imx_data->boarddata.tuning_start_tap) tmp |= imx_data->boarddata.tuning_start_tap; - } + else + tmp |= ESDHC_TUNING_START_TAP_DEFAULT; if (imx_data->boarddata.tuning_step) { - tmp &= ~ESDHC_TUNING_STEP_MASK; tmp |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT; + } else { + tmp |= ESDHC_TUNING_STEP_DEFAULT + << ESDHC_TUNING_STEP_SHIFT; } /* Disable the CMD CRC check for tuning, if not, need to diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index b16e12e62e72..3db9f32d6a7b 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -1492,9 +1492,11 @@ static int sunxi_mmc_remove(struct platform_device *pdev) struct sunxi_mmc_host *host = mmc_priv(mmc); mmc_remove_host(mmc); - pm_runtime_force_suspend(&pdev->dev); - disable_irq(host->irq); - sunxi_mmc_disable(host); + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) { + disable_irq(host->irq); + sunxi_mmc_disable(host); + } dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); mmc_free_host(mmc); diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c deleted file mode 100644 index 53a2ad9a24b8..000000000000 --- a/drivers/mmc/host/tmio_mmc.c +++ /dev/null @@ -1,227 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Driver for the MMC / SD / SDIO cell found in: - * - * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 - * - * Copyright (C) 2017 Renesas Electronics Corporation - * Copyright (C) 2017 Horms Solutions, Simon Horman - * Copyright (C) 2007 Ian Molton - * Copyright (C) 2004 Ian Molton - */ - -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/mfd/core.h> -#include <linux/mfd/tmio.h> -#include <linux/mmc/host.h> -#include <linux/module.h> -#include <linux/pagemap.h> -#include <linux/scatterlist.h> - -#include "tmio_mmc.h" - -/* Registers specific to this variant */ -#define CTL_SDIO_REGS 0x100 -#define CTL_CLK_AND_WAIT_CTL 0x138 -#define CTL_RESET_SDIO 0x1e0 - -static void tmio_mmc_clk_start(struct tmio_mmc_host *host) -{ - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | - sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); - - usleep_range(10000, 11000); - sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); - usleep_range(10000, 11000); -} - -static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) -{ - sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); - usleep_range(10000, 11000); - - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & - sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); - - usleep_range(10000, 11000); -} - -static void tmio_mmc_set_clock(struct tmio_mmc_host *host, - unsigned int new_clock) -{ - unsigned int divisor; - u32 clk = 0; - int clk_sel; - - if (new_clock == 0) { - tmio_mmc_clk_stop(host); - return; - } - - divisor = host->pdata->hclk / new_clock; - - /* bit7 set: 1/512, ... bit0 set: 1/4, all bits clear: 1/2 */ - clk_sel = (divisor <= 1); - clk = clk_sel ? 0 : (roundup_pow_of_two(divisor) >> 2); - - host->pdata->set_clk_div(host->pdev, clk_sel); - - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & - sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK); - usleep_range(10000, 11000); - - tmio_mmc_clk_start(host); -} - -static void tmio_mmc_reset(struct tmio_mmc_host *host, bool preserve) -{ - sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); - usleep_range(10000, 11000); - sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); - usleep_range(10000, 11000); -} - -#ifdef CONFIG_PM_SLEEP -static int tmio_mmc_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - const struct mfd_cell *cell = mfd_get_cell(pdev); - int ret; - - ret = pm_runtime_force_suspend(dev); - - /* Tell MFD core it can disable us now.*/ - if (!ret && cell->disable) - cell->disable(pdev); - - return ret; -} - -static int tmio_mmc_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - const struct mfd_cell *cell = mfd_get_cell(pdev); - int ret = 0; - - /* Tell the MFD core we are ready to be enabled */ - if (cell->resume) - ret = cell->resume(pdev); - - if (!ret) - ret = pm_runtime_force_resume(dev); - - return ret; -} -#endif - -static int tmio_mmc_probe(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - struct tmio_mmc_data *pdata; - struct tmio_mmc_host *host; - struct resource *res; - int ret = -EINVAL, irq; - - if (pdev->num_resources != 2) - goto out; - - pdata = pdev->dev.platform_data; - if (!pdata || !pdata->hclk) - goto out; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto out; - } - - /* Tell the MFD core we are ready to be enabled */ - if (cell->enable) { - ret = cell->enable(pdev); - if (ret) - goto out; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -EINVAL; - goto cell_disable; - } - - host = tmio_mmc_host_alloc(pdev, pdata); - if (IS_ERR(host)) { - ret = PTR_ERR(host); - goto cell_disable; - } - - /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ - host->bus_shift = resource_size(res) >> 10; - host->set_clock = tmio_mmc_set_clock; - host->reset = tmio_mmc_reset; - - host->mmc->f_max = pdata->hclk; - host->mmc->f_min = pdata->hclk / 512; - - ret = tmio_mmc_host_probe(host); - if (ret) - goto host_free; - - ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, - IRQF_TRIGGER_FALLING, - dev_name(&pdev->dev), host); - if (ret) - goto host_remove; - - pr_info("%s at 0x%p irq %d\n", mmc_hostname(host->mmc), host->ctl, irq); - - return 0; - -host_remove: - tmio_mmc_host_remove(host); -host_free: - tmio_mmc_host_free(host); -cell_disable: - if (cell->disable) - cell->disable(pdev); -out: - return ret; -} - -static int tmio_mmc_remove(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - struct tmio_mmc_host *host = platform_get_drvdata(pdev); - - tmio_mmc_host_remove(host); - if (cell->disable) - cell->disable(pdev); - - return 0; -} - -/* ------------------- device registration ----------------------- */ - -static const struct dev_pm_ops tmio_mmc_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_suspend, tmio_mmc_resume) - SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend, - tmio_mmc_host_runtime_resume, NULL) -}; - -static struct platform_driver tmio_mmc_driver = { - .driver = { - .name = "tmio-mmc", - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .pm = &tmio_mmc_dev_pm_ops, - }, - .probe = tmio_mmc_probe, - .remove = tmio_mmc_remove, -}; - -module_platform_driver(tmio_mmc_driver); - -MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver"); -MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:tmio-mmc"); diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 98ea1c9e65c8..048b1c8f08ee 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -79,7 +79,7 @@ config MTD_NAND_NDFC config MTD_NAND_S3C2410 tristate "Samsung S3C NAND controller" - depends on ARCH_S3C24XX || ARCH_S3C64XX + depends on ARCH_S3C64XX help This enables the NAND flash controller on the S3C24xx and S3C64xx SoCs diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c index f0a4535c812a..80d96f94d6cb 100644 --- a/drivers/mtd/nand/raw/s3c2410.c +++ b/drivers/mtd/nand/raw/s3c2410.c @@ -166,10 +166,6 @@ struct s3c2410_nand_info { enum s3c_nand_clk_state clk_state; enum s3c_cpu_type cpu_type; - -#ifdef CONFIG_ARM_S3C24XX_CPUFREQ - struct notifier_block freq_transition; -#endif }; struct s3c24XX_nand_devtype_data { @@ -711,54 +707,6 @@ static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf, } } -/* cpufreq driver support */ - -#ifdef CONFIG_ARM_S3C24XX_CPUFREQ - -static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct s3c2410_nand_info *info; - unsigned long newclk; - - info = container_of(nb, struct s3c2410_nand_info, freq_transition); - newclk = clk_get_rate(info->clk); - - if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) || - (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) { - s3c2410_nand_setrate(info); - } - - return 0; -} - -static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) -{ - info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition; - - return cpufreq_register_notifier(&info->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -static inline void -s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) -{ - cpufreq_unregister_notifier(&info->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -#else -static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) -{ - return 0; -} - -static inline void -s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) -{ -} -#endif - /* device management functions */ static int s3c24xx_nand_remove(struct platform_device *pdev) @@ -768,8 +716,6 @@ static int s3c24xx_nand_remove(struct platform_device *pdev) if (info == NULL) return 0; - s3c2410_nand_cpufreq_deregister(info); - /* Release all our mtds and their partitions, then go through * freeing the resources used */ @@ -1184,12 +1130,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) if (err != 0) goto exit_error; - err = s3c2410_nand_cpufreq_register(info); - if (err < 0) { - dev_err(&pdev->dev, "failed to init cpufreq support\n"); - goto exit_error; - } - if (allow_clk_suspend(info)) { dev_info(&pdev->dev, "clock idle support enabled\n"); s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND); diff --git a/drivers/mtd/parsers/scpart.c b/drivers/mtd/parsers/scpart.c index 02601bb33de4..6e5e11c37078 100644 --- a/drivers/mtd/parsers/scpart.c +++ b/drivers/mtd/parsers/scpart.c @@ -50,7 +50,7 @@ static int scpart_scan_partmap(struct mtd_info *master, loff_t partmap_offs, int cnt = 0; int res = 0; int res2; - loff_t offs; + uint32_t offs; size_t retlen; struct sc_part_desc *pdesc = NULL; struct sc_part_desc *tmpdesc; diff --git a/drivers/mtd/parsers/tplink_safeloader.c b/drivers/mtd/parsers/tplink_safeloader.c index f601e7bd8627..1c689dafca2a 100644 --- a/drivers/mtd/parsers/tplink_safeloader.c +++ b/drivers/mtd/parsers/tplink_safeloader.c @@ -91,7 +91,7 @@ static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd, buf = mtd_parser_tplink_safeloader_read_table(mtd); if (!buf) { err = -ENOENT; - goto err_out; + goto err_free_parts; } for (idx = 0, offset = TPLINK_SAFELOADER_DATA_OFFSET; @@ -118,6 +118,8 @@ static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd, err_free: for (idx -= 1; idx >= 0; idx--) kfree(parts[idx].name); +err_free_parts: + kfree(parts); err_out: return err; }; diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index d8703d7dfd0a..d67c926bca8b 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -10,6 +10,7 @@ #include <linux/err.h> #include <linux/errno.h> #include <linux/module.h> +#include <linux/delay.h> #include <linux/device.h> #include <linux/mutex.h> #include <linux/math64.h> diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 455b555275f1..c99ffe6c683a 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1549,6 +1549,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) slave_err(bond->dev, port->slave->dev, "Port %d did not find a suitable aggregator\n", port->actor_port_number); + return; } } /* if all aggregator's ports are READY_N == TRUE, set ready=TRUE diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c index 4f9b4a18c74c..594094526648 100644 --- a/drivers/net/bonding/bond_debugfs.c +++ b/drivers/net/bonding/bond_debugfs.c @@ -76,7 +76,7 @@ void bond_debug_reregister(struct bonding *bond) d = debugfs_rename(bonding_debug_root, bond->debug_dir, bonding_debug_root, bond->dev->name); - if (d) { + if (!IS_ERR(d)) { bond->debug_dir = d; } else { netdev_warn(bond->dev, "failed to reregister, so just unregister old one\n"); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b4c65783960a..0363ce597661 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2654,10 +2654,12 @@ static void bond_miimon_link_change(struct bonding *bond, static void bond_miimon_commit(struct bonding *bond) { - struct slave *slave, *primary; + struct slave *slave, *primary, *active; bool do_failover = false; struct list_head *iter; + ASSERT_RTNL(); + bond_for_each_slave(bond, slave, iter) { switch (slave->link_new_state) { case BOND_LINK_NOCHANGE: @@ -2700,8 +2702,8 @@ static void bond_miimon_commit(struct bonding *bond) bond_miimon_link_change(bond, slave, BOND_LINK_UP); - if (!rcu_access_pointer(bond->curr_active_slave) || slave == primary || - slave->prio > rcu_dereference(bond->curr_active_slave)->prio) + active = rtnl_dereference(bond->curr_active_slave); + if (!active || slave == primary || slave->prio > active->prio) do_failover = true; continue; diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c index 3585f02575df..57eeb066a945 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c @@ -48,6 +48,7 @@ mcp251xfd_ring_set_ringparam(struct net_device *ndev, priv->rx_obj_num = layout.cur_rx; priv->rx_obj_num_coalesce_irq = layout.rx_coalesce; priv->tx->obj_num = layout.cur_tx; + priv->tx_obj_num_coalesce_irq = layout.tx_coalesce; return 0; } diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index c26755f662c1..f6f3b43dfb06 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -35,12 +35,13 @@ config NET_DSA_LANTIQ_GSWIP the xrx200 / VR9 SoC. config NET_DSA_MT7530 - tristate "MediaTek MT753x and MT7621 Ethernet switch support" + tristate "MediaTek MT7530 and MT7531 Ethernet switch support" select NET_DSA_TAG_MTK select MEDIATEK_GE_PHY help - This enables support for the MediaTek MT7530, MT7531, and MT7621 - Ethernet switch chips. + This enables support for the MediaTek MT7530 and MT7531 Ethernet + switch chips. Multi-chip module MT7530 in MT7621AT, MT7621DAT, + MT7621ST and MT7623AI SoCs is supported. config NET_DSA_MV88E6060 tristate "Marvell 88E6060 ethernet switch chip support" diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 47b54ecf2c6f..6178a96e389f 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -540,10 +540,10 @@ int ksz9477_fdb_del(struct ksz_device *dev, int port, ksz_read32(dev, REG_SW_ALU_VAL_D, &alu_table[3]); /* clear forwarding port */ - alu_table[2] &= ~BIT(port); + alu_table[1] &= ~BIT(port); /* if there is no port to forward, clear table */ - if ((alu_table[2] & ALU_V_PORT_MAP) == 0) { + if ((alu_table[1] & ALU_V_PORT_MAP) == 0) { alu_table[0] = 0; alu_table[1] = 0; alu_table[2] = 0; diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c index c1a633ca1e6d..e315f669ec06 100644 --- a/drivers/net/dsa/microchip/ksz9477_i2c.c +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c @@ -104,7 +104,7 @@ static const struct of_device_id ksz9477_dt_ids[] = { }, { .compatible = "microchip,ksz8563", - .data = &ksz_switch_chips[KSZ9893] + .data = &ksz_switch_chips[KSZ8563] }, { .compatible = "microchip,ksz9567", diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 908fa89444c9..338f238f2043 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -1309,14 +1309,26 @@ mt7530_port_set_vlan_aware(struct dsa_switch *ds, int port) if (!priv->ports[port].pvid) mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK, MT7530_VLAN_ACC_TAGGED); - } - /* Set the port as a user port which is to be able to recognize VID - * from incoming packets before fetching entry within the VLAN table. - */ - mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK | PVC_EG_TAG_MASK, - VLAN_ATTR(MT7530_VLAN_USER) | - PVC_EG_TAG(MT7530_VLAN_EG_DISABLED)); + /* Set the port as a user port which is to be able to recognize + * VID from incoming packets before fetching entry within the + * VLAN table. + */ + mt7530_rmw(priv, MT7530_PVC_P(port), + VLAN_ATTR_MASK | PVC_EG_TAG_MASK, + VLAN_ATTR(MT7530_VLAN_USER) | + PVC_EG_TAG(MT7530_VLAN_EG_DISABLED)); + } else { + /* Also set CPU ports to the "user" VLAN port attribute, to + * allow VLAN classification, but keep the EG_TAG attribute as + * "consistent" (i.o.w. don't change its value) for packets + * received by the switch from the CPU, so that tagged packets + * are forwarded to user ports as tagged, and untagged as + * untagged. + */ + mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK, + VLAN_ATTR(MT7530_VLAN_USER)); + } } static void diff --git a/drivers/net/dsa/mv88e6xxx/Kconfig b/drivers/net/dsa/mv88e6xxx/Kconfig index 7a2445a34eb7..e3181d5471df 100644 --- a/drivers/net/dsa/mv88e6xxx/Kconfig +++ b/drivers/net/dsa/mv88e6xxx/Kconfig @@ -2,7 +2,6 @@ config NET_DSA_MV88E6XXX tristate "Marvell 88E6xxx Ethernet switch fabric support" depends on NET_DSA - depends on PTP_1588_CLOCK_OPTIONAL select IRQ_DOMAIN select NET_DSA_TAG_EDSA select NET_DSA_TAG_DSA @@ -13,7 +12,8 @@ config NET_DSA_MV88E6XXX config NET_DSA_MV88E6XXX_PTP bool "PTP support for Marvell 88E6xxx" default n - depends on NET_DSA_MV88E6XXX && PTP_1588_CLOCK + depends on (NET_DSA_MV88E6XXX = y && PTP_1588_CLOCK = y) || \ + (NET_DSA_MV88E6XXX = m && PTP_1588_CLOCK) help Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch chips that support it. diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index c5c3b4e92f28..2f224b166bbb 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -37,77 +37,104 @@ qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) } static int -qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) +qca8k_mii_write_lo(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) { - u16 *cached_lo = &priv->mdio_cache.lo; - struct mii_bus *bus = priv->bus; int ret; + u16 lo; - if (lo == *cached_lo) - return 0; - + lo = val & 0xffff; ret = bus->write(bus, phy_id, regnum, lo); if (ret < 0) dev_err_ratelimited(&bus->dev, "failed to write qca8k 32bit lo register\n"); - *cached_lo = lo; - return 0; + return ret; } static int -qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) +qca8k_mii_write_hi(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) { - u16 *cached_hi = &priv->mdio_cache.hi; - struct mii_bus *bus = priv->bus; int ret; + u16 hi; - if (hi == *cached_hi) - return 0; - + hi = (u16)(val >> 16); ret = bus->write(bus, phy_id, regnum, hi); if (ret < 0) dev_err_ratelimited(&bus->dev, "failed to write qca8k 32bit hi register\n"); - *cached_hi = hi; - return 0; + return ret; } static int -qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) +qca8k_mii_read_lo(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) { int ret; ret = bus->read(bus, phy_id, regnum); - if (ret >= 0) { - *val = ret; - ret = bus->read(bus, phy_id, regnum + 1); - *val |= ret << 16; - } + if (ret < 0) + goto err; - if (ret < 0) { - dev_err_ratelimited(&bus->dev, - "failed to read qca8k 32bit register\n"); - *val = 0; - return ret; - } + *val = ret & 0xffff; + return 0; + +err: + dev_err_ratelimited(&bus->dev, + "failed to read qca8k 32bit lo register\n"); + *val = 0; + + return ret; +} +static int +qca8k_mii_read_hi(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) +{ + int ret; + + ret = bus->read(bus, phy_id, regnum); + if (ret < 0) + goto err; + + *val = ret << 16; return 0; + +err: + dev_err_ratelimited(&bus->dev, + "failed to read qca8k 32bit hi register\n"); + *val = 0; + + return ret; } -static void -qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) +static int +qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) { - u16 lo, hi; + u32 hi, lo; int ret; - lo = val & 0xffff; - hi = (u16)(val >> 16); + *val = 0; - ret = qca8k_set_lo(priv, phy_id, regnum, lo); - if (ret >= 0) - ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); + ret = qca8k_mii_read_lo(bus, phy_id, regnum, &lo); + if (ret < 0) + goto err; + + ret = qca8k_mii_read_hi(bus, phy_id, regnum + 1, &hi); + if (ret < 0) + goto err; + + *val = lo | hi; + +err: + return ret; +} + +static void +qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) +{ + if (qca8k_mii_write_lo(bus, phy_id, regnum, val) < 0) + return; + + qca8k_mii_write_hi(bus, phy_id, regnum + 1, val); } static int @@ -146,7 +173,16 @@ static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) command = get_unaligned_le32(&mgmt_ethhdr->command); cmd = FIELD_GET(QCA_HDR_MGMT_CMD, command); + len = FIELD_GET(QCA_HDR_MGMT_LENGTH, command); + /* Special case for len of 15 as this is the max value for len and needs to + * be increased before converting it from word to dword. + */ + if (len == 15) + len++; + + /* We can ignore odd value, we always round up them in the alloc function. */ + len *= sizeof(u16); /* Make sure the seq match the requested packet */ if (get_unaligned_le32(&mgmt_ethhdr->seq) == mgmt_eth_data->seq) @@ -193,17 +229,33 @@ static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 * if (!skb) return NULL; - /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte - * Actually for some reason the steps are: - * 0: nothing - * 1-4: first 4 byte - * 5-6: first 12 byte - * 7-15: all 16 byte + /* Hdr mgmt length value is in step of word size. + * As an example to process 4 byte of data the correct length to set is 2. + * To process 8 byte 4, 12 byte 6, 16 byte 8... + * + * Odd values will always return the next size on the ack packet. + * (length of 3 (6 byte) will always return 8 bytes of data) + * + * This means that a value of 15 (0xf) actually means reading/writing 32 bytes + * of data. + * + * To correctly calculate the length we devide the requested len by word and + * round up. + * On the ack function we can skip the odd check as we already handle the + * case here. */ - if (len == 16) - real_len = 15; - else - real_len = len; + real_len = DIV_ROUND_UP(len, sizeof(u16)); + + /* We check if the result len is odd and we round up another time to + * the next size. (length of 3 will be increased to 4 as switch will always + * return 8 bytes) + */ + if (real_len % sizeof(u16) != 0) + real_len++; + + /* Max reg value is 0xf(15) but switch will always return the next size (32 byte) */ + if (real_len == 16) + real_len--; skb_reset_mac_header(skb); skb_set_network_header(skb, skb->len); @@ -417,7 +469,7 @@ qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) if (ret < 0) goto exit; - qca8k_mii_write32(priv, 0x10 | r2, r1, val); + qca8k_mii_write32(bus, 0x10 | r2, r1, val); exit: mutex_unlock(&bus->mdio_lock); @@ -450,7 +502,7 @@ qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_ val &= ~mask; val |= write_val; - qca8k_mii_write32(priv, 0x10 | r2, r1, val); + qca8k_mii_write32(bus, 0x10 | r2, r1, val); exit: mutex_unlock(&bus->mdio_lock); @@ -688,9 +740,9 @@ qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask) qca8k_split_addr(reg, &r1, &r2, &page); - ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0, + ret = read_poll_timeout(qca8k_mii_read_hi, ret1, !(val & mask), 0, QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, - bus, 0x10 | r2, r1, &val); + bus, 0x10 | r2, r1 + 1, &val); /* Check if qca8k_read has failed for a different reason * before returnting -ETIMEDOUT @@ -725,14 +777,14 @@ qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data) if (ret) goto exit; - qca8k_mii_write32(priv, 0x10 | r2, r1, val); + qca8k_mii_write32(bus, 0x10 | r2, r1, val); ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, QCA8K_MDIO_MASTER_BUSY); exit: /* even if the busy_wait timeouts try to clear the MASTER_EN */ - qca8k_mii_write32(priv, 0x10 | r2, r1, 0); + qca8k_mii_write_hi(bus, 0x10 | r2, r1 + 1, 0); mutex_unlock(&bus->mdio_lock); @@ -762,18 +814,18 @@ qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum) if (ret) goto exit; - qca8k_mii_write32(priv, 0x10 | r2, r1, val); + qca8k_mii_write_hi(bus, 0x10 | r2, r1 + 1, val); ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, QCA8K_MDIO_MASTER_BUSY); if (ret) goto exit; - ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); + ret = qca8k_mii_read_lo(bus, 0x10 | r2, r1, &val); exit: /* even if the busy_wait timeouts try to clear the MASTER_EN */ - qca8k_mii_write32(priv, 0x10 | r2, r1, 0); + qca8k_mii_write_hi(bus, 0x10 | r2, r1 + 1, 0); mutex_unlock(&bus->mdio_lock); @@ -1943,8 +1995,6 @@ qca8k_sw_probe(struct mdio_device *mdiodev) } priv->mdio_cache.page = 0xffff; - priv->mdio_cache.lo = 0xffff; - priv->mdio_cache.hi = 0xffff; /* Check the detected switch id */ ret = qca8k_read_switch_id(priv); diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h index 0b7a5cb12321..03514f7a20be 100644 --- a/drivers/net/dsa/qca/qca8k.h +++ b/drivers/net/dsa/qca/qca8k.h @@ -375,11 +375,6 @@ struct qca8k_mdio_cache { * mdio writes */ u16 page; -/* lo and hi can also be cached and from Documentation we can skip one - * extra mdio write if lo or hi is didn't change. - */ - u16 lo; - u16 hi; }; struct qca8k_pcs { diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index 0805f249fff2..c26b8597945b 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -356,7 +356,7 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv) if ((port_priv->flags & IFF_ALLMULTI && rxb->pkt_type == PACKET_MULTICAST) || (port_priv->flags & IFF_BROADCAST && rxb->pkt_type == PACKET_BROADCAST)) - rxb->offload_fwd_mark = 1; + rxb->offload_fwd_mark = port_priv->priv->forwarding; netif_rx(rxb); diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 8c8b4c88c7de..451c3a1b6255 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -2400,29 +2400,18 @@ int ena_com_fill_hash_function(struct ena_com_dev *ena_dev, return -EOPNOTSUPP; } - switch (func) { - case ENA_ADMIN_TOEPLITZ: - if (key) { - if (key_len != sizeof(hash_key->key)) { - netdev_err(ena_dev->net_device, - "key len (%u) doesn't equal the supported size (%zu)\n", - key_len, sizeof(hash_key->key)); - return -EINVAL; - } - memcpy(hash_key->key, key, key_len); - rss->hash_init_val = init_val; - hash_key->key_parts = key_len / sizeof(hash_key->key[0]); + if ((func == ENA_ADMIN_TOEPLITZ) && key) { + if (key_len != sizeof(hash_key->key)) { + netdev_err(ena_dev->net_device, + "key len (%u) doesn't equal the supported size (%zu)\n", + key_len, sizeof(hash_key->key)); + return -EINVAL; } - break; - case ENA_ADMIN_CRC32: - rss->hash_init_val = init_val; - break; - default: - netdev_err(ena_dev->net_device, "Invalid hash function (%d)\n", - func); - return -EINVAL; + memcpy(hash_key->key, key, key_len); + hash_key->key_parts = key_len / sizeof(hash_key->key[0]); } + rss->hash_init_val = init_val; old_func = rss->hash_func; rss->hash_func = func; rc = ena_com_set_hash_function(ena_dev); diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index 48ae6d810f8f..8da79eedc057 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -887,11 +887,7 @@ static int ena_set_tunable(struct net_device *netdev, switch (tuna->id) { case ETHTOOL_RX_COPYBREAK: len = *(u32 *)data; - if (len > adapter->netdev->mtu) { - ret = -EINVAL; - break; - } - adapter->rx_copybreak = len; + ret = ena_set_rx_copybreak(adapter, len); break; default: ret = -EINVAL; diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index a95529a69cbb..e8ad5ea31aff 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -374,9 +374,9 @@ static int ena_xdp_xmit(struct net_device *dev, int n, static int ena_xdp_execute(struct ena_ring *rx_ring, struct xdp_buff *xdp) { + u32 verdict = ENA_XDP_PASS; struct bpf_prog *xdp_prog; struct ena_ring *xdp_ring; - u32 verdict = XDP_PASS; struct xdp_frame *xdpf; u64 *xdp_stat; @@ -393,7 +393,7 @@ static int ena_xdp_execute(struct ena_ring *rx_ring, struct xdp_buff *xdp) if (unlikely(!xdpf)) { trace_xdp_exception(rx_ring->netdev, xdp_prog, verdict); xdp_stat = &rx_ring->rx_stats.xdp_aborted; - verdict = XDP_ABORTED; + verdict = ENA_XDP_DROP; break; } @@ -409,29 +409,35 @@ static int ena_xdp_execute(struct ena_ring *rx_ring, struct xdp_buff *xdp) spin_unlock(&xdp_ring->xdp_tx_lock); xdp_stat = &rx_ring->rx_stats.xdp_tx; + verdict = ENA_XDP_TX; break; case XDP_REDIRECT: if (likely(!xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog))) { xdp_stat = &rx_ring->rx_stats.xdp_redirect; + verdict = ENA_XDP_REDIRECT; break; } trace_xdp_exception(rx_ring->netdev, xdp_prog, verdict); xdp_stat = &rx_ring->rx_stats.xdp_aborted; - verdict = XDP_ABORTED; + verdict = ENA_XDP_DROP; break; case XDP_ABORTED: trace_xdp_exception(rx_ring->netdev, xdp_prog, verdict); xdp_stat = &rx_ring->rx_stats.xdp_aborted; + verdict = ENA_XDP_DROP; break; case XDP_DROP: xdp_stat = &rx_ring->rx_stats.xdp_drop; + verdict = ENA_XDP_DROP; break; case XDP_PASS: xdp_stat = &rx_ring->rx_stats.xdp_pass; + verdict = ENA_XDP_PASS; break; default: bpf_warn_invalid_xdp_action(rx_ring->netdev, xdp_prog, verdict); xdp_stat = &rx_ring->rx_stats.xdp_invalid; + verdict = ENA_XDP_DROP; } ena_increase_stat(xdp_stat, 1, &rx_ring->syncp); @@ -512,16 +518,18 @@ static void ena_xdp_exchange_program_rx_in_range(struct ena_adapter *adapter, struct bpf_prog *prog, int first, int count) { + struct bpf_prog *old_bpf_prog; struct ena_ring *rx_ring; int i = 0; for (i = first; i < count; i++) { rx_ring = &adapter->rx_ring[i]; - xchg(&rx_ring->xdp_bpf_prog, prog); - if (prog) { + old_bpf_prog = xchg(&rx_ring->xdp_bpf_prog, prog); + + if (!old_bpf_prog && prog) { ena_xdp_register_rxq_info(rx_ring); rx_ring->rx_headroom = XDP_PACKET_HEADROOM; - } else { + } else if (old_bpf_prog && !prog) { ena_xdp_unregister_rxq_info(rx_ring); rx_ring->rx_headroom = NET_SKB_PAD; } @@ -672,6 +680,7 @@ static void ena_init_io_rings_common(struct ena_adapter *adapter, ring->ena_dev = adapter->ena_dev; ring->per_napi_packets = 0; ring->cpu = 0; + ring->numa_node = 0; ring->no_interrupt_event_cnt = 0; u64_stats_init(&ring->syncp); } @@ -775,6 +784,7 @@ static int ena_setup_tx_resources(struct ena_adapter *adapter, int qid) tx_ring->next_to_use = 0; tx_ring->next_to_clean = 0; tx_ring->cpu = ena_irq->cpu; + tx_ring->numa_node = node; return 0; err_push_buf_intermediate_buf: @@ -907,6 +917,7 @@ static int ena_setup_rx_resources(struct ena_adapter *adapter, rx_ring->next_to_clean = 0; rx_ring->next_to_use = 0; rx_ring->cpu = ena_irq->cpu; + rx_ring->numa_node = node; return 0; } @@ -1619,12 +1630,12 @@ static int ena_xdp_handle_buff(struct ena_ring *rx_ring, struct xdp_buff *xdp) * we expect, then we simply drop it */ if (unlikely(rx_ring->ena_bufs[0].len > ENA_XDP_MAX_MTU)) - return XDP_DROP; + return ENA_XDP_DROP; ret = ena_xdp_execute(rx_ring, xdp); /* The xdp program might expand the headers */ - if (ret == XDP_PASS) { + if (ret == ENA_XDP_PASS) { rx_info->page_offset = xdp->data - xdp->data_hard_start; rx_ring->ena_bufs[0].len = xdp->data_end - xdp->data; } @@ -1663,7 +1674,7 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, xdp_init_buff(&xdp, ENA_PAGE_SIZE, &rx_ring->xdp_rxq); do { - xdp_verdict = XDP_PASS; + xdp_verdict = ENA_XDP_PASS; skb = NULL; ena_rx_ctx.ena_bufs = rx_ring->ena_bufs; ena_rx_ctx.max_bufs = rx_ring->sgl_size; @@ -1691,7 +1702,7 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, xdp_verdict = ena_xdp_handle_buff(rx_ring, &xdp); /* allocate skb and fill it */ - if (xdp_verdict == XDP_PASS) + if (xdp_verdict == ENA_XDP_PASS) skb = ena_rx_skb(rx_ring, rx_ring->ena_bufs, ena_rx_ctx.descs, @@ -1709,14 +1720,15 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, /* Packets was passed for transmission, unmap it * from RX side. */ - if (xdp_verdict == XDP_TX || xdp_verdict == XDP_REDIRECT) { + if (xdp_verdict & ENA_XDP_FORWARDED) { ena_unmap_rx_buff(rx_ring, &rx_ring->rx_buffer_info[req_id]); rx_ring->rx_buffer_info[req_id].page = NULL; } } - if (xdp_verdict != XDP_PASS) { + if (xdp_verdict != ENA_XDP_PASS) { xdp_flags |= xdp_verdict; + total_len += ena_rx_ctx.ena_bufs[0].len; res_budget--; continue; } @@ -1760,7 +1772,7 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, ena_refill_rx_bufs(rx_ring, refill_required); } - if (xdp_flags & XDP_REDIRECT) + if (xdp_flags & ENA_XDP_REDIRECT) xdp_do_flush_map(); return work_done; @@ -1814,8 +1826,9 @@ static void ena_adjust_adaptive_rx_intr_moderation(struct ena_napi *ena_napi) static void ena_unmask_interrupt(struct ena_ring *tx_ring, struct ena_ring *rx_ring) { + u32 rx_interval = tx_ring->smoothed_interval; struct ena_eth_io_intr_reg intr_reg; - u32 rx_interval = 0; + /* Rx ring can be NULL when for XDP tx queues which don't have an * accompanying rx_ring pair. */ @@ -1853,20 +1866,27 @@ static void ena_update_ring_numa_node(struct ena_ring *tx_ring, if (likely(tx_ring->cpu == cpu)) goto out; + tx_ring->cpu = cpu; + if (rx_ring) + rx_ring->cpu = cpu; + numa_node = cpu_to_node(cpu); + + if (likely(tx_ring->numa_node == numa_node)) + goto out; + put_cpu(); if (numa_node != NUMA_NO_NODE) { ena_com_update_numa_node(tx_ring->ena_com_io_cq, numa_node); - if (rx_ring) + tx_ring->numa_node = numa_node; + if (rx_ring) { + rx_ring->numa_node = numa_node; ena_com_update_numa_node(rx_ring->ena_com_io_cq, numa_node); + } } - tx_ring->cpu = cpu; - if (rx_ring) - rx_ring->cpu = cpu; - return; out: put_cpu(); @@ -1987,11 +2007,10 @@ static int ena_io_poll(struct napi_struct *napi, int budget) if (ena_com_get_adaptive_moderation_enabled(rx_ring->ena_dev)) ena_adjust_adaptive_rx_intr_moderation(ena_napi); + ena_update_ring_numa_node(tx_ring, rx_ring); ena_unmask_interrupt(tx_ring, rx_ring); } - ena_update_ring_numa_node(tx_ring, rx_ring); - ret = rx_work_done; } else { ret = budget; @@ -2376,7 +2395,7 @@ static int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid) ctx.mem_queue_type = ena_dev->tx_mem_queue_type; ctx.msix_vector = msix_vector; ctx.queue_size = tx_ring->ring_size; - ctx.numa_node = cpu_to_node(tx_ring->cpu); + ctx.numa_node = tx_ring->numa_node; rc = ena_com_create_io_queue(ena_dev, &ctx); if (rc) { @@ -2444,7 +2463,7 @@ static int ena_create_io_rx_queue(struct ena_adapter *adapter, int qid) ctx.mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST; ctx.msix_vector = msix_vector; ctx.queue_size = rx_ring->ring_size; - ctx.numa_node = cpu_to_node(rx_ring->cpu); + ctx.numa_node = rx_ring->numa_node; rc = ena_com_create_io_queue(ena_dev, &ctx); if (rc) { @@ -2805,6 +2824,24 @@ int ena_update_queue_sizes(struct ena_adapter *adapter, return dev_was_up ? ena_up(adapter) : 0; } +int ena_set_rx_copybreak(struct ena_adapter *adapter, u32 rx_copybreak) +{ + struct ena_ring *rx_ring; + int i; + + if (rx_copybreak > min_t(u16, adapter->netdev->mtu, ENA_PAGE_SIZE)) + return -EINVAL; + + adapter->rx_copybreak = rx_copybreak; + + for (i = 0; i < adapter->num_io_queues; i++) { + rx_ring = &adapter->rx_ring[i]; + rx_ring->rx_copybreak = rx_copybreak; + } + + return 0; +} + int ena_update_queue_count(struct ena_adapter *adapter, u32 new_channel_count) { struct ena_com_dev *ena_dev = adapter->ena_dev; diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 1bdce99bf688..2cb141079474 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -262,9 +262,11 @@ struct ena_ring { bool disable_meta_caching; u16 no_interrupt_event_cnt; - /* cpu for TPH */ + /* cpu and NUMA for TPH */ int cpu; - /* number of tx/rx_buffer_info's entries */ + int numa_node; + + /* number of tx/rx_buffer_info's entries */ int ring_size; enum ena_admin_placement_policy_type tx_mem_queue_type; @@ -392,6 +394,8 @@ int ena_update_queue_sizes(struct ena_adapter *adapter, int ena_update_queue_count(struct ena_adapter *adapter, u32 new_channel_count); +int ena_set_rx_copybreak(struct ena_adapter *adapter, u32 rx_copybreak); + int ena_get_sset_count(struct net_device *netdev, int sset); static inline void ena_reset_device(struct ena_adapter *adapter, @@ -409,6 +413,15 @@ enum ena_xdp_errors_t { ENA_XDP_NO_ENOUGH_QUEUES, }; +enum ENA_XDP_ACTIONS { + ENA_XDP_PASS = 0, + ENA_XDP_TX = BIT(0), + ENA_XDP_REDIRECT = BIT(1), + ENA_XDP_DROP = BIT(2) +}; + +#define ENA_XDP_FORWARDED (ENA_XDP_TX | ENA_XDP_REDIRECT) + static inline bool ena_xdp_present(struct ena_adapter *adapter) { return !!adapter->xdp_bpf_prog; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 3936543a74d8..4030d619e84f 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -524,19 +524,28 @@ static void xgbe_disable_vxlan(struct xgbe_prv_data *pdata) netif_dbg(pdata, drv, pdata->netdev, "VXLAN acceleration disabled\n"); } +static unsigned int xgbe_get_fc_queue_count(struct xgbe_prv_data *pdata) +{ + unsigned int max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES; + + /* From MAC ver 30H the TFCR is per priority, instead of per queue */ + if (XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER) >= 0x30) + return max_q_count; + else + return min_t(unsigned int, pdata->tx_q_count, max_q_count); +} + static int xgbe_disable_tx_flow_control(struct xgbe_prv_data *pdata) { - unsigned int max_q_count, q_count; unsigned int reg, reg_val; - unsigned int i; + unsigned int i, q_count; /* Clear MTL flow control */ for (i = 0; i < pdata->rx_q_count; i++) XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, 0); /* Clear MAC flow control */ - max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES; - q_count = min_t(unsigned int, pdata->tx_q_count, max_q_count); + q_count = xgbe_get_fc_queue_count(pdata); reg = MAC_Q0TFCR; for (i = 0; i < q_count; i++) { reg_val = XGMAC_IOREAD(pdata, reg); @@ -553,9 +562,8 @@ static int xgbe_enable_tx_flow_control(struct xgbe_prv_data *pdata) { struct ieee_pfc *pfc = pdata->pfc; struct ieee_ets *ets = pdata->ets; - unsigned int max_q_count, q_count; unsigned int reg, reg_val; - unsigned int i; + unsigned int i, q_count; /* Set MTL flow control */ for (i = 0; i < pdata->rx_q_count; i++) { @@ -579,8 +587,7 @@ static int xgbe_enable_tx_flow_control(struct xgbe_prv_data *pdata) } /* Set MAC flow control */ - max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES; - q_count = min_t(unsigned int, pdata->tx_q_count, max_q_count); + q_count = xgbe_get_fc_queue_count(pdata); reg = MAC_Q0TFCR; for (i = 0; i < q_count; i++) { reg_val = XGMAC_IOREAD(pdata, reg); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 7b666106feee..614c0278419b 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1064,6 +1064,9 @@ static void xgbe_free_irqs(struct xgbe_prv_data *pdata) devm_free_irq(pdata->dev, pdata->dev_irq, pdata); + tasklet_kill(&pdata->tasklet_dev); + tasklet_kill(&pdata->tasklet_ecc); + if (pdata->vdata->ecc_support && (pdata->dev_irq != pdata->ecc_irq)) devm_free_irq(pdata->dev, pdata->ecc_irq, pdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c b/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c index 22d4fc547a0a..a9ccc4258ee5 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c @@ -447,8 +447,10 @@ static void xgbe_i2c_stop(struct xgbe_prv_data *pdata) xgbe_i2c_disable(pdata); xgbe_i2c_clear_all_interrupts(pdata); - if (pdata->dev_irq != pdata->i2c_irq) + if (pdata->dev_irq != pdata->i2c_irq) { devm_free_irq(pdata->dev, pdata->i2c_irq, pdata); + tasklet_kill(&pdata->tasklet_i2c); + } } static int xgbe_i2c_start(struct xgbe_prv_data *pdata) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 4e97b4869522..43fdd111235a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -496,6 +496,7 @@ static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata, reg |= XGBE_KR_TRAINING_ENABLE; reg |= XGBE_KR_TRAINING_START; XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); + pdata->kr_start_time = jiffies; netif_dbg(pdata, link, pdata->netdev, "KR training initiated\n"); @@ -632,6 +633,8 @@ static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata) xgbe_switch_mode(pdata); + pdata->an_result = XGBE_AN_READY; + xgbe_an_restart(pdata); return XGBE_AN_INCOMPAT_LINK; @@ -1275,9 +1278,30 @@ static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata) static void xgbe_check_link_timeout(struct xgbe_prv_data *pdata) { unsigned long link_timeout; + unsigned long kr_time; + int wait; link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * HZ); if (time_after(jiffies, link_timeout)) { + if ((xgbe_cur_mode(pdata) == XGBE_MODE_KR) && + pdata->phy.autoneg == AUTONEG_ENABLE) { + /* AN restart should not happen while KR training is in progress. + * The while loop ensures no AN restart during KR training, + * waits up to 500ms and AN restart is triggered only if KR + * training is failed. + */ + wait = XGBE_KR_TRAINING_WAIT_ITER; + while (wait--) { + kr_time = pdata->kr_start_time + + msecs_to_jiffies(XGBE_AN_MS_TIMEOUT); + if (time_after(jiffies, kr_time)) + break; + /* AN restart is not required, if AN result is COMPLETE */ + if (pdata->an_result == XGBE_AN_COMPLETE) + return; + usleep_range(10000, 11000); + } + } netif_dbg(pdata, link, pdata->netdev, "AN link timeout\n"); xgbe_phy_config_aneg(pdata); } @@ -1390,8 +1414,10 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata) /* Disable auto-negotiation */ xgbe_an_disable_all(pdata); - if (pdata->dev_irq != pdata->an_irq) + if (pdata->dev_irq != pdata->an_irq) { devm_free_irq(pdata->dev, pdata->an_irq, pdata); + tasklet_kill(&pdata->tasklet_an); + } pdata->phy_if.phy_impl.stop(pdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 71f24cb47935..7a41367c437d 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -290,6 +290,7 @@ /* Auto-negotiation */ #define XGBE_AN_MS_TIMEOUT 500 #define XGBE_LINK_TIMEOUT 5 +#define XGBE_KR_TRAINING_WAIT_ITER 50 #define XGBE_SGMII_AN_LINK_STATUS BIT(1) #define XGBE_SGMII_AN_LINK_SPEED (BIT(2) | BIT(3)) @@ -1280,6 +1281,7 @@ struct xgbe_prv_data { unsigned int parallel_detect; unsigned int fec_ability; unsigned long an_start; + unsigned long kr_start_time; enum xgbe_an_mode an_mode; /* I2C support */ diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index d91fdb0c2649..2cf96892e565 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -2784,17 +2784,11 @@ static int bcm_enet_shared_probe(struct platform_device *pdev) return 0; } -static int bcm_enet_shared_remove(struct platform_device *pdev) -{ - return 0; -} - /* this "shared" driver is needed because both macs share a single * address space */ struct platform_driver bcm63xx_enet_shared_driver = { .probe = bcm_enet_shared_probe, - .remove = bcm_enet_shared_remove, .driver = { .name = "bcm63xx_enet_shared", .owner = THIS_MODULE, diff --git a/drivers/net/ethernet/broadcom/bgmac-bcma.c b/drivers/net/ethernet/broadcom/bgmac-bcma.c index 02bd3cf9a260..6e4f36aaf5db 100644 --- a/drivers/net/ethernet/broadcom/bgmac-bcma.c +++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c @@ -240,12 +240,12 @@ static int bgmac_probe(struct bcma_device *core) bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1; bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY; - if (ci->pkg == BCMA_PKG_ID_BCM47188 || - ci->pkg == BCMA_PKG_ID_BCM47186) { + if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM47186) || + (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188)) { bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII; bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED; } - if (ci->pkg == BCMA_PKG_ID_BCM5358) + if (ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM5358) bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_EPHYRMII; break; case BCMA_CHIP_ID_BCM53573: diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 4c7d07c684c4..6c32f5c427b5 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -991,10 +991,9 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp, dma_addr -= bp->rx_dma_offset; dma_unmap_page_attrs(&bp->pdev->dev, dma_addr, PAGE_SIZE, bp->rx_dir, DMA_ATTR_WEAK_ORDERING); - skb = build_skb(page_address(page), BNXT_PAGE_MODE_BUF_SIZE + - bp->rx_dma_offset); + skb = build_skb(page_address(page), PAGE_SIZE); if (!skb) { - __free_page(page); + page_pool_recycle_direct(rxr->page_pool, page); return NULL; } skb_mark_for_recycle(skb); @@ -1032,7 +1031,7 @@ static struct sk_buff *bnxt_rx_page_skb(struct bnxt *bp, skb = napi_alloc_skb(&rxr->bnapi->napi, payload); if (!skb) { - __free_page(page); + page_pool_recycle_direct(rxr->page_pool, page); return NULL; } @@ -1925,7 +1924,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, dma_addr = rx_buf->mapping; if (bnxt_xdp_attached(bp, rxr)) { - bnxt_xdp_buff_init(bp, rxr, cons, &data_ptr, &len, &xdp); + bnxt_xdp_buff_init(bp, rxr, cons, data_ptr, len, &xdp); if (agg_bufs) { u32 frag_len = bnxt_rx_agg_pages_xdp(bp, cpr, &xdp, cp_cons, agg_bufs, @@ -1940,7 +1939,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, } if (xdp_active) { - if (bnxt_rx_xdp(bp, rxr, cons, xdp, data, &len, event)) { + if (bnxt_rx_xdp(bp, rxr, cons, xdp, data, &data_ptr, &len, event)) { rc = 1; goto next_rx; } @@ -3969,8 +3968,10 @@ void bnxt_set_ring_params(struct bnxt *bp) bp->rx_agg_ring_mask = (bp->rx_agg_nr_pages * RX_DESC_CNT) - 1; if (BNXT_RX_PAGE_MODE(bp)) { - rx_space = BNXT_PAGE_MODE_BUF_SIZE; - rx_size = BNXT_MAX_PAGE_MODE_MTU; + rx_space = PAGE_SIZE; + rx_size = PAGE_SIZE - + ALIGN(max(NET_SKB_PAD, XDP_PACKET_HEADROOM), 8) - + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); } else { rx_size = SKB_DATA_ALIGN(BNXT_RX_COPY_THRESH + NET_IP_ALIGN); rx_space = rx_size + NET_SKB_PAD + @@ -5398,15 +5399,16 @@ static int bnxt_hwrm_vnic_set_hds(struct bnxt *bp, u16 vnic_id) req->flags = cpu_to_le32(VNIC_PLCMODES_CFG_REQ_FLAGS_JUMBO_PLACEMENT); req->enables = cpu_to_le32(VNIC_PLCMODES_CFG_REQ_ENABLES_JUMBO_THRESH_VALID); - if (BNXT_RX_PAGE_MODE(bp) && !BNXT_RX_JUMBO_MODE(bp)) { + if (BNXT_RX_PAGE_MODE(bp)) { + req->jumbo_thresh = cpu_to_le16(bp->rx_buf_use_size); + } else { req->flags |= cpu_to_le32(VNIC_PLCMODES_CFG_REQ_FLAGS_HDS_IPV4 | VNIC_PLCMODES_CFG_REQ_FLAGS_HDS_IPV6); req->enables |= cpu_to_le32(VNIC_PLCMODES_CFG_REQ_ENABLES_HDS_THRESHOLD_VALID); + req->jumbo_thresh = cpu_to_le16(bp->rx_copy_thresh); + req->hds_threshold = cpu_to_le16(bp->rx_copy_thresh); } - /* thresholds not implemented in firmware yet */ - req->jumbo_thresh = cpu_to_le16(bp->rx_copy_thresh); - req->hds_threshold = cpu_to_le16(bp->rx_copy_thresh); req->vnic_id = cpu_to_le32(vnic->fw_vnic_id); return hwrm_req_send(bp, req); } @@ -9272,10 +9274,14 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init) netdev_err(bp->dev, "ring reservation/IRQ init failure rc: %d\n", rc); return rc; } - if (tcs && (bp->tx_nr_rings_per_tc * tcs != bp->tx_nr_rings)) { + if (tcs && (bp->tx_nr_rings_per_tc * tcs != + bp->tx_nr_rings - bp->tx_nr_rings_xdp)) { netdev_err(bp->dev, "tx ring reservation failure\n"); netdev_reset_tc(bp->dev); - bp->tx_nr_rings_per_tc = bp->tx_nr_rings; + if (bp->tx_nr_rings_xdp) + bp->tx_nr_rings_per_tc = bp->tx_nr_rings_xdp; + else + bp->tx_nr_rings_per_tc = bp->tx_nr_rings; return -ENOMEM; } return 0; @@ -13591,7 +13597,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return -ENOMEM; bp = netdev_priv(dev); - SET_NETDEV_DEVLINK_PORT(dev, &bp->dl_port); bp->board_idx = ent->driver_data; bp->msg_enable = BNXT_DEF_MSG_ENABLE; bnxt_set_max_func_irqs(bp, max_irqs); @@ -13599,6 +13604,10 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (bnxt_vf_pciid(bp->board_idx)) bp->flags |= BNXT_FLAG_VF; + /* No devlink port registration in case of a VF */ + if (BNXT_PF(bp)) + SET_NETDEV_DEVLINK_PORT(dev, &bp->dl_port); + if (pdev->msix_cap) bp->flags |= BNXT_FLAG_MSIX_CAP; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 41c6dd0ae447..5163ef4a49ea 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -591,12 +591,20 @@ struct nqe_cn { #define BNXT_RX_PAGE_SIZE (1 << BNXT_RX_PAGE_SHIFT) #define BNXT_MAX_MTU 9500 -#define BNXT_PAGE_MODE_BUF_SIZE \ + +/* First RX buffer page in XDP multi-buf mode + * + * +-------------------------------------------------------------------------+ + * | XDP_PACKET_HEADROOM | bp->rx_buf_use_size | skb_shared_info| + * | (bp->rx_dma_offset) | | | + * +-------------------------------------------------------------------------+ + */ +#define BNXT_MAX_PAGE_MODE_MTU_SBUF \ ((unsigned int)PAGE_SIZE - VLAN_ETH_HLEN - NET_IP_ALIGN - \ XDP_PACKET_HEADROOM) #define BNXT_MAX_PAGE_MODE_MTU \ - BNXT_PAGE_MODE_BUF_SIZE - \ - SKB_DATA_ALIGN((unsigned int)sizeof(struct skb_shared_info)) + (BNXT_MAX_PAGE_MODE_MTU_SBUF - \ + SKB_DATA_ALIGN((unsigned int)sizeof(struct skb_shared_info))) #define BNXT_MIN_PKT_SIZE 52 @@ -2134,7 +2142,6 @@ struct bnxt { #define BNXT_DUMP_CRASH 1 struct bpf_prog *xdp_prog; - u8 xdp_has_frags; struct bnxt_ptp_cfg *ptp_cfg; u8 ptp_all_rx_tstamp; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index cbf17fcfb7ab..ec573127b707 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -3969,7 +3969,7 @@ void bnxt_ethtool_init(struct bnxt *bp) test_info->timeout = HWRM_CMD_TIMEOUT; for (i = 0; i < bp->num_tests; i++) { char *str = test_info->string[i]; - char *fw_str = resp->test0_name + i * 32; + char *fw_str = resp->test_name[i]; if (i == BNXT_MACLPBK_TEST_IDX) { strcpy(str, "Mac loopback test (offline)"); @@ -3980,14 +3980,9 @@ void bnxt_ethtool_init(struct bnxt *bp) } else if (i == BNXT_IRQ_TEST_IDX) { strcpy(str, "Interrupt_test (offline)"); } else { - strscpy(str, fw_str, ETH_GSTRING_LEN); - strncat(str, " test", ETH_GSTRING_LEN - strlen(str)); - if (test_info->offline_mask & (1 << i)) - strncat(str, " (offline)", - ETH_GSTRING_LEN - strlen(str)); - else - strncat(str, " (online)", - ETH_GSTRING_LEN - strlen(str)); + snprintf(str, ETH_GSTRING_LEN, "%s test (%s)", + fw_str, test_info->offline_mask & (1 << i) ? + "offline" : "online"); } } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h index 2686a714a59f..a5408879e077 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h @@ -10249,14 +10249,7 @@ struct hwrm_selftest_qlist_output { u8 unused_0; __le16 test_timeout; u8 unused_1[2]; - char test0_name[32]; - char test1_name[32]; - char test2_name[32]; - char test3_name[32]; - char test4_name[32]; - char test5_name[32]; - char test6_name[32]; - char test7_name[32]; + char test_name[8][32]; u8 eyescope_target_BER_support; #define SELFTEST_QLIST_RESP_EYESCOPE_TARGET_BER_SUPPORT_BER_1E8_SUPPORTED 0x0UL #define SELFTEST_QLIST_RESP_EYESCOPE_TARGET_BER_SUPPORT_BER_1E9_SUPPORTED 0x1UL diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index c3065ec0a479..36d5202c0aee 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -177,7 +177,7 @@ bool bnxt_xdp_attached(struct bnxt *bp, struct bnxt_rx_ring_info *rxr) } void bnxt_xdp_buff_init(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, - u16 cons, u8 **data_ptr, unsigned int *len, + u16 cons, u8 *data_ptr, unsigned int len, struct xdp_buff *xdp) { struct bnxt_sw_rx_bd *rx_buf; @@ -191,13 +191,10 @@ void bnxt_xdp_buff_init(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, offset = bp->rx_offset; mapping = rx_buf->mapping - bp->rx_dma_offset; - dma_sync_single_for_cpu(&pdev->dev, mapping + offset, *len, bp->rx_dir); - - if (bp->xdp_has_frags) - buflen = BNXT_PAGE_MODE_BUF_SIZE + offset; + dma_sync_single_for_cpu(&pdev->dev, mapping + offset, len, bp->rx_dir); xdp_init_buff(xdp, buflen, &rxr->xdp_rxq); - xdp_prepare_buff(xdp, *data_ptr - offset, offset, *len, false); + xdp_prepare_buff(xdp, data_ptr - offset, offset, len, false); } void bnxt_xdp_buff_frags_free(struct bnxt_rx_ring_info *rxr, @@ -222,7 +219,8 @@ void bnxt_xdp_buff_frags_free(struct bnxt_rx_ring_info *rxr, * false - packet should be passed to the stack. */ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons, - struct xdp_buff xdp, struct page *page, unsigned int *len, u8 *event) + struct xdp_buff xdp, struct page *page, u8 **data_ptr, + unsigned int *len, u8 *event) { struct bpf_prog *xdp_prog = READ_ONCE(rxr->xdp_prog); struct bnxt_tx_ring_info *txr; @@ -255,8 +253,10 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons, *event &= ~BNXT_RX_EVENT; *len = xdp.data_end - xdp.data; - if (orig_data != xdp.data) + if (orig_data != xdp.data) { offset = xdp.data - xdp.data_hard_start; + *data_ptr = xdp.data_hard_start + offset; + } switch (act) { case XDP_PASS: @@ -401,10 +401,8 @@ static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog) netdev_warn(dev, "ethtool rx/tx channels must be combined to support XDP.\n"); return -EOPNOTSUPP; } - if (prog) { + if (prog) tx_xdp = bp->rx_nr_rings; - bp->xdp_has_frags = prog->aux->xdp_has_frags; - } tc = netdev_get_num_tc(dev); if (!tc) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h index 505911ae095d..ea430d6961df 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h @@ -18,8 +18,8 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp, struct xdp_buff *xdp); void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts); bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons, - struct xdp_buff xdp, struct page *page, unsigned int *len, - u8 *event); + struct xdp_buff xdp, struct page *page, u8 **data_ptr, + unsigned int *len, u8 *event); int bnxt_xdp(struct net_device *dev, struct netdev_bpf *xdp); int bnxt_xdp_xmit(struct net_device *dev, int num_frames, struct xdp_frame **frames, u32 flags); @@ -27,7 +27,7 @@ int bnxt_xdp_xmit(struct net_device *dev, int num_frames, bool bnxt_xdp_attached(struct bnxt *bp, struct bnxt_rx_ring_info *rxr); void bnxt_xdp_buff_init(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, - u16 cons, u8 **data_ptr, unsigned int *len, + u16 cons, u8 *data_ptr, unsigned int len, struct xdp_buff *xdp); void bnxt_xdp_buff_frags_free(struct bnxt_rx_ring_info *rxr, struct xdp_buff *xdp); diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 59debdc344a5..58747292521d 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -11166,7 +11166,7 @@ static void tg3_reset_task(struct work_struct *work) rtnl_lock(); tg3_full_lock(tp, 0); - if (!netif_running(tp->dev)) { + if (tp->pcierr_recovery || !netif_running(tp->dev)) { tg3_flag_clear(tp, RESET_TASK_PENDING); tg3_full_unlock(tp); rtnl_unlock(); @@ -18101,6 +18101,9 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, netdev_info(netdev, "PCI I/O error detected\n"); + /* Want to make sure that the reset task doesn't run */ + tg3_reset_task_cancel(tp); + rtnl_lock(); /* Could be second call or maybe we don't have netdev yet */ @@ -18117,9 +18120,6 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, tg3_timer_stop(tp); - /* Want to make sure that the reset task doesn't run */ - tg3_reset_task_cancel(tp); - netif_device_detach(netdev); /* Clean up software state, even if MMIO is blocked */ diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 95667b979fab..6cda31520c42 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -2187,7 +2187,6 @@ static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev) bool cloned = skb_cloned(*skb) || skb_header_cloned(*skb) || skb_is_nonlinear(*skb); int padlen = ETH_ZLEN - (*skb)->len; - int headroom = skb_headroom(*skb); int tailroom = skb_tailroom(*skb); struct sk_buff *nskb; u32 fcs; @@ -2201,9 +2200,6 @@ static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev) /* FCS could be appeded to tailroom. */ if (tailroom >= ETH_FCS_LEN) goto add_fcs; - /* FCS could be appeded by moving data to headroom. */ - else if (!cloned && headroom + tailroom >= ETH_FCS_LEN) - padlen = 0; /* No room for FCS, need to reallocate skb. */ else padlen = ETH_FCS_LEN; @@ -2212,10 +2208,7 @@ static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev) padlen += ETH_FCS_LEN; } - if (!cloned && headroom + tailroom >= padlen) { - (*skb)->data = memmove((*skb)->head, (*skb)->data, (*skb)->len); - skb_set_tail_pointer(*skb, (*skb)->len); - } else { + if (cloned || tailroom < padlen) { nskb = skb_copy_expand(*skb, 0, padlen, GFP_ATOMIC); if (!nskb) return -ENOMEM; @@ -4634,25 +4627,26 @@ static int init_reset_optional(struct platform_device *pdev) if (ret) return dev_err_probe(&pdev->dev, ret, "failed to init SGMII PHY\n"); - } - ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_GEM_CONFIG); - if (!ret) { - u32 pm_info[2]; + ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_GEM_CONFIG); + if (!ret) { + u32 pm_info[2]; + + ret = of_property_read_u32_array(pdev->dev.of_node, "power-domains", + pm_info, ARRAY_SIZE(pm_info)); + if (ret) { + dev_err(&pdev->dev, "Failed to read power management information\n"); + goto err_out_phy_exit; + } + ret = zynqmp_pm_set_gem_config(pm_info[1], GEM_CONFIG_FIXED, 0); + if (ret) + goto err_out_phy_exit; - ret = of_property_read_u32_array(pdev->dev.of_node, "power-domains", - pm_info, ARRAY_SIZE(pm_info)); - if (ret) { - dev_err(&pdev->dev, "Failed to read power management information\n"); - goto err_out_phy_exit; + ret = zynqmp_pm_set_gem_config(pm_info[1], GEM_CONFIG_SGMII_MODE, 1); + if (ret) + goto err_out_phy_exit; } - ret = zynqmp_pm_set_gem_config(pm_info[1], GEM_CONFIG_FIXED, 0); - if (ret) - goto err_out_phy_exit; - ret = zynqmp_pm_set_gem_config(pm_info[1], GEM_CONFIG_SGMII_MODE, 1); - if (ret) - goto err_out_phy_exit; } /* Fully reset controller at hardware level if mapped in device tree */ diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c index bf0190e1d2ea..00e2108f2ca4 100644 --- a/drivers/net/ethernet/engleder/tsnep_main.c +++ b/drivers/net/ethernet/engleder/tsnep_main.c @@ -450,7 +450,7 @@ static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb, /* ring full, shall not happen because queue is stopped if full * below */ - netif_stop_queue(tx->adapter->netdev); + netif_stop_subqueue(tx->adapter->netdev, tx->queue_index); spin_unlock_irqrestore(&tx->lock, flags); @@ -493,7 +493,7 @@ static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb, if (tsnep_tx_desc_available(tx) < (MAX_SKB_FRAGS + 1)) { /* ring can get full with next frame */ - netif_stop_queue(tx->adapter->netdev); + netif_stop_subqueue(tx->adapter->netdev, tx->queue_index); } spin_unlock_irqrestore(&tx->lock, flags); @@ -503,11 +503,14 @@ static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb, static bool tsnep_tx_poll(struct tsnep_tx *tx, int napi_budget) { + struct tsnep_tx_entry *entry; + struct netdev_queue *nq; unsigned long flags; int budget = 128; - struct tsnep_tx_entry *entry; - int count; int length; + int count; + + nq = netdev_get_tx_queue(tx->adapter->netdev, tx->queue_index); spin_lock_irqsave(&tx->lock, flags); @@ -564,8 +567,8 @@ static bool tsnep_tx_poll(struct tsnep_tx *tx, int napi_budget) } while (likely(budget)); if ((tsnep_tx_desc_available(tx) >= ((MAX_SKB_FRAGS + 1) * 2)) && - netif_queue_stopped(tx->adapter->netdev)) { - netif_wake_queue(tx->adapter->netdev); + netif_tx_queue_stopped(nq)) { + netif_tx_wake_queue(nq); } spin_unlock_irqrestore(&tx->lock, flags); diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 3f8032947d86..027fff9f7db0 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -2410,6 +2410,9 @@ static int dpaa_eth_poll(struct napi_struct *napi, int budget) cleaned = qman_p_poll_dqrr(np->p, budget); + if (np->xdp_act & XDP_REDIRECT) + xdp_do_flush(); + if (cleaned < budget) { napi_complete_done(napi, cleaned); qman_p_irqsource_add(np->p, QM_PIRQ_DQRI); @@ -2417,9 +2420,6 @@ static int dpaa_eth_poll(struct napi_struct *napi, int budget) qman_p_irqsource_add(np->p, QM_PIRQ_DQRI); } - if (np->xdp_act & XDP_REDIRECT) - xdp_do_flush(); - return cleaned; } diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 0c35abb7d065..2e79d18fc3c7 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -1993,10 +1993,15 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget) if (rx_cleaned >= budget || txconf_cleaned >= DPAA2_ETH_TXCONF_PER_NAPI) { work_done = budget; + if (ch->xdp.res & XDP_REDIRECT) + xdp_do_flush(); goto out; } } while (store_cleaned); + if (ch->xdp.res & XDP_REDIRECT) + xdp_do_flush(); + /* Update NET DIM with the values for this CDAN */ dpaa2_io_update_net_dim(ch->dpio, ch->stats.frames_per_cdan, ch->stats.bytes_per_cdan); @@ -2032,9 +2037,7 @@ out: txc_fq->dq_bytes = 0; } - if (ch->xdp.res & XDP_REDIRECT) - xdp_do_flush_map(); - else if (rx_cleaned && ch->xdp.res & XDP_TX) + if (rx_cleaned && ch->xdp.res & XDP_TX) dpaa2_eth_xdp_tx_flush(priv, ch, &priv->fq[flowid]); return work_done; diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index 3a79ead5219a..e96449eedfb5 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -2290,14 +2290,14 @@ static void enetc_tx_onestep_tstamp(struct work_struct *work) priv = container_of(work, struct enetc_ndev_priv, tx_onestep_tstamp); - netif_tx_lock(priv->ndev); + netif_tx_lock_bh(priv->ndev); clear_bit_unlock(ENETC_TX_ONESTEP_TSTAMP_IN_PROGRESS, &priv->flags); skb = skb_dequeue(&priv->tx_skbs); if (skb) enetc_start_xmit(skb, priv->ndev); - netif_tx_unlock(priv->ndev); + netif_tx_unlock_bh(priv->ndev); } static void enetc_tx_onestep_tstamp_init(struct enetc_ndev_priv *priv) diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ierb.c b/drivers/net/ethernet/freescale/enetc/enetc_ierb.c index 91f02c505028..b307bef4dc29 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_ierb.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_ierb.c @@ -127,11 +127,6 @@ static int enetc_ierb_probe(struct platform_device *pdev) return 0; } -static int enetc_ierb_remove(struct platform_device *pdev) -{ - return 0; -} - static const struct of_device_id enetc_ierb_match[] = { { .compatible = "fsl,ls1028a-enetc-ierb", }, {}, @@ -144,7 +139,6 @@ static struct platform_driver enetc_ierb_driver = { .of_match_table = enetc_ierb_match, }, .probe = enetc_ierb_probe, - .remove = enetc_ierb_remove, }; module_platform_driver(enetc_ierb_driver); diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 644f3c963730..2341597408d1 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3191,7 +3191,7 @@ static void fec_enet_free_buffers(struct net_device *ndev) for (q = 0; q < fep->num_rx_queues; q++) { rxq = fep->rx_queue[q]; for (i = 0; i < rxq->bd.ring_size; i++) - page_pool_release_page(rxq->page_pool, rxq->rx_skb_info[i].page); + page_pool_put_full_page(rxq->page_pool, rxq->rx_skb_info[i].page, false); for (i = 0; i < XDP_STATS_TOTAL; i++) rxq->stats[i] = 0; diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c index d00bae15a901..d528ca681b6f 100644 --- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c +++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c @@ -1430,7 +1430,7 @@ int dtsec_initialization(struct mac_device *mac_dev, dtsec->dtsec_drv_param->tx_pad_crc = true; phy_node = of_parse_phandle(mac_node, "tbi-handle", 0); - if (!phy_node || of_device_is_available(phy_node)) { + if (!phy_node || !of_device_is_available(phy_node)) { of_node_put(phy_node); err = -EINVAL; dev_err_probe(mac_dev->dev, err, diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net/ethernet/freescale/fman/fman_memac.c index 9349f841bd06..587ad81a2dc3 100644 --- a/drivers/net/ethernet/freescale/fman/fman_memac.c +++ b/drivers/net/ethernet/freescale/fman/fman_memac.c @@ -1055,6 +1055,9 @@ static struct phylink_pcs *memac_pcs_create(struct device_node *mac_node, return ERR_PTR(-EPROBE_DEFER); pcs = lynx_pcs_create(mdiodev); + if (!pcs) + mdio_device_free(mdiodev); + return pcs; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 0ec5730b1788..b4c4fb873568 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -3855,18 +3855,16 @@ static int hns3_gro_complete(struct sk_buff *skb, u32 l234info) return 0; } -static bool hns3_checksum_complete(struct hns3_enet_ring *ring, +static void hns3_checksum_complete(struct hns3_enet_ring *ring, struct sk_buff *skb, u32 ptype, u16 csum) { if (ptype == HNS3_INVALID_PTYPE || hns3_rx_ptype_tbl[ptype].ip_summed != CHECKSUM_COMPLETE) - return false; + return; hns3_ring_stats_update(ring, csum_complete); skb->ip_summed = CHECKSUM_COMPLETE; skb->csum = csum_unfold((__force __sum16)csum); - - return true; } static void hns3_rx_handle_csum(struct sk_buff *skb, u32 l234info, @@ -3926,8 +3924,7 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb, ptype = hnae3_get_field(ol_info, HNS3_RXD_PTYPE_M, HNS3_RXD_PTYPE_S); - if (hns3_checksum_complete(ring, skb, ptype, csum)) - return; + hns3_checksum_complete(ring, skb, ptype, csum); /* check if hardware has done checksum */ if (!(bd_base_info & BIT(HNS3_RXD_L3L4P_B))) @@ -3936,6 +3933,7 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb, if (unlikely(l234info & (BIT(HNS3_RXD_L3E_B) | BIT(HNS3_RXD_L4E_B) | BIT(HNS3_RXD_OL3E_B) | BIT(HNS3_RXD_OL4E_B)))) { + skb->ip_summed = CHECKSUM_NONE; hns3_ring_stats_update(ring, l3l4_csum_err); return; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 4e54f91f7a6c..07ad5f35219e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3910,9 +3910,17 @@ static int hclge_set_all_vf_rst(struct hclge_dev *hdev, bool reset) return ret; } - if (!reset || !test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) + if (!reset || + !test_bit(HCLGE_VPORT_STATE_INITED, &vport->state)) continue; + if (!test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state) && + hdev->reset_type == HNAE3_FUNC_RESET) { + set_bit(HCLGE_VPORT_NEED_NOTIFY_RESET, + &vport->need_notify); + continue; + } + /* Inform VF to process the reset. * hclge_inform_reset_assert_to_vf may fail if VF * driver is not loaded. @@ -4609,18 +4617,25 @@ static void hclge_reset_service_task(struct hclge_dev *hdev) static void hclge_update_vport_alive(struct hclge_dev *hdev) { +#define HCLGE_ALIVE_SECONDS_NORMAL 8 + + unsigned long alive_time = HCLGE_ALIVE_SECONDS_NORMAL * HZ; int i; /* start from vport 1 for PF is always alive */ for (i = 1; i < hdev->num_alloc_vport; i++) { struct hclge_vport *vport = &hdev->vport[i]; - if (time_after(jiffies, vport->last_active_jiffies + 8 * HZ)) + if (!test_bit(HCLGE_VPORT_STATE_INITED, &vport->state) || + !test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) + continue; + if (time_after(jiffies, vport->last_active_jiffies + + alive_time)) { clear_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state); - - /* If vf is not alive, set to default value */ - if (!test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) - vport->mps = HCLGE_MAC_DEFAULT_FRAME; + dev_warn(&hdev->pdev->dev, + "VF %u heartbeat timeout\n", + i - HCLGE_VF_VPORT_START_NUM); + } } } @@ -8064,9 +8079,11 @@ int hclge_vport_start(struct hclge_vport *vport) { struct hclge_dev *hdev = vport->back; + set_bit(HCLGE_VPORT_STATE_INITED, &vport->state); set_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state); set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state); vport->last_active_jiffies = jiffies; + vport->need_notify = 0; if (test_bit(vport->vport_id, hdev->vport_config_block)) { if (vport->vport_id) { @@ -8084,7 +8101,9 @@ int hclge_vport_start(struct hclge_vport *vport) void hclge_vport_stop(struct hclge_vport *vport) { + clear_bit(HCLGE_VPORT_STATE_INITED, &vport->state); clear_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state); + vport->need_notify = 0; } static int hclge_client_start(struct hnae3_handle *handle) @@ -9208,7 +9227,8 @@ static int hclge_set_vf_mac(struct hnae3_handle *handle, int vf, return 0; } - dev_info(&hdev->pdev->dev, "MAC of VF %d has been set to %s\n", + dev_info(&hdev->pdev->dev, + "MAC of VF %d has been set to %s, will be active after VF reset\n", vf, format_mac_addr); return 0; } @@ -10465,12 +10485,16 @@ static int hclge_set_vf_vlan_filter(struct hnae3_handle *handle, int vfid, * for DEVICE_VERSION_V3, vf doesn't need to know about the port based * VLAN state. */ - if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V3 && - test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) - (void)hclge_push_vf_port_base_vlan_info(&hdev->vport[0], - vport->vport_id, - state, &vlan_info); - + if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V3) { + if (test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) + (void)hclge_push_vf_port_base_vlan_info(&hdev->vport[0], + vport->vport_id, + state, + &vlan_info); + else + set_bit(HCLGE_VPORT_NEED_NOTIFY_VF_VLAN, + &vport->need_notify); + } return 0; } @@ -11941,7 +11965,7 @@ static void hclge_reset_vport_state(struct hclge_dev *hdev) int i; for (i = 0; i < hdev->num_alloc_vport; i++) { - hclge_vport_stop(vport); + clear_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state); vport++; } } @@ -12754,60 +12778,71 @@ static int hclge_gro_en(struct hnae3_handle *handle, bool enable) return ret; } -static void hclge_sync_promisc_mode(struct hclge_dev *hdev) +static int hclge_sync_vport_promisc_mode(struct hclge_vport *vport) { - struct hclge_vport *vport = &hdev->vport[0]; struct hnae3_handle *handle = &vport->nic; + struct hclge_dev *hdev = vport->back; + bool uc_en = false; + bool mc_en = false; u8 tmp_flags; + bool bc_en; int ret; - u16 i; if (vport->last_promisc_flags != vport->overflow_promisc_flags) { set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state); vport->last_promisc_flags = vport->overflow_promisc_flags; } - if (test_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state)) { + if (!test_and_clear_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, + &vport->state)) + return 0; + + /* for PF */ + if (!vport->vport_id) { tmp_flags = handle->netdev_flags | vport->last_promisc_flags; ret = hclge_set_promisc_mode(handle, tmp_flags & HNAE3_UPE, tmp_flags & HNAE3_MPE); - if (!ret) { - clear_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, - &vport->state); + if (!ret) set_bit(HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE, &vport->state); - } + else + set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, + &vport->state); + return ret; } - for (i = 1; i < hdev->num_alloc_vport; i++) { - bool uc_en = false; - bool mc_en = false; - bool bc_en; + /* for VF */ + if (vport->vf_info.trusted) { + uc_en = vport->vf_info.request_uc_en > 0 || + vport->overflow_promisc_flags & HNAE3_OVERFLOW_UPE; + mc_en = vport->vf_info.request_mc_en > 0 || + vport->overflow_promisc_flags & HNAE3_OVERFLOW_MPE; + } + bc_en = vport->vf_info.request_bc_en > 0; - vport = &hdev->vport[i]; + ret = hclge_cmd_set_promisc_mode(hdev, vport->vport_id, uc_en, + mc_en, bc_en); + if (ret) { + set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state); + return ret; + } + hclge_set_vport_vlan_fltr_change(vport); - if (!test_and_clear_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, - &vport->state)) - continue; + return 0; +} - if (vport->vf_info.trusted) { - uc_en = vport->vf_info.request_uc_en > 0 || - vport->overflow_promisc_flags & - HNAE3_OVERFLOW_UPE; - mc_en = vport->vf_info.request_mc_en > 0 || - vport->overflow_promisc_flags & - HNAE3_OVERFLOW_MPE; - } - bc_en = vport->vf_info.request_bc_en > 0; +static void hclge_sync_promisc_mode(struct hclge_dev *hdev) +{ + struct hclge_vport *vport; + int ret; + u16 i; - ret = hclge_cmd_set_promisc_mode(hdev, vport->vport_id, uc_en, - mc_en, bc_en); - if (ret) { - set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, - &vport->state); + for (i = 0; i < hdev->num_alloc_vport; i++) { + vport = &hdev->vport[i]; + + ret = hclge_sync_vport_promisc_mode(vport); + if (ret) return; - } - hclge_set_vport_vlan_fltr_change(vport); } } @@ -12944,6 +12979,11 @@ static void hclge_clear_vport_vf_info(struct hclge_vport *vport, int vfid) struct hclge_vlan_info vlan_info; int ret; + clear_bit(HCLGE_VPORT_STATE_INITED, &vport->state); + clear_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state); + vport->need_notify = 0; + vport->mps = 0; + /* after disable sriov, clean VF rate configured by PF */ ret = hclge_tm_qs_shaper_cfg(vport, 0); if (ret) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 495b639b0dc2..13f23d606e77 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -995,9 +995,15 @@ enum HCLGE_VPORT_STATE { HCLGE_VPORT_STATE_MAC_TBL_CHANGE, HCLGE_VPORT_STATE_PROMISC_CHANGE, HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE, + HCLGE_VPORT_STATE_INITED, HCLGE_VPORT_STATE_MAX }; +enum HCLGE_VPORT_NEED_NOTIFY { + HCLGE_VPORT_NEED_NOTIFY_RESET, + HCLGE_VPORT_NEED_NOTIFY_VF_VLAN, +}; + struct hclge_vlan_info { u16 vlan_proto; /* so far support 802.1Q only */ u16 qos; @@ -1044,6 +1050,7 @@ struct hclge_vport { struct hnae3_handle roce; unsigned long state; + unsigned long need_notify; unsigned long last_active_jiffies; u32 mps; /* Max packet size */ struct hclge_vf_info vf_info; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index a7b06c63143c..04ff9bf12185 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -124,17 +124,26 @@ static int hclge_send_mbx_msg(struct hclge_vport *vport, u8 *msg, u16 msg_len, return status; } +static int hclge_inform_vf_reset(struct hclge_vport *vport, u16 reset_type) +{ + __le16 msg_data; + u8 dest_vfid; + + dest_vfid = (u8)vport->vport_id; + msg_data = cpu_to_le16(reset_type); + + /* send this requested info to VF */ + return hclge_send_mbx_msg(vport, (u8 *)&msg_data, sizeof(msg_data), + HCLGE_MBX_ASSERTING_RESET, dest_vfid); +} + int hclge_inform_reset_assert_to_vf(struct hclge_vport *vport) { struct hclge_dev *hdev = vport->back; - __le16 msg_data; u16 reset_type; - u8 dest_vfid; BUILD_BUG_ON(HNAE3_MAX_RESET > U16_MAX); - dest_vfid = (u8)vport->vport_id; - if (hdev->reset_type == HNAE3_FUNC_RESET) reset_type = HNAE3_VF_PF_FUNC_RESET; else if (hdev->reset_type == HNAE3_FLR_RESET) @@ -142,11 +151,7 @@ int hclge_inform_reset_assert_to_vf(struct hclge_vport *vport) else reset_type = HNAE3_VF_FUNC_RESET; - msg_data = cpu_to_le16(reset_type); - - /* send this requested info to VF */ - return hclge_send_mbx_msg(vport, (u8 *)&msg_data, sizeof(msg_data), - HCLGE_MBX_ASSERTING_RESET, dest_vfid); + return hclge_inform_vf_reset(vport, reset_type); } static void hclge_free_vector_ring_chain(struct hnae3_ring_chain_node *head) @@ -652,9 +657,56 @@ static int hclge_reset_vf(struct hclge_vport *vport) return hclge_func_reset_cmd(hdev, vport->vport_id); } +static void hclge_notify_vf_config(struct hclge_vport *vport) +{ + struct hclge_dev *hdev = vport->back; + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); + struct hclge_port_base_vlan_config *vlan_cfg; + int ret; + + hclge_push_vf_link_status(vport); + if (test_bit(HCLGE_VPORT_NEED_NOTIFY_RESET, &vport->need_notify)) { + ret = hclge_inform_vf_reset(vport, HNAE3_VF_PF_FUNC_RESET); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to inform VF %u reset!", + vport->vport_id - HCLGE_VF_VPORT_START_NUM); + return; + } + vport->need_notify = 0; + return; + } + + if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V3 && + test_bit(HCLGE_VPORT_NEED_NOTIFY_VF_VLAN, &vport->need_notify)) { + vlan_cfg = &vport->port_base_vlan_cfg; + ret = hclge_push_vf_port_base_vlan_info(&hdev->vport[0], + vport->vport_id, + vlan_cfg->state, + &vlan_cfg->vlan_info); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to inform VF %u port base vlan!", + vport->vport_id - HCLGE_VF_VPORT_START_NUM); + return; + } + clear_bit(HCLGE_VPORT_NEED_NOTIFY_VF_VLAN, &vport->need_notify); + } +} + static void hclge_vf_keep_alive(struct hclge_vport *vport) { + struct hclge_dev *hdev = vport->back; + vport->last_active_jiffies = jiffies; + + if (test_bit(HCLGE_VPORT_STATE_INITED, &vport->state) && + !test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) { + set_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state); + dev_info(&hdev->pdev->dev, "VF %u is alive!", + vport->vport_id - HCLGE_VF_VPORT_START_NUM); + hclge_notify_vf_config(vport); + } } static int hclge_set_vf_mtu(struct hclge_vport *vport, @@ -954,6 +1006,7 @@ static int hclge_mbx_vf_uninit_handler(struct hclge_mbx_ops_param *param) hclge_rm_vport_all_mac_table(param->vport, true, HCLGE_MAC_ADDR_MC); hclge_rm_vport_all_vlan_table(param->vport, true); + param->vport->mps = 0; return 0; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index db6f7cdba958..e84e5be8e59e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -2767,7 +2767,8 @@ static int hclgevf_pci_reset(struct hclgevf_dev *hdev) struct pci_dev *pdev = hdev->pdev; int ret = 0; - if (hdev->reset_type == HNAE3_VF_FULL_RESET && + if ((hdev->reset_type == HNAE3_VF_FULL_RESET || + hdev->reset_type == HNAE3_FLR_RESET) && test_bit(HCLGEVF_STATE_IRQ_INITED, &hdev->state)) { hclgevf_misc_irq_uninit(hdev); hclgevf_uninit_msi(hdev); @@ -3129,7 +3130,7 @@ static int hclgevf_set_channels(struct hnae3_handle *handle, u32 new_tqps_num, hclgevf_update_rss_size(handle, new_tqps_num); - hclge_comm_get_rss_tc_info(cur_rss_size, hdev->hw_tc_map, + hclge_comm_get_rss_tc_info(kinfo->rss_size, hdev->hw_tc_map, tc_offset, tc_valid, tc_size); ret = hclge_comm_set_rss_tc_mode(&hdev->hw.hw, tc_offset, tc_valid, tc_size); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 53d0083e35da..52eec0a50492 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2921,7 +2921,7 @@ static int i40e_change_mtu(struct net_device *netdev, int new_mtu) struct i40e_pf *pf = vsi->back; if (i40e_enabled_xdp_vsi(vsi)) { - int frame_size = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; + int frame_size = new_mtu + I40E_PACKET_HDR_PAD; if (frame_size > i40e_max_xdp_frame_size(vsi)) return -EINVAL; @@ -13167,6 +13167,8 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev, } br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); + if (!br_spec) + return -EINVAL; nla_for_each_nested(attr, br_spec, rem) { __u16 mode; diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h index 0d1bab4ac1b0..2a9f1eeeb701 100644 --- a/drivers/net/ethernet/intel/iavf/iavf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@ -249,6 +249,7 @@ struct iavf_cloud_filter { /* board specific private data structure */ struct iavf_adapter { + struct workqueue_struct *wq; struct work_struct reset_task; struct work_struct adminq_task; struct delayed_work client_task; @@ -459,7 +460,6 @@ struct iavf_device { /* needed by iavf_ethtool.c */ extern char iavf_driver_name[]; -extern struct workqueue_struct *iavf_wq; static inline const char *iavf_state_str(enum iavf_state_t state) { diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c index d79ead5e8d0c..6f171d1d85b7 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c +++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c @@ -532,7 +532,7 @@ static int iavf_set_priv_flags(struct net_device *netdev, u32 flags) if (changed_flags & IAVF_FLAG_LEGACY_RX) { if (netif_running(netdev)) { adapter->flags |= IAVF_FLAG_RESET_NEEDED; - queue_work(iavf_wq, &adapter->reset_task); + queue_work(adapter->wq, &adapter->reset_task); } } @@ -672,7 +672,7 @@ static int iavf_set_ringparam(struct net_device *netdev, if (netif_running(netdev)) { adapter->flags |= IAVF_FLAG_RESET_NEEDED; - queue_work(iavf_wq, &adapter->reset_task); + queue_work(adapter->wq, &adapter->reset_task); } return 0; @@ -1433,7 +1433,7 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx adapter->aq_required |= IAVF_FLAG_AQ_ADD_FDIR_FILTER; spin_unlock_bh(&adapter->fdir_fltr_lock); - mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0); + mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); ret: if (err && fltr) @@ -1474,7 +1474,7 @@ static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx spin_unlock_bh(&adapter->fdir_fltr_lock); if (fltr && fltr->state == IAVF_FDIR_FLTR_DEL_REQUEST) - mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0); + mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); return err; } @@ -1658,7 +1658,7 @@ iavf_set_adv_rss_hash_opt(struct iavf_adapter *adapter, spin_unlock_bh(&adapter->adv_rss_lock); if (!err) - mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0); + mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); mutex_unlock(&adapter->crit_lock); diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index c4e451ef7942..4b09785d2147 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -49,7 +49,6 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Adaptive Virtual Function Network Driver") MODULE_LICENSE("GPL v2"); static const struct net_device_ops iavf_netdev_ops; -struct workqueue_struct *iavf_wq; int iavf_status_to_errno(enum iavf_status status) { @@ -277,7 +276,7 @@ void iavf_schedule_reset(struct iavf_adapter *adapter) if (!(adapter->flags & (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED))) { adapter->flags |= IAVF_FLAG_RESET_NEEDED; - queue_work(iavf_wq, &adapter->reset_task); + queue_work(adapter->wq, &adapter->reset_task); } } @@ -291,7 +290,7 @@ void iavf_schedule_reset(struct iavf_adapter *adapter) void iavf_schedule_request_stats(struct iavf_adapter *adapter) { adapter->aq_required |= IAVF_FLAG_AQ_REQUEST_STATS; - mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0); + mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); } /** @@ -411,7 +410,7 @@ static irqreturn_t iavf_msix_aq(int irq, void *data) if (adapter->state != __IAVF_REMOVE) /* schedule work on the private workqueue */ - queue_work(iavf_wq, &adapter->adminq_task); + queue_work(adapter->wq, &adapter->adminq_task); return IRQ_HANDLED; } @@ -1034,7 +1033,7 @@ int iavf_replace_primary_mac(struct iavf_adapter *adapter, /* schedule the watchdog task to immediately process the request */ if (f) { - queue_work(iavf_wq, &adapter->watchdog_task.work); + mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); return 0; } return -ENOMEM; @@ -1257,7 +1256,7 @@ static void iavf_up_complete(struct iavf_adapter *adapter) adapter->aq_required |= IAVF_FLAG_AQ_ENABLE_QUEUES; if (CLIENT_ENABLED(adapter)) adapter->flags |= IAVF_FLAG_CLIENT_NEEDS_OPEN; - mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0); + mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); } /** @@ -1414,7 +1413,7 @@ void iavf_down(struct iavf_adapter *adapter) adapter->aq_required |= IAVF_FLAG_AQ_DISABLE_QUEUES; } - mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0); + mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); } /** @@ -2248,7 +2247,7 @@ iavf_set_vlan_offload_features(struct iavf_adapter *adapter, if (aq_required) { adapter->aq_required |= aq_required; - mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0); + mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); } } @@ -2693,6 +2692,15 @@ static void iavf_watchdog_task(struct work_struct *work) goto restart_watchdog; } + if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES) && + adapter->netdev_registered && + !test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section) && + rtnl_trylock()) { + netdev_update_features(adapter->netdev); + rtnl_unlock(); + adapter->flags &= ~IAVF_FLAG_SETUP_NETDEV_FEATURES; + } + if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) iavf_change_state(adapter, __IAVF_COMM_FAILED); @@ -2700,7 +2708,7 @@ static void iavf_watchdog_task(struct work_struct *work) adapter->aq_required = 0; adapter->current_op = VIRTCHNL_OP_UNKNOWN; mutex_unlock(&adapter->crit_lock); - queue_work(iavf_wq, &adapter->reset_task); + queue_work(adapter->wq, &adapter->reset_task); return; } @@ -2708,31 +2716,31 @@ static void iavf_watchdog_task(struct work_struct *work) case __IAVF_STARTUP: iavf_startup(adapter); mutex_unlock(&adapter->crit_lock); - queue_delayed_work(iavf_wq, &adapter->watchdog_task, + queue_delayed_work(adapter->wq, &adapter->watchdog_task, msecs_to_jiffies(30)); return; case __IAVF_INIT_VERSION_CHECK: iavf_init_version_check(adapter); mutex_unlock(&adapter->crit_lock); - queue_delayed_work(iavf_wq, &adapter->watchdog_task, + queue_delayed_work(adapter->wq, &adapter->watchdog_task, msecs_to_jiffies(30)); return; case __IAVF_INIT_GET_RESOURCES: iavf_init_get_resources(adapter); mutex_unlock(&adapter->crit_lock); - queue_delayed_work(iavf_wq, &adapter->watchdog_task, + queue_delayed_work(adapter->wq, &adapter->watchdog_task, msecs_to_jiffies(1)); return; case __IAVF_INIT_EXTENDED_CAPS: iavf_init_process_extended_caps(adapter); mutex_unlock(&adapter->crit_lock); - queue_delayed_work(iavf_wq, &adapter->watchdog_task, + queue_delayed_work(adapter->wq, &adapter->watchdog_task, msecs_to_jiffies(1)); return; case __IAVF_INIT_CONFIG_ADAPTER: iavf_init_config_adapter(adapter); mutex_unlock(&adapter->crit_lock); - queue_delayed_work(iavf_wq, &adapter->watchdog_task, + queue_delayed_work(adapter->wq, &adapter->watchdog_task, msecs_to_jiffies(1)); return; case __IAVF_INIT_FAILED: @@ -2751,14 +2759,14 @@ static void iavf_watchdog_task(struct work_struct *work) adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED; iavf_shutdown_adminq(hw); mutex_unlock(&adapter->crit_lock); - queue_delayed_work(iavf_wq, + queue_delayed_work(adapter->wq, &adapter->watchdog_task, (5 * HZ)); return; } /* Try again from failed step*/ iavf_change_state(adapter, adapter->last_state); mutex_unlock(&adapter->crit_lock); - queue_delayed_work(iavf_wq, &adapter->watchdog_task, HZ); + queue_delayed_work(adapter->wq, &adapter->watchdog_task, HZ); return; case __IAVF_COMM_FAILED: if (test_bit(__IAVF_IN_REMOVE_TASK, @@ -2789,13 +2797,14 @@ static void iavf_watchdog_task(struct work_struct *work) adapter->aq_required = 0; adapter->current_op = VIRTCHNL_OP_UNKNOWN; mutex_unlock(&adapter->crit_lock); - queue_delayed_work(iavf_wq, + queue_delayed_work(adapter->wq, &adapter->watchdog_task, msecs_to_jiffies(10)); return; case __IAVF_RESETTING: mutex_unlock(&adapter->crit_lock); - queue_delayed_work(iavf_wq, &adapter->watchdog_task, HZ * 2); + queue_delayed_work(adapter->wq, &adapter->watchdog_task, + HZ * 2); return; case __IAVF_DOWN: case __IAVF_DOWN_PENDING: @@ -2834,9 +2843,9 @@ static void iavf_watchdog_task(struct work_struct *work) adapter->aq_required = 0; adapter->current_op = VIRTCHNL_OP_UNKNOWN; dev_err(&adapter->pdev->dev, "Hardware reset detected\n"); - queue_work(iavf_wq, &adapter->reset_task); + queue_work(adapter->wq, &adapter->reset_task); mutex_unlock(&adapter->crit_lock); - queue_delayed_work(iavf_wq, + queue_delayed_work(adapter->wq, &adapter->watchdog_task, HZ * 2); return; } @@ -2845,12 +2854,13 @@ static void iavf_watchdog_task(struct work_struct *work) mutex_unlock(&adapter->crit_lock); restart_watchdog: if (adapter->state >= __IAVF_DOWN) - queue_work(iavf_wq, &adapter->adminq_task); + queue_work(adapter->wq, &adapter->adminq_task); if (adapter->aq_required) - queue_delayed_work(iavf_wq, &adapter->watchdog_task, + queue_delayed_work(adapter->wq, &adapter->watchdog_task, msecs_to_jiffies(20)); else - queue_delayed_work(iavf_wq, &adapter->watchdog_task, HZ * 2); + queue_delayed_work(adapter->wq, &adapter->watchdog_task, + HZ * 2); } /** @@ -2952,7 +2962,7 @@ static void iavf_reset_task(struct work_struct *work) */ if (!mutex_trylock(&adapter->crit_lock)) { if (adapter->state != __IAVF_REMOVE) - queue_work(iavf_wq, &adapter->reset_task); + queue_work(adapter->wq, &adapter->reset_task); goto reset_finish; } @@ -3116,7 +3126,7 @@ continue_reset: bitmap_clear(adapter->vsi.active_cvlans, 0, VLAN_N_VID); bitmap_clear(adapter->vsi.active_svlans, 0, VLAN_N_VID); - mod_delayed_work(iavf_wq, &adapter->watchdog_task, 2); + mod_delayed_work(adapter->wq, &adapter->watchdog_task, 2); /* We were running when the reset started, so we need to restore some * state here. @@ -3208,7 +3218,7 @@ static void iavf_adminq_task(struct work_struct *work) if (adapter->state == __IAVF_REMOVE) return; - queue_work(iavf_wq, &adapter->adminq_task); + queue_work(adapter->wq, &adapter->adminq_task); goto out; } @@ -3232,24 +3242,6 @@ static void iavf_adminq_task(struct work_struct *work) } while (pending); mutex_unlock(&adapter->crit_lock); - if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES)) { - if (adapter->netdev_registered || - !test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) { - struct net_device *netdev = adapter->netdev; - - rtnl_lock(); - netdev_update_features(netdev); - rtnl_unlock(); - /* Request VLAN offload settings */ - if (VLAN_V2_ALLOWED(adapter)) - iavf_set_vlan_offload_features - (adapter, 0, netdev->features); - - iavf_set_queue_vlan_tag_loc(adapter); - } - - adapter->flags &= ~IAVF_FLAG_SETUP_NETDEV_FEATURES; - } if ((adapter->flags & (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED)) || adapter->state == __IAVF_RESETTING) @@ -3850,7 +3842,7 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter, field_flags |= IAVF_CLOUD_FIELD_IIP; } else { dev_err(&adapter->pdev->dev, "Bad ip src mask 0x%08x\n", - be32_to_cpu(match.mask->dst)); + be32_to_cpu(match.mask->src)); return -EINVAL; } } @@ -4349,7 +4341,7 @@ static int iavf_change_mtu(struct net_device *netdev, int new_mtu) if (netif_running(netdev)) { adapter->flags |= IAVF_FLAG_RESET_NEEDED; - queue_work(iavf_wq, &adapter->reset_task); + queue_work(adapter->wq, &adapter->reset_task); } return 0; @@ -4898,6 +4890,13 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw = &adapter->hw; hw->back = adapter; + adapter->wq = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, + iavf_driver_name); + if (!adapter->wq) { + err = -ENOMEM; + goto err_alloc_wq; + } + adapter->msg_enable = BIT(DEFAULT_DEBUG_LEVEL_SHIFT) - 1; iavf_change_state(adapter, __IAVF_STARTUP); @@ -4942,7 +4941,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_WORK(&adapter->adminq_task, iavf_adminq_task); INIT_DELAYED_WORK(&adapter->watchdog_task, iavf_watchdog_task); INIT_DELAYED_WORK(&adapter->client_task, iavf_client_task); - queue_delayed_work(iavf_wq, &adapter->watchdog_task, + queue_delayed_work(adapter->wq, &adapter->watchdog_task, msecs_to_jiffies(5 * (pdev->devfn & 0x07))); /* Setup the wait queue for indicating transition to down status */ @@ -4954,6 +4953,8 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; err_ioremap: + destroy_workqueue(adapter->wq); +err_alloc_wq: free_netdev(netdev); err_alloc_etherdev: pci_disable_pcie_error_reporting(pdev); @@ -5023,7 +5024,7 @@ static int __maybe_unused iavf_resume(struct device *dev_d) return err; } - queue_work(iavf_wq, &adapter->reset_task); + queue_work(adapter->wq, &adapter->reset_task); netif_device_attach(adapter->netdev); @@ -5170,6 +5171,8 @@ static void iavf_remove(struct pci_dev *pdev) } spin_unlock_bh(&adapter->adv_rss_lock); + destroy_workqueue(adapter->wq); + free_netdev(netdev); pci_disable_pcie_error_reporting(pdev); @@ -5196,24 +5199,11 @@ static struct pci_driver iavf_driver = { **/ static int __init iavf_init_module(void) { - int ret; - pr_info("iavf: %s\n", iavf_driver_string); pr_info("%s\n", iavf_copyright); - iavf_wq = alloc_workqueue("%s", WQ_UNBOUND | WQ_MEM_RECLAIM, 1, - iavf_driver_name); - if (!iavf_wq) { - pr_err("%s: Failed to create workqueue\n", iavf_driver_name); - return -ENOMEM; - } - - ret = pci_register_driver(&iavf_driver); - if (ret) - destroy_workqueue(iavf_wq); - - return ret; + return pci_register_driver(&iavf_driver); } module_init(iavf_init_module); @@ -5227,7 +5217,6 @@ module_init(iavf_init_module); static void __exit iavf_exit_module(void) { pci_unregister_driver(&iavf_driver); - destroy_workqueue(iavf_wq); } module_exit(iavf_exit_module); diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c index 24a701fd140e..365ca0c710c4 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c @@ -1952,7 +1952,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, if (!(adapter->flags & IAVF_FLAG_RESET_PENDING)) { adapter->flags |= IAVF_FLAG_RESET_PENDING; dev_info(&adapter->pdev->dev, "Scheduling reset task\n"); - queue_work(iavf_wq, &adapter->reset_task); + queue_work(adapter->wq, &adapter->reset_task); } break; default: @@ -2226,6 +2226,14 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, iavf_process_config(adapter); adapter->flags |= IAVF_FLAG_SETUP_NETDEV_FEATURES; + + /* Request VLAN offload settings */ + if (VLAN_V2_ALLOWED(adapter)) + iavf_set_vlan_offload_features(adapter, 0, + netdev->features); + + iavf_set_queue_vlan_tag_loc(adapter); + was_mac_changed = !ether_addr_equal(netdev->dev_addr, adapter->hw.mac.addr); diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 2f0b604abc5e..713069f809ec 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -880,7 +880,7 @@ void ice_set_ethtool_repr_ops(struct net_device *netdev); void ice_set_ethtool_safe_mode_ops(struct net_device *netdev); u16 ice_get_avail_txq_count(struct ice_pf *pf); u16 ice_get_avail_rxq_count(struct ice_pf *pf); -int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx); +int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx, bool locked); void ice_update_vsi_stats(struct ice_vsi *vsi); void ice_update_pf_stats(struct ice_pf *pf); void diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index d02b55b6aa9c..3e08847505ce 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -5524,7 +5524,7 @@ bool ice_fw_supports_report_dflt_cfg(struct ice_hw *hw) * returned by the firmware is a 16 bit * value, but is indexed * by [fls(speed) - 1] */ -static const u32 ice_aq_to_link_speed[15] = { +static const u32 ice_aq_to_link_speed[] = { SPEED_10, /* BIT(0) */ SPEED_100, SPEED_1000, @@ -5536,10 +5536,6 @@ static const u32 ice_aq_to_link_speed[15] = { SPEED_40000, SPEED_50000, SPEED_100000, /* BIT(10) */ - 0, - 0, - 0, - 0 /* BIT(14) */ }; /** @@ -5550,5 +5546,8 @@ static const u32 ice_aq_to_link_speed[15] = { */ u32 ice_get_link_speed(u16 index) { + if (index >= ARRAY_SIZE(ice_aq_to_link_speed)) + return 0; + return ice_aq_to_link_speed[index]; } diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c index 4f24d441c35e..0a55c552189a 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c @@ -441,7 +441,7 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked) goto out; } - ice_pf_dcb_recfg(pf); + ice_pf_dcb_recfg(pf, false); out: /* enable previously downed VSIs */ @@ -731,12 +731,13 @@ static int ice_dcb_noncontig_cfg(struct ice_pf *pf) /** * ice_pf_dcb_recfg - Reconfigure all VEBs and VSIs * @pf: pointer to the PF struct + * @locked: is adev device lock held * * Assumed caller has already disabled all VSIs before * calling this function. Reconfiguring DCB based on * local_dcbx_cfg. */ -void ice_pf_dcb_recfg(struct ice_pf *pf) +void ice_pf_dcb_recfg(struct ice_pf *pf, bool locked) { struct ice_dcbx_cfg *dcbcfg = &pf->hw.port_info->qos_cfg.local_dcbx_cfg; struct iidc_event *event; @@ -783,14 +784,16 @@ void ice_pf_dcb_recfg(struct ice_pf *pf) if (vsi->type == ICE_VSI_PF) ice_dcbnl_set_all(vsi); } - /* Notify the AUX drivers that TC change is finished */ - event = kzalloc(sizeof(*event), GFP_KERNEL); - if (!event) - return; + if (!locked) { + /* Notify the AUX drivers that TC change is finished */ + event = kzalloc(sizeof(*event), GFP_KERNEL); + if (!event) + return; - set_bit(IIDC_EVENT_AFTER_TC_CHANGE, event->type); - ice_send_event_to_aux(pf, event); - kfree(event); + set_bit(IIDC_EVENT_AFTER_TC_CHANGE, event->type); + ice_send_event_to_aux(pf, event); + kfree(event); + } } /** @@ -1044,7 +1047,7 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, } /* changes in configuration update VSI */ - ice_pf_dcb_recfg(pf); + ice_pf_dcb_recfg(pf, false); /* enable previously downed VSIs */ ice_dcb_ena_dis_vsi(pf, true, true); diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h index 4c421c842a13..800879a88c5e 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h @@ -23,7 +23,7 @@ u8 ice_dcb_get_tc(struct ice_vsi *vsi, int queue_index); int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked); int ice_dcb_bwchk(struct ice_pf *pf, struct ice_dcbx_cfg *dcbcfg); -void ice_pf_dcb_recfg(struct ice_pf *pf); +void ice_pf_dcb_recfg(struct ice_pf *pf, bool locked); void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi); int ice_init_pf_dcb(struct ice_pf *pf, bool locked); void ice_update_dcb_stats(struct ice_pf *pf); @@ -128,7 +128,7 @@ static inline u8 ice_get_pfc_mode(struct ice_pf *pf) return 0; } -static inline void ice_pf_dcb_recfg(struct ice_pf *pf) { } +static inline void ice_pf_dcb_recfg(struct ice_pf *pf, bool locked) { } static inline void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi) { } static inline void ice_update_dcb_stats(struct ice_pf *pf) { } static inline void diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.c b/drivers/net/ethernet/intel/ice/ice_devlink.c index 8286e47b4bae..0fae0186bd85 100644 --- a/drivers/net/ethernet/intel/ice/ice_devlink.c +++ b/drivers/net/ethernet/intel/ice/ice_devlink.c @@ -899,7 +899,7 @@ static int ice_set_object_tx_priority(struct ice_port_info *pi, struct ice_sched { int status; - if (node->tx_priority >= 8) { + if (priority >= 8) { NL_SET_ERR_MSG_MOD(extack, "Priority should be less than 8"); return -EINVAL; } @@ -929,7 +929,7 @@ static int ice_set_object_tx_weight(struct ice_port_info *pi, struct ice_sched_n { int status; - if (node->tx_weight > 200 || node->tx_weight < 1) { + if (weight > 200 || weight < 1) { NL_SET_ERR_MSG_MOD(extack, "Weight must be between 1 and 200"); return -EINVAL; } diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 4191994d8f3a..a359f1610fc1 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -3641,7 +3641,9 @@ static int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch) struct ice_vsi *vsi = np->vsi; struct ice_pf *pf = vsi->back; int new_rx = 0, new_tx = 0; + bool locked = false; u32 curr_combined; + int ret = 0; /* do not support changing channels in Safe Mode */ if (ice_is_safe_mode(pf)) { @@ -3705,15 +3707,33 @@ static int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch) return -EINVAL; } - ice_vsi_recfg_qs(vsi, new_rx, new_tx); + if (pf->adev) { + mutex_lock(&pf->adev_mutex); + device_lock(&pf->adev->dev); + locked = true; + if (pf->adev->dev.driver) { + netdev_err(dev, "Cannot change channels when RDMA is active\n"); + ret = -EBUSY; + goto adev_unlock; + } + } + + ice_vsi_recfg_qs(vsi, new_rx, new_tx, locked); - if (!netif_is_rxfh_configured(dev)) - return ice_vsi_set_dflt_rss_lut(vsi, new_rx); + if (!netif_is_rxfh_configured(dev)) { + ret = ice_vsi_set_dflt_rss_lut(vsi, new_rx); + goto adev_unlock; + } /* Update rss_size due to change in Rx queues */ vsi->rss_size = ice_get_valid_rss_size(&pf->hw, new_rx); - return 0; +adev_unlock: + if (locked) { + device_unlock(&pf->adev->dev); + mutex_unlock(&pf->adev_mutex); + } + return ret; } /** diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.c b/drivers/net/ethernet/intel/ice/ice_gnss.c index b5a7f246d230..43e199b5b513 100644 --- a/drivers/net/ethernet/intel/ice/ice_gnss.c +++ b/drivers/net/ethernet/intel/ice/ice_gnss.c @@ -363,6 +363,7 @@ ice_gnss_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) /* Send the data out to a hardware port */ write_buf = kzalloc(sizeof(*write_buf), GFP_KERNEL); if (!write_buf) { + kfree(cmd_buf); err = -ENOMEM; goto exit; } @@ -460,6 +461,9 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf) for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) { pf->gnss_tty_port[i] = kzalloc(sizeof(*pf->gnss_tty_port[i]), GFP_KERNEL); + if (!pf->gnss_tty_port[i]) + goto err_out; + pf->gnss_serial[i] = NULL; tty_port_init(pf->gnss_tty_port[i]); @@ -469,21 +473,23 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf) err = tty_register_driver(tty_driver); if (err) { dev_err(dev, "Failed to register TTY driver err=%d\n", err); - - for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) { - tty_port_destroy(pf->gnss_tty_port[i]); - kfree(pf->gnss_tty_port[i]); - } - kfree(ttydrv_name); - tty_driver_kref_put(pf->ice_gnss_tty_driver); - - return NULL; + goto err_out; } for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) dev_info(dev, "%s%d registered\n", ttydrv_name, i); return tty_driver; + +err_out: + while (i--) { + tty_port_destroy(pf->gnss_tty_port[i]); + kfree(pf->gnss_tty_port[i]); + } + kfree(ttydrv_name); + tty_driver_kref_put(pf->ice_gnss_tty_driver); + + return NULL; } /** diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 94aa834cd9a6..a596e07b3ce9 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -3235,9 +3235,6 @@ int ice_vsi_release(struct ice_vsi *vsi) } } - if (vsi->type == ICE_VSI_PF) - ice_devlink_destroy_pf_port(pf); - if (vsi->type == ICE_VSI_VF && vsi->agg_node && vsi->agg_node->valid) vsi->agg_node->num_vsis--; diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index a9a7f8b52140..8ec24f6cf6be 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -275,6 +275,8 @@ static int ice_set_promisc(struct ice_vsi *vsi, u8 promisc_m) if (status && status != -EEXIST) return status; + netdev_dbg(vsi->netdev, "set promisc filter bits for VSI %i: 0x%x\n", + vsi->vsi_num, promisc_m); return 0; } @@ -300,6 +302,8 @@ static int ice_clear_promisc(struct ice_vsi *vsi, u8 promisc_m) promisc_m, 0); } + netdev_dbg(vsi->netdev, "clear promisc filter bits for VSI %i: 0x%x\n", + vsi->vsi_num, promisc_m); return status; } @@ -414,6 +418,16 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) } err = 0; vlan_ops->dis_rx_filtering(vsi); + + /* promiscuous mode implies allmulticast so + * that VSIs that are in promiscuous mode are + * subscribed to multicast packets coming to + * the port + */ + err = ice_set_promisc(vsi, + ICE_MCAST_PROMISC_BITS); + if (err) + goto out_promisc; } } else { /* Clear Rx filter to remove traffic from wire */ @@ -430,6 +444,18 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) NETIF_F_HW_VLAN_CTAG_FILTER) vlan_ops->ena_rx_filtering(vsi); } + + /* disable allmulti here, but only if allmulti is not + * still enabled for the netdev + */ + if (!(vsi->current_netdev_flags & IFF_ALLMULTI)) { + err = ice_clear_promisc(vsi, + ICE_MCAST_PROMISC_BITS); + if (err) { + netdev_err(netdev, "Error %d clearing multicast promiscuous on VSI %i\n", + err, vsi->vsi_num); + } + } } } goto exit; @@ -4195,12 +4221,13 @@ bool ice_is_wol_supported(struct ice_hw *hw) * @vsi: VSI being changed * @new_rx: new number of Rx queues * @new_tx: new number of Tx queues + * @locked: is adev device_lock held * * Only change the number of queues if new_tx, or new_rx is non-0. * * Returns 0 on success. */ -int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx) +int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx, bool locked) { struct ice_pf *pf = vsi->back; int err = 0, timeout = 50; @@ -4229,7 +4256,7 @@ int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx) ice_vsi_close(vsi); ice_vsi_rebuild(vsi, false); - ice_pf_dcb_recfg(pf); + ice_pf_dcb_recfg(pf, locked); ice_vsi_open(vsi); done: clear_bit(ICE_CFG_BUSY, pf->state); @@ -4590,7 +4617,7 @@ static void ice_print_wake_reason(struct ice_pf *pf) } /** - * ice_register_netdev - register netdev and devlink port + * ice_register_netdev - register netdev * @pf: pointer to the PF struct */ static int ice_register_netdev(struct ice_pf *pf) @@ -4602,11 +4629,6 @@ static int ice_register_netdev(struct ice_pf *pf) if (!vsi || !vsi->netdev) return -EIO; - err = ice_devlink_create_pf_port(pf); - if (err) - goto err_devlink_create; - - SET_NETDEV_DEVLINK_PORT(vsi->netdev, &pf->devlink_port); err = register_netdev(vsi->netdev); if (err) goto err_register_netdev; @@ -4617,8 +4639,6 @@ static int ice_register_netdev(struct ice_pf *pf) return 0; err_register_netdev: - ice_devlink_destroy_pf_port(pf); -err_devlink_create: free_netdev(vsi->netdev); vsi->netdev = NULL; clear_bit(ICE_VSI_NETDEV_ALLOCD, vsi->state); @@ -4636,6 +4656,7 @@ static int ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) { struct device *dev = &pdev->dev; + struct ice_vsi *vsi; struct ice_pf *pf; struct ice_hw *hw; int i, err; @@ -4918,6 +4939,18 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) pcie_print_link_status(pf->pdev); probe_done: + err = ice_devlink_create_pf_port(pf); + if (err) + goto err_create_pf_port; + + vsi = ice_get_main_vsi(pf); + if (!vsi || !vsi->netdev) { + err = -EINVAL; + goto err_netdev_reg; + } + + SET_NETDEV_DEVLINK_PORT(vsi->netdev, &pf->devlink_port); + err = ice_register_netdev(pf); if (err) goto err_netdev_reg; @@ -4955,6 +4988,8 @@ err_init_aux_unroll: err_devlink_reg_param: ice_devlink_unregister_params(pf); err_netdev_reg: + ice_devlink_destroy_pf_port(pf); +err_create_pf_port: err_send_version_unroll: ice_vsi_release_all(pf); err_alloc_sw_unroll: @@ -5083,6 +5118,7 @@ static void ice_remove(struct pci_dev *pdev) ice_setup_mc_magic_wake(pf); ice_vsi_release_all(pf); mutex_destroy(&(&pf->hw)->fdir_fltr_lock); + ice_devlink_destroy_pf_port(pf); ice_set_wake(pf); ice_free_irq_msix_misc(pf); ice_for_each_vsi(pf, i) { @@ -5531,7 +5567,7 @@ static int __init ice_module_init(void) pr_info("%s\n", ice_driver_string); pr_info("%s\n", ice_copyright); - ice_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 0, KBUILD_MODNAME); + ice_wq = alloc_workqueue("%s", 0, 0, KBUILD_MODNAME); if (!ice_wq) { pr_err("Failed to create workqueue\n"); return -ENOMEM; diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 9b762f7972ce..61f844d22512 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -5420,7 +5420,7 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, */ status = ice_add_special_words(rinfo, lkup_exts, ice_is_dvm_ena(hw)); if (status) - goto err_free_lkup_exts; + goto err_unroll; /* Group match words into recipes using preferred recipe grouping * criteria. diff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.c b/drivers/net/ethernet/intel/ice/ice_tc_lib.c index faba0f857cd9..95f392ab9670 100644 --- a/drivers/net/ethernet/intel/ice/ice_tc_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.c @@ -1681,7 +1681,7 @@ ice_tc_forward_to_queue(struct ice_vsi *vsi, struct ice_tc_flower_fltr *fltr, struct ice_vsi *ch_vsi = NULL; u16 queue = act->rx_queue; - if (queue > vsi->num_rxq) { + if (queue >= vsi->num_rxq) { NL_SET_ERR_MSG_MOD(fltr->extack, "Unable to add filter because specified queue is invalid"); return -EINVAL; diff --git a/drivers/net/ethernet/intel/ice/ice_vf_mbx.c b/drivers/net/ethernet/intel/ice/ice_vf_mbx.c index d4a4001b6e5d..f56fa94ff3d0 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_mbx.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_mbx.c @@ -39,7 +39,7 @@ ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval, return ice_sq_send_cmd(hw, &hw->mailboxq, &desc, msg, msglen, cd); } -static const u32 ice_legacy_aq_to_vc_speed[15] = { +static const u32 ice_legacy_aq_to_vc_speed[] = { VIRTCHNL_LINK_SPEED_100MB, /* BIT(0) */ VIRTCHNL_LINK_SPEED_100MB, VIRTCHNL_LINK_SPEED_1GB, @@ -51,10 +51,6 @@ static const u32 ice_legacy_aq_to_vc_speed[15] = { VIRTCHNL_LINK_SPEED_40GB, VIRTCHNL_LINK_SPEED_40GB, VIRTCHNL_LINK_SPEED_40GB, - VIRTCHNL_LINK_SPEED_UNKNOWN, - VIRTCHNL_LINK_SPEED_UNKNOWN, - VIRTCHNL_LINK_SPEED_UNKNOWN, - VIRTCHNL_LINK_SPEED_UNKNOWN /* BIT(14) */ }; /** @@ -71,21 +67,20 @@ static const u32 ice_legacy_aq_to_vc_speed[15] = { */ u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed) { - u32 speed; + /* convert a BIT() value into an array index */ + u32 index = fls(link_speed) - 1; - if (adv_link_support) { - /* convert a BIT() value into an array index */ - speed = ice_get_link_speed(fls(link_speed) - 1); - } else { + if (adv_link_support) + return ice_get_link_speed(index); + else if (index < ARRAY_SIZE(ice_legacy_aq_to_vc_speed)) /* Virtchnl speeds are not defined for every speed supported in * the hardware. To maintain compatibility with older AVF * drivers, while reporting the speed the new speed values are * resolved to the closest known virtchnl speeds */ - speed = ice_legacy_aq_to_vc_speed[fls(link_speed) - 1]; - } + return ice_legacy_aq_to_vc_speed[index]; - return speed; + return VIRTCHNL_LINK_SPEED_UNKNOWN; } /* The mailbox overflow detection algorithm helps to check if there diff --git a/drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.c b/drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.c index 5ecc0ee9a78e..b1ffb81893d4 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.c @@ -44,13 +44,17 @@ void ice_vf_vsi_init_vlan_ops(struct ice_vsi *vsi) /* outer VLAN ops regardless of port VLAN config */ vlan_ops->add_vlan = ice_vsi_add_vlan; - vlan_ops->dis_rx_filtering = ice_vsi_dis_rx_vlan_filtering; vlan_ops->ena_tx_filtering = ice_vsi_ena_tx_vlan_filtering; vlan_ops->dis_tx_filtering = ice_vsi_dis_tx_vlan_filtering; if (ice_vf_is_port_vlan_ena(vf)) { /* setup outer VLAN ops */ vlan_ops->set_port_vlan = ice_vsi_set_outer_port_vlan; + /* all Rx traffic should be in the domain of the + * assigned port VLAN, so prevent disabling Rx VLAN + * filtering + */ + vlan_ops->dis_rx_filtering = noop_vlan; vlan_ops->ena_rx_filtering = ice_vsi_ena_rx_vlan_filtering; @@ -63,6 +67,9 @@ void ice_vf_vsi_init_vlan_ops(struct ice_vsi *vsi) vlan_ops->ena_insertion = ice_vsi_ena_inner_insertion; vlan_ops->dis_insertion = ice_vsi_dis_inner_insertion; } else { + vlan_ops->dis_rx_filtering = + ice_vsi_dis_rx_vlan_filtering; + if (!test_bit(ICE_FLAG_VF_VLAN_PRUNING, pf->flags)) vlan_ops->ena_rx_filtering = noop_vlan; else @@ -96,7 +103,14 @@ void ice_vf_vsi_init_vlan_ops(struct ice_vsi *vsi) vlan_ops->set_port_vlan = ice_vsi_set_inner_port_vlan; vlan_ops->ena_rx_filtering = ice_vsi_ena_rx_vlan_filtering; + /* all Rx traffic should be in the domain of the + * assigned port VLAN, so prevent disabling Rx VLAN + * filtering + */ + vlan_ops->dis_rx_filtering = noop_vlan; } else { + vlan_ops->dis_rx_filtering = + ice_vsi_dis_rx_vlan_filtering; if (!test_bit(ICE_FLAG_VF_VLAN_PRUNING, pf->flags)) vlan_ops->ena_rx_filtering = noop_vlan; else diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c index 907055b77af0..374b7f10b549 100644 --- a/drivers/net/ethernet/intel/ice/ice_xsk.c +++ b/drivers/net/ethernet/intel/ice/ice_xsk.c @@ -783,7 +783,7 @@ construct_skb: static void ice_clean_xdp_tx_buf(struct ice_tx_ring *xdp_ring, struct ice_tx_buf *tx_buf) { - xdp_return_frame((struct xdp_frame *)tx_buf->raw_buf); + page_frag_free(tx_buf->raw_buf); xdp_ring->xdp_tx_active--; dma_unmap_single(xdp_ring->dev, dma_unmap_addr(tx_buf, dma), dma_unmap_len(tx_buf, len), DMA_TO_DEVICE); @@ -800,6 +800,7 @@ static void ice_clean_xdp_irq_zc(struct ice_tx_ring *xdp_ring) struct ice_tx_desc *tx_desc; u16 cnt = xdp_ring->count; struct ice_tx_buf *tx_buf; + u16 completed_frames = 0; u16 xsk_frames = 0; u16 last_rs; int i; @@ -809,19 +810,21 @@ static void ice_clean_xdp_irq_zc(struct ice_tx_ring *xdp_ring) if ((tx_desc->cmd_type_offset_bsz & cpu_to_le64(ICE_TX_DESC_DTYPE_DESC_DONE))) { if (last_rs >= ntc) - xsk_frames = last_rs - ntc + 1; + completed_frames = last_rs - ntc + 1; else - xsk_frames = last_rs + cnt - ntc + 1; + completed_frames = last_rs + cnt - ntc + 1; } - if (!xsk_frames) + if (!completed_frames) return; - if (likely(!xdp_ring->xdp_tx_active)) + if (likely(!xdp_ring->xdp_tx_active)) { + xsk_frames = completed_frames; goto skip; + } ntc = xdp_ring->next_to_clean; - for (i = 0; i < xsk_frames; i++) { + for (i = 0; i < completed_frames; i++) { tx_buf = &xdp_ring->tx_buf[ntc]; if (tx_buf->raw_buf) { @@ -837,7 +840,7 @@ static void ice_clean_xdp_irq_zc(struct ice_tx_ring *xdp_ring) } skip: tx_desc->cmd_type_offset_bsz = 0; - xdp_ring->next_to_clean += xsk_frames; + xdp_ring->next_to_clean += completed_frames; if (xdp_ring->next_to_clean >= cnt) xdp_ring->next_to_clean -= cnt; if (xsk_frames) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 3c0c35ecea10..b5b443883da9 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -2256,6 +2256,30 @@ static void igb_enable_mas(struct igb_adapter *adapter) } } +#ifdef CONFIG_IGB_HWMON +/** + * igb_set_i2c_bb - Init I2C interface + * @hw: pointer to hardware structure + **/ +static void igb_set_i2c_bb(struct e1000_hw *hw) +{ + u32 ctrl_ext; + s32 i2cctl; + + ctrl_ext = rd32(E1000_CTRL_EXT); + ctrl_ext |= E1000_CTRL_I2C_ENA; + wr32(E1000_CTRL_EXT, ctrl_ext); + wrfl(); + + i2cctl = rd32(E1000_I2CPARAMS); + i2cctl |= E1000_I2CBB_EN + | E1000_I2C_CLK_OE_N + | E1000_I2C_DATA_OE_N; + wr32(E1000_I2CPARAMS, i2cctl); + wrfl(); +} +#endif + void igb_reset(struct igb_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; @@ -2400,7 +2424,8 @@ void igb_reset(struct igb_adapter *adapter) * interface. */ if (adapter->ets) - mac->ops.init_thermal_sensor_thresh(hw); + igb_set_i2c_bb(hw); + mac->ops.init_thermal_sensor_thresh(hw); } } #endif @@ -3117,21 +3142,12 @@ static void igb_init_mas(struct igb_adapter *adapter) **/ static s32 igb_init_i2c(struct igb_adapter *adapter) { - struct e1000_hw *hw = &adapter->hw; s32 status = 0; - s32 i2cctl; /* I2C interface supported on i350 devices */ if (adapter->hw.mac.type != e1000_i350) return 0; - i2cctl = rd32(E1000_I2CPARAMS); - i2cctl |= E1000_I2CBB_EN - | E1000_I2C_CLK_OUT | E1000_I2C_CLK_OE_N - | E1000_I2C_DATA_OUT | E1000_I2C_DATA_OE_N; - wr32(E1000_I2CPARAMS, i2cctl); - wrfl(); - /* Initialize the i2c bus which is controlled by the registers. * This bus will use the i2c_algo_bit structure that implements * the protocol through toggling of the 4 bits in the register. @@ -3521,6 +3537,12 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->ets = true; else adapter->ets = false; + /* Only enable I2C bit banging if an external thermal + * sensor is supported. + */ + if (adapter->ets) + igb_set_i2c_bb(hw); + hw->mac.ops.init_thermal_sensor_thresh(hw); if (igb_sysfs_init(adapter)) dev_err(&pdev->dev, "failed to allocate sysfs resources\n"); @@ -6794,7 +6816,7 @@ static void igb_perout(struct igb_adapter *adapter, int tsintr_tt) struct timespec64 ts; u32 tsauxc; - if (pin < 0 || pin >= IGB_N_PEROUT) + if (pin < 0 || pin >= IGB_N_SDP) return; spin_lock(&adapter->tmreg_lock); @@ -6802,7 +6824,7 @@ static void igb_perout(struct igb_adapter *adapter, int tsintr_tt) if (hw->mac.type == e1000_82580 || hw->mac.type == e1000_i354 || hw->mac.type == e1000_i350) { - s64 ns = timespec64_to_ns(&adapter->perout[pin].period); + s64 ns = timespec64_to_ns(&adapter->perout[tsintr_tt].period); u32 systiml, systimh, level_mask, level, rem; u64 systim, now; @@ -6850,8 +6872,8 @@ static void igb_perout(struct igb_adapter *adapter, int tsintr_tt) ts.tv_nsec = (u32)systim; ts.tv_sec = ((u32)(systim >> 32)) & 0xFF; } else { - ts = timespec64_add(adapter->perout[pin].start, - adapter->perout[pin].period); + ts = timespec64_add(adapter->perout[tsintr_tt].start, + adapter->perout[tsintr_tt].period); } /* u32 conversion of tv_sec is safe until y2106 */ @@ -6860,7 +6882,7 @@ static void igb_perout(struct igb_adapter *adapter, int tsintr_tt) tsauxc = rd32(E1000_TSAUXC); tsauxc |= TSAUXC_EN_TT0; wr32(E1000_TSAUXC, tsauxc); - adapter->perout[pin].start = ts; + adapter->perout[tsintr_tt].start = ts; spin_unlock(&adapter->tmreg_lock); } @@ -6874,7 +6896,7 @@ static void igb_extts(struct igb_adapter *adapter, int tsintr_tt) struct ptp_clock_event event; struct timespec64 ts; - if (pin < 0 || pin >= IGB_N_EXTTS) + if (pin < 0 || pin >= IGB_N_SDP) return; if (hw->mac.type == e1000_82580 || diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index a7b22639cfcd..e9747ec5ac0b 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -475,7 +475,9 @@ #define IGC_TSAUXC_EN_TT0 BIT(0) /* Enable target time 0. */ #define IGC_TSAUXC_EN_TT1 BIT(1) /* Enable target time 1. */ #define IGC_TSAUXC_EN_CLK0 BIT(2) /* Enable Configurable Frequency Clock 0. */ +#define IGC_TSAUXC_ST0 BIT(4) /* Start Clock 0 Toggle on Target Time 0. */ #define IGC_TSAUXC_EN_CLK1 BIT(5) /* Enable Configurable Frequency Clock 1. */ +#define IGC_TSAUXC_ST1 BIT(7) /* Start Clock 1 Toggle on Target Time 1. */ #define IGC_TSAUXC_EN_TS0 BIT(8) /* Enable hardware timestamp 0. */ #define IGC_TSAUXC_AUTT0 BIT(9) /* Auxiliary Timestamp Taken. */ #define IGC_TSAUXC_EN_TS1 BIT(10) /* Enable hardware timestamp 0. */ diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 44b1740dc098..1dd2a7fee8d4 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2942,7 +2942,9 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget) if (tx_buffer->next_to_watch && time_after(jiffies, tx_buffer->time_stamp + (adapter->tx_timeout_factor * HZ)) && - !(rd32(IGC_STATUS) & IGC_STATUS_TXOFF)) { + !(rd32(IGC_STATUS) & IGC_STATUS_TXOFF) && + (rd32(IGC_TDH(tx_ring->reg_idx)) != + readl(tx_ring->tail))) { /* detected Tx unit hang */ netdev_err(tx_ring->netdev, "Detected Tx Unit Hang\n" @@ -5069,6 +5071,24 @@ static int igc_change_mtu(struct net_device *netdev, int new_mtu) } /** + * igc_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + * @txqueue: queue number that timed out + **/ +static void igc_tx_timeout(struct net_device *netdev, + unsigned int __always_unused txqueue) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; + + /* Do the reset outside of interrupt context */ + adapter->tx_timeout_count++; + schedule_work(&adapter->reset_task); + wr32(IGC_EICS, + (adapter->eims_enable_mask & ~adapter->eims_other)); +} + +/** * igc_get_stats64 - Get System Network Statistics * @netdev: network interface device structure * @stats: rtnl_link_stats64 pointer @@ -5495,7 +5515,7 @@ static void igc_watchdog_task(struct work_struct *work) case SPEED_100: case SPEED_1000: case SPEED_2500: - adapter->tx_timeout_factor = 7; + adapter->tx_timeout_factor = 1; break; } @@ -6320,6 +6340,7 @@ static const struct net_device_ops igc_netdev_ops = { .ndo_set_rx_mode = igc_set_rx_mode, .ndo_set_mac_address = igc_set_mac, .ndo_change_mtu = igc_change_mtu, + .ndo_tx_timeout = igc_tx_timeout, .ndo_get_stats64 = igc_get_stats64, .ndo_fix_features = igc_fix_features, .ndo_set_features = igc_set_features, diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c index 8dbb9f903ca7..4e10ced736db 100644 --- a/drivers/net/ethernet/intel/igc/igc_ptp.c +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -322,7 +322,7 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp, ts = ns_to_timespec64(ns); if (rq->perout.index == 1) { if (use_freq) { - tsauxc_mask = IGC_TSAUXC_EN_CLK1; + tsauxc_mask = IGC_TSAUXC_EN_CLK1 | IGC_TSAUXC_ST1; tsim_mask = 0; } else { tsauxc_mask = IGC_TSAUXC_EN_TT1; @@ -333,7 +333,7 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp, freqout = IGC_FREQOUT1; } else { if (use_freq) { - tsauxc_mask = IGC_TSAUXC_EN_CLK0; + tsauxc_mask = IGC_TSAUXC_EN_CLK0 | IGC_TSAUXC_ST0; tsim_mask = 0; } else { tsauxc_mask = IGC_TSAUXC_EN_TT0; @@ -347,10 +347,12 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp, tsauxc = rd32(IGC_TSAUXC); tsim = rd32(IGC_TSIM); if (rq->perout.index == 1) { - tsauxc &= ~(IGC_TSAUXC_EN_TT1 | IGC_TSAUXC_EN_CLK1); + tsauxc &= ~(IGC_TSAUXC_EN_TT1 | IGC_TSAUXC_EN_CLK1 | + IGC_TSAUXC_ST1); tsim &= ~IGC_TSICR_TT1; } else { - tsauxc &= ~(IGC_TSAUXC_EN_TT0 | IGC_TSAUXC_EN_CLK0); + tsauxc &= ~(IGC_TSAUXC_EN_TT0 | IGC_TSAUXC_EN_CLK0 | + IGC_TSAUXC_ST0); tsim &= ~IGC_TSICR_TT0; } if (on) { @@ -415,10 +417,12 @@ static int igc_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin, * * We need to convert the system time value stored in the RX/TXSTMP registers * into a hwtstamp which can be used by the upper level timestamping functions. + * + * Returns 0 on success. **/ -static void igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter, - struct skb_shared_hwtstamps *hwtstamps, - u64 systim) +static int igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter, + struct skb_shared_hwtstamps *hwtstamps, + u64 systim) { switch (adapter->hw.mac.type) { case igc_i225: @@ -428,8 +432,9 @@ static void igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter, systim & 0xFFFFFFFF); break; default: - break; + return -EINVAL; } + return 0; } /** @@ -650,7 +655,8 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) regval = rd32(IGC_TXSTMPL); regval |= (u64)rd32(IGC_TXSTMPH) << 32; - igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval); + if (igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval)) + return; switch (adapter->link_speed) { case SPEED_10: diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index bc68b8f2176d..8736ca4b2628 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -73,6 +73,8 @@ #define IXGBE_RXBUFFER_4K 4096 #define IXGBE_MAX_RXBUFFER 16384 /* largest size for a single descriptor */ +#define IXGBE_PKT_HDR_PAD (ETH_HLEN + ETH_FCS_LEN + (VLAN_HLEN * 2)) + /* Attempt to maximize the headroom available for incoming frames. We * use a 2K buffer for receives and need 1536/1534 to store the data for * the frame. This leaves us with 512 bytes of room. From that we need diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index ab8370c413f3..4507fba8747a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6778,6 +6778,18 @@ static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter) } /** + * ixgbe_max_xdp_frame_size - returns the maximum allowed frame size for XDP + * @adapter: device handle, pointer to adapter + */ +static int ixgbe_max_xdp_frame_size(struct ixgbe_adapter *adapter) +{ + if (PAGE_SIZE >= 8192 || adapter->flags2 & IXGBE_FLAG2_RX_LEGACY) + return IXGBE_RXBUFFER_2K; + else + return IXGBE_RXBUFFER_3K; +} + +/** * ixgbe_change_mtu - Change the Maximum Transfer Unit * @netdev: network interface device structure * @new_mtu: new value for maximum frame size @@ -6788,18 +6800,12 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - if (adapter->xdp_prog) { - int new_frame_size = new_mtu + ETH_HLEN + ETH_FCS_LEN + - VLAN_HLEN; - int i; - - for (i = 0; i < adapter->num_rx_queues; i++) { - struct ixgbe_ring *ring = adapter->rx_ring[i]; + if (ixgbe_enabled_xdp_adapter(adapter)) { + int new_frame_size = new_mtu + IXGBE_PKT_HDR_PAD; - if (new_frame_size > ixgbe_rx_bufsz(ring)) { - e_warn(probe, "Requested MTU size is not supported with XDP\n"); - return -EINVAL; - } + if (new_frame_size > ixgbe_max_xdp_frame_size(adapter)) { + e_warn(probe, "Requested MTU size is not supported with XDP\n"); + return -EINVAL; } } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index 24aa97f993ca..123dca9ce468 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -855,9 +855,11 @@ static struct pci_dev *ixgbe_get_first_secondary_devfn(unsigned int devfn) rp_pdev = pci_get_domain_bus_and_slot(0, 0, devfn); if (rp_pdev && rp_pdev->subordinate) { bus = rp_pdev->subordinate->number; + pci_dev_put(rp_pdev); return pci_get_domain_bus_and_slot(0, bus, 0); } + pci_dev_put(rp_pdev); return NULL; } @@ -874,6 +876,7 @@ static bool ixgbe_x550em_a_has_mii(struct ixgbe_hw *hw) struct ixgbe_adapter *adapter = hw->back; struct pci_dev *pdev = adapter->pdev; struct pci_dev *func0_pdev; + bool has_mii = false; /* For the C3000 family of SoCs (x550em_a) the internal ixgbe devices * are always downstream of root ports @ 0000:00:16.0 & 0000:00:17.0 @@ -884,15 +887,16 @@ static bool ixgbe_x550em_a_has_mii(struct ixgbe_hw *hw) func0_pdev = ixgbe_get_first_secondary_devfn(PCI_DEVFN(0x16, 0)); if (func0_pdev) { if (func0_pdev == pdev) - return true; - else - return false; + has_mii = true; + goto out; } func0_pdev = ixgbe_get_first_secondary_devfn(PCI_DEVFN(0x17, 0)); if (func0_pdev == pdev) - return true; + has_mii = true; - return false; +out: + pci_dev_put(func0_pdev); + return has_mii; } /** diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index b2b71fe80d61..724df6398bbe 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -774,9 +774,9 @@ int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable) cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_CFG); if (enable) - cfg |= CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN; + cfg |= DATA_PKT_RX_EN | DATA_PKT_TX_EN; else - cfg &= ~(CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN); + cfg &= ~(DATA_PKT_RX_EN | DATA_PKT_TX_EN); cgx_write(cgx, lmac_id, CGXX_CMRX_CFG, cfg); return 0; } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h index fb2d37676d84..5a20d93004c7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h @@ -26,7 +26,6 @@ #define CMR_P2X_SEL_SHIFT 59ULL #define CMR_P2X_SEL_NIX0 1ULL #define CMR_P2X_SEL_NIX1 2ULL -#define CMR_EN BIT_ULL(55) #define DATA_PKT_TX_EN BIT_ULL(53) #define DATA_PKT_RX_EN BIT_ULL(54) #define CGX_LMAC_TYPE_SHIFT 40 diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c b/drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c index fa8029a94068..eb25e458266c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c @@ -589,7 +589,7 @@ int rvu_mbox_handler_mcs_free_resources(struct rvu *rvu, u16 pcifunc = req->hdr.pcifunc; struct mcs_rsrc_map *map; struct mcs *mcs; - int rc; + int rc = 0; if (req->mcs_id >= rvu->mcs_blk_cnt) return MCS_AF_ERR_INVALID_MCSID; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c index bda1a6fa2ec4..e4407f09c9d3 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c @@ -1500,6 +1500,9 @@ static const struct devlink_param rvu_af_dl_params[] = { BIT(DEVLINK_PARAM_CMODE_RUNTIME), rvu_af_dl_dwrr_mtu_get, rvu_af_dl_dwrr_mtu_set, rvu_af_dl_dwrr_mtu_validate), +}; + +static const struct devlink_param rvu_af_dl_param_exact_match[] = { DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE, "npc_exact_feature_disable", DEVLINK_PARAM_TYPE_STRING, BIT(DEVLINK_PARAM_CMODE_RUNTIME), @@ -1556,7 +1559,6 @@ int rvu_register_dl(struct rvu *rvu) { struct rvu_devlink *rvu_dl; struct devlink *dl; - size_t size; int err; dl = devlink_alloc(&rvu_devlink_ops, sizeof(struct rvu_devlink), @@ -1578,21 +1580,32 @@ int rvu_register_dl(struct rvu *rvu) goto err_dl_health; } + err = devlink_params_register(dl, rvu_af_dl_params, ARRAY_SIZE(rvu_af_dl_params)); + if (err) { + dev_err(rvu->dev, + "devlink params register failed with error %d", err); + goto err_dl_health; + } + /* Register exact match devlink only for CN10K-B */ - size = ARRAY_SIZE(rvu_af_dl_params); if (!rvu_npc_exact_has_match_table(rvu)) - size -= 1; + goto done; - err = devlink_params_register(dl, rvu_af_dl_params, size); + err = devlink_params_register(dl, rvu_af_dl_param_exact_match, + ARRAY_SIZE(rvu_af_dl_param_exact_match)); if (err) { dev_err(rvu->dev, - "devlink params register failed with error %d", err); - goto err_dl_health; + "devlink exact match params register failed with error %d", err); + goto err_dl_exact_match; } +done: devlink_register(dl); return 0; +err_dl_exact_match: + devlink_params_unregister(dl, rvu_af_dl_params, ARRAY_SIZE(rvu_af_dl_params)); + err_dl_health: rvu_health_reporters_destroy(rvu); devlink_free(dl); @@ -1605,8 +1618,14 @@ void rvu_unregister_dl(struct rvu *rvu) struct devlink *dl = rvu_dl->dl; devlink_unregister(dl); - devlink_params_unregister(dl, rvu_af_dl_params, - ARRAY_SIZE(rvu_af_dl_params)); + + devlink_params_unregister(dl, rvu_af_dl_params, ARRAY_SIZE(rvu_af_dl_params)); + + /* Unregister exact match devlink only for CN10K-B */ + if (rvu_npc_exact_has_match_table(rvu)) + devlink_params_unregister(dl, rvu_af_dl_param_exact_match, + ARRAY_SIZE(rvu_af_dl_param_exact_match)); + rvu_health_reporters_destroy(rvu); devlink_free(dl); } diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c index 9e10e7471b88..8a41ad8ca04f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c @@ -1376,18 +1376,23 @@ int otx2_sq_aura_pool_init(struct otx2_nic *pfvf) sq = &qset->sq[qidx]; sq->sqb_count = 0; sq->sqb_ptrs = kcalloc(num_sqbs, sizeof(*sq->sqb_ptrs), GFP_KERNEL); - if (!sq->sqb_ptrs) - return -ENOMEM; + if (!sq->sqb_ptrs) { + err = -ENOMEM; + goto err_mem; + } for (ptr = 0; ptr < num_sqbs; ptr++) { - if (otx2_alloc_rbuf(pfvf, pool, &bufptr)) - return -ENOMEM; + err = otx2_alloc_rbuf(pfvf, pool, &bufptr); + if (err) + goto err_mem; pfvf->hw_ops->aura_freeptr(pfvf, pool_id, bufptr); sq->sqb_ptrs[sq->sqb_count++] = (u64)bufptr; } } - return 0; +err_mem: + return err ? -ENOMEM : 0; + fail: otx2_mbox_reset(&pfvf->mbox.mbox, 0); otx2_aura_pool_free(pfvf); @@ -1430,13 +1435,13 @@ int otx2_rq_aura_pool_init(struct otx2_nic *pfvf) for (pool_id = 0; pool_id < hw->rqpool_cnt; pool_id++) { pool = &pfvf->qset.pool[pool_id]; for (ptr = 0; ptr < num_ptrs; ptr++) { - if (otx2_alloc_rbuf(pfvf, pool, &bufptr)) + err = otx2_alloc_rbuf(pfvf, pool, &bufptr); + if (err) return -ENOMEM; pfvf->hw_ops->aura_freeptr(pfvf, pool_id, bufptr + OTX2_HEAD_ROOM); } } - return 0; fail: otx2_mbox_reset(&pfvf->mbox.mbox, 0); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index 5bee3c3a7ce4..3d22cc6a2804 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -736,8 +736,10 @@ static inline void cn10k_aura_freeptr(void *dev, int aura, u64 buf) u64 ptrs[2]; ptrs[1] = buf; + get_cpu(); /* Free only one buffer at time during init and teardown */ __cn10k_aura_freeptr(pfvf, aura, ptrs, 2); + put_cpu(); } /* Alloc pointer from pool/aura */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c index 86653bb8e403..7f8ffbf79cf7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c @@ -758,6 +758,8 @@ static void otx2vf_remove(struct pci_dev *pdev) if (vf->otx2_wq) destroy_workqueue(vf->otx2_wq); otx2_ptp_destroy(vf); + otx2_mcam_flow_del(vf); + otx2_shutdown_tc(vf); otx2vf_disable_mbox_intr(vf); otx2_detach_resources(&vf->mbox); if (test_bit(CN10K_LMTST, &vf->hw.cap_flag)) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index e3de9a53b2d9..e3123723522e 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -1570,8 +1570,8 @@ static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth, if (IS_ERR(pp)) return pp; - err = __xdp_rxq_info_reg(xdp_q, ð->dummy_dev, eth->rx_napi.napi_id, - id, PAGE_SIZE); + err = __xdp_rxq_info_reg(xdp_q, ð->dummy_dev, id, + eth->rx_napi.napi_id, PAGE_SIZE); if (err < 0) goto err_free_pp; @@ -1870,7 +1870,9 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, while (done < budget) { unsigned int pktlen, *rxdcsum; + bool has_hwaccel_tag = false; struct net_device *netdev; + u16 vlan_proto, vlan_tci; dma_addr_t dma_addr; u32 hash, reason; int mac = 0; @@ -2010,27 +2012,29 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { - if (trxd.rxd3 & RX_DMA_VTAG_V2) - __vlan_hwaccel_put_tag(skb, - htons(RX_DMA_VPID(trxd.rxd4)), - RX_DMA_VID(trxd.rxd4)); + if (trxd.rxd3 & RX_DMA_VTAG_V2) { + vlan_proto = RX_DMA_VPID(trxd.rxd4); + vlan_tci = RX_DMA_VID(trxd.rxd4); + has_hwaccel_tag = true; + } } else if (trxd.rxd2 & RX_DMA_VTAG) { - __vlan_hwaccel_put_tag(skb, htons(RX_DMA_VPID(trxd.rxd3)), - RX_DMA_VID(trxd.rxd3)); + vlan_proto = RX_DMA_VPID(trxd.rxd3); + vlan_tci = RX_DMA_VID(trxd.rxd3); + has_hwaccel_tag = true; } } /* When using VLAN untagging in combination with DSA, the * hardware treats the MTK special tag as a VLAN and untags it. */ - if (skb_vlan_tag_present(skb) && netdev_uses_dsa(netdev)) { - unsigned int port = ntohs(skb->vlan_proto) & GENMASK(2, 0); + if (has_hwaccel_tag && netdev_uses_dsa(netdev)) { + unsigned int port = vlan_proto & GENMASK(2, 0); if (port < ARRAY_SIZE(eth->dsa_meta) && eth->dsa_meta[port]) skb_dst_set_noref(skb, ð->dsa_meta[port]->dst); - - __vlan_hwaccel_clear_tag(skb); + } else if (has_hwaccel_tag) { + __vlan_hwaccel_put_tag(skb, htons(vlan_proto), vlan_tci); } skb_record_rx_queue(skb, 0); @@ -3111,7 +3115,7 @@ static void mtk_gdm_config(struct mtk_eth *eth, u32 config) val |= config; - if (!i && eth->netdev[0] && netdev_uses_dsa(eth->netdev[0])) + if (eth->netdev[i] && netdev_uses_dsa(eth->netdev[i])) val |= MTK_GDMA_SPECIAL_TAG; mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 18a50529ce7b..2d9186d32bc0 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -519,7 +519,7 @@ #define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0) #define SGMII_SPEED_100 FIELD_PREP(SGMII_SPEED_MASK, 1) #define SGMII_SPEED_1000 FIELD_PREP(SGMII_SPEED_MASK, 2) -#define SGMII_DUPLEX_FULL BIT(4) +#define SGMII_DUPLEX_HALF BIT(4) #define SGMII_IF_MODE_BIT5 BIT(5) #define SGMII_REMOTE_FAULT_DIS BIT(8) #define SGMII_CODE_SYNC_SET_VAL BIT(9) @@ -1036,11 +1036,13 @@ struct mtk_soc_data { * @regmap: The register map pointing at the range used to setup * SGMII modes * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap + * @interface: Currently configured interface mode * @pcs: Phylink PCS structure */ struct mtk_pcs { struct regmap *regmap; u32 ana_rgc3; + phy_interface_t interface; struct phylink_pcs pcs; }; diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c index 269208a841c7..1ff024f42444 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c @@ -615,8 +615,7 @@ mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP; int type; - flow_info = kzalloc(offsetof(struct mtk_flow_entry, l2_data.end), - GFP_ATOMIC); + flow_info = kzalloc(sizeof(*flow_info), GFP_ATOMIC); if (!flow_info) return; diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h index ea64fac1d425..b5e432031340 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe.h +++ b/drivers/net/ethernet/mediatek/mtk_ppe.h @@ -279,7 +279,6 @@ struct mtk_flow_entry { struct { struct mtk_flow_entry *base_flow; struct hlist_node list; - struct {} end; } l2_data; }; struct rhash_head node; diff --git a/drivers/net/ethernet/mediatek/mtk_sgmii.c b/drivers/net/ethernet/mediatek/mtk_sgmii.c index 5c286f2c9418..bb00de1003ac 100644 --- a/drivers/net/ethernet/mediatek/mtk_sgmii.c +++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c @@ -43,11 +43,6 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, int advertise, link_timer; bool changed, use_an; - if (interface == PHY_INTERFACE_MODE_2500BASEX) - rgc3 = RG_PHY_SPEED_3_125G; - else - rgc3 = 0; - advertise = phylink_mii_c22_pcs_encode_advertisement(interface, advertising); if (advertise < 0) @@ -88,9 +83,22 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, bmcr = 0; } - /* Configure the underlying interface speed */ - regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, - RG_PHY_SPEED_3_125G, rgc3); + if (mpcs->interface != interface) { + /* PHYA power down */ + regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, + SGMII_PHYA_PWD, SGMII_PHYA_PWD); + + if (interface == PHY_INTERFACE_MODE_2500BASEX) + rgc3 = RG_PHY_SPEED_3_125G; + else + rgc3 = 0; + + /* Configure the underlying interface speed */ + regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, + RG_PHY_SPEED_3_125G, rgc3); + + mpcs->interface = interface; + } /* Update the advertisement, noting whether it has changed */ regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE, @@ -108,9 +116,17 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, SGMII_AN_RESTART | SGMII_AN_ENABLE, bmcr); - /* Release PHYA power down state */ - regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, - SGMII_PHYA_PWD, 0); + /* Release PHYA power down state + * Only removing bit SGMII_PHYA_PWD isn't enough. + * There are cases when the SGMII_PHYA_PWD register contains 0x9 which + * prevents SGMII from working. The SGMII still shows link but no traffic + * can flow. Writing 0x0 to the PHYA_PWD register fix the issue. 0x0 was + * taken from a good working state of the SGMII interface. + * Unknown how much the QPHY needs but it is racy without a sleep. + * Tested on mt7622 & mt7986. + */ + usleep_range(50, 100); + regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0); return changed; } @@ -138,11 +154,11 @@ static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, else sgm_mode = SGMII_SPEED_1000; - if (duplex == DUPLEX_FULL) - sgm_mode |= SGMII_DUPLEX_FULL; + if (duplex != DUPLEX_FULL) + sgm_mode |= SGMII_DUPLEX_HALF; regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, - SGMII_DUPLEX_FULL | SGMII_SPEED_MASK, + SGMII_DUPLEX_HALF | SGMII_SPEED_MASK, sgm_mode); } } @@ -171,6 +187,8 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) return PTR_ERR(ss->pcs[i].regmap); ss->pcs[i].pcs.ops = &mtk_pcs_ops; + ss->pcs[i].pcs.poll = true; + ss->pcs[i].interface = PHY_INTERFACE_MODE_NA; } return 0; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index d3ca745d107d..c837103a9ee3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -2176,15 +2176,9 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev) return -EINVAL; } - cmd->stats = kvcalloc(MLX5_CMD_OP_MAX, sizeof(*cmd->stats), GFP_KERNEL); - if (!cmd->stats) - return -ENOMEM; - cmd->pool = dma_pool_create("mlx5_cmd", mlx5_core_dma_dev(dev), size, align, 0); - if (!cmd->pool) { - err = -ENOMEM; - goto dma_pool_err; - } + if (!cmd->pool) + return -ENOMEM; err = alloc_cmd_page(dev, cmd); if (err) @@ -2268,8 +2262,6 @@ err_free_page: err_free_pool: dma_pool_destroy(cmd->pool); -dma_pool_err: - kvfree(cmd->stats); return err; } @@ -2282,7 +2274,6 @@ void mlx5_cmd_cleanup(struct mlx5_core_dev *dev) destroy_msg_cache(dev); free_cmd_page(dev, cmd); dma_pool_destroy(cmd->pool); - kvfree(cmd->stats); } void mlx5_cmd_set_state(struct mlx5_core_dev *dev, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c index 3e232a65a0c3..bb95b40d25eb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c @@ -245,8 +245,9 @@ void mlx5_pages_debugfs_init(struct mlx5_core_dev *dev) pages = dev->priv.dbg.pages_debugfs; debugfs_create_u32("fw_pages_total", 0400, pages, &dev->priv.fw_pages); - debugfs_create_u32("fw_pages_vfs", 0400, pages, &dev->priv.vfs_pages); - debugfs_create_u32("fw_pages_host_pf", 0400, pages, &dev->priv.host_pf_pages); + debugfs_create_u32("fw_pages_vfs", 0400, pages, &dev->priv.page_counters[MLX5_VF]); + debugfs_create_u32("fw_pages_sfs", 0400, pages, &dev->priv.page_counters[MLX5_SF]); + debugfs_create_u32("fw_pages_host_pf", 0400, pages, &dev->priv.page_counters[MLX5_HOST_PF]); debugfs_create_u32("fw_pages_alloc_failed", 0400, pages, &dev->priv.fw_pages_alloc_failed); debugfs_create_u32("fw_pages_give_dropped", 0400, pages, &dev->priv.give_pages_dropped); debugfs_create_u32("fw_pages_reclaim_discard", 0400, pages, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index ddb197970c22..5bd83c0275f8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -468,7 +468,7 @@ static int mlx5_devlink_enable_roce_validate(struct devlink *devlink, u32 id, bool new_state = val.vbool; if (new_state && !MLX5_CAP_GEN(dev, roce) && - !MLX5_CAP_GEN(dev, roce_rw_supported)) { + !(MLX5_CAP_GEN(dev, roce_rw_supported) && MLX5_CAP_GEN_MAX(dev, roce))) { NL_SET_ERR_MSG_MOD(extack, "Device doesn't support RoCE"); return -EOPNOTSUPP; } @@ -563,7 +563,7 @@ static int mlx5_devlink_eq_depth_validate(struct devlink *devlink, u32 id, union devlink_param_value val, struct netlink_ext_ack *extack) { - return (val.vu16 >= 64 && val.vu16 <= 4096) ? 0 : -EINVAL; + return (val.vu32 >= 64 && val.vu32 <= 4096) ? 0 : -EINVAL; } static const struct devlink_param mlx5_devlink_params[] = { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c index 21831386b26e..5b05b884b5fb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c @@ -64,6 +64,7 @@ static int mlx5_query_mtrc_caps(struct mlx5_fw_tracer *tracer) MLX5_GET(mtrc_cap, out, num_string_trace); tracer->str_db.num_string_db = MLX5_GET(mtrc_cap, out, num_string_db); tracer->owner = !!MLX5_GET(mtrc_cap, out, trace_owner); + tracer->str_db.loaded = false; for (i = 0; i < tracer->str_db.num_string_db; i++) { mtrc_cap_sp = MLX5_ADDR_OF(mtrc_cap, out, string_db_param[i]); @@ -756,6 +757,7 @@ static int mlx5_fw_tracer_set_mtrc_conf(struct mlx5_fw_tracer *tracer) if (err) mlx5_core_warn(dev, "FWTracer: Failed to set tracer configurations %d\n", err); + tracer->buff.consumer_index = 0; return err; } @@ -820,7 +822,6 @@ static void mlx5_fw_tracer_ownership_change(struct work_struct *work) mlx5_core_dbg(tracer->dev, "FWTracer: ownership changed, current=(%d)\n", tracer->owner); if (tracer->owner) { tracer->owner = false; - tracer->buff.consumer_index = 0; return; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c b/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c index 464eb3a18450..cdc87ecae5d3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c @@ -87,7 +87,7 @@ void mlx5_ec_cleanup(struct mlx5_core_dev *dev) mlx5_host_pf_cleanup(dev); - err = mlx5_wait_for_pages(dev, &dev->priv.host_pf_pages); + err = mlx5_wait_for_pages(dev, &dev->priv.page_counters[MLX5_HOST_PF]); if (err) mlx5_core_warn(dev, "Timeout reclaiming external host PF pages err(%d)\n", err); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/htb.c b/drivers/net/ethernet/mellanox/mlx5/core/en/htb.c index 6dac76fa58a3..09d441ecb9f6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/htb.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/htb.c @@ -637,7 +637,7 @@ mlx5e_htb_update_children(struct mlx5e_htb *htb, struct mlx5e_qos_node *node, if (child->bw_share == old_bw_share) continue; - err_one = mlx5_qos_update_node(htb->mdev, child->hw_id, child->bw_share, + err_one = mlx5_qos_update_node(htb->mdev, child->bw_share, child->max_average_bw, child->hw_id); if (!err && err_one) { err = err_one; @@ -671,7 +671,7 @@ mlx5e_htb_node_modify(struct mlx5e_htb *htb, u16 classid, u64 rate, u64 ceil, mlx5e_htb_convert_rate(htb, rate, node->parent, &bw_share); mlx5e_htb_convert_ceil(htb, ceil, &max_average_bw); - err = mlx5_qos_update_node(htb->mdev, node->parent->hw_id, bw_share, + err = mlx5_qos_update_node(htb->mdev, bw_share, max_average_bw, node->hw_id); if (err) { NL_SET_ERR_MSG_MOD(extack, "Firmware error when modifying a node."); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c index 585bdc8383ee..4ad19c981294 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c @@ -578,7 +578,6 @@ int mlx5e_mpwrq_validate_xsk(struct mlx5_core_dev *mdev, struct mlx5e_params *pa { enum mlx5e_mpwrq_umr_mode umr_mode = mlx5e_mpwrq_umr_mode(mdev, xsk); u8 page_shift = mlx5e_mpwrq_page_shift(mdev, xsk); - bool unaligned = xsk ? xsk->unaligned : false; u16 max_mtu_pkts; if (!mlx5e_check_fragmented_striding_rq_cap(mdev, page_shift, umr_mode)) @@ -591,7 +590,7 @@ int mlx5e_mpwrq_validate_xsk(struct mlx5_core_dev *mdev, struct mlx5e_params *pa * needed number of WQEs exceeds the maximum. */ max_mtu_pkts = min_t(u8, MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE, - mlx5e_mpwrq_max_log_rq_pkts(mdev, page_shift, unaligned)); + mlx5e_mpwrq_max_log_rq_pkts(mdev, page_shift, xsk->unaligned)); if (params->log_rq_mtu_frames > max_mtu_pkts) { mlx5_core_err(mdev, "Current RQ length %d is too big for XSK with given frame size %u\n", 1 << params->log_rq_mtu_frames, xsk->chunk_size); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c index 8099a21e674c..ce85b48d327d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c @@ -438,10 +438,6 @@ static int mlx5_esw_bridge_switchdev_event(struct notifier_block *nb, switch (event) { case SWITCHDEV_FDB_ADD_TO_BRIDGE: - /* only handle the event on native eswtich of representor */ - if (!mlx5_esw_bridge_is_local(dev, rep, esw)) - break; - fdb_info = container_of(info, struct switchdev_notifier_fdb_info, info); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c index 5f6f95ad6888..1ae15b8536a8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c @@ -459,7 +459,11 @@ static int mlx5e_rx_reporter_diagnose(struct devlink_health_reporter *reporter, goto unlock; for (i = 0; i < priv->channels.num; i++) { - struct mlx5e_rq *rq = &priv->channels.c[i]->rq; + struct mlx5e_channel *c = priv->channels.c[i]; + struct mlx5e_rq *rq; + + rq = test_bit(MLX5E_CHANNEL_STATE_XSK, c->state) ? + &c->xskrq : &c->rq; err = mlx5e_rx_reporter_build_diagnose_output(rq, fmsg); if (err) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/police.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/police.c index 512d43148922..c4378afdec09 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/police.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/police.c @@ -34,12 +34,6 @@ static int police_act_validate(const struct flow_action_entry *act, return -EOPNOTSUPP; } - if (act->police.rate_pkt_ps) { - NL_SET_ERR_MSG_MOD(extack, - "QoS offload not support packets per second"); - return -EOPNOTSUPP; - } - return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.c index 8d7d761482d2..50b60fd00946 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.c @@ -127,6 +127,7 @@ mlx5e_post_meter_add_rule(struct mlx5e_priv *priv, attr->counter = act_counter; attr->flags |= MLX5_ATTR_FLAG_NO_IN_PORT; + attr->inner_match_level = MLX5_MATCH_NONE; attr->outer_match_level = MLX5_MATCH_NONE; attr->chain = 0; attr->prio = 0; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/sample.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/sample.c index 1cbd2eb9d04f..f2c2c752bd1c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/sample.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/sample.c @@ -477,7 +477,6 @@ mlx5e_tc_sample_offload(struct mlx5e_tc_psample *tc_psample, struct mlx5e_sample_flow *sample_flow; struct mlx5e_sample_attr *sample_attr; struct mlx5_flow_attr *pre_attr; - u32 tunnel_id = attr->tunnel_id; struct mlx5_eswitch *esw; u32 default_tbl_id; u32 obj_id; @@ -522,7 +521,7 @@ mlx5e_tc_sample_offload(struct mlx5e_tc_psample *tc_psample, restore_obj.sample.group_id = sample_attr->group_num; restore_obj.sample.rate = sample_attr->rate; restore_obj.sample.trunc_size = sample_attr->trunc_size; - restore_obj.sample.tunnel_id = tunnel_id; + restore_obj.sample.tunnel_id = attr->tunnel_id; err = mapping_add(esw->offloads.reg_c0_obj_pool, &restore_obj, &obj_id); if (err) goto err_obj_id; @@ -548,7 +547,7 @@ mlx5e_tc_sample_offload(struct mlx5e_tc_psample *tc_psample, /* For decap action, do decap in the original flow table instead of the * default flow table. */ - if (tunnel_id) + if (attr->action & MLX5_FLOW_CONTEXT_ACTION_DECAP) pre_attr->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP; pre_attr->modify_hdr = sample_flow->restore->modify_hdr; pre_attr->flags = MLX5_ATTR_FLAG_SAMPLE; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c index a69849e0deed..313df8232db7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c @@ -2103,14 +2103,9 @@ out_err: static void mlx5_ct_tc_create_dbgfs(struct mlx5_tc_ct_priv *ct_priv) { - bool is_fdb = ct_priv->ns_type == MLX5_FLOW_NAMESPACE_FDB; struct mlx5_tc_ct_debugfs *ct_dbgfs = &ct_priv->debugfs; - char dirname[16] = {}; - if (sscanf(dirname, "ct_%s", is_fdb ? "fdb" : "nic") < 0) - return; - - ct_dbgfs->root = debugfs_create_dir(dirname, mlx5_debugfs_get_dev_root(ct_priv->dev)); + ct_dbgfs->root = debugfs_create_dir("ct", mlx5_debugfs_get_dev_root(ct_priv->dev)); debugfs_create_atomic_t("offloaded", 0400, ct_dbgfs->root, &ct_dbgfs->stats.offloaded); debugfs_create_atomic_t("rx_dropped", 0400, ct_dbgfs->root, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c index ff73d25bc6eb..2aaf8ab857b8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c @@ -222,7 +222,7 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv, int err; list_for_each_entry(flow, flow_list, tmp_list) { - if (!mlx5e_is_offloaded_flow(flow) || flow_flag_test(flow, SLOW)) + if (!mlx5e_is_offloaded_flow(flow)) continue; attr = mlx5e_tc_get_encap_attr(flow); @@ -231,6 +231,13 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv, esw_attr->dests[flow->tmp_entry_index].flags &= ~MLX5_ESW_DEST_ENCAP_VALID; esw_attr->dests[flow->tmp_entry_index].pkt_reformat = NULL; + /* Clear pkt_reformat before checking slow path flag. Because + * in next iteration, the same flow is already set slow path + * flag, but still need to clear the pkt_reformat. + */ + if (flow_flag_test(flow, SLOW)) + continue; + /* update from encap rule to slow path rule */ spec = &flow->attr->parse_attr->spec; rule = mlx5e_tc_offload_to_slow_path(esw, flow, spec); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_geneve.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_geneve.c index f5b26f5a7de4..054d80c4e65c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_geneve.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_geneve.c @@ -273,6 +273,11 @@ static int mlx5e_tc_tun_parse_geneve_options(struct mlx5e_priv *priv, geneve_tlv_option_0_data, be32_to_cpu(opt_data_key)); MLX5_SET(fte_match_set_misc3, misc_3_c, geneve_tlv_option_0_data, be32_to_cpu(opt_data_mask)); + if (MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, + ft_field_support.geneve_tlv_option_0_exist)) { + MLX5_SET_TO_ONES(fte_match_set_misc, misc_c, geneve_tlv_option_0_exist); + MLX5_SET_TO_ONES(fte_match_set_misc, misc_v, geneve_tlv_option_0_exist); + } spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_3; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c index fd07c4cbfd1d..1f62c702b625 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c @@ -88,6 +88,8 @@ static int mlx5e_gen_ip_tunnel_header_vxlan(char buf[], struct udphdr *udp = (struct udphdr *)(buf); struct vxlanhdr *vxh; + if (tun_key->tun_flags & TUNNEL_VXLAN_OPT) + return -EOPNOTSUPP; vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr)); *ip_proto = IPPROTO_UDP; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h index a92e19c4c499..8bed9c361075 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h @@ -122,11 +122,8 @@ struct mlx5e_ipsec_aso { u8 ctx[MLX5_ST_SZ_BYTES(ipsec_aso)]; dma_addr_t dma_addr; struct mlx5_aso *aso; - /* IPsec ASO caches data on every query call, - * so in nested calls, we can use this boolean to save - * recursive calls to mlx5e_ipsec_aso_query() - */ - u8 use_cache : 1; + /* Protect ASO WQ access, as it is global to whole IPsec */ + spinlock_t lock; }; struct mlx5e_ipsec { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c index 8e3614218fc4..2461462b7b99 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c @@ -320,7 +320,6 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work) if (ret) goto unlock; - aso->use_cache = true; if (attrs->esn_trigger && !MLX5_GET(ipsec_aso, aso->ctx, esn_event_arm)) { u32 mode_param = MLX5_GET(ipsec_aso, aso->ctx, mode_parameter); @@ -333,7 +332,6 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work) !MLX5_GET(ipsec_aso, aso->ctx, hard_lft_arm) || !MLX5_GET(ipsec_aso, aso->ctx, remove_flow_enable)) xfrm_state_check_expire(sa_entry->x); - aso->use_cache = false; unlock: spin_unlock(&sa_entry->x->lock); @@ -398,6 +396,7 @@ int mlx5e_ipsec_aso_init(struct mlx5e_ipsec *ipsec) goto err_aso_create; } + spin_lock_init(&aso->lock); ipsec->nb.notifier_call = mlx5e_ipsec_event; mlx5_notifier_register(mdev, &ipsec->nb); @@ -456,13 +455,12 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry, struct mlx5e_hw_objs *res; struct mlx5_aso_wqe *wqe; u8 ds_cnt; + int ret; lockdep_assert_held(&sa_entry->x->lock); - if (aso->use_cache) - return 0; - res = &mdev->mlx5e_res.hw_objs; + spin_lock_bh(&aso->lock); memset(aso->ctx, 0, sizeof(aso->ctx)); wqe = mlx5_aso_get_wqe(aso->aso); ds_cnt = DIV_ROUND_UP(sizeof(*wqe), MLX5_SEND_WQE_DS); @@ -477,7 +475,9 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry, mlx5e_ipsec_aso_copy(ctrl, data); mlx5_aso_post_wqe(aso->aso, false, &wqe->ctrl); - return mlx5_aso_poll_cq(aso->aso, false); + ret = mlx5_aso_poll_cq(aso->aso, false); + spin_unlock_bh(&aso->lock); + return ret; } void mlx5e_ipsec_aso_update_curlft(struct mlx5e_ipsec_sa_entry *sa_entry, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c index 9369a580743e..7f6b940830b3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c @@ -62,6 +62,7 @@ struct mlx5e_macsec_sa { u32 enc_key_id; u32 next_pn; sci_t sci; + ssci_t ssci; salt_t salt; struct rhash_head hash; @@ -358,7 +359,6 @@ static int mlx5e_macsec_init_sa(struct macsec_context *ctx, struct mlx5_core_dev *mdev = priv->mdev; struct mlx5_macsec_obj_attrs obj_attrs; union mlx5e_macsec_rule *macsec_rule; - struct macsec_key *key; int err; obj_attrs.next_pn = sa->next_pn; @@ -368,13 +368,9 @@ static int mlx5e_macsec_init_sa(struct macsec_context *ctx, obj_attrs.aso_pdn = macsec->aso.pdn; obj_attrs.epn_state = sa->epn_state; - key = (is_tx) ? &ctx->sa.tx_sa->key : &ctx->sa.rx_sa->key; - if (sa->epn_state.epn_enabled) { - obj_attrs.ssci = (is_tx) ? cpu_to_be32((__force u32)ctx->sa.tx_sa->ssci) : - cpu_to_be32((__force u32)ctx->sa.rx_sa->ssci); - - memcpy(&obj_attrs.salt, &key->salt, sizeof(key->salt)); + obj_attrs.ssci = cpu_to_be32((__force u32)sa->ssci); + memcpy(&obj_attrs.salt, &sa->salt, sizeof(sa->salt)); } obj_attrs.replay_window = ctx->secy->replay_window; @@ -499,10 +495,11 @@ mlx5e_macsec_get_macsec_device_context(const struct mlx5e_macsec *macsec, } static void update_macsec_epn(struct mlx5e_macsec_sa *sa, const struct macsec_key *key, - const pn_t *next_pn_halves) + const pn_t *next_pn_halves, ssci_t ssci) { struct mlx5e_macsec_epn_state *epn_state = &sa->epn_state; + sa->ssci = ssci; sa->salt = key->salt; epn_state->epn_enabled = 1; epn_state->epn_msb = next_pn_halves->upper; @@ -550,7 +547,8 @@ static int mlx5e_macsec_add_txsa(struct macsec_context *ctx) tx_sa->assoc_num = assoc_num; if (secy->xpn) - update_macsec_epn(tx_sa, &ctx_tx_sa->key, &ctx_tx_sa->next_pn_halves); + update_macsec_epn(tx_sa, &ctx_tx_sa->key, &ctx_tx_sa->next_pn_halves, + ctx_tx_sa->ssci); err = mlx5_create_encryption_key(mdev, ctx->sa.key, secy->key_len, MLX5_ACCEL_OBJ_MACSEC_KEY, @@ -945,7 +943,8 @@ static int mlx5e_macsec_add_rxsa(struct macsec_context *ctx) rx_sa->fs_id = rx_sc->sc_xarray_element->fs_id; if (ctx->secy->xpn) - update_macsec_epn(rx_sa, &ctx_rx_sa->key, &ctx_rx_sa->next_pn_halves); + update_macsec_epn(rx_sa, &ctx_rx_sa->key, &ctx_rx_sa->next_pn_halves, + ctx_rx_sa->ssci); err = mlx5_create_encryption_key(mdev, ctx->sa.key, ctx->secy->key_len, MLX5_ACCEL_OBJ_MACSEC_KEY, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c index 1892ccb889b3..7cd36f4ac3ef 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c @@ -443,7 +443,7 @@ void mlx5e_enable_cvlan_filter(struct mlx5e_flow_steering *fs, bool promisc) void mlx5e_disable_cvlan_filter(struct mlx5e_flow_steering *fs, bool promisc) { - if (fs->vlan->cvlan_filter_disabled) + if (!fs->vlan || fs->vlan->cvlan_filter_disabled) return; fs->vlan->cvlan_filter_disabled = true; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 8d36e2de53a9..6c24f33a5ea5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -591,7 +591,8 @@ static int mlx5e_init_rxq_rq(struct mlx5e_channel *c, struct mlx5e_params *param rq->ix = c->ix; rq->channel = c; rq->mdev = mdev; - rq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu); + rq->hw_mtu = + MLX5E_SW2HW_MTU(params, params->sw_mtu) - ETH_FCS_LEN * !params->scatter_fcs_en; rq->xdpsq = &c->rq_xdpsq; rq->stats = &c->priv->channel_stats[c->ix]->rq; rq->ptp_cyc2time = mlx5_rq_ts_translator(mdev); @@ -1014,35 +1015,6 @@ int mlx5e_flush_rq(struct mlx5e_rq *rq, int curr_state) return mlx5e_rq_to_ready(rq, curr_state); } -static int mlx5e_modify_rq_scatter_fcs(struct mlx5e_rq *rq, bool enable) -{ - struct mlx5_core_dev *mdev = rq->mdev; - - void *in; - void *rqc; - int inlen; - int err; - - inlen = MLX5_ST_SZ_BYTES(modify_rq_in); - in = kvzalloc(inlen, GFP_KERNEL); - if (!in) - return -ENOMEM; - - rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx); - - MLX5_SET(modify_rq_in, in, rq_state, MLX5_RQC_STATE_RDY); - MLX5_SET64(modify_rq_in, in, modify_bitmask, - MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_SCATTER_FCS); - MLX5_SET(rqc, rqc, scatter_fcs, enable); - MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RDY); - - err = mlx5_core_modify_rq(mdev, rq->rqn, in); - - kvfree(in); - - return err; -} - static int mlx5e_modify_rq_vsd(struct mlx5e_rq *rq, bool vsd) { struct mlx5_core_dev *mdev = rq->mdev; @@ -1305,7 +1277,7 @@ static int mlx5e_alloc_xdpsq(struct mlx5e_channel *c, sq->channel = c; sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map; sq->min_inline_mode = params->tx_min_inline_mode; - sq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu); + sq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu) - ETH_FCS_LEN; sq->xsk_pool = xsk_pool; sq->stats = sq->xsk_pool ? @@ -3314,20 +3286,6 @@ static void mlx5e_cleanup_nic_tx(struct mlx5e_priv *priv) mlx5e_destroy_tises(priv); } -static int mlx5e_modify_channels_scatter_fcs(struct mlx5e_channels *chs, bool enable) -{ - int err = 0; - int i; - - for (i = 0; i < chs->num; i++) { - err = mlx5e_modify_rq_scatter_fcs(&chs->c[i]->rq, enable); - if (err) - return err; - } - - return 0; -} - static int mlx5e_modify_channels_vsd(struct mlx5e_channels *chs, bool vsd) { int err; @@ -3903,41 +3861,27 @@ static int mlx5e_set_rx_port_ts(struct mlx5_core_dev *mdev, bool enable) return mlx5_set_ports_check(mdev, in, sizeof(in)); } +static int mlx5e_set_rx_port_ts_wrap(struct mlx5e_priv *priv, void *ctx) +{ + struct mlx5_core_dev *mdev = priv->mdev; + bool enable = *(bool *)ctx; + + return mlx5e_set_rx_port_ts(mdev, enable); +} + static int set_feature_rx_fcs(struct net_device *netdev, bool enable) { struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5e_channels *chs = &priv->channels; - struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5e_params new_params; int err; mutex_lock(&priv->state_lock); - if (enable) { - err = mlx5e_set_rx_port_ts(mdev, false); - if (err) - goto out; - - chs->params.scatter_fcs_en = true; - err = mlx5e_modify_channels_scatter_fcs(chs, true); - if (err) { - chs->params.scatter_fcs_en = false; - mlx5e_set_rx_port_ts(mdev, true); - } - } else { - chs->params.scatter_fcs_en = false; - err = mlx5e_modify_channels_scatter_fcs(chs, false); - if (err) { - chs->params.scatter_fcs_en = true; - goto out; - } - err = mlx5e_set_rx_port_ts(mdev, true); - if (err) { - mlx5_core_warn(mdev, "Failed to set RX port timestamp %d\n", err); - err = 0; - } - } - -out: + new_params = chs->params; + new_params.scatter_fcs_en = enable; + err = mlx5e_safe_switch_params(priv, &new_params, mlx5e_set_rx_port_ts_wrap, + &new_params.scatter_fcs_en, true); mutex_unlock(&priv->state_lock); return err; } @@ -4074,6 +4018,10 @@ static netdev_features_t mlx5e_fix_uplink_rep_features(struct net_device *netdev if (netdev->features & NETIF_F_GRO_HW) netdev_warn(netdev, "Disabling HW_GRO, not supported in switchdev mode\n"); + features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; + if (netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER) + netdev_warn(netdev, "Disabling HW_VLAN CTAG FILTERING, not supported in switchdev mode\n"); + return features; } @@ -4084,6 +4032,9 @@ static netdev_features_t mlx5e_fix_features(struct net_device *netdev, struct mlx5e_vlan_table *vlan; struct mlx5e_params *params; + if (!netif_device_present(netdev)) + return features; + vlan = mlx5e_fs_get_vlan(priv->fs); mutex_lock(&priv->state_lock); params = &priv->channels.params; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 75b9e1528fd2..7d90e5b72854 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -191,7 +191,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(vport_rep) if (err) { netdev_warn(priv->netdev, "vport %d error %d reading stats\n", rep->vport, err); - return; + goto out; } #define MLX5_GET_CTR(p, x) \ @@ -241,6 +241,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(vport_rep) rep_stats->tx_vport_rdma_multicast_bytes = MLX5_GET_CTR(out, received_ib_multicast.octets); +out: kvfree(out); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index c8820ab22169..3df455f6b168 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -2419,7 +2419,7 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq, priv = mlx5i_epriv(netdev); tstamp = &priv->tstamp; - stats = rq->stats; + stats = &priv->channel_stats[rq->ix]->rq; flags_rqpn = be32_to_cpu(cqe->flags_rqpn); g = (flags_rqpn >> 28) & 3; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 9af2aa2922f5..243d5d7750be 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -166,6 +166,7 @@ struct mlx5_fs_chains *mlx5e_nic_chains(struct mlx5e_tc_table *tc) * it's different than the ht->mutex here. */ static struct lock_class_key tc_ht_lock_key; +static struct lock_class_key tc_ht_wq_key; static void mlx5e_put_flow_tunnel_id(struct mlx5e_tc_flow *flow); static void free_flow_post_acts(struct mlx5e_tc_flow *flow); @@ -1301,7 +1302,6 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) { err = mlx5e_attach_mod_hdr(priv, flow, parse_attr); - mlx5e_mod_hdr_dealloc(&parse_attr->mod_hdr_acts); if (err) return err; } @@ -1359,8 +1359,10 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv, } mutex_unlock(&tc->t_lock); - if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) + if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) { + mlx5e_mod_hdr_dealloc(&attr->parse_attr->mod_hdr_acts); mlx5e_detach_mod_hdr(priv, flow); + } if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) mlx5_fc_destroy(priv->mdev, attr->counter); @@ -5181,6 +5183,7 @@ int mlx5e_tc_nic_init(struct mlx5e_priv *priv) return err; lockdep_set_class(&tc->ht.mutex, &tc_ht_lock_key); + lockdep_init_map(&tc->ht.run_work.lockdep_map, "tc_ht_wq_key", &tc_ht_wq_key, 0); mapping_id = mlx5_query_nic_system_image_guid(dev); @@ -5287,6 +5290,7 @@ int mlx5e_tc_ht_init(struct rhashtable *tc_ht) return err; lockdep_set_class(&tc_ht->mutex, &tc_ht_lock_key); + lockdep_init_map(&tc_ht->run_work.lockdep_map, "tc_ht_wq_key", &tc_ht_wq_key, 0); return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/egress_lgcy.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/egress_lgcy.c index 60a73990017c..6b4c9ffad95b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/egress_lgcy.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/egress_lgcy.c @@ -67,6 +67,7 @@ static void esw_acl_egress_lgcy_groups_destroy(struct mlx5_vport *vport) int esw_acl_egress_lgcy_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { + bool vst_mode_steering = esw_vst_mode_is_steering(esw); struct mlx5_flow_destination drop_ctr_dst = {}; struct mlx5_flow_destination *dst = NULL; struct mlx5_fc *drop_counter = NULL; @@ -77,6 +78,7 @@ int esw_acl_egress_lgcy_setup(struct mlx5_eswitch *esw, */ int table_size = 2; int dest_num = 0; + int actions_flag; int err = 0; if (vport->egress.legacy.drop_counter) { @@ -119,8 +121,11 @@ int esw_acl_egress_lgcy_setup(struct mlx5_eswitch *esw, vport->vport, vport->info.vlan, vport->info.qos); /* Allowed vlan rule */ + actions_flag = MLX5_FLOW_CONTEXT_ACTION_ALLOW; + if (vst_mode_steering) + actions_flag |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP; err = esw_egress_acl_vlan_create(esw, vport, NULL, vport->info.vlan, - MLX5_FLOW_CONTEXT_ACTION_ALLOW); + actions_flag); if (err) goto out; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/ingress_lgcy.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/ingress_lgcy.c index b1a5199260f6..093ed86a0acd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/ingress_lgcy.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/ingress_lgcy.c @@ -139,11 +139,14 @@ static void esw_acl_ingress_lgcy_groups_destroy(struct mlx5_vport *vport) int esw_acl_ingress_lgcy_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { + bool vst_mode_steering = esw_vst_mode_is_steering(esw); struct mlx5_flow_destination drop_ctr_dst = {}; struct mlx5_flow_destination *dst = NULL; struct mlx5_flow_act flow_act = {}; struct mlx5_flow_spec *spec = NULL; struct mlx5_fc *counter = NULL; + bool vst_check_cvlan = false; + bool vst_push_cvlan = false; /* The ingress acl table contains 4 groups * (2 active rules at the same time - * 1 allow rule from one of the first 3 groups. @@ -203,7 +206,26 @@ int esw_acl_ingress_lgcy_setup(struct mlx5_eswitch *esw, goto out; } - if (vport->info.vlan || vport->info.qos) + if ((vport->info.vlan || vport->info.qos)) { + if (vst_mode_steering) + vst_push_cvlan = true; + else if (!MLX5_CAP_ESW(esw->dev, vport_cvlan_insert_always)) + vst_check_cvlan = true; + } + + if (vst_check_cvlan || vport->info.spoofchk) + spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + + /* Create ingress allow rule */ + flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW; + if (vst_push_cvlan) { + flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH; + flow_act.vlan[0].prio = vport->info.qos; + flow_act.vlan[0].vid = vport->info.vlan; + flow_act.vlan[0].ethtype = ETH_P_8021Q; + } + + if (vst_check_cvlan) MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag); @@ -218,9 +240,6 @@ int esw_acl_ingress_lgcy_setup(struct mlx5_eswitch *esw, ether_addr_copy(smac_v, vport->info.mac); } - /* Create ingress allow rule */ - spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; - flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW; vport->ingress.allow_rule = mlx5_add_flow_rules(vport->ingress.acl, spec, &flow_act, NULL, 0); if (IS_ERR(vport->ingress.allow_rule)) { @@ -232,6 +251,9 @@ int esw_acl_ingress_lgcy_setup(struct mlx5_eswitch *esw, goto out; } + if (!vst_check_cvlan && !vport->info.spoofchk) + goto out; + memset(&flow_act, 0, sizeof(flow_act)); flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP; /* Attach drop flow counter */ @@ -257,7 +279,8 @@ int esw_acl_ingress_lgcy_setup(struct mlx5_eswitch *esw, return 0; out: - esw_acl_ingress_lgcy_cleanup(esw, vport); + if (err) + esw_acl_ingress_lgcy_cleanup(esw, vport); kvfree(spec); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c index b176648d1343..3cdcb0e0b20f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c @@ -1715,7 +1715,7 @@ void mlx5_esw_bridge_fdb_update_used(struct net_device *dev, u16 vport_num, u16 struct mlx5_esw_bridge *bridge; port = mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id, br_offloads); - if (!port || port->flags & MLX5_ESW_BRIDGE_PORT_FLAG_PEER) + if (!port) return; bridge = port->bridge; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c index 4f8a24d84a86..75015d370922 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c @@ -22,15 +22,13 @@ struct mlx5_esw_rate_group { }; static int esw_qos_tsar_config(struct mlx5_core_dev *dev, u32 *sched_ctx, - u32 parent_ix, u32 tsar_ix, - u32 max_rate, u32 bw_share) + u32 tsar_ix, u32 max_rate, u32 bw_share) { u32 bitmask = 0; if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling)) return -EOPNOTSUPP; - MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent_ix); MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate); MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share); bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW; @@ -51,7 +49,7 @@ static int esw_qos_group_config(struct mlx5_eswitch *esw, struct mlx5_esw_rate_g int err; err = esw_qos_tsar_config(dev, sched_ctx, - esw->qos.root_tsar_ix, group->tsar_ix, + group->tsar_ix, max_rate, bw_share); if (err) NL_SET_ERR_MSG_MOD(extack, "E-Switch modify group TSAR element failed"); @@ -67,23 +65,13 @@ static int esw_qos_vport_config(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack) { u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {}; - struct mlx5_esw_rate_group *group = vport->qos.group; struct mlx5_core_dev *dev = esw->dev; - u32 parent_tsar_ix; - void *vport_elem; int err; if (!vport->qos.enabled) return -EIO; - parent_tsar_ix = group ? group->tsar_ix : esw->qos.root_tsar_ix; - MLX5_SET(scheduling_context, sched_ctx, element_type, - SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT); - vport_elem = MLX5_ADDR_OF(scheduling_context, sched_ctx, - element_attributes); - MLX5_SET(vport_element, vport_elem, vport_number, vport->vport); - - err = esw_qos_tsar_config(dev, sched_ctx, parent_tsar_ix, vport->qos.esw_tsar_ix, + err = esw_qos_tsar_config(dev, sched_ctx, vport->qos.esw_tsar_ix, max_rate, bw_share); if (err) { esw_warn(esw->dev, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 527e4bffda8d..9daf55e90367 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -161,10 +161,17 @@ static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u16 vport, esw_vport_context.vport_cvlan_strip, 1); if (set_flags & SET_VLAN_INSERT) { - /* insert only if no vlan in packet */ - MLX5_SET(modify_esw_vport_context_in, in, - esw_vport_context.vport_cvlan_insert, 1); - + if (MLX5_CAP_ESW(dev, vport_cvlan_insert_always)) { + /* insert either if vlan exist in packet or not */ + MLX5_SET(modify_esw_vport_context_in, in, + esw_vport_context.vport_cvlan_insert, + MLX5_VPORT_CVLAN_INSERT_ALWAYS); + } else { + /* insert only if no vlan in packet */ + MLX5_SET(modify_esw_vport_context_in, in, + esw_vport_context.vport_cvlan_insert, + MLX5_VPORT_CVLAN_INSERT_WHEN_NO_CVLAN); + } MLX5_SET(modify_esw_vport_context_in, in, esw_vport_context.cvlan_pcp, qos); MLX5_SET(modify_esw_vport_context_in, in, @@ -809,6 +816,7 @@ out_free: static int esw_vport_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { + bool vst_mode_steering = esw_vst_mode_is_steering(esw); u16 vport_num = vport->vport; int flags; int err; @@ -839,8 +847,9 @@ static int esw_vport_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport) flags = (vport->info.vlan || vport->info.qos) ? SET_VLAN_STRIP | SET_VLAN_INSERT : 0; - modify_esw_vport_cvlan(esw->dev, vport_num, vport->info.vlan, - vport->info.qos, flags); + if (esw->mode == MLX5_ESWITCH_OFFLOADS || !vst_mode_steering) + modify_esw_vport_cvlan(esw->dev, vport_num, vport->info.vlan, + vport->info.qos, flags); return 0; @@ -1455,6 +1464,7 @@ void mlx5_eswitch_disable(struct mlx5_eswitch *esw) mlx5_lag_disable_change(esw->dev); down_write(&esw->mode_lock); mlx5_eswitch_disable_locked(esw); + esw->mode = MLX5_ESWITCH_LEGACY; up_write(&esw->mode_lock); mlx5_lag_enable_change(esw->dev); } @@ -1848,6 +1858,7 @@ int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw, u16 vport, u16 vlan, u8 qos, u8 set_flags) { struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport); + bool vst_mode_steering = esw_vst_mode_is_steering(esw); int err = 0; if (IS_ERR(evport)) @@ -1855,9 +1866,11 @@ int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw, if (vlan > 4095 || qos > 7) return -EINVAL; - err = modify_esw_vport_cvlan(esw->dev, vport, vlan, qos, set_flags); - if (err) - return err; + if (esw->mode == MLX5_ESWITCH_OFFLOADS || !vst_mode_steering) { + err = modify_esw_vport_cvlan(esw->dev, vport, vlan, qos, set_flags); + if (err) + return err; + } evport->info.vlan = vlan; evport->info.qos = qos; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 5a85a5d32be7..92644fbb5081 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -527,6 +527,12 @@ int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw, int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw, u16 vport, u16 vlan, u8 qos, u8 set_flags); +static inline bool esw_vst_mode_is_steering(struct mlx5_eswitch *esw) +{ + return (MLX5_CAP_ESW_EGRESS_ACL(esw->dev, pop_vlan) && + MLX5_CAP_ESW_INGRESS_ACL(esw->dev, push_vlan)); +} + static inline bool mlx5_eswitch_vlan_actions_supported(struct mlx5_core_dev *dev, u8 vlan_depth) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index e455b215c708..c981fa77f439 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -143,7 +143,7 @@ mlx5_eswitch_set_rule_source_port(struct mlx5_eswitch *esw, if (mlx5_esw_indir_table_decap_vport(attr)) vport = mlx5_esw_indir_table_decap_vport(attr); - if (attr && !attr->chain && esw_attr->int_port) + if (!attr->chain && esw_attr && esw_attr->int_port) metadata = mlx5e_tc_int_port_get_metadata_for_match(esw_attr->int_port); else @@ -4143,8 +4143,6 @@ int mlx5_devlink_port_fn_migratable_set(struct devlink_port *port, bool enable, } hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability); - memcpy(hca_caps, MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability), - MLX5_UN_SZ_BYTES(hca_cap_union)); MLX5_SET(cmd_hca_cap_2, hca_caps, migratable, 1); err = mlx5_vport_set_other_func_cap(esw->dev, hca_caps, vport->vport, @@ -4236,8 +4234,6 @@ int mlx5_devlink_port_fn_roce_set(struct devlink_port *port, bool enable, } hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability); - memcpy(hca_caps, MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability), - MLX5_UN_SZ_BYTES(hca_cap_union)); MLX5_SET(cmd_hca_cap, hca_caps, roce, enable); err = mlx5_vport_set_other_func_cap(esw->dev, hca_caps, vport_num, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 86ed87d704f7..879555ba847d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -674,6 +674,13 @@ static void mlx5_fw_fatal_reporter_err_work(struct work_struct *work) dev = container_of(priv, struct mlx5_core_dev, priv); devlink = priv_to_devlink(dev); + mutex_lock(&dev->intf_state_mutex); + if (test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags)) { + mlx5_core_err(dev, "health works are not permitted at this stage\n"); + mutex_unlock(&dev->intf_state_mutex); + return; + } + mutex_unlock(&dev->intf_state_mutex); enter_error_state(dev, false); if (IS_ERR_OR_NULL(health->fw_fatal_reporter)) { devl_lock(devlink); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c index c247cca154e9..e09518f887a0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c @@ -90,9 +90,21 @@ static void mlx5i_get_ringparam(struct net_device *dev, static int mlx5i_set_channels(struct net_device *dev, struct ethtool_channels *ch) { - struct mlx5e_priv *priv = mlx5i_epriv(dev); + struct mlx5i_priv *ipriv = netdev_priv(dev); + struct mlx5e_priv *epriv = mlx5i_epriv(dev); + + /* rtnl lock protects from race between this ethtool op and sub + * interface ndo_init/uninit. + */ + ASSERT_RTNL(); + if (ipriv->num_sub_interfaces > 0) { + mlx5_core_warn(epriv->mdev, + "can't change number of channels for interfaces with sub interfaces (%u)\n", + ipriv->num_sub_interfaces); + return -EINVAL; + } - return mlx5e_ethtool_set_channels(priv, ch); + return mlx5e_ethtool_set_channels(epriv, ch); } static void mlx5i_get_channels(struct net_device *dev, @@ -177,16 +189,16 @@ static inline int mlx5_ptys_rate_enum_to_int(enum mlx5_ptys_rate rate) } } -static int mlx5i_get_speed_settings(u16 ib_link_width_oper, u16 ib_proto_oper) +static u32 mlx5i_get_speed_settings(u16 ib_link_width_oper, u16 ib_proto_oper) { int rate, width; rate = mlx5_ptys_rate_enum_to_int(ib_proto_oper); if (rate < 0) - return -EINVAL; + return SPEED_UNKNOWN; width = mlx5_ptys_width_enum_to_int(ib_link_width_oper); if (width < 0) - return -EINVAL; + return SPEED_UNKNOWN; return rate * width; } @@ -209,16 +221,13 @@ static int mlx5i_get_link_ksettings(struct net_device *netdev, ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); speed = mlx5i_get_speed_settings(ib_link_width_oper, ib_proto_oper); - if (speed < 0) - return -EINVAL; + link_ksettings->base.speed = speed; + link_ksettings->base.duplex = speed == SPEED_UNKNOWN ? DUPLEX_UNKNOWN : DUPLEX_FULL; - link_ksettings->base.duplex = DUPLEX_FULL; link_ksettings->base.port = PORT_OTHER; link_ksettings->base.autoneg = AUTONEG_DISABLE; - link_ksettings->base.speed = speed; - return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 7c5c500fd215..911cf4d23964 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -71,6 +71,10 @@ static void mlx5i_build_nic_params(struct mlx5_core_dev *mdev, params->packet_merge.type = MLX5E_PACKET_MERGE_NONE; params->hard_mtu = MLX5_IB_GRH_BYTES + MLX5_IPOIB_HARD_LEN; params->tunneled_offload_en = false; + + /* CQE compression is not supported for IPoIB */ + params->rx_cqe_compress_def = false; + MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_CQE_COMPRESS, params->rx_cqe_compress_def); } /* Called directly after IPoIB netdevice was created to initialize SW structs */ @@ -156,6 +160,44 @@ void mlx5i_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) stats->tx_dropped = sstats->tx_queue_dropped; } +struct net_device *mlx5i_parent_get(struct net_device *netdev) +{ + struct mlx5e_priv *priv = mlx5i_epriv(netdev); + struct mlx5i_priv *ipriv, *parent_ipriv; + struct net_device *parent_dev; + int parent_ifindex; + + ipriv = priv->ppriv; + + parent_ifindex = netdev->netdev_ops->ndo_get_iflink(netdev); + parent_dev = dev_get_by_index(dev_net(netdev), parent_ifindex); + if (!parent_dev) + return NULL; + + parent_ipriv = netdev_priv(parent_dev); + + ASSERT_RTNL(); + parent_ipriv->num_sub_interfaces++; + + ipriv->parent_dev = parent_dev; + + return parent_dev; +} + +void mlx5i_parent_put(struct net_device *netdev) +{ + struct mlx5e_priv *priv = mlx5i_epriv(netdev); + struct mlx5i_priv *ipriv, *parent_ipriv; + + ipriv = priv->ppriv; + parent_ipriv = netdev_priv(ipriv->parent_dev); + + ASSERT_RTNL(); + parent_ipriv->num_sub_interfaces--; + + dev_put(ipriv->parent_dev); +} + int mlx5i_init_underlay_qp(struct mlx5e_priv *priv) { struct mlx5_core_dev *mdev = priv->mdev; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h index 99d46fda9f82..f3f2af972020 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h @@ -54,9 +54,11 @@ struct mlx5i_priv { struct rdma_netdev rn; /* keep this first */ u32 qpn; bool sub_interface; + u32 num_sub_interfaces; u32 qkey; u16 pkey_index; struct mlx5i_pkey_qpn_ht *qpn_htbl; + struct net_device *parent_dev; char *mlx5e_priv[]; }; @@ -117,5 +119,9 @@ void mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb, struct mlx5_av *av, u32 dqpn, u32 dqkey, bool xmit_more); void mlx5i_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats); +/* Reference management for child to parent interfaces. */ +struct net_device *mlx5i_parent_get(struct net_device *netdev); +void mlx5i_parent_put(struct net_device *netdev); + #endif /* CONFIG_MLX5_CORE_IPOIB */ #endif /* __MLX5E_IPOB_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c index 4d9c9e49645c..03e681297937 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c @@ -158,21 +158,28 @@ static int mlx5i_pkey_dev_init(struct net_device *dev) struct mlx5e_priv *priv = mlx5i_epriv(dev); struct mlx5i_priv *ipriv, *parent_ipriv; struct net_device *parent_dev; - int parent_ifindex; ipriv = priv->ppriv; - /* Get QPN to netdevice hash table from parent */ - parent_ifindex = dev->netdev_ops->ndo_get_iflink(dev); - parent_dev = dev_get_by_index(dev_net(dev), parent_ifindex); + /* Link to parent */ + parent_dev = mlx5i_parent_get(dev); if (!parent_dev) { mlx5_core_warn(priv->mdev, "failed to get parent device\n"); return -EINVAL; } + if (dev->num_rx_queues < parent_dev->real_num_rx_queues) { + mlx5_core_warn(priv->mdev, + "failed to create child device with rx queues [%d] less than parent's [%d]\n", + dev->num_rx_queues, + parent_dev->real_num_rx_queues); + mlx5i_parent_put(dev); + return -EINVAL; + } + + /* Get QPN to netdevice hash table from parent */ parent_ipriv = netdev_priv(parent_dev); ipriv->qpn_htbl = parent_ipriv->qpn_htbl; - dev_put(parent_dev); return mlx5i_dev_init(dev); } @@ -184,6 +191,7 @@ static int mlx5i_pkey_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static void mlx5i_pkey_dev_cleanup(struct net_device *netdev) { + mlx5i_parent_put(netdev); return mlx5i_dev_cleanup(netdev); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c index 32c3e0a649a7..ad32b80e8501 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c @@ -228,6 +228,7 @@ static void mlx5_ldev_free(struct kref *ref) if (ldev->nb.notifier_call) unregister_netdevice_notifier_net(&init_net, &ldev->nb); mlx5_lag_mp_cleanup(ldev); + cancel_delayed_work_sync(&ldev->bond_work); destroy_workqueue(ldev->wq); mlx5_lag_mpesw_cleanup(ldev); mutex_destroy(&ldev->lock); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c index 69cfe60c558a..69318b143268 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c @@ -681,7 +681,7 @@ static int mlx5_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin, static const struct ptp_clock_info mlx5_ptp_clock_info = { .owner = THIS_MODULE, .name = "mlx5_ptp", - .max_adj = 100000000, + .max_adj = 50000000, .n_alarm = 0, .n_ext_ts = 0, .n_per_out = 0, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 7f5db13e3550..4e1b5757528a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -613,7 +613,7 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx) MLX5_SET(cmd_hca_cap, set_hca_cap, num_total_dynamic_vf_msix, MLX5_CAP_GEN_MAX(dev, num_total_dynamic_vf_msix)); - if (MLX5_CAP_GEN(dev, roce_rw_supported)) + if (MLX5_CAP_GEN(dev, roce_rw_supported) && MLX5_CAP_GEN_MAX(dev, roce)) MLX5_SET(cmd_hca_cap, set_hca_cap, roce, mlx5_is_roce_on(dev)); @@ -1050,6 +1050,8 @@ err_rl_cleanup: err_tables_cleanup: mlx5_geneve_destroy(dev->geneve); mlx5_vxlan_destroy(dev->vxlan); + mlx5_cleanup_clock(dev); + mlx5_cleanup_reserved_gids(dev); mlx5_cq_debugfs_cleanup(dev); mlx5_fw_reset_cleanup(dev); err_events_cleanup: @@ -2096,7 +2098,7 @@ static void mlx5_core_verify_params(void) } } -static int __init init(void) +static int __init mlx5_init(void) { int err; @@ -2108,7 +2110,7 @@ static int __init init(void) mlx5_core_verify_params(); mlx5_register_debugfs(); - err = pci_register_driver(&mlx5_core_driver); + err = mlx5e_init(); if (err) goto err_debug; @@ -2116,28 +2118,28 @@ static int __init init(void) if (err) goto err_sf; - err = mlx5e_init(); + err = pci_register_driver(&mlx5_core_driver); if (err) - goto err_en; + goto err_pci; return 0; -err_en: +err_pci: mlx5_sf_driver_unregister(); err_sf: - pci_unregister_driver(&mlx5_core_driver); + mlx5e_cleanup(); err_debug: mlx5_unregister_debugfs(); return err; } -static void __exit cleanup(void) +static void __exit mlx5_cleanup(void) { - mlx5e_cleanup(); - mlx5_sf_driver_unregister(); pci_unregister_driver(&mlx5_core_driver); + mlx5_sf_driver_unregister(); + mlx5e_cleanup(); mlx5_unregister_debugfs(); } -module_init(init); -module_exit(cleanup); +module_init(mlx5_init); +module_exit(mlx5_cleanup); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index 60596357bfc7..0eb50be175cc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -74,6 +74,14 @@ static u32 get_function(u16 func_id, bool ec_function) return (u32)func_id | (ec_function << 16); } +static u16 func_id_to_type(struct mlx5_core_dev *dev, u16 func_id, bool ec_function) +{ + if (!func_id) + return mlx5_core_is_ecpf(dev) && !ec_function ? MLX5_HOST_PF : MLX5_PF; + + return func_id <= mlx5_core_max_vfs(dev) ? MLX5_VF : MLX5_SF; +} + static struct rb_root *page_root_per_function(struct mlx5_core_dev *dev, u32 function) { struct rb_root *root; @@ -332,6 +340,7 @@ static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages, u32 out[MLX5_ST_SZ_DW(manage_pages_out)] = {0}; int inlen = MLX5_ST_SZ_BYTES(manage_pages_in); int notify_fail = event; + u16 func_type; u64 addr; int err; u32 *in; @@ -383,11 +392,9 @@ retry: goto out_dropped; } + func_type = func_id_to_type(dev, func_id, ec_function); + dev->priv.page_counters[func_type] += npages; dev->priv.fw_pages += npages; - if (func_id) - dev->priv.vfs_pages += npages; - else if (mlx5_core_is_ecpf(dev) && !ec_function) - dev->priv.host_pf_pages += npages; mlx5_core_dbg(dev, "npages %d, ec_function %d, func_id 0x%x, err %d\n", npages, ec_function, func_id, err); @@ -414,6 +421,7 @@ static void release_all_pages(struct mlx5_core_dev *dev, u16 func_id, struct rb_root *root; struct rb_node *p; int npages = 0; + u16 func_type; root = xa_load(&dev->priv.page_root_xa, function); if (WARN_ON_ONCE(!root)) @@ -428,11 +436,9 @@ static void release_all_pages(struct mlx5_core_dev *dev, u16 func_id, free_fwp(dev, fwp, fwp->free_count); } + func_type = func_id_to_type(dev, func_id, ec_function); + dev->priv.page_counters[func_type] -= npages; dev->priv.fw_pages -= npages; - if (func_id) - dev->priv.vfs_pages -= npages; - else if (mlx5_core_is_ecpf(dev) && !ec_function) - dev->priv.host_pf_pages -= npages; mlx5_core_dbg(dev, "npages %d, ec_function %d, func_id 0x%x\n", npages, ec_function, func_id); @@ -498,6 +504,7 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u16 func_id, int npages, int outlen = MLX5_ST_SZ_BYTES(manage_pages_out); u32 in[MLX5_ST_SZ_DW(manage_pages_in)] = {}; int num_claimed; + u16 func_type; u32 *out; int err; int i; @@ -549,11 +556,9 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u16 func_id, int npages, if (nclaimed) *nclaimed = num_claimed; + func_type = func_id_to_type(dev, func_id, ec_function); + dev->priv.page_counters[func_type] -= num_claimed; dev->priv.fw_pages -= num_claimed; - if (func_id) - dev->priv.vfs_pages -= num_claimed; - else if (mlx5_core_is_ecpf(dev) && !ec_function) - dev->priv.host_pf_pages -= num_claimed; out_free: kvfree(out); @@ -706,12 +711,12 @@ int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev) WARN(dev->priv.fw_pages, "FW pages counter is %d after reclaiming all pages\n", dev->priv.fw_pages); - WARN(dev->priv.vfs_pages, + WARN(dev->priv.page_counters[MLX5_VF], "VFs FW pages counter is %d after reclaiming all pages\n", - dev->priv.vfs_pages); - WARN(dev->priv.host_pf_pages, + dev->priv.page_counters[MLX5_VF]); + WARN(dev->priv.page_counters[MLX5_HOST_PF], "External host PF FW pages counter is %d after reclaiming all pages\n", - dev->priv.host_pf_pages); + dev->priv.page_counters[MLX5_HOST_PF]); return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/qos.c index 0777be24a307..8bce730b5c5b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qos.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qos.c @@ -62,13 +62,12 @@ int mlx5_qos_create_root_node(struct mlx5_core_dev *mdev, u32 *id) return mlx5_qos_create_inner_node(mdev, MLX5_QOS_DEFAULT_DWRR_UID, 0, 0, id); } -int mlx5_qos_update_node(struct mlx5_core_dev *mdev, u32 parent_id, +int mlx5_qos_update_node(struct mlx5_core_dev *mdev, u32 bw_share, u32 max_avg_bw, u32 id) { u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0}; u32 bitmask = 0; - MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent_id); MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share); MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_avg_bw); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qos.h b/drivers/net/ethernet/mellanox/mlx5/core/qos.h index 125e4e47e6f7..624ce822b7f5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qos.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/qos.h @@ -23,7 +23,7 @@ int mlx5_qos_create_leaf_node(struct mlx5_core_dev *mdev, u32 parent_id, int mlx5_qos_create_inner_node(struct mlx5_core_dev *mdev, u32 parent_id, u32 bw_share, u32 max_avg_bw, u32 *id); int mlx5_qos_create_root_node(struct mlx5_core_dev *mdev, u32 *id); -int mlx5_qos_update_node(struct mlx5_core_dev *mdev, u32 parent_id, u32 bw_share, +int mlx5_qos_update_node(struct mlx5_core_dev *mdev, u32 bw_share, u32 max_avg_bw, u32 id); int mlx5_qos_destroy_node(struct mlx5_core_dev *mdev, u32 id); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c index c0e6c487c63c..3008e9ce2bbf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c @@ -147,7 +147,7 @@ mlx5_device_disable_sriov(struct mlx5_core_dev *dev, int num_vfs, bool clear_vf) mlx5_eswitch_disable_sriov(dev->priv.eswitch, clear_vf); - if (mlx5_wait_for_pages(dev, &dev->priv.vfs_pages)) + if (mlx5_wait_for_pages(dev, &dev->priv.page_counters[MLX5_VF])) mlx5_core_warn(dev, "timeout reclaiming VFs pages\n"); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c index 74cbe53ee9db..042ca0349124 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c @@ -3,7 +3,12 @@ #include "dr_types.h" +#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN < 2048) +/* don't try to optimize STE allocation if the stack is too constaraining */ +#define DR_RULE_MAX_STES_OPTIMIZED 0 +#else #define DR_RULE_MAX_STES_OPTIMIZED 5 +#endif #define DR_RULE_MAX_STE_CHAIN_OPTIMIZED (DR_RULE_MAX_STES_OPTIMIZED + DR_ACTION_MAX_STES) static int dr_rule_append_to_miss_list(struct mlx5dr_domain *dmn, @@ -1133,12 +1138,14 @@ dr_rule_create_rule_nic(struct mlx5dr_rule *rule, rule->flow_source)) return 0; + mlx5dr_domain_nic_lock(nic_dmn); + ret = mlx5dr_matcher_select_builders(matcher, nic_matcher, dr_rule_get_ipv(¶m->outer), dr_rule_get_ipv(¶m->inner)); if (ret) - return ret; + goto err_unlock; hw_ste_arr_is_opt = nic_matcher->num_of_builders <= DR_RULE_MAX_STES_OPTIMIZED; if (likely(hw_ste_arr_is_opt)) { @@ -1147,12 +1154,12 @@ dr_rule_create_rule_nic(struct mlx5dr_rule *rule, hw_ste_arr = kzalloc((nic_matcher->num_of_builders + DR_ACTION_MAX_STES) * DR_STE_SIZE, GFP_KERNEL); - if (!hw_ste_arr) - return -ENOMEM; + if (!hw_ste_arr) { + ret = -ENOMEM; + goto err_unlock; + } } - mlx5dr_domain_nic_lock(nic_dmn); - ret = mlx5dr_matcher_add_to_tbl_nic(dmn, nic_matcher); if (ret) goto free_hw_ste; @@ -1236,11 +1243,12 @@ remove_from_nic_tbl: mlx5dr_matcher_remove_from_tbl_nic(dmn, nic_matcher); free_hw_ste: - mlx5dr_domain_nic_unlock(nic_dmn); - - if (unlikely(!hw_ste_arr_is_opt)) + if (!hw_ste_arr_is_opt) kfree(hw_ste_arr); +err_unlock: + mlx5dr_domain_nic_unlock(nic_dmn); + return ret; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index c22c3ac4e2a1..09e32778b012 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2951,7 +2951,7 @@ struct mlxsw_sp_nexthop_group_info { gateway:1, /* routes using the group use a gateway */ is_resilient:1; struct list_head list; /* member in nh_res_grp_list */ - struct mlxsw_sp_nexthop nexthops[0]; + struct mlxsw_sp_nexthop nexthops[]; #define nh_rif nexthops[0].rif }; diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c index 5314c064ceae..55b484b10562 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c @@ -608,12 +608,12 @@ allocate_new: lan966x_fdma_rx_reload(rx); } - if (counter < weight && napi_complete_done(napi, counter)) - lan_wr(0xff, lan966x, FDMA_INTR_DB_ENA); - if (redirect) xdp_do_flush(); + if (counter < weight && napi_complete_done(napi, counter)) + lan_wr(0xff, lan966x, FDMA_INTR_DB_ENA); + return counter; } diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c index cadde20505ba..580c91d24a52 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c @@ -1043,11 +1043,6 @@ static int lan966x_probe(struct platform_device *pdev) lan966x->base_mac[5] &= 0xf0; } - ports = device_get_named_child_node(&pdev->dev, "ethernet-ports"); - if (!ports) - return dev_err_probe(&pdev->dev, -ENODEV, - "no ethernet-ports child found\n"); - err = lan966x_create_targets(pdev, lan966x); if (err) return dev_err_probe(&pdev->dev, err, @@ -1125,6 +1120,11 @@ static int lan966x_probe(struct platform_device *pdev) } } + ports = device_get_named_child_node(&pdev->dev, "ethernet-ports"); + if (!ports) + return dev_err_probe(&pdev->dev, -ENODEV, + "no ethernet-ports child found\n"); + /* init switch */ lan966x_init(lan966x); lan966x_stats_init(lan966x); @@ -1162,6 +1162,8 @@ static int lan966x_probe(struct platform_device *pdev) goto cleanup_ports; } + fwnode_handle_put(ports); + lan966x_mdb_init(lan966x); err = lan966x_fdb_init(lan966x); if (err) @@ -1191,6 +1193,7 @@ cleanup_fdb: lan966x_fdb_deinit(lan966x); cleanup_ports: + fwnode_handle_put(ports); fwnode_handle_put(portnp); lan966x_cleanup_ports(lan966x); diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c index 1a61c6cdb077..0050fcb988b7 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c @@ -381,7 +381,7 @@ int lan966x_port_pcs_set(struct lan966x_port *port, } /* Take PCS out of reset */ - lan_rmw(DEV_CLOCK_CFG_LINK_SPEED_SET(2) | + lan_rmw(DEV_CLOCK_CFG_LINK_SPEED_SET(LAN966X_SPEED_1000) | DEV_CLOCK_CFG_PCS_RX_RST_SET(0) | DEV_CLOCK_CFG_PCS_TX_RST_SET(0), DEV_CLOCK_CFG_LINK_SPEED | diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c index f9ebfaafbebc..a8348437dd87 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c @@ -1073,6 +1073,9 @@ void lan966x_ptp_deinit(struct lan966x *lan966x) struct lan966x_port *port; int i; + if (!lan966x->ptp) + return; + for (i = 0; i < lan966x->num_phys_ports; i++) { port = lan966x->ports[i]; if (!port) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c index d8dc9fbb81e1..a54c0426a35f 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c @@ -95,10 +95,7 @@ lan966x_vcap_is2_get_port_keysets(struct net_device *dev, int lookup, bool found = false; u32 val; - /* Check if the port keyset selection is enabled */ val = lan_rd(lan966x, ANA_VCAP_S2_CFG(port->chip_port)); - if (!ANA_VCAP_S2_CFG_ENA_GET(val)) - return -ENOENT; /* Collect all keysets for the port in a list */ if (l3_proto == ETH_P_ALL) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c index d25f4f09faa0..3c5d4fe99373 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c @@ -834,7 +834,7 @@ static int mchp_sparx5_probe(struct platform_device *pdev) if (err) goto cleanup_config; - if (!of_get_mac_address(np, sparx5->base_mac)) { + if (of_get_mac_address(np, sparx5->base_mac)) { dev_info(sparx5->dev, "MAC addr was not set, use random MAC\n"); eth_random_addr(sparx5->base_mac); sparx5->base_mac[5] = 0; diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c index 0ed1ea7727c5..69e76634f9aa 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c @@ -633,7 +633,7 @@ int sparx5_ptp_init(struct sparx5 *sparx5) /* Enable master counters */ spx5_wr(PTP_PTP_DOM_CFG_PTP_ENA_SET(0x7), sparx5, PTP_PTP_DOM_CFG); - for (i = 0; i < sparx5->port_count; i++) { + for (i = 0; i < SPX5_PORTS; i++) { port = sparx5->ports[i]; if (!port) continue; @@ -649,7 +649,7 @@ void sparx5_ptp_deinit(struct sparx5 *sparx5) struct sparx5_port *port; int i; - for (i = 0; i < sparx5->port_count; i++) { + for (i = 0; i < SPX5_PORTS; i++) { port = sparx5->ports[i]; if (!port) continue; diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c index e708c2d04983..f9b8f372ec8a 100644 --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c @@ -1217,9 +1217,7 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) unsigned int max_queues_per_port = num_online_cpus(); struct gdma_context *gc = pci_get_drvdata(pdev); struct gdma_irq_context *gic; - unsigned int max_irqs; - u16 *cpus; - cpumask_var_t req_mask; + unsigned int max_irqs, cpu; int nvec, irq; int err, i = 0, j; @@ -1240,39 +1238,31 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) goto free_irq_vector; } - if (!zalloc_cpumask_var(&req_mask, GFP_KERNEL)) { - err = -ENOMEM; - goto free_irq; - } - - cpus = kcalloc(nvec, sizeof(*cpus), GFP_KERNEL); - if (!cpus) { - err = -ENOMEM; - goto free_mask; - } - for (i = 0; i < nvec; i++) - cpus[i] = cpumask_local_spread(i, gc->numa_node); - for (i = 0; i < nvec; i++) { - cpumask_set_cpu(cpus[i], req_mask); gic = &gc->irq_contexts[i]; gic->handler = NULL; gic->arg = NULL; + if (!i) + snprintf(gic->name, MANA_IRQ_NAME_SZ, "mana_hwc@pci:%s", + pci_name(pdev)); + else + snprintf(gic->name, MANA_IRQ_NAME_SZ, "mana_q%d@pci:%s", + i - 1, pci_name(pdev)); + irq = pci_irq_vector(pdev, i); if (irq < 0) { err = irq; - goto free_mask; + goto free_irq; } - err = request_irq(irq, mana_gd_intr, 0, "mana_intr", gic); + err = request_irq(irq, mana_gd_intr, 0, gic->name, gic); if (err) - goto free_mask; - irq_set_affinity_and_hint(irq, req_mask); - cpumask_clear(req_mask); + goto free_irq; + + cpu = cpumask_local_spread(i, gc->numa_node); + irq_set_affinity_and_hint(irq, cpumask_of(cpu)); } - free_cpumask_var(req_mask); - kfree(cpus); err = mana_gd_alloc_res_map(nvec, &gc->msix_resource); if (err) @@ -1283,13 +1273,12 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) return 0; -free_mask: - free_cpumask_var(req_mask); - kfree(cpus); free_irq: for (j = i - 1; j >= 0; j--) { irq = pci_irq_vector(pdev, j); gic = &gc->irq_contexts[j]; + + irq_update_affinity_hint(irq, NULL); free_irq(irq, gic); } @@ -1317,6 +1306,9 @@ static void mana_gd_remove_irqs(struct pci_dev *pdev) continue; gic = &gc->irq_contexts[i]; + + /* Need to clear the hint before free_irq */ + irq_update_affinity_hint(irq, NULL); free_irq(irq, gic); } diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index 7c0897e779dc..ee052404eb55 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -605,6 +605,18 @@ ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress, flow_rule_match_control(rule, &match); } + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { + struct flow_match_vlan match; + + flow_rule_match_vlan(rule, &match); + filter->key_type = OCELOT_VCAP_KEY_ANY; + filter->vlan.vid.value = match.key->vlan_id; + filter->vlan.vid.mask = match.mask->vlan_id; + filter->vlan.pcp.value[0] = match.key->vlan_priority; + filter->vlan.pcp.mask[0] = match.mask->vlan_priority; + match_protocol = false; + } + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { struct flow_match_eth_addrs match; @@ -737,18 +749,6 @@ ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress, match_protocol = false; } - if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { - struct flow_match_vlan match; - - flow_rule_match_vlan(rule, &match); - filter->key_type = OCELOT_VCAP_KEY_ANY; - filter->vlan.vid.value = match.key->vlan_id; - filter->vlan.vid.mask = match.mask->vlan_id; - filter->vlan.pcp.value[0] = match.key->vlan_priority; - filter->vlan.pcp.mask[0] = match.mask->vlan_priority; - match_protocol = false; - } - finished_key_parsing: if (match_protocol && proto != ETH_P_ALL) { if (filter->block_id == VCAP_ES0) { diff --git a/drivers/net/ethernet/mscc/ocelot_ptp.c b/drivers/net/ethernet/mscc/ocelot_ptp.c index 1a82f10c8853..2180ae94c744 100644 --- a/drivers/net/ethernet/mscc/ocelot_ptp.c +++ b/drivers/net/ethernet/mscc/ocelot_ptp.c @@ -335,8 +335,8 @@ static void ocelot_populate_ipv6_ptp_event_trap_key(struct ocelot_vcap_filter *trap) { trap->key_type = OCELOT_VCAP_KEY_IPV6; - trap->key.ipv4.proto.value[0] = IPPROTO_UDP; - trap->key.ipv4.proto.mask[0] = 0xff; + trap->key.ipv6.proto.value[0] = IPPROTO_UDP; + trap->key.ipv6.proto.mask[0] = 0xff; trap->key.ipv6.dport.value = PTP_EV_PORT; trap->key.ipv6.dport.mask = 0xffff; } @@ -355,8 +355,8 @@ static void ocelot_populate_ipv6_ptp_general_trap_key(struct ocelot_vcap_filter *trap) { trap->key_type = OCELOT_VCAP_KEY_IPV6; - trap->key.ipv4.proto.value[0] = IPPROTO_UDP; - trap->key.ipv4.proto.mask[0] = 0xff; + trap->key.ipv6.proto.value[0] = IPPROTO_UDP; + trap->key.ipv6.proto.mask[0] = 0xff; trap->key.ipv6.dport.value = PTP_GEN_PORT; trap->key.ipv6.dport.mask = 0xffff; } diff --git a/drivers/net/ethernet/netronome/nfp/crypto/ipsec.c b/drivers/net/ethernet/netronome/nfp/crypto/ipsec.c index 4632268695cb..063cd371033a 100644 --- a/drivers/net/ethernet/netronome/nfp/crypto/ipsec.c +++ b/drivers/net/ethernet/netronome/nfp/crypto/ipsec.c @@ -129,26 +129,31 @@ struct nfp_ipsec_cfg_mssg { }; }; -static int nfp_ipsec_cfg_cmd_issue(struct nfp_net *nn, int type, int saidx, - struct nfp_ipsec_cfg_mssg *msg) +static int nfp_net_ipsec_cfg(struct nfp_net *nn, struct nfp_mbox_amsg_entry *entry) { + unsigned int offset = nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL; + struct nfp_ipsec_cfg_mssg *msg = (struct nfp_ipsec_cfg_mssg *)entry->msg; int i, msg_size, ret; - msg->cmd = type; - msg->sa_idx = saidx; - msg->rsp = 0; - msg_size = ARRAY_SIZE(msg->raw); + ret = nfp_net_mbox_lock(nn, sizeof(*msg)); + if (ret) + return ret; + msg_size = ARRAY_SIZE(msg->raw); for (i = 0; i < msg_size; i++) - nn_writel(nn, NFP_NET_CFG_MBOX_VAL + 4 * i, msg->raw[i]); + nn_writel(nn, offset + 4 * i, msg->raw[i]); - ret = nfp_net_mbox_reconfig(nn, NFP_NET_CFG_MBOX_CMD_IPSEC); - if (ret < 0) + ret = nfp_net_mbox_reconfig(nn, entry->cmd); + if (ret < 0) { + nn_ctrl_bar_unlock(nn); return ret; + } /* For now we always read the whole message response back */ for (i = 0; i < msg_size; i++) - msg->raw[i] = nn_readl(nn, NFP_NET_CFG_MBOX_VAL + 4 * i); + msg->raw[i] = nn_readl(nn, offset + 4 * i); + + nn_ctrl_bar_unlock(nn); switch (msg->rsp) { case NFP_IPSEC_CFG_MSSG_OK: @@ -477,7 +482,10 @@ static int nfp_net_xfrm_add_state(struct xfrm_state *x) } /* Allocate saidx and commit the SA */ - err = nfp_ipsec_cfg_cmd_issue(nn, NFP_IPSEC_CFG_MSSG_ADD_SA, saidx, &msg); + msg.cmd = NFP_IPSEC_CFG_MSSG_ADD_SA; + msg.sa_idx = saidx; + err = nfp_net_sched_mbox_amsg_work(nn, NFP_NET_CFG_MBOX_CMD_IPSEC, &msg, + sizeof(msg), nfp_net_ipsec_cfg); if (err) { xa_erase(&nn->xa_ipsec, saidx); nn_err(nn, "Failed to issue IPsec command err ret=%d\n", err); @@ -491,14 +499,17 @@ static int nfp_net_xfrm_add_state(struct xfrm_state *x) static void nfp_net_xfrm_del_state(struct xfrm_state *x) { + struct nfp_ipsec_cfg_mssg msg = { + .cmd = NFP_IPSEC_CFG_MSSG_INV_SA, + .sa_idx = x->xso.offload_handle - 1, + }; struct net_device *netdev = x->xso.dev; - struct nfp_ipsec_cfg_mssg msg; struct nfp_net *nn; int err; nn = netdev_priv(netdev); - err = nfp_ipsec_cfg_cmd_issue(nn, NFP_IPSEC_CFG_MSSG_INV_SA, - x->xso.offload_handle - 1, &msg); + err = nfp_net_sched_mbox_amsg_work(nn, NFP_NET_CFG_MBOX_CMD_IPSEC, &msg, + sizeof(msg), nfp_net_ipsec_cfg); if (err) nn_warn(nn, "Failed to invalidate SA in hardware\n"); diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c index a8678d5612ee..060a77f2265d 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c @@ -460,6 +460,7 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app, sizeof(struct nfp_tun_neigh_v4); unsigned long cookie = (unsigned long)neigh; struct nfp_flower_priv *priv = app->priv; + struct nfp_tun_neigh_lag lag_info; struct nfp_neigh_entry *nn_entry; u32 port_id; u8 mtype; @@ -468,6 +469,11 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app, if (!port_id) return; + if ((port_id & NFP_FL_LAG_OUT) == NFP_FL_LAG_OUT) { + memset(&lag_info, 0, sizeof(struct nfp_tun_neigh_lag)); + nfp_flower_lag_get_info_from_netdev(app, netdev, &lag_info); + } + spin_lock_bh(&priv->predt_lock); nn_entry = rhashtable_lookup_fast(&priv->neigh_table, &cookie, neigh_table_params); @@ -515,7 +521,7 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app, neigh_ha_snapshot(common->dst_addr, neigh, netdev); if ((port_id & NFP_FL_LAG_OUT) == NFP_FL_LAG_OUT) - nfp_flower_lag_get_info_from_netdev(app, netdev, lag); + memcpy(lag, &lag_info, sizeof(struct nfp_tun_neigh_lag)); common->port_id = cpu_to_be32(port_id); if (rhashtable_insert_fast(&priv->neigh_table, diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index da33f09facb9..939cfce15830 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -617,6 +617,10 @@ struct nfp_net_dp { * @vnic_no_name: For non-port PF vNIC make ndo_get_phys_port_name return * -EOPNOTSUPP to keep backwards compatibility (set by app) * @port: Pointer to nfp_port structure if vNIC is a port + * @mbox_amsg: Asynchronously processed message via mailbox + * @mbox_amsg.lock: Protect message list + * @mbox_amsg.list: List of message to process + * @mbox_amsg.work: Work to process message asynchronously * @app_priv: APP private data for this vNIC */ struct nfp_net { @@ -718,9 +722,25 @@ struct nfp_net { struct nfp_port *port; + struct { + spinlock_t lock; + struct list_head list; + struct work_struct work; + } mbox_amsg; + void *app_priv; }; +struct nfp_mbox_amsg_entry { + struct list_head list; + int (*cfg)(struct nfp_net *nn, struct nfp_mbox_amsg_entry *entry); + u32 cmd; + char msg[]; +}; + +int nfp_net_sched_mbox_amsg_work(struct nfp_net *nn, u32 cmd, const void *data, size_t len, + int (*cb)(struct nfp_net *, struct nfp_mbox_amsg_entry *)); + /* Functions to read/write from/to a BAR * Performs any endian conversion necessary. */ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 09053373288f..70d7484c82af 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -1334,9 +1334,54 @@ err_unlock: return err; } -static int nfp_net_mc_cfg(struct net_device *netdev, const unsigned char *addr, const u32 cmd) +int nfp_net_sched_mbox_amsg_work(struct nfp_net *nn, u32 cmd, const void *data, size_t len, + int (*cb)(struct nfp_net *, struct nfp_mbox_amsg_entry *)) { - struct nfp_net *nn = netdev_priv(netdev); + struct nfp_mbox_amsg_entry *entry; + + entry = kmalloc(sizeof(*entry) + len, GFP_ATOMIC); + if (!entry) + return -ENOMEM; + + memcpy(entry->msg, data, len); + entry->cmd = cmd; + entry->cfg = cb; + + spin_lock_bh(&nn->mbox_amsg.lock); + list_add_tail(&entry->list, &nn->mbox_amsg.list); + spin_unlock_bh(&nn->mbox_amsg.lock); + + schedule_work(&nn->mbox_amsg.work); + + return 0; +} + +static void nfp_net_mbox_amsg_work(struct work_struct *work) +{ + struct nfp_net *nn = container_of(work, struct nfp_net, mbox_amsg.work); + struct nfp_mbox_amsg_entry *entry, *tmp; + struct list_head tmp_list; + + INIT_LIST_HEAD(&tmp_list); + + spin_lock_bh(&nn->mbox_amsg.lock); + list_splice_init(&nn->mbox_amsg.list, &tmp_list); + spin_unlock_bh(&nn->mbox_amsg.lock); + + list_for_each_entry_safe(entry, tmp, &tmp_list, list) { + int err = entry->cfg(nn, entry); + + if (err) + nn_err(nn, "Config cmd %d to HW failed %d.\n", entry->cmd, err); + + list_del(&entry->list); + kfree(entry); + } +} + +static int nfp_net_mc_cfg(struct nfp_net *nn, struct nfp_mbox_amsg_entry *entry) +{ + unsigned char *addr = entry->msg; int ret; ret = nfp_net_mbox_lock(nn, NFP_NET_CFG_MULTICAST_SZ); @@ -1348,7 +1393,7 @@ static int nfp_net_mc_cfg(struct net_device *netdev, const unsigned char *addr, nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_MULTICAST_MAC_LO, get_unaligned_be16(addr + 4)); - return nfp_net_mbox_reconfig_and_unlock(nn, cmd); + return nfp_net_mbox_reconfig_and_unlock(nn, entry->cmd); } static int nfp_net_mc_sync(struct net_device *netdev, const unsigned char *addr) @@ -1361,12 +1406,16 @@ static int nfp_net_mc_sync(struct net_device *netdev, const unsigned char *addr) return -EINVAL; } - return nfp_net_mc_cfg(netdev, addr, NFP_NET_CFG_MBOX_CMD_MULTICAST_ADD); + return nfp_net_sched_mbox_amsg_work(nn, NFP_NET_CFG_MBOX_CMD_MULTICAST_ADD, addr, + NFP_NET_CFG_MULTICAST_SZ, nfp_net_mc_cfg); } static int nfp_net_mc_unsync(struct net_device *netdev, const unsigned char *addr) { - return nfp_net_mc_cfg(netdev, addr, NFP_NET_CFG_MBOX_CMD_MULTICAST_DEL); + struct nfp_net *nn = netdev_priv(netdev); + + return nfp_net_sched_mbox_amsg_work(nn, NFP_NET_CFG_MBOX_CMD_MULTICAST_DEL, addr, + NFP_NET_CFG_MULTICAST_SZ, nfp_net_mc_cfg); } static void nfp_net_set_rx_mode(struct net_device *netdev) @@ -2633,6 +2682,11 @@ int nfp_net_init(struct nfp_net *nn) if (!nn->dp.netdev) return 0; + + spin_lock_init(&nn->mbox_amsg.lock); + INIT_LIST_HEAD(&nn->mbox_amsg.list); + INIT_WORK(&nn->mbox_amsg.work, nfp_net_mbox_amsg_work); + return register_netdev(nn->dp.netdev); err_clean_mbox: @@ -2652,5 +2706,6 @@ void nfp_net_clean(struct nfp_net *nn) unregister_netdev(nn->dp.netdev); nfp_net_ipsec_clean(nn); nfp_ccm_mbox_clean(nn); + flush_work(&nn->mbox_amsg.work); nfp_net_reconfig_wait_posted(nn); } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index 51124309ae1f..f03dcadff738 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -403,7 +403,6 @@ */ #define NFP_NET_CFG_MBOX_BASE 0x1800 #define NFP_NET_CFG_MBOX_VAL_MAX_SZ 0x1F8 -#define NFP_NET_CFG_MBOX_VAL 0x1808 #define NFP_NET_CFG_MBOX_SIMPLE_CMD 0x0 #define NFP_NET_CFG_MBOX_SIMPLE_RET 0x4 #define NFP_NET_CFG_MBOX_SIMPLE_VAL 0x8 diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index a4a89ef3f18b..cc97b3d00414 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -293,35 +293,131 @@ nfp_net_set_fec_link_mode(struct nfp_eth_table_port *eth_port, } } -static const u16 nfp_eth_media_table[] = { - [NFP_MEDIA_1000BASE_CX] = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, - [NFP_MEDIA_1000BASE_KX] = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, - [NFP_MEDIA_10GBASE_KX4] = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, - [NFP_MEDIA_10GBASE_KR] = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, - [NFP_MEDIA_10GBASE_CX4] = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, - [NFP_MEDIA_10GBASE_CR] = ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, - [NFP_MEDIA_10GBASE_SR] = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, - [NFP_MEDIA_10GBASE_ER] = ETHTOOL_LINK_MODE_10000baseER_Full_BIT, - [NFP_MEDIA_25GBASE_KR] = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, - [NFP_MEDIA_25GBASE_KR_S] = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, - [NFP_MEDIA_25GBASE_CR] = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, - [NFP_MEDIA_25GBASE_CR_S] = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, - [NFP_MEDIA_25GBASE_SR] = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, - [NFP_MEDIA_40GBASE_CR4] = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, - [NFP_MEDIA_40GBASE_KR4] = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, - [NFP_MEDIA_40GBASE_SR4] = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, - [NFP_MEDIA_40GBASE_LR4] = ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, - [NFP_MEDIA_50GBASE_KR] = ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, - [NFP_MEDIA_50GBASE_SR] = ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, - [NFP_MEDIA_50GBASE_CR] = ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, - [NFP_MEDIA_50GBASE_LR] = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, - [NFP_MEDIA_50GBASE_ER] = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, - [NFP_MEDIA_50GBASE_FR] = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, - [NFP_MEDIA_100GBASE_KR4] = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, - [NFP_MEDIA_100GBASE_SR4] = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, - [NFP_MEDIA_100GBASE_CR4] = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, - [NFP_MEDIA_100GBASE_KP4] = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, - [NFP_MEDIA_100GBASE_CR10] = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, +static const struct nfp_eth_media_link_mode { + u16 ethtool_link_mode; + u16 speed; +} nfp_eth_media_table[NFP_MEDIA_LINK_MODES_NUMBER] = { + [NFP_MEDIA_1000BASE_CX] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, + .speed = NFP_SPEED_1G, + }, + [NFP_MEDIA_1000BASE_KX] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, + .speed = NFP_SPEED_1G, + }, + [NFP_MEDIA_10GBASE_KX4] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, + .speed = NFP_SPEED_10G, + }, + [NFP_MEDIA_10GBASE_KR] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, + .speed = NFP_SPEED_10G, + }, + [NFP_MEDIA_10GBASE_CX4] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, + .speed = NFP_SPEED_10G, + }, + [NFP_MEDIA_10GBASE_CR] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, + .speed = NFP_SPEED_10G, + }, + [NFP_MEDIA_10GBASE_SR] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, + .speed = NFP_SPEED_10G, + }, + [NFP_MEDIA_10GBASE_ER] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_10000baseER_Full_BIT, + .speed = NFP_SPEED_10G, + }, + [NFP_MEDIA_25GBASE_KR] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, + .speed = NFP_SPEED_25G, + }, + [NFP_MEDIA_25GBASE_KR_S] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, + .speed = NFP_SPEED_25G, + }, + [NFP_MEDIA_25GBASE_CR] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, + .speed = NFP_SPEED_25G, + }, + [NFP_MEDIA_25GBASE_CR_S] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, + .speed = NFP_SPEED_25G, + }, + [NFP_MEDIA_25GBASE_SR] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, + .speed = NFP_SPEED_25G, + }, + [NFP_MEDIA_40GBASE_CR4] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, + .speed = NFP_SPEED_40G, + }, + [NFP_MEDIA_40GBASE_KR4] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, + .speed = NFP_SPEED_40G, + }, + [NFP_MEDIA_40GBASE_SR4] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, + .speed = NFP_SPEED_40G, + }, + [NFP_MEDIA_40GBASE_LR4] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, + .speed = NFP_SPEED_40G, + }, + [NFP_MEDIA_50GBASE_KR] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, + .speed = NFP_SPEED_50G, + }, + [NFP_MEDIA_50GBASE_SR] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, + .speed = NFP_SPEED_50G, + }, + [NFP_MEDIA_50GBASE_CR] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, + .speed = NFP_SPEED_50G, + }, + [NFP_MEDIA_50GBASE_LR] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, + .speed = NFP_SPEED_50G, + }, + [NFP_MEDIA_50GBASE_ER] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, + .speed = NFP_SPEED_50G, + }, + [NFP_MEDIA_50GBASE_FR] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, + .speed = NFP_SPEED_50G, + }, + [NFP_MEDIA_100GBASE_KR4] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, + .speed = NFP_SPEED_100G, + }, + [NFP_MEDIA_100GBASE_SR4] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, + .speed = NFP_SPEED_100G, + }, + [NFP_MEDIA_100GBASE_CR4] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, + .speed = NFP_SPEED_100G, + }, + [NFP_MEDIA_100GBASE_KP4] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, + .speed = NFP_SPEED_100G, + }, + [NFP_MEDIA_100GBASE_CR10] = { + .ethtool_link_mode = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, + .speed = NFP_SPEED_100G, + }, +}; + +static const unsigned int nfp_eth_speed_map[NFP_SUP_SPEED_NUMBER] = { + [NFP_SPEED_1G] = SPEED_1000, + [NFP_SPEED_10G] = SPEED_10000, + [NFP_SPEED_25G] = SPEED_25000, + [NFP_SPEED_40G] = SPEED_40000, + [NFP_SPEED_50G] = SPEED_50000, + [NFP_SPEED_100G] = SPEED_100000, }; static void nfp_add_media_link_mode(struct nfp_port *port, @@ -334,8 +430,12 @@ static void nfp_add_media_link_mode(struct nfp_port *port, }; struct nfp_cpp *cpp = port->app->cpp; - if (nfp_eth_read_media(cpp, ðm)) + if (nfp_eth_read_media(cpp, ðm)) { + bitmap_fill(port->speed_bitmap, NFP_SUP_SPEED_NUMBER); return; + } + + bitmap_zero(port->speed_bitmap, NFP_SUP_SPEED_NUMBER); for (u32 i = 0; i < 2; i++) { supported_modes[i] = le64_to_cpu(ethm.supported_modes[i]); @@ -344,20 +444,26 @@ static void nfp_add_media_link_mode(struct nfp_port *port, for (u32 i = 0; i < NFP_MEDIA_LINK_MODES_NUMBER; i++) { if (i < 64) { - if (supported_modes[0] & BIT_ULL(i)) - __set_bit(nfp_eth_media_table[i], + if (supported_modes[0] & BIT_ULL(i)) { + __set_bit(nfp_eth_media_table[i].ethtool_link_mode, cmd->link_modes.supported); + __set_bit(nfp_eth_media_table[i].speed, + port->speed_bitmap); + } if (advertised_modes[0] & BIT_ULL(i)) - __set_bit(nfp_eth_media_table[i], + __set_bit(nfp_eth_media_table[i].ethtool_link_mode, cmd->link_modes.advertising); } else { - if (supported_modes[1] & BIT_ULL(i - 64)) - __set_bit(nfp_eth_media_table[i], + if (supported_modes[1] & BIT_ULL(i - 64)) { + __set_bit(nfp_eth_media_table[i].ethtool_link_mode, cmd->link_modes.supported); + __set_bit(nfp_eth_media_table[i].speed, + port->speed_bitmap); + } if (advertised_modes[1] & BIT_ULL(i - 64)) - __set_bit(nfp_eth_media_table[i], + __set_bit(nfp_eth_media_table[i].ethtool_link_mode, cmd->link_modes.advertising); } } @@ -468,6 +574,22 @@ nfp_net_set_link_ksettings(struct net_device *netdev, if (cmd->base.speed != SPEED_UNKNOWN) { u32 speed = cmd->base.speed / eth_port->lanes; + bool is_supported = false; + + for (u32 i = 0; i < NFP_SUP_SPEED_NUMBER; i++) { + if (cmd->base.speed == nfp_eth_speed_map[i] && + test_bit(i, port->speed_bitmap)) { + is_supported = true; + break; + } + } + + if (!is_supported) { + netdev_err(netdev, "Speed %u is not supported.\n", + cmd->base.speed); + err = -EINVAL; + goto err_bad_set; + } if (req_aneg) { netdev_err(netdev, "Speed changing is not allowed when working on autoneg mode.\n"); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h index f8cd157ca1d7..9c04f9f0e2c9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -38,6 +38,16 @@ enum nfp_port_flags { NFP_PORT_CHANGED = 0, }; +enum { + NFP_SPEED_1G, + NFP_SPEED_10G, + NFP_SPEED_25G, + NFP_SPEED_40G, + NFP_SPEED_50G, + NFP_SPEED_100G, + NFP_SUP_SPEED_NUMBER +}; + /** * struct nfp_port - structure representing NFP port * @netdev: backpointer to associated netdev @@ -52,6 +62,7 @@ enum nfp_port_flags { * @eth_forced: for %NFP_PORT_PHYS_PORT port is forced UP or DOWN, don't change * @eth_port: for %NFP_PORT_PHYS_PORT translated ETH Table port entry * @eth_stats: for %NFP_PORT_PHYS_PORT MAC stats if available + * @speed_bitmap: for %NFP_PORT_PHYS_PORT supported speed bitmap * @pf_id: for %NFP_PORT_PF_PORT, %NFP_PORT_VF_PORT ID of the PCI PF (0-3) * @vf_id: for %NFP_PORT_VF_PORT ID of the PCI VF within @pf_id * @pf_split: for %NFP_PORT_PF_PORT %true if PCI PF has more than one vNIC @@ -78,6 +89,7 @@ struct nfp_port { bool eth_forced; struct nfp_eth_table_port *eth_port; u8 __iomem *eth_stats; + DECLARE_BITMAP(speed_bitmap, NFP_SUP_SPEED_NUMBER); }; /* NFP_PORT_PF_PORT, NFP_PORT_VF_PORT */ struct { diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c index 626b9113e7c4..d911f4fd9af6 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c @@ -708,9 +708,16 @@ void ionic_q_post(struct ionic_queue *q, bool ring_doorbell, ionic_desc_cb cb, q->lif->index, q->name, q->hw_type, q->hw_index, q->head_idx, ring_doorbell); - if (ring_doorbell) + if (ring_doorbell) { ionic_dbell_ring(lif->kern_dbpage, q->hw_type, q->dbval | q->head_idx); + + q->dbell_jiffies = jiffies; + + if (q_to_qcq(q)->napi_qcq) + mod_timer(&q_to_qcq(q)->napi_qcq->napi_deadline, + jiffies + IONIC_NAPI_DEADLINE); + } } static bool ionic_q_is_posted(struct ionic_queue *q, unsigned int pos) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 2a1d7b9c07e7..bce3ca38669b 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -25,6 +25,12 @@ #define IONIC_DEV_INFO_REG_COUNT 32 #define IONIC_DEV_CMD_REG_COUNT 32 +#define IONIC_NAPI_DEADLINE (HZ / 200) /* 5ms */ +#define IONIC_ADMIN_DOORBELL_DEADLINE (HZ / 2) /* 500ms */ +#define IONIC_TX_DOORBELL_DEADLINE (HZ / 100) /* 10ms */ +#define IONIC_RX_MIN_DOORBELL_DEADLINE (HZ / 100) /* 10ms */ +#define IONIC_RX_MAX_DOORBELL_DEADLINE (HZ * 5) /* 5s */ + struct ionic_dev_bar { void __iomem *vaddr; phys_addr_t bus_addr; @@ -216,6 +222,8 @@ struct ionic_queue { struct ionic_lif *lif; struct ionic_desc_info *info; u64 dbval; + unsigned long dbell_deadline; + unsigned long dbell_jiffies; u16 head_idx; u16 tail_idx; unsigned int index; @@ -361,4 +369,8 @@ void ionic_q_service(struct ionic_queue *q, struct ionic_cq_info *cq_info, int ionic_heartbeat_check(struct ionic *ionic); bool ionic_is_fw_running(struct ionic_dev *idev); +bool ionic_adminq_poke_doorbell(struct ionic_queue *q); +bool ionic_txq_poke_doorbell(struct ionic_queue *q); +bool ionic_rxq_poke_doorbell(struct ionic_queue *q); + #endif /* _IONIC_DEV_H_ */ diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 4dd16c487f2b..63a78a9ac241 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -16,6 +16,7 @@ #include "ionic.h" #include "ionic_bus.h" +#include "ionic_dev.h" #include "ionic_lif.h" #include "ionic_txrx.h" #include "ionic_ethtool.h" @@ -200,6 +201,13 @@ void ionic_link_status_check_request(struct ionic_lif *lif, bool can_sleep) } } +static void ionic_napi_deadline(struct timer_list *timer) +{ + struct ionic_qcq *qcq = container_of(timer, struct ionic_qcq, napi_deadline); + + napi_schedule(&qcq->napi); +} + static irqreturn_t ionic_isr(int irq, void *data) { struct napi_struct *napi = data; @@ -269,6 +277,7 @@ static int ionic_qcq_enable(struct ionic_qcq *qcq) .oper = IONIC_Q_ENABLE, }, }; + int ret; idev = &lif->ionic->idev; dev = lif->ionic->dev; @@ -276,16 +285,24 @@ static int ionic_qcq_enable(struct ionic_qcq *qcq) dev_dbg(dev, "q_enable.index %d q_enable.qtype %d\n", ctx.cmd.q_control.index, ctx.cmd.q_control.type); + if (qcq->flags & IONIC_QCQ_F_INTR) + ionic_intr_clean(idev->intr_ctrl, qcq->intr.index); + + ret = ionic_adminq_post_wait(lif, &ctx); + if (ret) + return ret; + + if (qcq->napi.poll) + napi_enable(&qcq->napi); + if (qcq->flags & IONIC_QCQ_F_INTR) { irq_set_affinity_hint(qcq->intr.vector, &qcq->intr.affinity_mask); - napi_enable(&qcq->napi); - ionic_intr_clean(idev->intr_ctrl, qcq->intr.index); ionic_intr_mask(idev->intr_ctrl, qcq->intr.index, IONIC_INTR_MASK_CLEAR); } - return ionic_adminq_post_wait(lif, &ctx); + return 0; } static int ionic_qcq_disable(struct ionic_lif *lif, struct ionic_qcq *qcq, int fw_err) @@ -316,6 +333,7 @@ static int ionic_qcq_disable(struct ionic_lif *lif, struct ionic_qcq *qcq, int f synchronize_irq(qcq->intr.vector); irq_set_affinity_hint(qcq->intr.vector, NULL); napi_disable(&qcq->napi); + del_timer_sync(&qcq->napi_deadline); } /* If there was a previous fw communcation error, don't bother with @@ -451,6 +469,7 @@ static void ionic_link_qcq_interrupts(struct ionic_qcq *src_qcq, n_qcq->intr.vector = src_qcq->intr.vector; n_qcq->intr.index = src_qcq->intr.index; + n_qcq->napi_qcq = src_qcq->napi_qcq; } static int ionic_alloc_qcq_interrupt(struct ionic_lif *lif, struct ionic_qcq *qcq) @@ -564,13 +583,15 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type, } if (flags & IONIC_QCQ_F_NOTIFYQ) { - int q_size, cq_size; + int q_size; - /* q & cq need to be contiguous in case of notifyq */ + /* q & cq need to be contiguous in NotifyQ, so alloc it all in q + * and don't alloc qc. We leave new->qc_size and new->qc_base + * as 0 to be sure we don't try to free it later. + */ q_size = ALIGN(num_descs * desc_size, PAGE_SIZE); - cq_size = ALIGN(num_descs * cq_desc_size, PAGE_SIZE); - - new->q_size = PAGE_SIZE + q_size + cq_size; + new->q_size = PAGE_SIZE + q_size + + ALIGN(num_descs * cq_desc_size, PAGE_SIZE); new->q_base = dma_alloc_coherent(dev, new->q_size, &new->q_base_pa, GFP_KERNEL); if (!new->q_base) { @@ -773,8 +794,14 @@ static int ionic_lif_txq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) dev_dbg(dev, "txq->hw_type %d\n", q->hw_type); dev_dbg(dev, "txq->hw_index %d\n", q->hw_index); - if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) + q->dbell_deadline = IONIC_TX_DOORBELL_DEADLINE; + q->dbell_jiffies = jiffies; + + if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) { netif_napi_add(lif->netdev, &qcq->napi, ionic_tx_napi); + qcq->napi_qcq = qcq; + timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0); + } qcq->flags |= IONIC_QCQ_F_INITED; @@ -828,11 +855,17 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) dev_dbg(dev, "rxq->hw_type %d\n", q->hw_type); dev_dbg(dev, "rxq->hw_index %d\n", q->hw_index); + q->dbell_deadline = IONIC_RX_MIN_DOORBELL_DEADLINE; + q->dbell_jiffies = jiffies; + if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) netif_napi_add(lif->netdev, &qcq->napi, ionic_rx_napi); else netif_napi_add(lif->netdev, &qcq->napi, ionic_txrx_napi); + qcq->napi_qcq = qcq; + timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0); + qcq->flags |= IONIC_QCQ_F_INITED; return 0; @@ -1150,6 +1183,7 @@ static int ionic_adminq_napi(struct napi_struct *napi, int budget) struct ionic_dev *idev = &lif->ionic->idev; unsigned long irqflags; unsigned int flags = 0; + bool resched = false; int rx_work = 0; int tx_work = 0; int n_work = 0; @@ -1187,6 +1221,16 @@ static int ionic_adminq_napi(struct napi_struct *napi, int budget) ionic_intr_credits(idev->intr_ctrl, intr->index, credits, flags); } + if (!a_work && ionic_adminq_poke_doorbell(&lif->adminqcq->q)) + resched = true; + if (lif->hwstamp_rxq && !rx_work && ionic_rxq_poke_doorbell(&lif->hwstamp_rxq->q)) + resched = true; + if (lif->hwstamp_txq && !tx_work && ionic_txq_poke_doorbell(&lif->hwstamp_txq->q)) + resched = true; + if (resched) + mod_timer(&lif->adminqcq->napi_deadline, + jiffies + IONIC_NAPI_DEADLINE); + return work_done; } @@ -3245,8 +3289,14 @@ static int ionic_lif_adminq_init(struct ionic_lif *lif) dev_dbg(dev, "adminq->hw_type %d\n", q->hw_type); dev_dbg(dev, "adminq->hw_index %d\n", q->hw_index); + q->dbell_deadline = IONIC_ADMIN_DOORBELL_DEADLINE; + q->dbell_jiffies = jiffies; + netif_napi_add(lif->netdev, &qcq->napi, ionic_adminq_napi); + qcq->napi_qcq = qcq; + timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0); + napi_enable(&qcq->napi); if (qcq->flags & IONIC_QCQ_F_INTR) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h index a53984bf3544..734519895614 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h @@ -74,8 +74,10 @@ struct ionic_qcq { struct ionic_queue q; struct ionic_cq cq; struct ionic_intr_info intr; + struct timer_list napi_deadline; struct napi_struct napi; unsigned int flags; + struct ionic_qcq *napi_qcq; struct dentry *dentry; }; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c index a13530ec4dd8..08c42b039d92 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_main.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c @@ -289,6 +289,35 @@ static void ionic_adminq_cb(struct ionic_queue *q, complete_all(&ctx->work); } +bool ionic_adminq_poke_doorbell(struct ionic_queue *q) +{ + struct ionic_lif *lif = q->lif; + unsigned long now, then, dif; + unsigned long irqflags; + + spin_lock_irqsave(&lif->adminq_lock, irqflags); + + if (q->tail_idx == q->head_idx) { + spin_unlock_irqrestore(&lif->adminq_lock, irqflags); + return false; + } + + now = READ_ONCE(jiffies); + then = q->dbell_jiffies; + dif = now - then; + + if (dif > q->dbell_deadline) { + ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type, + q->dbval | q->head_idx); + + q->dbell_jiffies = now; + } + + spin_unlock_irqrestore(&lif->adminq_lock, irqflags); + + return true; +} + int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) { struct ionic_desc_info *desc_info; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 0c3977416cd1..f761780f0162 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -22,6 +22,67 @@ static inline void ionic_rxq_post(struct ionic_queue *q, bool ring_dbell, ionic_q_post(q, ring_dbell, cb_func, cb_arg); } +bool ionic_txq_poke_doorbell(struct ionic_queue *q) +{ + unsigned long now, then, dif; + struct netdev_queue *netdev_txq; + struct net_device *netdev; + + netdev = q->lif->netdev; + netdev_txq = netdev_get_tx_queue(netdev, q->index); + + HARD_TX_LOCK(netdev, netdev_txq, smp_processor_id()); + + if (q->tail_idx == q->head_idx) { + HARD_TX_UNLOCK(netdev, netdev_txq); + return false; + } + + now = READ_ONCE(jiffies); + then = q->dbell_jiffies; + dif = now - then; + + if (dif > q->dbell_deadline) { + ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type, + q->dbval | q->head_idx); + + q->dbell_jiffies = now; + } + + HARD_TX_UNLOCK(netdev, netdev_txq); + + return true; +} + +bool ionic_rxq_poke_doorbell(struct ionic_queue *q) +{ + unsigned long now, then, dif; + + /* no lock, called from rx napi or txrx napi, nothing else can fill */ + + if (q->tail_idx == q->head_idx) + return false; + + now = READ_ONCE(jiffies); + then = q->dbell_jiffies; + dif = now - then; + + if (dif > q->dbell_deadline) { + ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type, + q->dbval | q->head_idx); + + q->dbell_jiffies = now; + + dif = 2 * q->dbell_deadline; + if (dif > IONIC_RX_MAX_DOORBELL_DEADLINE) + dif = IONIC_RX_MAX_DOORBELL_DEADLINE; + + q->dbell_deadline = dif; + } + + return true; +} + static inline struct netdev_queue *q_to_ndq(struct ionic_queue *q) { return netdev_get_tx_queue(q->lif->netdev, q->index); @@ -424,6 +485,12 @@ void ionic_rx_fill(struct ionic_queue *q) ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type, q->dbval | q->head_idx); + + q->dbell_deadline = IONIC_RX_MIN_DOORBELL_DEADLINE; + q->dbell_jiffies = jiffies; + + mod_timer(&q_to_qcq(q)->napi_qcq->napi_deadline, + jiffies + IONIC_NAPI_DEADLINE); } void ionic_rx_empty(struct ionic_queue *q) @@ -511,6 +578,9 @@ int ionic_tx_napi(struct napi_struct *napi, int budget) work_done, flags); } + if (!work_done && ionic_txq_poke_doorbell(&qcq->q)) + mod_timer(&qcq->napi_deadline, jiffies + IONIC_NAPI_DEADLINE); + return work_done; } @@ -544,23 +614,29 @@ int ionic_rx_napi(struct napi_struct *napi, int budget) work_done, flags); } + if (!work_done && ionic_rxq_poke_doorbell(&qcq->q)) + mod_timer(&qcq->napi_deadline, jiffies + IONIC_NAPI_DEADLINE); + return work_done; } int ionic_txrx_napi(struct napi_struct *napi, int budget) { - struct ionic_qcq *qcq = napi_to_qcq(napi); + struct ionic_qcq *rxqcq = napi_to_qcq(napi); struct ionic_cq *rxcq = napi_to_cq(napi); unsigned int qi = rxcq->bound_q->index; + struct ionic_qcq *txqcq; struct ionic_dev *idev; struct ionic_lif *lif; struct ionic_cq *txcq; + bool resched = false; u32 rx_work_done = 0; u32 tx_work_done = 0; u32 flags = 0; lif = rxcq->bound_q->lif; idev = &lif->ionic->idev; + txqcq = lif->txqcqs[qi]; txcq = &lif->txqcqs[qi]->cq; tx_work_done = ionic_cq_service(txcq, IONIC_TX_BUDGET_DEFAULT, @@ -572,7 +648,7 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget) ionic_rx_fill(rxcq->bound_q); if (rx_work_done < budget && napi_complete_done(napi, rx_work_done)) { - ionic_dim_update(qcq, 0); + ionic_dim_update(rxqcq, 0); flags |= IONIC_INTR_CRED_UNMASK; rxcq->bound_intr->rearm_count++; } @@ -583,6 +659,13 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget) tx_work_done + rx_work_done, flags); } + if (!rx_work_done && ionic_rxq_poke_doorbell(&rxqcq->q)) + resched = true; + if (!tx_work_done && ionic_txq_poke_doorbell(&txqcq->q)) + resched = true; + if (resched) + mod_timer(&rxqcq->napi_deadline, jiffies + IONIC_NAPI_DEADLINE); + return rx_work_done; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.c b/drivers/net/ethernet/qlogic/qed/qed_debug.c index 86ecb080b153..cdcead614e9f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_debug.c +++ b/drivers/net/ethernet/qlogic/qed/qed_debug.c @@ -1832,7 +1832,8 @@ static enum dbg_status qed_find_nvram_image(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 image_type, u32 *nvram_offset_bytes, - u32 *nvram_size_bytes) + u32 *nvram_size_bytes, + bool b_can_sleep) { u32 ret_mcp_resp, ret_mcp_param, ret_txn_size; struct mcp_file_att file_att; @@ -1846,7 +1847,8 @@ static enum dbg_status qed_find_nvram_image(struct qed_hwfn *p_hwfn, &ret_mcp_resp, &ret_mcp_param, &ret_txn_size, - (u32 *)&file_att, false); + (u32 *)&file_att, + b_can_sleep); /* Check response */ if (nvm_result || (ret_mcp_resp & FW_MSG_CODE_MASK) != @@ -1873,7 +1875,9 @@ static enum dbg_status qed_find_nvram_image(struct qed_hwfn *p_hwfn, static enum dbg_status qed_nvram_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 nvram_offset_bytes, - u32 nvram_size_bytes, u32 *ret_buf) + u32 nvram_size_bytes, + u32 *ret_buf, + bool b_can_sleep) { u32 ret_mcp_resp, ret_mcp_param, ret_read_size, bytes_to_copy; s32 bytes_left = nvram_size_bytes; @@ -1899,7 +1903,7 @@ static enum dbg_status qed_nvram_read(struct qed_hwfn *p_hwfn, &ret_mcp_resp, &ret_mcp_param, &ret_read_size, (u32 *)((u8 *)ret_buf + read_offset), - false)) + b_can_sleep)) return DBG_STATUS_NVRAM_READ_FAILED; /* Check response */ @@ -3380,7 +3384,8 @@ static u32 qed_grc_dump_mcp_hw_dump(struct qed_hwfn *p_hwfn, p_ptt, NVM_TYPE_HW_DUMP_OUT, &hw_dump_offset_bytes, - &hw_dump_size_bytes); + &hw_dump_size_bytes, + false); if (status != DBG_STATUS_OK) return 0; @@ -3397,7 +3402,9 @@ static u32 qed_grc_dump_mcp_hw_dump(struct qed_hwfn *p_hwfn, status = qed_nvram_read(p_hwfn, p_ptt, hw_dump_offset_bytes, - hw_dump_size_bytes, dump_buf + offset); + hw_dump_size_bytes, + dump_buf + offset, + false); if (status != DBG_STATUS_OK) { DP_NOTICE(p_hwfn, "Failed to read MCP HW Dump image from NVRAM\n"); @@ -4123,7 +4130,9 @@ static enum dbg_status qed_mcp_trace_get_meta_info(struct qed_hwfn *p_hwfn, return qed_find_nvram_image(p_hwfn, p_ptt, nvram_image_type, - trace_meta_offset, trace_meta_size); + trace_meta_offset, + trace_meta_size, + true); } /* Reads the MCP Trace meta data from NVRAM into the specified buffer */ @@ -4139,7 +4148,10 @@ static enum dbg_status qed_mcp_trace_read_meta(struct qed_hwfn *p_hwfn, /* Read meta data from NVRAM */ status = qed_nvram_read(p_hwfn, p_ptt, - nvram_offset_in_bytes, size_in_bytes, buf); + nvram_offset_in_bytes, + size_in_bytes, + buf, + true); if (status != DBG_STATUS_OK) return status; diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c index 7c2af482192d..cb1746bc0e0c 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_fp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c @@ -1438,6 +1438,10 @@ int qede_poll(struct napi_struct *napi, int budget) rx_work_done = (likely(fp->type & QEDE_FASTPATH_RX) && qede_has_rx_work(fp->rxq)) ? qede_rx_int(fp, budget) : 0; + + if (fp->xdp_xmit & QEDE_XDP_REDIRECT) + xdp_do_flush(); + /* Handle case where we are called by netpoll with a budget of 0 */ if (rx_work_done < budget || !budget) { if (!qede_poll_is_more_work(fp)) { @@ -1457,9 +1461,6 @@ int qede_poll(struct napi_struct *napi, int budget) qede_update_tx_producer(fp->xdp_tx); } - if (fp->xdp_xmit & QEDE_XDP_REDIRECT) - xdp_do_flush_map(); - return rx_work_done; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index dbb800769cb6..c95d56e56c59 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -2505,7 +2505,13 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter) goto disable_mbx_intr; qlcnic_83xx_clear_function_resources(adapter); - qlcnic_dcb_enable(adapter->dcb); + + err = qlcnic_dcb_enable(adapter->dcb); + if (err) { + qlcnic_dcb_free(adapter->dcb); + goto disable_mbx_intr; + } + qlcnic_83xx_initialize_nic(adapter, 1); qlcnic_dcb_get_info(adapter->dcb); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h index 7519773eaca6..22afa2be85fd 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h @@ -41,11 +41,6 @@ struct qlcnic_dcb { unsigned long state; }; -static inline void qlcnic_clear_dcb_ops(struct qlcnic_dcb *dcb) -{ - kfree(dcb); -} - static inline int qlcnic_dcb_get_hw_capability(struct qlcnic_dcb *dcb) { if (dcb && dcb->ops->get_hw_capability) @@ -112,9 +107,8 @@ static inline void qlcnic_dcb_init_dcbnl_ops(struct qlcnic_dcb *dcb) dcb->ops->init_dcbnl_ops(dcb); } -static inline void qlcnic_dcb_enable(struct qlcnic_dcb *dcb) +static inline int qlcnic_dcb_enable(struct qlcnic_dcb *dcb) { - if (dcb && qlcnic_dcb_attach(dcb)) - qlcnic_clear_dcb_ops(dcb); + return dcb ? qlcnic_dcb_attach(dcb) : 0; } #endif diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 28476b982bab..44dac3c0908e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -2599,7 +2599,13 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) "Device does not support MSI interrupts\n"); if (qlcnic_82xx_check(adapter)) { - qlcnic_dcb_enable(adapter->dcb); + err = qlcnic_dcb_enable(adapter->dcb); + if (err) { + qlcnic_dcb_free(adapter->dcb); + dev_err(&pdev->dev, "Failed to enable DCB\n"); + goto err_out_free_hw; + } + qlcnic_dcb_get_info(adapter->dcb); err = qlcnic_setup_intr(adapter); diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index a9dcc98b6af1..dadd61bccfe7 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1996,10 +1996,7 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) /* 8168F family. */ { 0x7c8, 0x488, RTL_GIGA_MAC_VER_38 }, - /* It seems this chip version never made it to - * the wild. Let's disable detection. - * { 0x7cf, 0x481, RTL_GIGA_MAC_VER_36 }, - */ + { 0x7cf, 0x481, RTL_GIGA_MAC_VER_36 }, { 0x7cf, 0x480, RTL_GIGA_MAC_VER_35 }, /* 8168E family. */ @@ -2210,28 +2207,6 @@ static int rtl_set_mac_address(struct net_device *dev, void *p) return 0; } -static void rtl_wol_enable_rx(struct rtl8169_private *tp) -{ - if (tp->mac_version >= RTL_GIGA_MAC_VER_25) - RTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) | - AcceptBroadcast | AcceptMulticast | AcceptMyPhys); -} - -static void rtl_prepare_power_down(struct rtl8169_private *tp) -{ - if (tp->dash_type != RTL_DASH_NONE) - return; - - if (tp->mac_version == RTL_GIGA_MAC_VER_32 || - tp->mac_version == RTL_GIGA_MAC_VER_33) - rtl_ephy_write(tp, 0x19, 0xff64); - - if (device_may_wakeup(tp_to_dev(tp))) { - phy_speed_down(tp->phydev, false); - rtl_wol_enable_rx(tp); - } -} - static void rtl_init_rxcfg(struct rtl8169_private *tp) { switch (tp->mac_version) { @@ -2455,6 +2430,31 @@ static void rtl_enable_rxdvgate(struct rtl8169_private *tp) rtl_wait_txrx_fifo_empty(tp); } +static void rtl_wol_enable_rx(struct rtl8169_private *tp) +{ + if (tp->mac_version >= RTL_GIGA_MAC_VER_25) + RTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) | + AcceptBroadcast | AcceptMulticast | AcceptMyPhys); + + if (tp->mac_version >= RTL_GIGA_MAC_VER_40) + rtl_disable_rxdvgate(tp); +} + +static void rtl_prepare_power_down(struct rtl8169_private *tp) +{ + if (tp->dash_type != RTL_DASH_NONE) + return; + + if (tp->mac_version == RTL_GIGA_MAC_VER_32 || + tp->mac_version == RTL_GIGA_MAC_VER_33) + rtl_ephy_write(tp, 0x19, 0xff64); + + if (device_may_wakeup(tp_to_dev(tp))) { + phy_speed_down(tp->phydev, false); + rtl_wol_enable_rx(tp); + } +} + static void rtl_set_tx_config_registers(struct rtl8169_private *tp) { u32 val = TX_DMA_BURST << TxDMAShift | @@ -3872,7 +3872,7 @@ static void rtl8169_tx_clear(struct rtl8169_private *tp) netdev_reset_queue(tp->dev); } -static void rtl8169_cleanup(struct rtl8169_private *tp, bool going_down) +static void rtl8169_cleanup(struct rtl8169_private *tp) { napi_disable(&tp->napi); @@ -3884,9 +3884,6 @@ static void rtl8169_cleanup(struct rtl8169_private *tp, bool going_down) rtl_rx_close(tp); - if (going_down && tp->dev->wol_enabled) - goto no_reset; - switch (tp->mac_version) { case RTL_GIGA_MAC_VER_28: case RTL_GIGA_MAC_VER_31: @@ -3907,7 +3904,7 @@ static void rtl8169_cleanup(struct rtl8169_private *tp, bool going_down) } rtl_hw_reset(tp); -no_reset: + rtl8169_tx_clear(tp); rtl8169_init_ring_indexes(tp); } @@ -3918,7 +3915,7 @@ static void rtl_reset_work(struct rtl8169_private *tp) netif_stop_queue(tp->dev); - rtl8169_cleanup(tp, false); + rtl8169_cleanup(tp); for (i = 0; i < NUM_RX_DESC; i++) rtl8169_mark_to_asic(tp->RxDescArray + i); @@ -4605,7 +4602,7 @@ static void rtl8169_down(struct rtl8169_private *tp) pci_clear_master(tp->pci_dev); rtl_pci_commit(tp); - rtl8169_cleanup(tp, true); + rtl8169_cleanup(tp); rtl_disable_exit_l1(tp); rtl_prepare_power_down(tp); } diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index b4e0fc7f65bd..0f54849a3823 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1101,14 +1101,14 @@ static void ravb_error_interrupt(struct net_device *ndev) ravb_write(ndev, ~(EIS_QFS | EIS_RESERVED), EIS); if (eis & EIS_QFS) { ris2 = ravb_read(ndev, RIS2); - ravb_write(ndev, ~(RIS2_QFF0 | RIS2_RFFF | RIS2_RESERVED), + ravb_write(ndev, ~(RIS2_QFF0 | RIS2_QFF1 | RIS2_RFFF | RIS2_RESERVED), RIS2); /* Receive Descriptor Empty int */ if (ris2 & RIS2_QFF0) priv->stats[RAVB_BE].rx_over_errors++; - /* Receive Descriptor Empty int */ + /* Receive Descriptor Empty int */ if (ris2 & RIS2_QFF1) priv->stats[RAVB_NC].rx_over_errors++; @@ -2973,6 +2973,9 @@ static int __maybe_unused ravb_suspend(struct device *dev) else ret = ravb_close(ndev); + if (priv->info->ccc_gac) + ravb_ptp_stop(ndev); + return ret; } @@ -3011,6 +3014,9 @@ static int __maybe_unused ravb_resume(struct device *dev) /* Restore descriptor base address table */ ravb_write(ndev, priv->desc_bat_dma, DBAT); + if (priv->info->ccc_gac) + ravb_ptp_init(ndev, priv->pdev); + if (netif_running(ndev)) { if (priv->wol_enabled) { ret = ravb_wol_restore(ndev); diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index e42ceaa0099f..2370c7797a0a 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -1074,8 +1074,11 @@ static struct device_node *rswitch_get_port_node(struct rswitch_device *rdev) port = NULL; goto out; } - if (index == rdev->etha->index) + if (index == rdev->etha->index) { + if (!of_device_is_available(port)) + port = NULL; break; + } } out: @@ -1106,7 +1109,7 @@ static int rswitch_etha_get_params(struct rswitch_device *rdev) port = rswitch_get_port_node(rdev); if (!port) - return -ENODEV; + return 0; /* ignored */ err = of_get_phy_mode(port, &rdev->etha->phy_interface); of_node_put(port); @@ -1324,13 +1327,13 @@ static int rswitch_ether_port_init_all(struct rswitch_private *priv) { int i, err; - for (i = 0; i < RSWITCH_NUM_PORTS; i++) { + rswitch_for_each_enabled_port(priv, i) { err = rswitch_ether_port_init_one(priv->rdev[i]); if (err) goto err_init_one; } - for (i = 0; i < RSWITCH_NUM_PORTS; i++) { + rswitch_for_each_enabled_port(priv, i) { err = rswitch_serdes_init(priv->rdev[i]); if (err) goto err_serdes; @@ -1339,12 +1342,12 @@ static int rswitch_ether_port_init_all(struct rswitch_private *priv) return 0; err_serdes: - for (i--; i >= 0; i--) + rswitch_for_each_enabled_port_continue_reverse(priv, i) rswitch_serdes_deinit(priv->rdev[i]); i = RSWITCH_NUM_PORTS; err_init_one: - for (i--; i >= 0; i--) + rswitch_for_each_enabled_port_continue_reverse(priv, i) rswitch_ether_port_deinit_one(priv->rdev[i]); return err; @@ -1578,6 +1581,7 @@ static int rswitch_device_alloc(struct rswitch_private *priv, int index) { struct platform_device *pdev = priv->pdev; struct rswitch_device *rdev; + struct device_node *port; struct net_device *ndev; int err; @@ -1606,7 +1610,10 @@ static int rswitch_device_alloc(struct rswitch_private *priv, int index) netif_napi_add(ndev, &rdev->napi, rswitch_poll); - err = of_get_ethdev_address(pdev->dev.of_node, ndev); + port = rswitch_get_port_node(rdev); + rdev->disabled = !port; + err = of_get_ethdev_address(port, ndev); + of_node_put(port); if (err) { if (is_valid_ether_addr(rdev->etha->mac_addr)) eth_hw_addr_set(ndev, rdev->etha->mac_addr); @@ -1704,16 +1711,16 @@ static int rswitch_init(struct rswitch_private *priv) if (err) goto err_ether_port_init_all; - for (i = 0; i < RSWITCH_NUM_PORTS; i++) { + rswitch_for_each_enabled_port(priv, i) { err = register_netdev(priv->rdev[i]->ndev); if (err) { - for (i--; i >= 0; i--) + rswitch_for_each_enabled_port_continue_reverse(priv, i) unregister_netdev(priv->rdev[i]->ndev); goto err_register_netdev; } } - for (i = 0; i < RSWITCH_NUM_PORTS; i++) + rswitch_for_each_enabled_port(priv, i) netdev_info(priv->rdev[i]->ndev, "MAC address %pM\n", priv->rdev[i]->ndev->dev_addr); @@ -1786,6 +1793,11 @@ static int renesas_eth_sw_probe(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); ret = rswitch_init(priv); + if (ret < 0) { + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); + return ret; + } device_set_wakeup_capable(&pdev->dev, 1); diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h index edbdd1b98d3d..49efb0f31c77 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -13,6 +13,17 @@ #define RSWITCH_MAX_NUM_QUEUES 128 #define RSWITCH_NUM_PORTS 3 +#define rswitch_for_each_enabled_port(priv, i) \ + for (i = 0; i < RSWITCH_NUM_PORTS; i++) \ + if (priv->rdev[i]->disabled) \ + continue; \ + else + +#define rswitch_for_each_enabled_port_continue_reverse(priv, i) \ + for (i--; i >= 0; i--) \ + if (priv->rdev[i]->disabled) \ + continue; \ + else #define TX_RING_SIZE 1024 #define RX_RING_SIZE 1024 @@ -938,6 +949,7 @@ struct rswitch_device { struct rswitch_gwca_queue *tx_queue; struct rswitch_gwca_queue *rx_queue; u8 ts_tag; + bool disabled; int port; struct rswitch_etha *etha; diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 0556542d7a6b..3a86f1213a05 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1003,8 +1003,11 @@ static int efx_pci_probe_post_io(struct efx_nic *efx) /* Determine netdevice features */ net_dev->features |= (efx->type->offload_features | NETIF_F_SG | NETIF_F_TSO | NETIF_F_RXCSUM | NETIF_F_RXALL); - if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM)) + if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM)) { net_dev->features |= NETIF_F_TSO6; + if (efx_has_cap(efx, TX_TSO_V2_ENCAP)) + net_dev->hw_enc_features |= NETIF_F_TSO6; + } /* Check whether device supports TSO */ if (!efx->type->tso_versions || !efx->type->tso_versions(efx)) net_dev->features &= ~NETIF_F_ALL_TSO; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c index d42e1afb6521..2f7d8e4561d9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c @@ -90,7 +90,6 @@ struct mediatek_dwmac_plat_data { struct mediatek_dwmac_variant { int (*dwmac_set_phy_interface)(struct mediatek_dwmac_plat_data *plat); int (*dwmac_set_delay)(struct mediatek_dwmac_plat_data *plat); - void (*dwmac_fix_mac_speed)(void *priv, unsigned int speed); /* clock ids to be requested */ const char * const *clk_list; @@ -443,32 +442,9 @@ static int mt8195_set_delay(struct mediatek_dwmac_plat_data *plat) return 0; } -static void mt8195_fix_mac_speed(void *priv, unsigned int speed) -{ - struct mediatek_dwmac_plat_data *priv_plat = priv; - - if ((phy_interface_mode_is_rgmii(priv_plat->phy_mode))) { - /* prefer 2ns fixed delay which is controlled by TXC_PHASE_CTRL, - * when link speed is 1Gbps with RGMII interface, - * Fall back to delay macro circuit for 10/100Mbps link speed. - */ - if (speed == SPEED_1000) - regmap_update_bits(priv_plat->peri_regmap, - MT8195_PERI_ETH_CTRL0, - MT8195_RGMII_TXC_PHASE_CTRL | - MT8195_DLY_GTXC_ENABLE | - MT8195_DLY_GTXC_INV | - MT8195_DLY_GTXC_STAGES, - MT8195_RGMII_TXC_PHASE_CTRL); - else - mt8195_set_delay(priv_plat); - } -} - static const struct mediatek_dwmac_variant mt8195_gmac_variant = { .dwmac_set_phy_interface = mt8195_set_interface, .dwmac_set_delay = mt8195_set_delay, - .dwmac_fix_mac_speed = mt8195_fix_mac_speed, .clk_list = mt8195_dwmac_clk_l, .num_clks = ARRAY_SIZE(mt8195_dwmac_clk_l), .dma_bit_mask = 35, @@ -619,8 +595,6 @@ static int mediatek_dwmac_common_data(struct platform_device *pdev, plat->bsp_priv = priv_plat; plat->init = mediatek_dwmac_init; plat->clks_config = mediatek_dwmac_clks_config; - if (priv_plat->variant->dwmac_fix_mac_speed) - plat->fix_mac_speed = priv_plat->variant->dwmac_fix_mac_speed; plat->safety_feat_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->safety_feat_cfg), diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 835caa15d55f..732774645c1a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -560,6 +560,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev) plat_dat->has_gmac4 = 1; plat_dat->pmt = 1; plat_dat->tso_en = of_property_read_bool(np, "snps,tso"); + if (of_device_is_compatible(np, "qcom,qcs404-ethqos")) + plat_dat->rx_clk_runs_in_lpi = 1; ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); if (ret) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c index 9c2d40f853ed..e95d35f1e5a0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c @@ -186,11 +186,25 @@ static void dwmac5_handle_dma_err(struct net_device *ndev, int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp, struct stmmac_safety_feature_cfg *safety_feat_cfg) { + struct stmmac_safety_feature_cfg all_safety_feats = { + .tsoee = 1, + .mrxpee = 1, + .mestee = 1, + .mrxee = 1, + .mtxee = 1, + .epsi = 1, + .edpp = 1, + .prtyen = 1, + .tmouten = 1, + }; u32 value; if (!asp) return -EINVAL; + if (!safety_feat_cfg) + safety_feat_cfg = &all_safety_feats; + /* 1. Enable Safety Features */ value = readl(ioaddr + MTL_ECC_CONTROL); value |= MEEAO; /* MTL ECC Error Addr Status Override */ @@ -527,9 +541,9 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index, return 0; } - val |= PPSCMDx(index, 0x2); val |= TRGTMODSELx(index, 0x2); val |= PPSEN0; + writel(val, ioaddr + MAC_PPS_CONTROL); writel(cfg->start.tv_sec, ioaddr + MAC_PPSx_TARGET_TIME_SEC(index)); @@ -554,6 +568,7 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index, writel(period - 1, ioaddr + MAC_PPSx_WIDTH(index)); /* Finally, activate it */ + val |= PPSCMDx(index, 0x2); writel(val, ioaddr + MAC_PPS_CONTROL); return 0; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index f453b0d09366..35c8dd92d369 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -551,16 +551,16 @@ static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data) p = (char *)priv + offsetof(struct stmmac_priv, xstats.txq_stats[q].tx_pkt_n); for (stat = 0; stat < STMMAC_TXQ_STATS; stat++) { - *data++ = (*(u64 *)p); - p += sizeof(u64 *); + *data++ = (*(unsigned long *)p); + p += sizeof(unsigned long); } } for (q = 0; q < rx_cnt; q++) { p = (char *)priv + offsetof(struct stmmac_priv, xstats.rxq_stats[q].rx_pkt_n); for (stat = 0; stat < STMMAC_RXQ_STATS; stat++) { - *data++ = (*(u64 *)p); - p += sizeof(u64 *); + *data++ = (*(unsigned long *)p); + p += sizeof(unsigned long); } } } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index c6951c976f5d..1a5b8dab5e9b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1080,7 +1080,8 @@ static void stmmac_mac_link_up(struct phylink_config *config, stmmac_mac_set(priv, priv->ioaddr, true); if (phy && priv->dma_cap.eee) { - priv->eee_active = phy_init_eee(phy, 1) >= 0; + priv->eee_active = + phy_init_eee(phy, !priv->plat->rx_clk_runs_in_lpi) >= 0; priv->eee_enabled = stmmac_eee_init(priv); priv->tx_lpi_enabled = priv->eee_enabled; stmmac_set_eee_pls(priv, priv->hw, true); @@ -1150,6 +1151,11 @@ static int stmmac_init_phy(struct net_device *dev) int addr = priv->plat->phy_addr; struct phy_device *phydev; + if (addr < 0) { + netdev_err(priv->dev, "no phy found\n"); + return -ENODEV; + } + phydev = mdiobus_get_phy(priv->mii, addr); if (!phydev) { netdev_err(priv->dev, "no phy at addr %d\n", addr); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index eb6d9cd8e93f..0046a4ee6e64 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -559,7 +559,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) dma_cfg->mixed_burst = of_property_read_bool(np, "snps,mixed-burst"); plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode"); - if (plat->force_thresh_dma_mode) { + if (plat->force_thresh_dma_mode && plat->force_sf_dma_mode) { plat->force_sf_dma_mode = 0; dev_warn(&pdev->dev, "force_sf_dma_mode is ignored if force_thresh_dma_mode is set.\n"); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c index fc06ddeac0d5..b4388ca8d211 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c @@ -210,7 +210,10 @@ static int stmmac_enable(struct ptp_clock_info *ptp, } writel(acr_value, ptpaddr + PTP_ACR); mutex_unlock(&priv->aux_ts_lock); - ret = 0; + /* wait for auxts fifo clear to finish */ + ret = readl_poll_timeout(ptpaddr + PTP_ACR, acr_value, + !(acr_value & PTP_ACR_ATSFC), + 10, 10000); break; default: diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index ecbde83b5243..6cda4b7c10cb 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -501,7 +501,15 @@ static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common) k3_udma_glue_disable_tx_chn(common->tx_chns[i].tx_chn); } + reinit_completion(&common->tdown_complete); k3_udma_glue_tdown_rx_chn(common->rx_chns.rx_chn, true); + + if (common->pdata.quirks & AM64_CPSW_QUIRK_DMA_RX_TDOWN_IRQ) { + i = wait_for_completion_timeout(&common->tdown_complete, msecs_to_jiffies(1000)); + if (!i) + dev_err(common->dev, "rx teardown timeout\n"); + } + napi_disable(&common->napi_rx); for (i = 0; i < AM65_CPSW_MAX_RX_FLOWS; i++) @@ -721,6 +729,8 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_common *common, if (cppi5_desc_is_tdcm(desc_dma)) { dev_dbg(dev, "%s RX tdown flow: %u\n", __func__, flow_idx); + if (common->pdata.quirks & AM64_CPSW_QUIRK_DMA_RX_TDOWN_IRQ) + complete(&common->tdown_complete); return 0; } @@ -2672,7 +2682,7 @@ static const struct am65_cpsw_pdata j721e_pdata = { }; static const struct am65_cpsw_pdata am64x_cpswxg_pdata = { - .quirks = 0, + .quirks = AM64_CPSW_QUIRK_DMA_RX_TDOWN_IRQ, .ale_dev_id = "am64-cpswxg", .fdqring_mode = K3_RINGACC_RING_MODE_RING, }; diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.h b/drivers/net/ethernet/ti/am65-cpsw-nuss.h index 4b75620f8d28..e5f1c44788c1 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.h +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.h @@ -90,6 +90,7 @@ struct am65_cpsw_rx_chn { }; #define AM65_CPSW_QUIRK_I2027_NO_TX_CSUM BIT(0) +#define AM64_CPSW_QUIRK_DMA_RX_TDOWN_IRQ BIT(1) struct am65_cpsw_pdata { u32 quirks; diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 9352dad58996..79f4e13620a4 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -987,9 +987,6 @@ static void netvsc_copy_to_send_buf(struct netvsc_device *net_device, void netvsc_dma_unmap(struct hv_device *hv_dev, struct hv_netvsc_packet *packet) { - u32 page_count = packet->cp_partial ? - packet->page_buf_cnt - packet->rmsg_pgcnt : - packet->page_buf_cnt; int i; if (!hv_is_isolation_supported()) @@ -998,7 +995,7 @@ void netvsc_dma_unmap(struct hv_device *hv_dev, if (!packet->dma_range) return; - for (i = 0; i < page_count; i++) + for (i = 0; i < packet->page_buf_cnt; i++) dma_unmap_single(&hv_dev->device, packet->dma_range[i].dma, packet->dma_range[i].mapping_size, DMA_TO_DEVICE); @@ -1028,9 +1025,7 @@ static int netvsc_dma_map(struct hv_device *hv_dev, struct hv_netvsc_packet *packet, struct hv_page_buffer *pb) { - u32 page_count = packet->cp_partial ? - packet->page_buf_cnt - packet->rmsg_pgcnt : - packet->page_buf_cnt; + u32 page_count = packet->page_buf_cnt; dma_addr_t dma; int i; @@ -1039,7 +1034,7 @@ static int netvsc_dma_map(struct hv_device *hv_dev, packet->dma_range = kcalloc(page_count, sizeof(*packet->dma_range), - GFP_KERNEL); + GFP_ATOMIC); if (!packet->dma_range) return -ENOMEM; diff --git a/drivers/net/ipa/data/ipa_data-v4.7.c b/drivers/net/ipa/data/ipa_data-v4.7.c index 7552c400961e..b83390c48615 100644 --- a/drivers/net/ipa/data/ipa_data-v4.7.c +++ b/drivers/net/ipa/data/ipa_data-v4.7.c @@ -357,7 +357,7 @@ static const struct ipa_mem ipa_mem_local_data[] = { static const struct ipa_mem_data ipa_mem_data = { .local_count = ARRAY_SIZE(ipa_mem_local_data), .local = ipa_mem_local_data, - .imem_addr = 0x146a9000, + .imem_addr = 0x146a8000, .imem_size = 0x00002000, .smem_id = 497, .smem_size = 0x00009000, diff --git a/drivers/net/ipa/ipa_interrupt.c b/drivers/net/ipa/ipa_interrupt.c index a49f66efacb8..c1b3977e1ae4 100644 --- a/drivers/net/ipa/ipa_interrupt.c +++ b/drivers/net/ipa/ipa_interrupt.c @@ -127,15 +127,25 @@ out_power_put: return IRQ_HANDLED; } +void ipa_interrupt_irq_disable(struct ipa *ipa) +{ + disable_irq(ipa->interrupt->irq); +} + +void ipa_interrupt_irq_enable(struct ipa *ipa) +{ + enable_irq(ipa->interrupt->irq); +} + /* Common function used to enable/disable TX_SUSPEND for an endpoint */ static void ipa_interrupt_suspend_control(struct ipa_interrupt *interrupt, u32 endpoint_id, bool enable) { struct ipa *ipa = interrupt->ipa; + u32 mask = BIT(endpoint_id % 32); u32 unit = endpoint_id / 32; const struct ipa_reg *reg; u32 offset; - u32 mask; u32 val; WARN_ON(!test_bit(endpoint_id, ipa->available)); @@ -148,7 +158,6 @@ static void ipa_interrupt_suspend_control(struct ipa_interrupt *interrupt, offset = ipa_reg_n_offset(reg, unit); val = ioread32(ipa->reg_virt + offset); - mask = BIT(endpoint_id); if (enable) val |= mask; else diff --git a/drivers/net/ipa/ipa_interrupt.h b/drivers/net/ipa/ipa_interrupt.h index f31fd9965fdc..8a1bd5b89393 100644 --- a/drivers/net/ipa/ipa_interrupt.h +++ b/drivers/net/ipa/ipa_interrupt.h @@ -86,6 +86,22 @@ void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt); void ipa_interrupt_simulate_suspend(struct ipa_interrupt *interrupt); /** + * ipa_interrupt_irq_enable() - Enable IPA interrupts + * @ipa: IPA pointer + * + * This enables the IPA interrupt line + */ +void ipa_interrupt_irq_enable(struct ipa *ipa); + +/** + * ipa_interrupt_irq_disable() - Disable IPA interrupts + * @ipa: IPA pointer + * + * This disables the IPA interrupt line + */ +void ipa_interrupt_irq_disable(struct ipa *ipa); + +/** * ipa_interrupt_config() - Configure the IPA interrupt framework * @ipa: IPA pointer * diff --git a/drivers/net/ipa/ipa_power.c b/drivers/net/ipa/ipa_power.c index 8420f93128a2..8057be8cda80 100644 --- a/drivers/net/ipa/ipa_power.c +++ b/drivers/net/ipa/ipa_power.c @@ -181,6 +181,17 @@ static int ipa_suspend(struct device *dev) __set_bit(IPA_POWER_FLAG_SYSTEM, ipa->power->flags); + /* Increment the disable depth to ensure that the IRQ won't + * be re-enabled until the matching _enable call in + * ipa_resume(). We do this to ensure that the interrupt + * handler won't run whilst PM runtime is disabled. + * + * Note that disabling the IRQ is NOT the same as disabling + * irq wake. If wakeup is enabled for the IPA then the IRQ + * will still cause the system to wake up, see irq_set_irq_wake(). + */ + ipa_interrupt_irq_disable(ipa); + return pm_runtime_force_suspend(dev); } @@ -193,6 +204,12 @@ static int ipa_resume(struct device *dev) __clear_bit(IPA_POWER_FLAG_SYSTEM, ipa->power->flags); + /* Now that PM runtime is enabled again it's safe + * to turn the IRQ back on and process any data + * that was received during suspend. + */ + ipa_interrupt_irq_enable(ipa); + return ret; } diff --git a/drivers/net/mdio/mdio-mux-meson-g12a.c b/drivers/net/mdio/mdio-mux-meson-g12a.c index 4a2e94faf57e..c4542ecf5623 100644 --- a/drivers/net/mdio/mdio-mux-meson-g12a.c +++ b/drivers/net/mdio/mdio-mux-meson-g12a.c @@ -4,6 +4,7 @@ */ #include <linux/bitfield.h> +#include <linux/delay.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/device.h> @@ -150,6 +151,7 @@ static const struct clk_ops g12a_ephy_pll_ops = { static int g12a_enable_internal_mdio(struct g12a_mdio_mux *priv) { + u32 value; int ret; /* Enable the phy clock */ @@ -163,18 +165,25 @@ static int g12a_enable_internal_mdio(struct g12a_mdio_mux *priv) /* Initialize ephy control */ writel(EPHY_G12A_ID, priv->regs + ETH_PHY_CNTL0); - writel(FIELD_PREP(PHY_CNTL1_ST_MODE, 3) | - FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) | - FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) | - PHY_CNTL1_CLK_EN | - PHY_CNTL1_CLKFREQ | - PHY_CNTL1_PHY_ENB, - priv->regs + ETH_PHY_CNTL1); + + /* Make sure we get a 0 -> 1 transition on the enable bit */ + value = FIELD_PREP(PHY_CNTL1_ST_MODE, 3) | + FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) | + FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) | + PHY_CNTL1_CLK_EN | + PHY_CNTL1_CLKFREQ; + writel(value, priv->regs + ETH_PHY_CNTL1); writel(PHY_CNTL2_USE_INTERNAL | PHY_CNTL2_SMI_SRC_MAC | PHY_CNTL2_RX_CLK_EPHY, priv->regs + ETH_PHY_CNTL2); + value |= PHY_CNTL1_PHY_ENB; + writel(value, priv->regs + ETH_PHY_CNTL1); + + /* The phy needs a bit of time to power up */ + mdelay(10); + return 0; } diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c index a6f05e35d91f..b7cb71817780 100644 --- a/drivers/net/phy/dp83822.c +++ b/drivers/net/phy/dp83822.c @@ -233,7 +233,8 @@ static int dp83822_config_intr(struct phy_device *phydev) DP83822_ENERGY_DET_INT_EN | DP83822_LINK_QUAL_INT_EN); - if (!dp83822->fx_enabled) + /* Private data pointer is NULL on DP83825/26 */ + if (!dp83822 || !dp83822->fx_enabled) misr_status |= DP83822_ANEG_COMPLETE_INT_EN | DP83822_DUP_MODE_CHANGE_INT_EN | DP83822_SPEED_CHANGED_INT_EN; @@ -253,7 +254,8 @@ static int dp83822_config_intr(struct phy_device *phydev) DP83822_PAGE_RX_INT_EN | DP83822_EEE_ERROR_CHANGE_INT_EN); - if (!dp83822->fx_enabled) + /* Private data pointer is NULL on DP83825/26 */ + if (!dp83822 || !dp83822->fx_enabled) misr_status |= DP83822_ANEG_ERR_INT_EN | DP83822_WOL_PKT_INT_EN; diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 1cd604cd1fa1..16e021b477f0 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -108,7 +108,12 @@ EXPORT_SYMBOL(mdiobus_unregister_device); struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr) { - struct mdio_device *mdiodev = bus->mdio_map[addr]; + struct mdio_device *mdiodev; + + if (addr < 0 || addr >= ARRAY_SIZE(bus->mdio_map)) + return NULL; + + mdiodev = bus->mdio_map[addr]; if (!mdiodev) return NULL; diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c index c49062ad72c6..a6015cd03bff 100644 --- a/drivers/net/phy/meson-gxl.c +++ b/drivers/net/phy/meson-gxl.c @@ -261,6 +261,8 @@ static struct phy_driver meson_gxl_phy[] = { .handle_interrupt = meson_gxl_handle_interrupt, .suspend = genphy_suspend, .resume = genphy_resume, + .read_mmd = genphy_read_mmd_unsupported, + .write_mmd = genphy_write_mmd_unsupported, }, { PHY_ID_MATCH_EXACT(0x01803301), .name = "Meson G12A Internal PHY", @@ -271,6 +273,8 @@ static struct phy_driver meson_gxl_phy[] = { .handle_interrupt = meson_gxl_handle_interrupt, .suspend = genphy_suspend, .resume = genphy_resume, + .read_mmd = genphy_read_mmd_unsupported, + .write_mmd = genphy_write_mmd_unsupported, }, }; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 716870a4499c..607aa786c8cb 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1517,7 +1517,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, * another mac interface, so we should create a device link between * phy dev and mac dev. */ - if (phydev->mdio.bus->parent && dev->dev.parent != phydev->mdio.bus->parent) + if (dev && phydev->mdio.bus->parent && dev->dev.parent != phydev->mdio.bus->parent) phydev->devlink = device_link_add(dev->dev.parent, &phydev->mdio.dev, DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS); diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 09cc65c0da93..4d2519cdb801 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1812,10 +1812,9 @@ int phylink_fwnode_phy_connect(struct phylink *pl, ret = phy_attach_direct(pl->netdev, phy_dev, flags, pl->link_interface); - if (ret) { - phy_device_free(phy_dev); + phy_device_free(phy_dev); + if (ret) return ret; - } ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface); if (ret) diff --git a/drivers/net/phy/xilinx_gmii2rgmii.c b/drivers/net/phy/xilinx_gmii2rgmii.c index 8dcb49ed1f3d..7fd9fe6a602b 100644 --- a/drivers/net/phy/xilinx_gmii2rgmii.c +++ b/drivers/net/phy/xilinx_gmii2rgmii.c @@ -105,6 +105,7 @@ static int xgmiitorgmii_probe(struct mdio_device *mdiodev) if (!priv->phy_dev->drv) { dev_info(dev, "Attached phy not ready\n"); + put_device(&priv->phy_dev->mdio.dev); return -EPROBE_DEFER; } diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index fcd43d62d86b..d10606f257c4 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1044,7 +1044,6 @@ static int team_port_enter(struct team *team, struct team_port *port) goto err_port_enter; } } - port->dev->priv_flags |= IFF_NO_ADDRCONF; return 0; @@ -1058,7 +1057,6 @@ static void team_port_leave(struct team *team, struct team_port *port) { if (team->ops.port_leave) team->ops.port_leave(team, port); - port->dev->priv_flags &= ~IFF_NO_ADDRCONF; dev_put(team->dev); } diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 8911cd2ed534..c140edb4b648 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -1008,6 +1008,12 @@ static const struct usb_device_id products[] = { USB_CDC_PROTO_NONE), .driver_info = (unsigned long)&wwan_info, }, { + /* Cinterion PLS62-W modem by GEMALTO/THALES */ + USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x005b, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, + USB_CDC_PROTO_NONE), + .driver_info = (unsigned long)&wwan_info, +}, { /* Cinterion PLS83/PLS63 modem by GEMALTO/THALES */ USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0069, USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c index 9f2b70ef39aa..613fc6910f14 100644 --- a/drivers/net/usb/kalmia.c +++ b/drivers/net/usb/kalmia.c @@ -65,8 +65,8 @@ kalmia_send_init_packet(struct usbnet *dev, u8 *init_msg, u8 init_msg_len, init_msg, init_msg_len, &act_len, KALMIA_USB_TIMEOUT); if (status != 0) { netdev_err(dev->net, - "Error sending init packet. Status %i, length %i\n", - status, act_len); + "Error sending init packet. Status %i\n", + status); return status; } else if (act_len != init_msg_len) { @@ -83,8 +83,8 @@ kalmia_send_init_packet(struct usbnet *dev, u8 *init_msg, u8 init_msg_len, if (status != 0) netdev_err(dev->net, - "Error receiving init result. Status %i, length %i\n", - status, act_len); + "Error receiving init result. Status %i\n", + status); else if (act_len != expected_len) netdev_err(dev->net, "Unexpected init result length: %i\n", act_len); diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index 2c82fbcaab22..7a2b0094de51 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -57,9 +57,7 @@ static inline int pl_vendor_req(struct usbnet *dev, u8 req, u8 val, u8 index) { - return usbnet_read_cmd(dev, req, - USB_DIR_IN | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, + return usbnet_write_cmd(dev, req, USB_TYPE_VENDOR | USB_RECIP_DEVICE, val, index, NULL, 0); } diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index a481a1d831e2..23da1d9dafd1 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -9836,6 +9836,7 @@ static const struct usb_device_id rtl8152_table[] = { REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab), REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07c6), REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0927), + REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0c5e), REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101), REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f), REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3054), diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index f79333fe1783..7b3739b29c8f 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -255,7 +255,8 @@ static int rndis_query(struct usbnet *dev, struct usb_interface *intf, off = le32_to_cpu(u.get_c->offset); len = le32_to_cpu(u.get_c->len); - if (unlikely((8 + off + len) > CONTROL_BUFFER_SIZE)) + if (unlikely((off > CONTROL_BUFFER_SIZE - 8) || + (len > CONTROL_BUFFER_SIZE - 8 - off))) goto response_error; if (*reply_len != -1 && len != *reply_len) diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c index 5a53e63d33a6..3164451e1010 100644 --- a/drivers/net/usb/sr9700.c +++ b/drivers/net/usb/sr9700.c @@ -413,7 +413,7 @@ static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb) /* ignore the CRC length */ len = (skb->data[1] | (skb->data[2] << 8)) - 4; - if (len > ETH_FRAME_LEN || len > skb->len) + if (len > ETH_FRAME_LEN || len > skb->len || len < 0) return 0; /* the last packet of current skb */ diff --git a/drivers/net/veth.c b/drivers/net/veth.c index ac7c0653695f..dfc7d87fad59 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -974,6 +974,9 @@ static int veth_poll(struct napi_struct *napi, int budget) xdp_set_return_frame_no_direct(); done = veth_xdp_rcv(rq, budget, &bq, &stats); + if (stats.xdp_redirect > 0) + xdp_do_flush(); + if (done < budget && napi_complete_done(napi, done)) { /* Write rx_notify_masked before reading ptr_ring */ smp_store_mb(rq->rx_notify_masked, false); @@ -987,8 +990,6 @@ static int veth_poll(struct napi_struct *napi, int budget) if (stats.xdp_tx > 0) veth_xdp_flush(rq, &bq); - if (stats.xdp_redirect > 0) - xdp_do_flush(); xdp_clear_return_frame_no_direct(); return done; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 7723b2a49d8e..61e33e4dd0cd 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1677,13 +1677,13 @@ static int virtnet_poll(struct napi_struct *napi, int budget) received = virtnet_receive(rq, budget, &xdp_xmit); + if (xdp_xmit & VIRTIO_XDP_REDIR) + xdp_do_flush(); + /* Out of packets? */ if (received < budget) virtqueue_napi_complete(napi, rq->vq, received); - if (xdp_xmit & VIRTIO_XDP_REDIR) - xdp_do_flush(); - if (xdp_xmit & VIRTIO_XDP_TX) { sq = virtnet_xdp_get_sq(vi); if (virtqueue_kick_prepare(sq->vq) && virtqueue_notify(sq->vq)) { @@ -1877,8 +1877,10 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) */ if (sq->vq->num_free < 2+MAX_SKB_FRAGS) { netif_stop_subqueue(dev, qnum); - if (!use_napi && - unlikely(!virtqueue_enable_cb_delayed(sq->vq))) { + if (use_napi) { + if (unlikely(!virtqueue_enable_cb_delayed(sq->vq))) + virtqueue_napi_schedule(&sq->napi, sq->vq); + } else if (unlikely(!virtqueue_enable_cb_delayed(sq->vq))) { /* More just got used, free them then recheck. */ free_old_xmit_skbs(sq, false); if (sq->vq->num_free >= 2+MAX_SKB_FRAGS) { @@ -2156,8 +2158,8 @@ static int virtnet_close(struct net_device *dev) cancel_delayed_work_sync(&vi->refill); for (i = 0; i < vi->max_queue_pairs; i++) { - xdp_rxq_info_unreg(&vi->rq[i].xdp_rxq); napi_disable(&vi->rq[i].napi); + xdp_rxq_info_unreg(&vi->rq[i].xdp_rxq); virtnet_napi_tx_disable(&vi->sq[i].napi); } diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 6f1e560fb15c..682987040ea8 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1288,6 +1288,10 @@ vmxnet3_rx_csum(struct vmxnet3_adapter *adapter, (le32_to_cpu(gdesc->dword[3]) & VMXNET3_RCD_CSUM_OK) == VMXNET3_RCD_CSUM_OK) { skb->ip_summed = CHECKSUM_UNNECESSARY; + if ((le32_to_cpu(gdesc->dword[0]) & + (1UL << VMXNET3_RCD_HDR_INNER_SHIFT))) { + skb->csum_level = 1; + } WARN_ON_ONCE(!(gdesc->rcd.tcp || gdesc->rcd.udp) && !(le32_to_cpu(gdesc->dword[0]) & (1UL << VMXNET3_RCD_HDR_INNER_SHIFT))); @@ -1297,6 +1301,10 @@ vmxnet3_rx_csum(struct vmxnet3_adapter *adapter, } else if (gdesc->rcd.v6 && (le32_to_cpu(gdesc->dword[3]) & (1 << VMXNET3_RCD_TUC_SHIFT))) { skb->ip_summed = CHECKSUM_UNNECESSARY; + if ((le32_to_cpu(gdesc->dword[0]) & + (1UL << VMXNET3_RCD_HDR_INNER_SHIFT))) { + skb->csum_level = 1; + } WARN_ON_ONCE(!(gdesc->rcd.tcp || gdesc->rcd.udp) && !(le32_to_cpu(gdesc->dword[0]) & (1UL << VMXNET3_RCD_HDR_INNER_SHIFT))); @@ -1538,31 +1546,6 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, rxd->len = rbi->len; } -#ifdef VMXNET3_RSS - if (rcd->rssType != VMXNET3_RCD_RSS_TYPE_NONE && - (adapter->netdev->features & NETIF_F_RXHASH)) { - enum pkt_hash_types hash_type; - - switch (rcd->rssType) { - case VMXNET3_RCD_RSS_TYPE_IPV4: - case VMXNET3_RCD_RSS_TYPE_IPV6: - hash_type = PKT_HASH_TYPE_L3; - break; - case VMXNET3_RCD_RSS_TYPE_TCPIPV4: - case VMXNET3_RCD_RSS_TYPE_TCPIPV6: - case VMXNET3_RCD_RSS_TYPE_UDPIPV4: - case VMXNET3_RCD_RSS_TYPE_UDPIPV6: - hash_type = PKT_HASH_TYPE_L4; - break; - default: - hash_type = PKT_HASH_TYPE_L3; - break; - } - skb_set_hash(ctx->skb, - le32_to_cpu(rcd->rssHash), - hash_type); - } -#endif skb_record_rx_queue(ctx->skb, rq->qid); skb_put(ctx->skb, rcd->len); @@ -1645,6 +1628,31 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, u32 mtu = adapter->netdev->mtu; skb->len += skb->data_len; +#ifdef VMXNET3_RSS + if (rcd->rssType != VMXNET3_RCD_RSS_TYPE_NONE && + (adapter->netdev->features & NETIF_F_RXHASH)) { + enum pkt_hash_types hash_type; + + switch (rcd->rssType) { + case VMXNET3_RCD_RSS_TYPE_IPV4: + case VMXNET3_RCD_RSS_TYPE_IPV6: + hash_type = PKT_HASH_TYPE_L3; + break; + case VMXNET3_RCD_RSS_TYPE_TCPIPV4: + case VMXNET3_RCD_RSS_TYPE_TCPIPV6: + case VMXNET3_RCD_RSS_TYPE_UDPIPV4: + case VMXNET3_RCD_RSS_TYPE_UDPIPV6: + hash_type = PKT_HASH_TYPE_L4; + break; + default: + hash_type = PKT_HASH_TYPE_L3; + break; + } + skb_set_hash(skb, + le32_to_cpu(rcd->rssHash), + hash_type); + } +#endif vmxnet3_rx_csum(adapter, skb, (union Vmxnet3_GenericDesc *)rcd); skb->protocol = eth_type_trans(skb, adapter->netdev); diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 6b5a4d036d15..bdb3a76a352e 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -1385,8 +1385,8 @@ static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev, /* loopback, multicast & non-ND link-local traffic; do not push through * packet taps again. Reset pkt_type for upper layers to process skb. - * For strict packets with a source LLA, determine the dst using the - * original ifindex. + * For non-loopback strict packets, determine the dst using the original + * ifindex. */ if (skb->pkt_type == PACKET_LOOPBACK || (need_strict && !is_ndisc)) { skb->dev = vrf_dev; @@ -1395,7 +1395,7 @@ static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev, if (skb->pkt_type == PACKET_LOOPBACK) skb->pkt_type = PACKET_HOST; - else if (ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL) + else vrf_ip6_input_dst(skb, vrf_dev, orig_iif); goto out; diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 92224b36787a..b1b179effe2a 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -2917,16 +2917,23 @@ static int vxlan_init(struct net_device *dev) vxlan_vnigroup_init(vxlan); dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); - if (!dev->tstats) - return -ENOMEM; + if (!dev->tstats) { + err = -ENOMEM; + goto err_vnigroup_uninit; + } err = gro_cells_init(&vxlan->gro_cells, dev); - if (err) { - free_percpu(dev->tstats); - return err; - } + if (err) + goto err_free_percpu; return 0; + +err_free_percpu: + free_percpu(dev->tstats); +err_vnigroup_uninit: + if (vxlan->cfg.flags & VXLAN_F_VNIFILTER) + vxlan_vnigroup_uninit(vxlan); + return err; } static void vxlan_fdb_delete_default(struct vxlan_dev *vxlan, __be32 vni) diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 22edea6ca4b8..1c53b5546927 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -1243,9 +1243,11 @@ static int ucc_hdlc_probe(struct platform_device *pdev) free_dev: free_netdev(dev); undo_uhdlc_init: - iounmap(utdm->siram); + if (utdm) + iounmap(utdm->siram); unmap_si_regs: - iounmap(utdm->si_regs); + if (utdm) + iounmap(utdm->si_regs); free_utdm: if (uhdlc_priv->tsa) kfree(utdm); diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 30f0765fb9fd..237f4ec2cffd 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -327,9 +327,9 @@ static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) } #ifdef CONFIG_ATH9K_HTC_DEBUGFS -#define __STAT_SAFE(hif_dev, expr) ((hif_dev)->htc_handle->drv_priv ? (expr) : 0) -#define CAB_STAT_INC(priv) ((priv)->debug.tx_stats.cab_queued++) -#define TX_QSTAT_INC(priv, q) ((priv)->debug.tx_stats.queue_stats[q]++) +#define __STAT_SAFE(hif_dev, expr) do { ((hif_dev)->htc_handle->drv_priv ? (expr) : 0); } while (0) +#define CAB_STAT_INC(priv) do { ((priv)->debug.tx_stats.cab_queued++); } while (0) +#define TX_QSTAT_INC(priv, q) do { ((priv)->debug.tx_stats.queue_stats[q]++); } while (0) #define TX_STAT_INC(hif_dev, c) \ __STAT_SAFE((hif_dev), (hif_dev)->htc_handle->drv_priv->debug.tx_stats.c++) @@ -378,10 +378,10 @@ void ath9k_htc_get_et_stats(struct ieee80211_hw *hw, struct ethtool_stats *stats, u64 *data); #else -#define TX_STAT_INC(hif_dev, c) -#define TX_STAT_ADD(hif_dev, c, a) -#define RX_STAT_INC(hif_dev, c) -#define RX_STAT_ADD(hif_dev, c, a) +#define TX_STAT_INC(hif_dev, c) do { } while (0) +#define TX_STAT_ADD(hif_dev, c, a) do { } while (0) +#define RX_STAT_INC(hif_dev, c) do { } while (0) +#define RX_STAT_ADD(hif_dev, c, a) do { } while (0) #define CAB_STAT_INC(priv) #define TX_QSTAT_INC(priv, c) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index bff3128c2f26..b115902eb475 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -7937,6 +7937,9 @@ cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); + if (chan->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; + /* set_channel */ chspec = channel_to_chanspec(&cfg->d11inf, chan); if (chspec != INVCHANSPEC) { @@ -7961,7 +7964,7 @@ brcmf_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev, struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); struct brcmf_dump_survey survey = {}; struct ieee80211_supported_band *band; - struct ieee80211_channel *chan; + enum nl80211_band band_id; struct cca_msrmnt_query req; u32 noise; int err; @@ -7974,26 +7977,25 @@ brcmf_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev, return -EBUSY; } - band = wiphy->bands[NL80211_BAND_2GHZ]; - if (band && idx >= band->n_channels) { - idx -= band->n_channels; - band = NULL; - } + for (band_id = 0; band_id < NUM_NL80211_BANDS; band_id++) { + band = wiphy->bands[band_id]; + if (!band) + continue; + if (idx >= band->n_channels) { + idx -= band->n_channels; + continue; + } - if (!band || idx >= band->n_channels) { - band = wiphy->bands[NL80211_BAND_5GHZ]; - if (idx >= band->n_channels) - return -ENOENT; + info->channel = &band->channels[idx]; + break; } + if (band_id == NUM_NL80211_BANDS) + return -ENOENT; /* Setting current channel to the requested channel */ - chan = &band->channels[idx]; - err = cfg80211_set_channel(wiphy, ndev, chan, NL80211_CHAN_HT20); - if (err) { - info->channel = chan; - info->filled = 0; + info->filled = 0; + if (cfg80211_set_channel(wiphy, ndev, info->channel, NL80211_CHAN_HT20)) return 0; - } /* Disable mpc */ brcmf_set_mpc(ifp, 0); @@ -8028,7 +8030,6 @@ brcmf_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev, if (err) goto exit; - info->channel = chan; info->noise = noise; info->time = ACS_MSRMNT_DELAY; info->time_busy = ACS_MSRMNT_DELAY - survey.idle; @@ -8040,7 +8041,7 @@ brcmf_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev, SURVEY_INFO_TIME_TX; brcmf_dbg(INFO, "OBSS dump: channel %d: survey duration %d\n", - ieee80211_frequency_to_channel(chan->center_freq), + ieee80211_frequency_to_channel(info->channel->center_freq), ACS_MSRMNT_DELAY); brcmf_dbg(INFO, "noise(%d) busy(%llu) rx(%llu) tx(%llu)\n", info->noise, info->time_busy, info->time_rx, info->time_tx); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c index a83699de01ec..fdd0c9abc1a1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c @@ -79,7 +79,8 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, /* Apple ARM64 platforms have their own idea of board type, passed in * via the device tree. They also have an antenna SKU parameter */ - if (!of_property_read_string(np, "brcm,board-type", &prop)) + err = of_property_read_string(np, "brcm,board-type", &prop); + if (!err) settings->board_type = prop; if (!of_property_read_string(np, "apple,antenna-sku", &prop)) @@ -87,7 +88,7 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, /* Set board-type to the first string of the machine compatible prop */ root = of_find_node_by_path("/"); - if (root && !settings->board_type) { + if (root && err) { char *board_type; const char *tmp; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index ae57a9a3ab05..b67f6d0810b6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -1228,7 +1228,7 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo) BRCMF_NROF_H2D_COMMON_MSGRINGS; max_completionrings = BRCMF_NROF_D2H_COMMON_MSGRINGS; } - if (max_flowrings > 256) { + if (max_flowrings > 512) { brcmf_err(bus, "invalid max_flowrings(%d)\n", max_flowrings); return -EIO; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index e6d64152c81a..a02e5a67b706 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -1106,6 +1106,11 @@ int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *c int i, j, num_sub_bands; s8 *gain; + /* many firmware images for JF lie about this */ + if (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id) == + CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF)) + return -EOPNOTSUPP; + if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) { IWL_DEBUG_RADIO(fwrt, "PPAG capability not supported by FW, command not sent.\n"); diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index f795548562f5..06161815c180 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -206,71 +206,103 @@ mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) } static int +mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, + struct mt76_queue_buf *buf, void *data) +{ + struct mt76_desc *desc = &q->desc[q->head]; + struct mt76_queue_entry *entry = &q->entry[q->head]; + struct mt76_txwi_cache *txwi = NULL; + u32 buf1 = 0, ctrl; + int idx = q->head; + int rx_token; + + ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len); + + if ((q->flags & MT_QFLAG_WED) && + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX) { + txwi = mt76_get_rxwi(dev); + if (!txwi) + return -ENOMEM; + + rx_token = mt76_rx_token_consume(dev, data, txwi, buf->addr); + if (rx_token < 0) { + mt76_put_rxwi(dev, txwi); + return -ENOMEM; + } + + buf1 |= FIELD_PREP(MT_DMA_CTL_TOKEN, rx_token); + ctrl |= MT_DMA_CTL_TO_HOST; + } + + WRITE_ONCE(desc->buf0, cpu_to_le32(buf->addr)); + WRITE_ONCE(desc->buf1, cpu_to_le32(buf1)); + WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl)); + WRITE_ONCE(desc->info, 0); + + entry->dma_addr[0] = buf->addr; + entry->dma_len[0] = buf->len; + entry->txwi = txwi; + entry->buf = data; + entry->wcid = 0xffff; + entry->skip_buf1 = true; + q->head = (q->head + 1) % q->ndesc; + q->queued++; + + return idx; +} + +static int mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_buf *buf, int nbufs, u32 info, struct sk_buff *skb, void *txwi) { struct mt76_queue_entry *entry; struct mt76_desc *desc; - u32 ctrl; int i, idx = -1; + u32 ctrl, next; + + if (txwi) { + q->entry[q->head].txwi = DMA_DUMMY_DATA; + q->entry[q->head].skip_buf0 = true; + } for (i = 0; i < nbufs; i += 2, buf += 2) { u32 buf0 = buf[0].addr, buf1 = 0; idx = q->head; - q->head = (q->head + 1) % q->ndesc; + next = (q->head + 1) % q->ndesc; desc = &q->desc[idx]; entry = &q->entry[idx]; - if ((q->flags & MT_QFLAG_WED) && - FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX) { - struct mt76_txwi_cache *t = txwi; - int rx_token; - - if (!t) - return -ENOMEM; - - rx_token = mt76_rx_token_consume(dev, (void *)skb, t, - buf[0].addr); - buf1 |= FIELD_PREP(MT_DMA_CTL_TOKEN, rx_token); - ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len) | - MT_DMA_CTL_TO_HOST; - } else { - if (txwi) { - q->entry[q->head].txwi = DMA_DUMMY_DATA; - q->entry[q->head].skip_buf0 = true; - } - - if (buf[0].skip_unmap) - entry->skip_buf0 = true; - entry->skip_buf1 = i == nbufs - 1; - - entry->dma_addr[0] = buf[0].addr; - entry->dma_len[0] = buf[0].len; - - ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len); - if (i < nbufs - 1) { - entry->dma_addr[1] = buf[1].addr; - entry->dma_len[1] = buf[1].len; - buf1 = buf[1].addr; - ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len); - if (buf[1].skip_unmap) - entry->skip_buf1 = true; - } - - if (i == nbufs - 1) - ctrl |= MT_DMA_CTL_LAST_SEC0; - else if (i == nbufs - 2) - ctrl |= MT_DMA_CTL_LAST_SEC1; + if (buf[0].skip_unmap) + entry->skip_buf0 = true; + entry->skip_buf1 = i == nbufs - 1; + + entry->dma_addr[0] = buf[0].addr; + entry->dma_len[0] = buf[0].len; + + ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len); + if (i < nbufs - 1) { + entry->dma_addr[1] = buf[1].addr; + entry->dma_len[1] = buf[1].len; + buf1 = buf[1].addr; + ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len); + if (buf[1].skip_unmap) + entry->skip_buf1 = true; } + if (i == nbufs - 1) + ctrl |= MT_DMA_CTL_LAST_SEC0; + else if (i == nbufs - 2) + ctrl |= MT_DMA_CTL_LAST_SEC1; + WRITE_ONCE(desc->buf0, cpu_to_le32(buf0)); WRITE_ONCE(desc->buf1, cpu_to_le32(buf1)); WRITE_ONCE(desc->info, cpu_to_le32(info)); WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl)); + q->head = next; q->queued++; } @@ -577,17 +609,9 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q) spin_lock_bh(&q->lock); while (q->queued < q->ndesc - 1) { - struct mt76_txwi_cache *t = NULL; struct mt76_queue_buf qbuf; void *buf = NULL; - if ((q->flags & MT_QFLAG_WED) && - FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX) { - t = mt76_get_rxwi(dev); - if (!t) - break; - } - buf = page_frag_alloc(rx_page, q->buf_size, GFP_ATOMIC); if (!buf) break; @@ -601,7 +625,12 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q) qbuf.addr = addr + offset; qbuf.len = len - offset; qbuf.skip_unmap = false; - mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, t); + if (mt76_dma_add_rx_buf(dev, q, &qbuf, buf) < 0) { + dma_unmap_single(dev->dma_dev, addr, len, + DMA_FROM_DEVICE); + skb_free_frag(buf); + break; + } frames++; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 0a95c3da241b..8388e2a65853 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -653,6 +653,13 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) desc->buf0 = cpu_to_le32(phy_addr); token = mt76_rx_token_consume(&dev->mt76, ptr, t, phy_addr); + if (token < 0) { + dma_unmap_single(dev->mt76.dma_dev, phy_addr, + wed->wlan.rx_size, DMA_TO_DEVICE); + skb_free_frag(ptr); + goto unmap; + } + desc->token |= cpu_to_le32(FIELD_PREP(MT_DMA_CTL_TOKEN, token)); desc++; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig index 5c5fc569e6d5..79fb47a73c91 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig @@ -2,6 +2,7 @@ config MT7996E tristate "MediaTek MT7996 (PCIe) support" select MT76_CONNAC_LIB + select RELAY depends on MAC80211 depends on PCI help diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 24568b98ed9d..1f309d05380a 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -764,11 +764,12 @@ int mt76_rx_token_consume(struct mt76_dev *dev, void *ptr, spin_lock_bh(&dev->rx_token_lock); token = idr_alloc(&dev->rx_token, t, 0, dev->rx_token_size, GFP_ATOMIC); + if (token >= 0) { + t->ptr = ptr; + t->dma_addr = phys; + } spin_unlock_bh(&dev->rx_token_lock); - t->ptr = ptr; - t->dma_addr = phys; - return token; } EXPORT_SYMBOL_GPL(mt76_rx_token_consume); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 82a7458e01ae..bf72e5fd39cf 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -696,8 +696,8 @@ static int rndis_query_oid(struct usbnet *dev, u32 oid, void *data, int *len) struct rndis_query *get; struct rndis_query_c *get_c; } u; - int ret, buflen; - int resplen, respoffs, copylen; + int ret; + size_t buflen, resplen, respoffs, copylen; buflen = *len + sizeof(*u.get); if (buflen < CONTROL_BUFFER_SIZE) @@ -732,22 +732,15 @@ static int rndis_query_oid(struct usbnet *dev, u32 oid, void *data, int *len) if (respoffs > buflen) { /* Device returned data offset outside buffer, error. */ - netdev_dbg(dev->net, "%s(%s): received invalid " - "data offset: %d > %d\n", __func__, - oid_to_string(oid), respoffs, buflen); + netdev_dbg(dev->net, + "%s(%s): received invalid data offset: %zu > %zu\n", + __func__, oid_to_string(oid), respoffs, buflen); ret = -EINVAL; goto exit_unlock; } - if ((resplen + respoffs) > buflen) { - /* Device would have returned more data if buffer would - * have been big enough. Copy just the bits that we got. - */ - copylen = buflen - respoffs; - } else { - copylen = resplen; - } + copylen = min(resplen, buflen - respoffs); if (copylen > *len) copylen = *len; diff --git a/drivers/net/wireless/ti/Makefile b/drivers/net/wireless/ti/Makefile index 0530dd744275..05ee016594f8 100644 --- a/drivers/net/wireless/ti/Makefile +++ b/drivers/net/wireless/ti/Makefile @@ -3,6 +3,3 @@ obj-$(CONFIG_WLCORE) += wlcore/ obj-$(CONFIG_WL12XX) += wl12xx/ obj-$(CONFIG_WL1251) += wl1251/ obj-$(CONFIG_WL18XX) += wl18xx/ - -# small builtin driver bit -obj-$(CONFIG_WILINK_PLATFORM_DATA) += wilink_platform_data.o diff --git a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif.c b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif.c index 7eff3531b9a5..7ff33c1d6ac7 100644 --- a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif.c +++ b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif.c @@ -152,6 +152,15 @@ static irqreturn_t t7xx_dpmaif_isr_handler(int irq, void *data) } t7xx_pcie_mac_clear_int(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t t7xx_dpmaif_isr_thread(int irq, void *data) +{ + struct dpmaif_isr_para *isr_para = data; + struct dpmaif_ctrl *dpmaif_ctrl = isr_para->dpmaif_ctrl; + t7xx_dpmaif_irq_cb(isr_para); t7xx_pcie_mac_set_int(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int); return IRQ_HANDLED; @@ -188,7 +197,7 @@ static void t7xx_dpmaif_register_pcie_irq(struct dpmaif_ctrl *dpmaif_ctrl) t7xx_pcie_mac_clear_int(t7xx_dev, int_type); t7xx_dev->intr_handler[int_type] = t7xx_dpmaif_isr_handler; - t7xx_dev->intr_thread[int_type] = NULL; + t7xx_dev->intr_thread[int_type] = t7xx_dpmaif_isr_thread; t7xx_dev->callback_param[int_type] = isr_para; t7xx_pcie_mac_clear_int_status(t7xx_dev, int_type); diff --git a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c index aa2174a10437..f4ff2198b5ef 100644 --- a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c +++ b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c @@ -840,14 +840,13 @@ int t7xx_dpmaif_napi_rx_poll(struct napi_struct *napi, const int budget) if (!rxq->que_started) { atomic_set(&rxq->rx_processing, 0); + pm_runtime_put_autosuspend(rxq->dpmaif_ctrl->dev); dev_err(rxq->dpmaif_ctrl->dev, "Work RXQ: %d has not been started\n", rxq->index); return work_done; } - if (!rxq->sleep_lock_pending) { - pm_runtime_get_noresume(rxq->dpmaif_ctrl->dev); + if (!rxq->sleep_lock_pending) t7xx_pci_disable_sleep(t7xx_dev); - } ret = try_wait_for_completion(&t7xx_dev->sleep_lock_acquire); if (!ret) { @@ -876,22 +875,22 @@ int t7xx_dpmaif_napi_rx_poll(struct napi_struct *napi, const int budget) napi_complete_done(napi, work_done); t7xx_dpmaif_clr_ip_busy_sts(&rxq->dpmaif_ctrl->hw_info); t7xx_dpmaif_dlq_unmask_rx_done(&rxq->dpmaif_ctrl->hw_info, rxq->index); + t7xx_pci_enable_sleep(rxq->dpmaif_ctrl->t7xx_dev); + pm_runtime_mark_last_busy(rxq->dpmaif_ctrl->dev); + pm_runtime_put_autosuspend(rxq->dpmaif_ctrl->dev); + atomic_set(&rxq->rx_processing, 0); } else { t7xx_dpmaif_clr_ip_busy_sts(&rxq->dpmaif_ctrl->hw_info); } - t7xx_pci_enable_sleep(rxq->dpmaif_ctrl->t7xx_dev); - pm_runtime_mark_last_busy(rxq->dpmaif_ctrl->dev); - pm_runtime_put_noidle(rxq->dpmaif_ctrl->dev); - atomic_set(&rxq->rx_processing, 0); - return work_done; } void t7xx_dpmaif_irq_rx_done(struct dpmaif_ctrl *dpmaif_ctrl, const unsigned int que_mask) { struct dpmaif_rx_queue *rxq; - int qno; + struct dpmaif_ctrl *ctrl; + int qno, ret; qno = ffs(que_mask) - 1; if (qno < 0 || qno > DPMAIF_RXQ_NUM - 1) { @@ -900,6 +899,18 @@ void t7xx_dpmaif_irq_rx_done(struct dpmaif_ctrl *dpmaif_ctrl, const unsigned int } rxq = &dpmaif_ctrl->rxq[qno]; + ctrl = rxq->dpmaif_ctrl; + /* We need to make sure that the modem has been resumed before + * calling napi. This can't be done inside the polling function + * as we could be blocked waiting for device to be resumed, + * which can't be done from softirq context the poll function + * is running in. + */ + ret = pm_runtime_resume_and_get(ctrl->dev); + if (ret < 0 && ret != -EACCES) { + dev_err(ctrl->dev, "Failed to resume device: %d\n", ret); + return; + } napi_schedule(&rxq->napi); } diff --git a/drivers/net/wwan/t7xx/t7xx_netdev.c b/drivers/net/wwan/t7xx/t7xx_netdev.c index 494a28e386a3..3ef4a8a4f8fd 100644 --- a/drivers/net/wwan/t7xx/t7xx_netdev.c +++ b/drivers/net/wwan/t7xx/t7xx_netdev.c @@ -27,6 +27,7 @@ #include <linux/list.h> #include <linux/netdev_features.h> #include <linux/netdevice.h> +#include <linux/pm_runtime.h> #include <linux/skbuff.h> #include <linux/types.h> #include <linux/wwan.h> @@ -45,12 +46,25 @@ static void t7xx_ccmni_enable_napi(struct t7xx_ccmni_ctrl *ctlb) { - int i; + struct dpmaif_ctrl *ctrl; + int i, ret; + + ctrl = ctlb->hif_ctrl; if (ctlb->is_napi_en) return; for (i = 0; i < RXQ_NUM; i++) { + /* The usage count has to be bumped every time before calling + * napi_schedule. It will be decresed in the poll routine, + * right after napi_complete_done is called. + */ + ret = pm_runtime_resume_and_get(ctrl->dev); + if (ret < 0) { + dev_err(ctrl->dev, "Failed to resume device: %d\n", + ret); + return; + } napi_enable(ctlb->napi[i]); napi_schedule(ctlb->napi[i]); } diff --git a/drivers/net/wwan/t7xx/t7xx_pci.c b/drivers/net/wwan/t7xx/t7xx_pci.c index 871f2a27a398..226fc1703e90 100644 --- a/drivers/net/wwan/t7xx/t7xx_pci.c +++ b/drivers/net/wwan/t7xx/t7xx_pci.c @@ -121,6 +121,8 @@ void t7xx_pci_pm_init_late(struct t7xx_pci_dev *t7xx_dev) iowrite32(T7XX_L1_BIT(0), IREG_BASE(t7xx_dev) + ENABLE_ASPM_LOWPWR); atomic_set(&t7xx_dev->md_pm_state, MTK_PM_RESUMED); + pm_runtime_mark_last_busy(&t7xx_dev->pdev->dev); + pm_runtime_allow(&t7xx_dev->pdev->dev); pm_runtime_put_noidle(&t7xx_dev->pdev->dev); } diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index c1ba4294f364..001636901dda 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -977,7 +977,7 @@ static int read_xenbus_vif_flags(struct backend_info *be) return 0; } -static int netback_remove(struct xenbus_device *dev) +static void netback_remove(struct xenbus_device *dev) { struct backend_info *be = dev_get_drvdata(&dev->dev); @@ -992,7 +992,6 @@ static int netback_remove(struct xenbus_device *dev) kfree(be->hotplug_script); kfree(be); dev_set_drvdata(&dev->dev, NULL); - return 0; } /* diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 14aec417fa06..12b074286df9 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -2646,7 +2646,7 @@ static void xennet_bus_close(struct xenbus_device *dev) } while (!ret); } -static int xennet_remove(struct xenbus_device *dev) +static void xennet_remove(struct xenbus_device *dev) { struct netfront_info *info = dev_get_drvdata(&dev->dev); @@ -2662,8 +2662,6 @@ static int xennet_remove(struct xenbus_device *dev) rtnl_unlock(); } xennet_free_netdev(info->netdev); - - return 0; } static const struct xenbus_device_id netfront_ids[] = { diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c index 6f71ac72012e..ed9c5e2cf3ad 100644 --- a/drivers/nfc/pn533/usb.c +++ b/drivers/nfc/pn533/usb.c @@ -153,10 +153,17 @@ static int pn533_usb_send_ack(struct pn533 *dev, gfp_t flags) return usb_submit_urb(phy->ack_urb, flags); } +struct pn533_out_arg { + struct pn533_usb_phy *phy; + struct completion done; +}; + static int pn533_usb_send_frame(struct pn533 *dev, struct sk_buff *out) { struct pn533_usb_phy *phy = dev->phy; + struct pn533_out_arg arg; + void *cntx; int rc; if (phy->priv == NULL) @@ -168,10 +175,17 @@ static int pn533_usb_send_frame(struct pn533 *dev, print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1, out->data, out->len, false); + init_completion(&arg.done); + cntx = phy->out_urb->context; + phy->out_urb->context = &arg; + rc = usb_submit_urb(phy->out_urb, GFP_KERNEL); if (rc) return rc; + wait_for_completion(&arg.done); + phy->out_urb->context = cntx; + if (dev->protocol_type == PN533_PROTO_REQ_RESP) { /* request for response for sent packet directly */ rc = pn533_submit_urb_for_response(phy, GFP_KERNEL); @@ -408,7 +422,31 @@ static int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy) return arg.rc; } -static void pn533_send_complete(struct urb *urb) +static void pn533_out_complete(struct urb *urb) +{ + struct pn533_out_arg *arg = urb->context; + struct pn533_usb_phy *phy = arg->phy; + + switch (urb->status) { + case 0: + break; /* success */ + case -ECONNRESET: + case -ENOENT: + dev_dbg(&phy->udev->dev, + "The urb has been stopped (status %d)\n", + urb->status); + break; + case -ESHUTDOWN: + default: + nfc_err(&phy->udev->dev, + "Urb failure (status %d)\n", + urb->status); + } + + complete(&arg->done); +} + +static void pn533_ack_complete(struct urb *urb) { struct pn533_usb_phy *phy = urb->context; @@ -496,10 +534,10 @@ static int pn533_usb_probe(struct usb_interface *interface, usb_fill_bulk_urb(phy->out_urb, phy->udev, usb_sndbulkpipe(phy->udev, out_endpoint), - NULL, 0, pn533_send_complete, phy); + NULL, 0, pn533_out_complete, phy); usb_fill_bulk_urb(phy->ack_urb, phy->udev, usb_sndbulkpipe(phy->udev, out_endpoint), - NULL, 0, pn533_send_complete, phy); + NULL, 0, pn533_ack_complete, phy); switch (id->driver_info) { case PN533_DEVICE_STD: diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig index 79d93126453d..77b06d54cc62 100644 --- a/drivers/nvdimm/Kconfig +++ b/drivers/nvdimm/Kconfig @@ -102,6 +102,25 @@ config NVDIMM_KEYS depends on ENCRYPTED_KEYS depends on (LIBNVDIMM=ENCRYPTED_KEYS) || LIBNVDIMM=m +config NVDIMM_KMSAN + bool + depends on KMSAN + help + KMSAN, and other memory debug facilities, increase the size of + 'struct page' to contain extra metadata. This collides with + the NVDIMM capability to store a potentially + larger-than-"System RAM" size 'struct page' array in a + reservation of persistent memory rather than limited / + precious DRAM. However, that reservation needs to persist for + the life of the given NVDIMM namespace. If you are using KMSAN + to debug an issue unrelated to NVDIMMs or DAX then say N to this + option. Otherwise, say Y but understand that any namespaces + (with the page array stored pmem) created with this build of + the kernel will permanently reserve and strand excess + capacity compared to the CONFIG_KMSAN=n case. + + Select N if unsure. + config NVDIMM_TEST_BUILD tristate "Build the unit test core" depends on m diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 85ca5b4da3cf..ec5219680092 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -652,7 +652,7 @@ void devm_namespace_disable(struct device *dev, struct nd_namespace_common *ndns); #if IS_ENABLED(CONFIG_ND_CLAIM) /* max struct page size independent of kernel config */ -#define MAX_STRUCT_PAGE_SIZE 128 +#define MAX_STRUCT_PAGE_SIZE 64 int nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap); #else static inline int nvdimm_setup_pfn(struct nd_pfn *nd_pfn, diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index 61af072ac98f..af7d9301520c 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c @@ -13,6 +13,8 @@ #include "pfn.h" #include "nd.h" +static const bool page_struct_override = IS_ENABLED(CONFIG_NVDIMM_KMSAN); + static void nd_pfn_release(struct device *dev) { struct nd_region *nd_region = to_nd_region(dev->parent); @@ -758,12 +760,6 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) return -ENXIO; } - /* - * Note, we use 64 here for the standard size of struct page, - * debugging options may cause it to be larger in which case the - * implementation will limit the pfns advertised through - * ->direct_access() to those that are included in the memmap. - */ start = nsio->res.start; size = resource_size(&nsio->res); npfns = PHYS_PFN(size - SZ_8K); @@ -782,20 +778,33 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) } end_trunc = start + size - ALIGN_DOWN(start + size, align); if (nd_pfn->mode == PFN_MODE_PMEM) { + unsigned long page_map_size = MAX_STRUCT_PAGE_SIZE * npfns; + /* * The altmap should be padded out to the block size used * when populating the vmemmap. This *should* be equal to * PMD_SIZE for most architectures. * - * Also make sure size of struct page is less than 128. We - * want to make sure we use large enough size here so that - * we don't have a dynamic reserve space depending on - * struct page size. But we also want to make sure we notice - * when we end up adding new elements to struct page. + * Also make sure size of struct page is less than + * MAX_STRUCT_PAGE_SIZE. The goal here is compatibility in the + * face of production kernel configurations that reduce the + * 'struct page' size below MAX_STRUCT_PAGE_SIZE. For debug + * kernel configurations that increase the 'struct page' size + * above MAX_STRUCT_PAGE_SIZE, the page_struct_override allows + * for continuing with the capacity that will be wasted when + * reverting to a production kernel configuration. Otherwise, + * those configurations are blocked by default. */ - BUILD_BUG_ON(sizeof(struct page) > MAX_STRUCT_PAGE_SIZE); - offset = ALIGN(start + SZ_8K + MAX_STRUCT_PAGE_SIZE * npfns, align) - - start; + if (sizeof(struct page) > MAX_STRUCT_PAGE_SIZE) { + if (page_struct_override) + page_map_size = sizeof(struct page) * npfns; + else { + dev_err(&nd_pfn->dev, + "Memory debug options prevent using pmem for the page map\n"); + return -EINVAL; + } + } + offset = ALIGN(start + SZ_8K + page_map_size, align) - start; } else if (nd_pfn->mode == PFN_MODE_RAM) offset = ALIGN(start + SZ_8K, align) - start; else @@ -818,7 +827,10 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) pfn_sb->version_minor = cpu_to_le16(4); pfn_sb->end_trunc = cpu_to_le32(end_trunc); pfn_sb->align = cpu_to_le32(nd_pfn->align); - pfn_sb->page_struct_size = cpu_to_le16(MAX_STRUCT_PAGE_SIZE); + if (sizeof(struct page) > MAX_STRUCT_PAGE_SIZE && page_struct_override) + pfn_sb->page_struct_size = cpu_to_le16(sizeof(struct page)); + else + pfn_sb->page_struct_size = cpu_to_le16(MAX_STRUCT_PAGE_SIZE); pfn_sb->page_size = cpu_to_le32(PAGE_SIZE); checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb); pfn_sb->checksum = cpu_to_le64(checksum); diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c index e36aeb50b4ed..b317ce6c4ec3 100644 --- a/drivers/nvme/host/apple.c +++ b/drivers/nvme/host/apple.c @@ -829,7 +829,23 @@ static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown) apple_nvme_remove_cq(anv); } - nvme_disable_ctrl(&anv->ctrl, shutdown); + /* + * Always disable the NVMe controller after shutdown. + * We need to do this to bring it back up later anyway, and we + * can't do it while the firmware is not running (e.g. in the + * resume reset path before RTKit is initialized), so for Apple + * controllers it makes sense to unconditionally do it here. + * Additionally, this sequence of events is reliable, while + * others (like disabling after bringing back the firmware on + * resume) seem to run into trouble under some circumstances. + * + * Both U-Boot and m1n1 also use this convention (i.e. an ANS + * NVMe controller is handed off with firmware shut down, in an + * NVMe disabled state, after a clean shutdown). + */ + if (shutdown) + nvme_disable_ctrl(&anv->ctrl, shutdown); + nvme_disable_ctrl(&anv->ctrl, false); } WRITE_ONCE(anv->ioq.enabled, false); @@ -985,11 +1001,11 @@ static void apple_nvme_reset_work(struct work_struct *work) goto out; } - if (anv->ctrl.ctrl_config & NVME_CC_ENABLE) - apple_nvme_disable(anv, false); - /* RTKit must be shut down cleanly for the (soft)-reset to work */ if (apple_rtkit_is_running(anv->rtk)) { + /* reset the controller if it is enabled */ + if (anv->ctrl.ctrl_config & NVME_CC_ENABLE) + apple_nvme_disable(anv, false); dev_dbg(anv->dev, "Trying to shut down RTKit before reset."); ret = apple_rtkit_shutdown(anv->rtk); if (ret) @@ -1493,7 +1509,7 @@ static int apple_nvme_probe(struct platform_device *pdev) } ret = nvme_init_ctrl(&anv->ctrl, anv->dev, &nvme_ctrl_ops, - NVME_QUIRK_SKIP_CID_GEN); + NVME_QUIRK_SKIP_CID_GEN | NVME_QUIRK_IDENTIFY_CNS); if (ret) { dev_err_probe(dev, ret, "Failed to initialize nvme_ctrl"); goto put_dev; diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c index bb0abbe4491c..901c59145811 100644 --- a/drivers/nvme/host/auth.c +++ b/drivers/nvme/host/auth.c @@ -45,6 +45,8 @@ struct nvme_dhchap_queue_context { int sess_key_len; }; +static struct workqueue_struct *nvme_auth_wq; + #define nvme_auth_flags_from_qid(qid) \ (qid == 0) ? 0 : BLK_MQ_REQ_NOWAIT | BLK_MQ_REQ_RESERVED #define nvme_auth_queue_from_qid(ctrl, qid) \ @@ -158,7 +160,7 @@ static int nvme_auth_process_dhchap_challenge(struct nvme_ctrl *ctrl, if (size > CHAP_BUF_SIZE) { chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD; - return NVME_SC_INVALID_FIELD; + return -EINVAL; } hmac_name = nvme_auth_hmac_name(data->hashid); @@ -167,7 +169,7 @@ static int nvme_auth_process_dhchap_challenge(struct nvme_ctrl *ctrl, "qid %d: invalid HASH ID %d\n", chap->qid, data->hashid); chap->status = NVME_AUTH_DHCHAP_FAILURE_HASH_UNUSABLE; - return NVME_SC_INVALID_FIELD; + return -EPROTO; } if (chap->hash_id == data->hashid && chap->shash_tfm && @@ -193,7 +195,7 @@ static int nvme_auth_process_dhchap_challenge(struct nvme_ctrl *ctrl, chap->qid, hmac_name, PTR_ERR(chap->shash_tfm)); chap->shash_tfm = NULL; chap->status = NVME_AUTH_DHCHAP_FAILURE_FAILED; - return NVME_SC_AUTH_REQUIRED; + return -ENOMEM; } if (crypto_shash_digestsize(chap->shash_tfm) != data->hl) { @@ -203,7 +205,7 @@ static int nvme_auth_process_dhchap_challenge(struct nvme_ctrl *ctrl, crypto_free_shash(chap->shash_tfm); chap->shash_tfm = NULL; chap->status = NVME_AUTH_DHCHAP_FAILURE_HASH_UNUSABLE; - return NVME_SC_AUTH_REQUIRED; + return -EPROTO; } chap->hash_id = data->hashid; @@ -219,7 +221,7 @@ select_kpp: chap->qid, data->dhgid); chap->status = NVME_AUTH_DHCHAP_FAILURE_DHGROUP_UNUSABLE; /* Leave previous dh_tfm intact */ - return NVME_SC_AUTH_REQUIRED; + return -EPROTO; } if (chap->dhgroup_id == data->dhgid && @@ -242,7 +244,7 @@ select_kpp: "qid %d: empty DH value\n", chap->qid); chap->status = NVME_AUTH_DHCHAP_FAILURE_DHGROUP_UNUSABLE; - return NVME_SC_INVALID_FIELD; + return -EPROTO; } chap->dh_tfm = crypto_alloc_kpp(kpp_name, 0, 0); @@ -254,7 +256,7 @@ select_kpp: chap->qid, ret, gid_name); chap->status = NVME_AUTH_DHCHAP_FAILURE_DHGROUP_UNUSABLE; chap->dh_tfm = NULL; - return NVME_SC_AUTH_REQUIRED; + return -ret; } dev_dbg(ctrl->device, "qid %d: selected DH group %s\n", chap->qid, gid_name); @@ -263,7 +265,7 @@ select_kpp: "qid %d: invalid DH value for NULL DH\n", chap->qid); chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD; - return NVME_SC_INVALID_FIELD; + return -EPROTO; } chap->dhgroup_id = data->dhgid; @@ -274,7 +276,7 @@ skip_kpp: chap->ctrl_key = kmalloc(dhvlen, GFP_KERNEL); if (!chap->ctrl_key) { chap->status = NVME_AUTH_DHCHAP_FAILURE_FAILED; - return NVME_SC_AUTH_REQUIRED; + return -ENOMEM; } chap->ctrl_key_len = dhvlen; memcpy(chap->ctrl_key, data->cval + chap->hash_len, @@ -344,7 +346,7 @@ static int nvme_auth_process_dhchap_success1(struct nvme_ctrl *ctrl, if (size > CHAP_BUF_SIZE) { chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD; - return NVME_SC_INVALID_FIELD; + return -EINVAL; } if (data->hl != chap->hash_len) { @@ -352,7 +354,7 @@ static int nvme_auth_process_dhchap_success1(struct nvme_ctrl *ctrl, "qid %d: invalid hash length %u\n", chap->qid, data->hl); chap->status = NVME_AUTH_DHCHAP_FAILURE_HASH_UNUSABLE; - return NVME_SC_INVALID_FIELD; + return -EPROTO; } /* Just print out information for the admin queue */ @@ -376,7 +378,7 @@ static int nvme_auth_process_dhchap_success1(struct nvme_ctrl *ctrl, "qid %d: controller authentication failed\n", chap->qid); chap->status = NVME_AUTH_DHCHAP_FAILURE_FAILED; - return NVME_SC_AUTH_REQUIRED; + return -ECONNREFUSED; } /* Just print out information for the admin queue */ @@ -730,7 +732,7 @@ static void nvme_queue_auth_work(struct work_struct *work) NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE); if (ret) { chap->status = ret; - chap->error = NVME_SC_AUTH_REQUIRED; + chap->error = -ECONNREFUSED; return; } @@ -798,7 +800,7 @@ static void nvme_queue_auth_work(struct work_struct *work) NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1); if (ret) { chap->status = ret; - chap->error = NVME_SC_AUTH_REQUIRED; + chap->error = -ECONNREFUSED; return; } @@ -819,7 +821,7 @@ static void nvme_queue_auth_work(struct work_struct *work) ret = nvme_auth_process_dhchap_success1(ctrl, chap); if (ret) { /* Controller authentication failed */ - chap->error = NVME_SC_AUTH_REQUIRED; + chap->error = -ECONNREFUSED; goto fail2; } @@ -866,7 +868,7 @@ int nvme_auth_negotiate(struct nvme_ctrl *ctrl, int qid) chap = &ctrl->dhchap_ctxs[qid]; cancel_work_sync(&chap->auth_work); - queue_work(nvme_wq, &chap->auth_work); + queue_work(nvme_auth_wq, &chap->auth_work); return 0; } EXPORT_SYMBOL_GPL(nvme_auth_negotiate); @@ -953,7 +955,7 @@ int nvme_auth_init_ctrl(struct nvme_ctrl *ctrl) goto err_free_dhchap_secret; if (!ctrl->opts->dhchap_secret && !ctrl->opts->dhchap_ctrl_secret) - return ret; + return 0; ctrl->dhchap_ctxs = kvcalloc(ctrl_max_dhchaps(ctrl), sizeof(*chap), GFP_KERNEL); @@ -1008,10 +1010,15 @@ EXPORT_SYMBOL_GPL(nvme_auth_free); int __init nvme_init_auth(void) { + nvme_auth_wq = alloc_workqueue("nvme-auth-wq", + WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, 0); + if (!nvme_auth_wq) + return -ENOMEM; + nvme_chap_buf_cache = kmem_cache_create("nvme-chap-buf-cache", CHAP_BUF_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL); if (!nvme_chap_buf_cache) - return -ENOMEM; + goto err_destroy_workqueue; nvme_chap_buf_pool = mempool_create(16, mempool_alloc_slab, mempool_free_slab, nvme_chap_buf_cache); @@ -1021,6 +1028,8 @@ int __init nvme_init_auth(void) return 0; err_destroy_chap_buf_cache: kmem_cache_destroy(nvme_chap_buf_cache); +err_destroy_workqueue: + destroy_workqueue(nvme_auth_wq); return -ENOMEM; } @@ -1028,4 +1037,5 @@ void __exit nvme_exit_auth(void) { mempool_destroy(nvme_chap_buf_pool); kmem_cache_destroy(nvme_chap_buf_cache); + destroy_workqueue(nvme_auth_wq); } diff --git a/drivers/nvme/host/constants.c b/drivers/nvme/host/constants.c index e958d5015585..bc523ca02254 100644 --- a/drivers/nvme/host/constants.c +++ b/drivers/nvme/host/constants.c @@ -54,6 +54,14 @@ static const char * const nvme_admin_ops[] = { [nvme_admin_get_lba_status] = "Get LBA Status", }; +static const char * const nvme_fabrics_ops[] = { + [nvme_fabrics_type_property_set] = "Property Set", + [nvme_fabrics_type_property_get] = "Property Get", + [nvme_fabrics_type_connect] = "Connect", + [nvme_fabrics_type_auth_send] = "Authentication Send", + [nvme_fabrics_type_auth_receive] = "Authentication Receive", +}; + static const char * const nvme_statuses[] = { [NVME_SC_SUCCESS] = "Success", [NVME_SC_INVALID_OPCODE] = "Invalid Command Opcode", @@ -185,3 +193,11 @@ const unsigned char *nvme_get_admin_opcode_str(u8 opcode) return nvme_admin_ops[opcode]; return "Unknown"; } +EXPORT_SYMBOL_GPL(nvme_get_admin_opcode_str); + +const unsigned char *nvme_get_fabrics_opcode_str(u8 opcode) { + if (opcode < ARRAY_SIZE(nvme_fabrics_ops) && nvme_fabrics_ops[opcode]) + return nvme_fabrics_ops[opcode]; + return "Unknown"; +} +EXPORT_SYMBOL_GPL(nvme_get_fabrics_opcode_str); diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 95c488ea91c3..8698410aeb84 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -806,9 +806,7 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req, cmnd->dsm.nr = cpu_to_le32(segments - 1); cmnd->dsm.attributes = cpu_to_le32(NVME_DSMGMT_AD); - req->special_vec.bv_page = virt_to_page(range); - req->special_vec.bv_offset = offset_in_page(range); - req->special_vec.bv_len = alloc_size; + bvec_set_virt(&req->special_vec, range, alloc_size); req->rq_flags |= RQF_SPECIAL_PAYLOAD; return BLK_STS_OK; @@ -1004,7 +1002,7 @@ EXPORT_SYMBOL_GPL(nvme_setup_cmd); * >0: nvme controller's cqe status response * <0: kernel error in lieu of controller response */ -static int nvme_execute_rq(struct request *rq, bool at_head) +int nvme_execute_rq(struct request *rq, bool at_head) { blk_status_t status; @@ -1015,6 +1013,7 @@ static int nvme_execute_rq(struct request *rq, bool at_head) return nvme_req(rq)->status; return blk_status_to_errno(status); } +EXPORT_SYMBOL_NS_GPL(nvme_execute_rq, NVME_TARGET_PASSTHRU); /* * Returns 0 on success. If the result is negative, it's a Linux error code; @@ -1060,44 +1059,32 @@ int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd, } EXPORT_SYMBOL_GPL(nvme_submit_sync_cmd); -static u32 nvme_known_admin_effects(u8 opcode) -{ - switch (opcode) { - case nvme_admin_format_nvm: - return NVME_CMD_EFFECTS_LBCC | NVME_CMD_EFFECTS_NCC | - NVME_CMD_EFFECTS_CSE_MASK; - case nvme_admin_sanitize_nvm: - return NVME_CMD_EFFECTS_LBCC | NVME_CMD_EFFECTS_CSE_MASK; - default: - break; - } - return 0; -} - u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode) { u32 effects = 0; if (ns) { - if (ns->head->effects) - effects = le32_to_cpu(ns->head->effects->iocs[opcode]); + effects = le32_to_cpu(ns->head->effects->iocs[opcode]); if (effects & ~(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC)) dev_warn_once(ctrl->device, - "IO command:%02x has unhandled effects:%08x\n", + "IO command:%02x has unusual effects:%08x\n", opcode, effects); - return 0; - } - if (ctrl->effects) + /* + * NVME_CMD_EFFECTS_CSE_MASK causes a freeze all I/O queues, + * which would deadlock when done on an I/O command. Note that + * We already warn about an unusual effect above. + */ + effects &= ~NVME_CMD_EFFECTS_CSE_MASK; + } else { effects = le32_to_cpu(ctrl->effects->acs[opcode]); - effects |= nvme_known_admin_effects(opcode); + } return effects; } EXPORT_SYMBOL_NS_GPL(nvme_command_effects, NVME_TARGET_PASSTHRU); -static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, - u8 opcode) +u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode) { u32 effects = nvme_command_effects(ctrl, ns, opcode); @@ -1115,6 +1102,7 @@ static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, } return effects; } +EXPORT_SYMBOL_NS_GPL(nvme_passthru_start, NVME_TARGET_PASSTHRU); void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects, struct nvme_command *cmd, int status) @@ -1156,17 +1144,6 @@ void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects, } EXPORT_SYMBOL_NS_GPL(nvme_passthru_end, NVME_TARGET_PASSTHRU); -int nvme_execute_passthru_rq(struct request *rq, u32 *effects) -{ - struct nvme_command *cmd = nvme_req(rq)->cmd; - struct nvme_ctrl *ctrl = nvme_req(rq)->ctrl; - struct nvme_ns *ns = rq->q->queuedata; - - *effects = nvme_passthru_start(ctrl, ns, cmd->common.opcode); - return nvme_execute_rq(rq, false); -} -EXPORT_SYMBOL_NS_GPL(nvme_execute_passthru_rq, NVME_TARGET_PASSTHRU); - /* * Recommended frequency for KATO commands per NVMe 1.4 section 7.12.1: * @@ -3102,6 +3079,62 @@ free_data: return ret; } +static void nvme_init_known_nvm_effects(struct nvme_ctrl *ctrl) +{ + struct nvme_effects_log *log = ctrl->effects; + + log->acs[nvme_admin_format_nvm] |= cpu_to_le32(NVME_CMD_EFFECTS_LBCC | + NVME_CMD_EFFECTS_NCC | + NVME_CMD_EFFECTS_CSE_MASK); + log->acs[nvme_admin_sanitize_nvm] |= cpu_to_le32(NVME_CMD_EFFECTS_LBCC | + NVME_CMD_EFFECTS_CSE_MASK); + + /* + * The spec says the result of a security receive command depends on + * the previous security send command. As such, many vendors log this + * command as one to submitted only when no other commands to the same + * namespace are outstanding. The intention is to tell the host to + * prevent mixing security send and receive. + * + * This driver can only enforce such exclusive access against IO + * queues, though. We are not readily able to enforce such a rule for + * two commands to the admin queue, which is the only queue that + * matters for this command. + * + * Rather than blindly freezing the IO queues for this effect that + * doesn't even apply to IO, mask it off. + */ + log->acs[nvme_admin_security_recv] &= ~NVME_CMD_EFFECTS_CSE_MASK; + + log->iocs[nvme_cmd_write] |= cpu_to_le32(NVME_CMD_EFFECTS_LBCC); + log->iocs[nvme_cmd_write_zeroes] |= cpu_to_le32(NVME_CMD_EFFECTS_LBCC); + log->iocs[nvme_cmd_write_uncor] |= cpu_to_le32(NVME_CMD_EFFECTS_LBCC); +} + +static int nvme_init_effects(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id) +{ + int ret = 0; + + if (ctrl->effects) + return 0; + + if (id->lpa & NVME_CTRL_LPA_CMD_EFFECTS_LOG) { + ret = nvme_get_effects_log(ctrl, NVME_CSI_NVM, &ctrl->effects); + if (ret < 0) + return ret; + } + + if (!ctrl->effects) { + ctrl->effects = kzalloc(sizeof(*ctrl->effects), GFP_KERNEL); + if (!ctrl->effects) + return -ENOMEM; + xa_store(&ctrl->cels, NVME_CSI_NVM, ctrl->effects, GFP_KERNEL); + } + + nvme_init_known_nvm_effects(ctrl); + return 0; +} + static int nvme_init_identify(struct nvme_ctrl *ctrl) { struct nvme_id_ctrl *id; @@ -3115,12 +3148,6 @@ static int nvme_init_identify(struct nvme_ctrl *ctrl) return -EIO; } - if (id->lpa & NVME_CTRL_LPA_CMD_EFFECTS_LOG) { - ret = nvme_get_effects_log(ctrl, NVME_CSI_NVM, &ctrl->effects); - if (ret < 0) - goto out_free; - } - if (!(ctrl->ops->flags & NVME_F_FABRICS)) ctrl->cntlid = le16_to_cpu(id->cntlid); @@ -3143,6 +3170,10 @@ static int nvme_init_identify(struct nvme_ctrl *ctrl) ret = nvme_init_subsystem(ctrl, id); if (ret) goto out_free; + + ret = nvme_init_effects(ctrl, id); + if (ret) + goto out_free; } memcpy(ctrl->subsys->firmware_rev, id->fr, sizeof(ctrl->subsys->firmware_rev)); @@ -4901,7 +4932,9 @@ out_cleanup_admin_q: blk_mq_destroy_queue(ctrl->admin_q); blk_put_queue(ctrl->admin_q); out_free_tagset: - blk_mq_free_tag_set(ctrl->admin_tagset); + blk_mq_free_tag_set(set); + ctrl->admin_q = NULL; + ctrl->fabrics_q = NULL; return ret; } EXPORT_SYMBOL_GPL(nvme_alloc_admin_tag_set); @@ -4926,7 +4959,7 @@ int nvme_alloc_io_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set, memset(set, 0, sizeof(*set)); set->ops = ops; - set->queue_depth = ctrl->sqsize + 1; + set->queue_depth = min_t(unsigned, ctrl->sqsize, BLK_MQ_MAX_DEPTH - 1); /* * Some Apple controllers requires tags to be unique across admin and * the (only) I/O queue, so reserve the first 32 tags of the I/O queue. @@ -4963,6 +4996,7 @@ int nvme_alloc_io_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set, out_free_tag_set: blk_mq_free_tag_set(set); + ctrl->connect_q = NULL; return ret; } EXPORT_SYMBOL_GPL(nvme_alloc_io_tag_set); diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index ce27276f552d..bbaa04a0c502 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -410,7 +410,14 @@ int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl) result = le32_to_cpu(res.u32); ctrl->cntlid = result & 0xFFFF; - if ((result >> 16) & 0x3) { + if (result & (NVME_CONNECT_AUTHREQ_ATR | NVME_CONNECT_AUTHREQ_ASCR)) { + /* Secure concatenation is not implemented */ + if (result & NVME_CONNECT_AUTHREQ_ASCR) { + dev_warn(ctrl->device, + "qid 0: secure concatenation is not supported\n"); + ret = NVME_SC_AUTH_REQUIRED; + goto out_free_data; + } /* Authentication required */ ret = nvme_auth_negotiate(ctrl, 0); if (ret) { @@ -486,7 +493,14 @@ int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid) &cmd, data); } result = le32_to_cpu(res.u32); - if ((result >> 16) & 2) { + if (result & (NVME_CONNECT_AUTHREQ_ATR | NVME_CONNECT_AUTHREQ_ASCR)) { + /* Secure concatenation is not implemented */ + if (result & NVME_CONNECT_AUTHREQ_ASCR) { + dev_warn(ctrl->device, + "qid 0: secure concatenation is not supported\n"); + ret = NVME_SC_AUTH_REQUIRED; + goto out_free_data; + } /* Authentication required */ ret = nvme_auth_negotiate(ctrl, qid); if (ret) { @@ -500,6 +514,7 @@ int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid) "qid %u: authentication failed\n", qid); } } +out_free_data: kfree(data); return ret; } diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 4564f16a0b20..456ee42a6133 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -3521,13 +3521,6 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, nvme_fc_init_queue(ctrl, 0); - ret = nvme_alloc_admin_tag_set(&ctrl->ctrl, &ctrl->admin_tag_set, - &nvme_fc_admin_mq_ops, - struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv, - ctrl->lport->ops->fcprqst_priv_sz)); - if (ret) - goto out_free_queues; - /* * Would have been nice to init io queues tag set as well. * However, we require interaction from the controller @@ -3537,10 +3530,17 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, ret = nvme_init_ctrl(&ctrl->ctrl, dev, &nvme_fc_ctrl_ops, 0); if (ret) - goto out_cleanup_tagset; + goto out_free_queues; /* at this point, teardown path changes to ref counting on nvme ctrl */ + ret = nvme_alloc_admin_tag_set(&ctrl->ctrl, &ctrl->admin_tag_set, + &nvme_fc_admin_mq_ops, + struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv, + ctrl->lport->ops->fcprqst_priv_sz)); + if (ret) + goto fail_ctrl; + spin_lock_irqsave(&rport->lock, flags); list_add_tail(&ctrl->ctrl_list, &rport->ctrl_list); spin_unlock_irqrestore(&rport->lock, flags); @@ -3592,8 +3592,6 @@ fail_ctrl: return ERR_PTR(-EIO); -out_cleanup_tagset: - nvme_remove_admin_tag_set(&ctrl->ctrl); out_free_queues: kfree(ctrl->queues); out_free_ida: diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c index 9ddda571f046..723e7d5b778f 100644 --- a/drivers/nvme/host/ioctl.c +++ b/drivers/nvme/host/ioctl.c @@ -8,13 +8,27 @@ #include <linux/io_uring.h> #include "nvme.h" +enum { + NVME_IOCTL_VEC = (1 << 0), + NVME_IOCTL_PARTITION = (1 << 1), +}; + static bool nvme_cmd_allowed(struct nvme_ns *ns, struct nvme_command *c, - fmode_t mode) + unsigned int flags, fmode_t mode) { + u32 effects; + if (capable(CAP_SYS_ADMIN)) return true; /* + * Do not allow unprivileged passthrough on partitions, as that allows an + * escape from the containment of the partition. + */ + if (flags & NVME_IOCTL_PARTITION) + return false; + + /* * Do not allow unprivileged processes to send vendor specific or fabrics * commands as we can't be sure about their effects. */ @@ -43,11 +57,29 @@ static bool nvme_cmd_allowed(struct nvme_ns *ns, struct nvme_command *c, } /* - * Only allow I/O commands that transfer data to the controller if the - * special file is open for writing, but always allow I/O commands that - * transfer data from the controller. + * Check if the controller provides a Commands Supported and Effects log + * and marks this command as supported. If not reject unprivileged + * passthrough. */ - if (nvme_is_write(c)) + effects = nvme_command_effects(ns->ctrl, ns, c->common.opcode); + if (!(effects & NVME_CMD_EFFECTS_CSUPP)) + return false; + + /* + * Don't allow passthrough for command that have intrusive (or unknown) + * effects. + */ + if (effects & ~(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC | + NVME_CMD_EFFECTS_UUID_SEL | + NVME_CMD_EFFECTS_SCOPE_MASK)) + return false; + + /* + * Only allow I/O commands that transfer data to the controller or that + * change the logical block contents if the file descriptor is open for + * writing. + */ + if (nvme_is_write(c) || (effects & NVME_CMD_EFFECTS_LBCC)) return mode & FMODE_WRITE; return true; } @@ -130,7 +162,7 @@ static struct request *nvme_alloc_user_request(struct request_queue *q, static int nvme_map_user_request(struct request *req, u64 ubuffer, unsigned bufflen, void __user *meta_buffer, unsigned meta_len, u32 meta_seed, void **metap, struct io_uring_cmd *ioucmd, - bool vec) + unsigned int flags) { struct request_queue *q = req->q; struct nvme_ns *ns = q->queuedata; @@ -143,7 +175,7 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer, struct iov_iter iter; /* fixedbufs is only for non-vectored io */ - if (WARN_ON_ONCE(vec)) + if (WARN_ON_ONCE(flags & NVME_IOCTL_VEC)) return -EINVAL; ret = io_uring_cmd_import_fixed(ubuffer, bufflen, rq_data_dir(req), &iter, ioucmd); @@ -152,8 +184,8 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer, ret = blk_rq_map_user_iov(q, req, NULL, &iter, GFP_KERNEL); } else { ret = blk_rq_map_user_io(req, NULL, nvme_to_user_ptr(ubuffer), - bufflen, GFP_KERNEL, vec, 0, 0, - rq_data_dir(req)); + bufflen, GFP_KERNEL, flags & NVME_IOCTL_VEC, 0, + 0, rq_data_dir(req)); } if (ret) @@ -183,10 +215,11 @@ out: } static int nvme_submit_user_cmd(struct request_queue *q, - struct nvme_command *cmd, u64 ubuffer, - unsigned bufflen, void __user *meta_buffer, unsigned meta_len, - u32 meta_seed, u64 *result, unsigned timeout, bool vec) + struct nvme_command *cmd, u64 ubuffer, unsigned bufflen, + void __user *meta_buffer, unsigned meta_len, u32 meta_seed, + u64 *result, unsigned timeout, unsigned int flags) { + struct nvme_ns *ns = q->queuedata; struct nvme_ctrl *ctrl; struct request *req; void *meta = NULL; @@ -201,7 +234,7 @@ static int nvme_submit_user_cmd(struct request_queue *q, req->timeout = timeout; if (ubuffer && bufflen) { ret = nvme_map_user_request(req, ubuffer, bufflen, meta_buffer, - meta_len, meta_seed, &meta, NULL, vec); + meta_len, meta_seed, &meta, NULL, flags); if (ret) return ret; } @@ -209,8 +242,8 @@ static int nvme_submit_user_cmd(struct request_queue *q, bio = req->bio; ctrl = nvme_req(req)->ctrl; - ret = nvme_execute_passthru_rq(req, &effects); - + effects = nvme_passthru_start(ctrl, ns, cmd->common.opcode); + ret = nvme_execute_rq(req, false); if (result) *result = le64_to_cpu(nvme_req(req)->result.u64); if (meta) @@ -284,10 +317,8 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) c.rw.apptag = cpu_to_le16(io.apptag); c.rw.appmask = cpu_to_le16(io.appmask); - return nvme_submit_user_cmd(ns->queue, &c, - io.addr, length, - metadata, meta_len, lower_32_bits(io.slba), NULL, 0, - false); + return nvme_submit_user_cmd(ns->queue, &c, io.addr, length, metadata, + meta_len, lower_32_bits(io.slba), NULL, 0, 0); } static bool nvme_validate_passthru_nsid(struct nvme_ctrl *ctrl, @@ -305,7 +336,8 @@ static bool nvme_validate_passthru_nsid(struct nvme_ctrl *ctrl, } static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns, - struct nvme_passthru_cmd __user *ucmd, fmode_t mode) + struct nvme_passthru_cmd __user *ucmd, unsigned int flags, + fmode_t mode) { struct nvme_passthru_cmd cmd; struct nvme_command c; @@ -333,16 +365,15 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns, c.common.cdw14 = cpu_to_le32(cmd.cdw14); c.common.cdw15 = cpu_to_le32(cmd.cdw15); - if (!nvme_cmd_allowed(ns, &c, mode)) + if (!nvme_cmd_allowed(ns, &c, 0, mode)) return -EACCES; if (cmd.timeout_ms) timeout = msecs_to_jiffies(cmd.timeout_ms); status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c, - cmd.addr, cmd.data_len, - nvme_to_user_ptr(cmd.metadata), cmd.metadata_len, - 0, &result, timeout, false); + cmd.addr, cmd.data_len, nvme_to_user_ptr(cmd.metadata), + cmd.metadata_len, 0, &result, timeout, 0); if (status >= 0) { if (put_user(result, &ucmd->result)) @@ -353,8 +384,8 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns, } static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns, - struct nvme_passthru_cmd64 __user *ucmd, bool vec, - fmode_t mode) + struct nvme_passthru_cmd64 __user *ucmd, unsigned int flags, + fmode_t mode) { struct nvme_passthru_cmd64 cmd; struct nvme_command c; @@ -381,16 +412,15 @@ static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns, c.common.cdw14 = cpu_to_le32(cmd.cdw14); c.common.cdw15 = cpu_to_le32(cmd.cdw15); - if (!nvme_cmd_allowed(ns, &c, mode)) + if (!nvme_cmd_allowed(ns, &c, flags, mode)) return -EACCES; if (cmd.timeout_ms) timeout = msecs_to_jiffies(cmd.timeout_ms); status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c, - cmd.addr, cmd.data_len, - nvme_to_user_ptr(cmd.metadata), cmd.metadata_len, - 0, &cmd.result, timeout, vec); + cmd.addr, cmd.data_len, nvme_to_user_ptr(cmd.metadata), + cmd.metadata_len, 0, &cmd.result, timeout, flags); if (status >= 0) { if (put_user(cmd.result, &ucmd->result)) @@ -525,7 +555,7 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns, struct nvme_uring_data d; struct nvme_command c; struct request *req; - blk_opf_t rq_flags = 0; + blk_opf_t rq_flags = REQ_ALLOC_CACHE; blk_mq_req_flags_t blk_flags = 0; void *meta = NULL; int ret; @@ -551,7 +581,7 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns, c.common.cdw14 = cpu_to_le32(READ_ONCE(cmd->cdw14)); c.common.cdw15 = cpu_to_le32(READ_ONCE(cmd->cdw15)); - if (!nvme_cmd_allowed(ns, &c, ioucmd->file->f_mode)) + if (!nvme_cmd_allowed(ns, &c, 0, ioucmd->file->f_mode)) return -EACCES; d.metadata = READ_ONCE(cmd->metadata); @@ -561,7 +591,7 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns, d.timeout_ms = READ_ONCE(cmd->timeout_ms); if (issue_flags & IO_URING_F_NONBLOCK) { - rq_flags = REQ_NOWAIT; + rq_flags |= REQ_NOWAIT; blk_flags = BLK_MQ_REQ_NOWAIT; } if (issue_flags & IO_URING_F_IOPOLL) @@ -621,9 +651,9 @@ static int nvme_ctrl_ioctl(struct nvme_ctrl *ctrl, unsigned int cmd, { switch (cmd) { case NVME_IOCTL_ADMIN_CMD: - return nvme_user_cmd(ctrl, NULL, argp, mode); + return nvme_user_cmd(ctrl, NULL, argp, 0, mode); case NVME_IOCTL_ADMIN64_CMD: - return nvme_user_cmd64(ctrl, NULL, argp, false, mode); + return nvme_user_cmd64(ctrl, NULL, argp, 0, mode); default: return sed_ioctl(ctrl->opal_dev, cmd, argp); } @@ -648,14 +678,14 @@ struct nvme_user_io32 { #endif /* COMPAT_FOR_U64_ALIGNMENT */ static int nvme_ns_ioctl(struct nvme_ns *ns, unsigned int cmd, - void __user *argp, fmode_t mode) + void __user *argp, unsigned int flags, fmode_t mode) { switch (cmd) { case NVME_IOCTL_ID: force_successful_syscall_return(); return ns->head->ns_id; case NVME_IOCTL_IO_CMD: - return nvme_user_cmd(ns->ctrl, ns, argp, mode); + return nvme_user_cmd(ns->ctrl, ns, argp, flags, mode); /* * struct nvme_user_io can have different padding on some 32-bit ABIs. * Just accept the compat version as all fields that are used are the @@ -666,37 +696,40 @@ static int nvme_ns_ioctl(struct nvme_ns *ns, unsigned int cmd, #endif case NVME_IOCTL_SUBMIT_IO: return nvme_submit_io(ns, argp); - case NVME_IOCTL_IO64_CMD: - return nvme_user_cmd64(ns->ctrl, ns, argp, false, mode); case NVME_IOCTL_IO64_CMD_VEC: - return nvme_user_cmd64(ns->ctrl, ns, argp, true, mode); + flags |= NVME_IOCTL_VEC; + fallthrough; + case NVME_IOCTL_IO64_CMD: + return nvme_user_cmd64(ns->ctrl, ns, argp, flags, mode); default: return -ENOTTY; } } -static int __nvme_ioctl(struct nvme_ns *ns, unsigned int cmd, void __user *arg, - fmode_t mode) -{ - if (is_ctrl_ioctl(cmd)) - return nvme_ctrl_ioctl(ns->ctrl, cmd, arg, mode); - return nvme_ns_ioctl(ns, cmd, arg, mode); -} - int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { struct nvme_ns *ns = bdev->bd_disk->private_data; + void __user *argp = (void __user *)arg; + unsigned int flags = 0; + + if (bdev_is_partition(bdev)) + flags |= NVME_IOCTL_PARTITION; - return __nvme_ioctl(ns, cmd, (void __user *)arg, mode); + if (is_ctrl_ioctl(cmd)) + return nvme_ctrl_ioctl(ns->ctrl, cmd, argp, mode); + return nvme_ns_ioctl(ns, cmd, argp, flags, mode); } long nvme_ns_chr_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct nvme_ns *ns = container_of(file_inode(file)->i_cdev, struct nvme_ns, cdev); + void __user *argp = (void __user *)arg; - return __nvme_ioctl(ns, cmd, (void __user *)arg, file->f_mode); + if (is_ctrl_ioctl(cmd)) + return nvme_ctrl_ioctl(ns->ctrl, cmd, argp, file->f_mode); + return nvme_ns_ioctl(ns, cmd, argp, 0, file->f_mode); } static int nvme_uring_cmd_checks(unsigned int issue_flags) @@ -786,6 +819,10 @@ int nvme_ns_head_ioctl(struct block_device *bdev, fmode_t mode, void __user *argp = (void __user *)arg; struct nvme_ns *ns; int srcu_idx, ret = -EWOULDBLOCK; + unsigned int flags = 0; + + if (bdev_is_partition(bdev)) + flags |= NVME_IOCTL_PARTITION; srcu_idx = srcu_read_lock(&head->srcu); ns = nvme_find_path(head); @@ -801,7 +838,7 @@ int nvme_ns_head_ioctl(struct block_device *bdev, fmode_t mode, return nvme_ns_head_ctrl_ioctl(ns, cmd, argp, head, srcu_idx, mode); - ret = nvme_ns_ioctl(ns, cmd, argp, mode); + ret = nvme_ns_ioctl(ns, cmd, argp, flags, mode); out_unlock: srcu_read_unlock(&head->srcu, srcu_idx); return ret; @@ -826,7 +863,7 @@ long nvme_ns_head_chr_ioctl(struct file *file, unsigned int cmd, return nvme_ns_head_ctrl_ioctl(ns, cmd, argp, head, srcu_idx, file->f_mode); - ret = nvme_ns_ioctl(ns, cmd, argp, file->f_mode); + ret = nvme_ns_ioctl(ns, cmd, argp, 0, file->f_mode); out_unlock: srcu_read_unlock(&head->srcu, srcu_idx); return ret; @@ -925,7 +962,7 @@ static int nvme_dev_user_cmd(struct nvme_ctrl *ctrl, void __user *argp, kref_get(&ns->kref); up_read(&ctrl->namespaces_rwsem); - ret = nvme_user_cmd(ctrl, ns, argp, mode); + ret = nvme_user_cmd(ctrl, ns, argp, 0, mode); nvme_put_ns(ns); return ret; @@ -942,9 +979,9 @@ long nvme_dev_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case NVME_IOCTL_ADMIN_CMD: - return nvme_user_cmd(ctrl, NULL, argp, file->f_mode); + return nvme_user_cmd(ctrl, NULL, argp, 0, file->f_mode); case NVME_IOCTL_ADMIN64_CMD: - return nvme_user_cmd64(ctrl, NULL, argp, false, file->f_mode); + return nvme_user_cmd64(ctrl, NULL, argp, 0, file->f_mode); case NVME_IOCTL_IO_CMD: return nvme_dev_user_cmd(ctrl, argp, file->f_mode); case NVME_IOCTL_RESET: diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index c03093b6813c..fc39d01e7b63 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -376,6 +376,8 @@ static void nvme_ns_head_submit_bio(struct bio *bio) * pool from the original queue to allocate the bvecs from. */ bio = bio_split_to_limits(bio); + if (!bio) + return; srcu_idx = srcu_read_lock(&head->srcu); ns = nvme_find_path(head); diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 6bbb73ef8b25..bf46f122e9e1 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -893,7 +893,7 @@ static inline void nvme_trace_bio_complete(struct request *req) { struct nvme_ns *ns = req->q->queuedata; - if (req->cmd_flags & REQ_NVME_MPATH) + if ((req->cmd_flags & REQ_NVME_MPATH) && req->bio) trace_block_bio_complete(ns->head->disk->queue, req->bio); } @@ -1070,7 +1070,8 @@ static inline void nvme_auth_free(struct nvme_ctrl *ctrl) {}; u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode); -int nvme_execute_passthru_rq(struct request *rq, u32 *effects); +u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode); +int nvme_execute_rq(struct request *rq, bool at_head); void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects, struct nvme_command *cmd, int status); struct nvme_ctrl *nvme_ctrl_from_file(struct file *file); @@ -1086,6 +1087,7 @@ static inline bool nvme_multi_css(struct nvme_ctrl *ctrl) const unsigned char *nvme_get_error_status_str(u16 status); const unsigned char *nvme_get_opcode_str(u8 opcode); const unsigned char *nvme_get_admin_opcode_str(u8 opcode); +const unsigned char *nvme_get_fabrics_opcode_str(u8 opcode); #else /* CONFIG_NVME_VERBOSE_ERRORS */ static inline const unsigned char *nvme_get_error_status_str(u16 status) { @@ -1099,6 +1101,18 @@ static inline const unsigned char *nvme_get_admin_opcode_str(u8 opcode) { return "Admin Cmd"; } + +static inline const unsigned char *nvme_get_fabrics_opcode_str(u8 opcode) +{ + return "Fabrics Cmd"; +} #endif /* CONFIG_NVME_VERBOSE_ERRORS */ +static inline const unsigned char *nvme_opcode_str(int qid, u8 opcode, u8 fctype) +{ + if (opcode == nvme_fabrics_command) + return nvme_get_fabrics_opcode_str(fctype); + return qid ? nvme_get_opcode_str(opcode) : + nvme_get_admin_opcode_str(opcode); +} #endif /* _NVME_H */ diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index f0f8027644bb..5b95c94ee40f 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -36,14 +36,15 @@ #define SQ_SIZE(q) ((q)->q_depth << (q)->sqes) #define CQ_SIZE(q) ((q)->q_depth * sizeof(struct nvme_completion)) -#define SGES_PER_PAGE (PAGE_SIZE / sizeof(struct nvme_sgl_desc)) +#define SGES_PER_PAGE (NVME_CTRL_PAGE_SIZE / sizeof(struct nvme_sgl_desc)) /* * These can be higher, but we need to ensure that any command doesn't * require an sg allocation that needs more than a page of data. */ -#define NVME_MAX_KB_SZ 4096 -#define NVME_MAX_SEGS 127 +#define NVME_MAX_KB_SZ 8192 +#define NVME_MAX_SEGS 128 +#define NVME_MAX_NR_ALLOCATIONS 5 static int use_threaded_interrupts; module_param(use_threaded_interrupts, int, 0444); @@ -110,6 +111,7 @@ struct nvme_queue; static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown); static void nvme_delete_io_queues(struct nvme_dev *dev); +static void nvme_update_attrs(struct nvme_dev *dev); /* * Represents an NVM Express device. Each nvme_dev is a PCI function. @@ -144,9 +146,9 @@ struct nvme_dev { mempool_t *iod_mempool; /* shadow doorbell buffer support: */ - u32 *dbbuf_dbs; + __le32 *dbbuf_dbs; dma_addr_t dbbuf_dbs_dma_addr; - u32 *dbbuf_eis; + __le32 *dbbuf_eis; dma_addr_t dbbuf_eis_dma_addr; /* host memory buffer support: */ @@ -208,13 +210,18 @@ struct nvme_queue { #define NVMEQ_SQ_CMB 1 #define NVMEQ_DELETE_ERROR 2 #define NVMEQ_POLLED 3 - u32 *dbbuf_sq_db; - u32 *dbbuf_cq_db; - u32 *dbbuf_sq_ei; - u32 *dbbuf_cq_ei; + __le32 *dbbuf_sq_db; + __le32 *dbbuf_cq_db; + __le32 *dbbuf_sq_ei; + __le32 *dbbuf_cq_ei; struct completion delete_done; }; +union nvme_descriptor { + struct nvme_sgl_desc *sg_list; + __le64 *prp_list; +}; + /* * The nvme_iod describes the data in an I/O. * @@ -224,7 +231,6 @@ struct nvme_queue { struct nvme_iod { struct nvme_request req; struct nvme_command cmd; - bool use_sgl; bool aborted; s8 nr_allocations; /* PRP list pool allocations. 0 means small pool in use */ @@ -232,6 +238,7 @@ struct nvme_iod { dma_addr_t first_dma; dma_addr_t meta_dma; struct sg_table sgt; + union nvme_descriptor list[NVME_MAX_NR_ALLOCATIONS]; }; static inline unsigned int nvme_dbbuf_size(struct nvme_dev *dev) @@ -343,11 +350,11 @@ static inline int nvme_dbbuf_need_event(u16 event_idx, u16 new_idx, u16 old) } /* Update dbbuf and return true if an MMIO is required */ -static bool nvme_dbbuf_update_and_check_event(u16 value, u32 *dbbuf_db, - volatile u32 *dbbuf_ei) +static bool nvme_dbbuf_update_and_check_event(u16 value, __le32 *dbbuf_db, + volatile __le32 *dbbuf_ei) { if (dbbuf_db) { - u16 old_value; + u16 old_value, event_idx; /* * Ensure that the queue is written before updating @@ -355,8 +362,8 @@ static bool nvme_dbbuf_update_and_check_event(u16 value, u32 *dbbuf_db, */ wmb(); - old_value = *dbbuf_db; - *dbbuf_db = value; + old_value = le32_to_cpu(*dbbuf_db); + *dbbuf_db = cpu_to_le32(value); /* * Ensure that the doorbell is updated before reading the event @@ -366,7 +373,8 @@ static bool nvme_dbbuf_update_and_check_event(u16 value, u32 *dbbuf_db, */ mb(); - if (!nvme_dbbuf_need_event(*dbbuf_ei, value, old_value)) + event_idx = le32_to_cpu(*dbbuf_ei); + if (!nvme_dbbuf_need_event(event_idx, value, old_value)) return false; } @@ -380,19 +388,9 @@ static bool nvme_dbbuf_update_and_check_event(u16 value, u32 *dbbuf_db, */ static int nvme_pci_npages_prp(void) { - unsigned nprps = DIV_ROUND_UP(NVME_MAX_KB_SZ + NVME_CTRL_PAGE_SIZE, - NVME_CTRL_PAGE_SIZE); - return DIV_ROUND_UP(8 * nprps, PAGE_SIZE - 8); -} - -/* - * Calculates the number of pages needed for the SGL segments. For example a 4k - * page can accommodate 256 SGL descriptors. - */ -static int nvme_pci_npages_sgl(void) -{ - return DIV_ROUND_UP(NVME_MAX_SEGS * sizeof(struct nvme_sgl_desc), - PAGE_SIZE); + unsigned max_bytes = (NVME_MAX_KB_SZ * 1024) + NVME_CTRL_PAGE_SIZE; + unsigned nprps = DIV_ROUND_UP(max_bytes, NVME_CTRL_PAGE_SIZE); + return DIV_ROUND_UP(8 * nprps, NVME_CTRL_PAGE_SIZE - 8); } static int nvme_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, @@ -508,16 +506,10 @@ static void nvme_commit_rqs(struct blk_mq_hw_ctx *hctx) spin_unlock(&nvmeq->sq_lock); } -static void **nvme_pci_iod_list(struct request *req) -{ - struct nvme_iod *iod = blk_mq_rq_to_pdu(req); - return (void **)(iod->sgt.sgl + blk_rq_nr_phys_segments(req)); -} - -static inline bool nvme_pci_use_sgls(struct nvme_dev *dev, struct request *req) +static inline bool nvme_pci_use_sgls(struct nvme_dev *dev, struct request *req, + int nseg) { struct nvme_queue *nvmeq = req->mq_hctx->driver_data; - int nseg = blk_rq_nr_phys_segments(req); unsigned int avg_seg_size; avg_seg_size = DIV_ROUND_UP(blk_rq_payload_bytes(req), nseg); @@ -539,7 +531,7 @@ static void nvme_free_prps(struct nvme_dev *dev, struct request *req) int i; for (i = 0; i < iod->nr_allocations; i++) { - __le64 *prp_list = nvme_pci_iod_list(req)[i]; + __le64 *prp_list = iod->list[i].prp_list; dma_addr_t next_dma_addr = le64_to_cpu(prp_list[last_prp]); dma_pool_free(dev->prp_page_pool, prp_list, dma_addr); @@ -547,22 +539,6 @@ static void nvme_free_prps(struct nvme_dev *dev, struct request *req) } } -static void nvme_free_sgls(struct nvme_dev *dev, struct request *req) -{ - const int last_sg = SGES_PER_PAGE - 1; - struct nvme_iod *iod = blk_mq_rq_to_pdu(req); - dma_addr_t dma_addr = iod->first_dma; - int i; - - for (i = 0; i < iod->nr_allocations; i++) { - struct nvme_sgl_desc *sg_list = nvme_pci_iod_list(req)[i]; - dma_addr_t next_dma_addr = le64_to_cpu((sg_list[last_sg]).addr); - - dma_pool_free(dev->prp_page_pool, sg_list, dma_addr); - dma_addr = next_dma_addr; - } -} - static void nvme_unmap_data(struct nvme_dev *dev, struct request *req) { struct nvme_iod *iod = blk_mq_rq_to_pdu(req); @@ -578,10 +554,11 @@ static void nvme_unmap_data(struct nvme_dev *dev, struct request *req) dma_unmap_sgtable(dev->dev, &iod->sgt, rq_dma_dir(req), 0); if (iod->nr_allocations == 0) - dma_pool_free(dev->prp_small_pool, nvme_pci_iod_list(req)[0], + dma_pool_free(dev->prp_small_pool, iod->list[0].sg_list, + iod->first_dma); + else if (iod->nr_allocations == 1) + dma_pool_free(dev->prp_page_pool, iod->list[0].sg_list, iod->first_dma); - else if (iod->use_sgl) - nvme_free_sgls(dev, req); else nvme_free_prps(dev, req); mempool_free(iod->sgt.sgl, dev->iod_mempool); @@ -612,7 +589,6 @@ static blk_status_t nvme_pci_setup_prps(struct nvme_dev *dev, u64 dma_addr = sg_dma_address(sg); int offset = dma_addr & (NVME_CTRL_PAGE_SIZE - 1); __le64 *prp_list; - void **list = nvme_pci_iod_list(req); dma_addr_t prp_dma; int nprps, i; @@ -650,7 +626,7 @@ static blk_status_t nvme_pci_setup_prps(struct nvme_dev *dev, iod->nr_allocations = -1; return BLK_STS_RESOURCE; } - list[0] = prp_list; + iod->list[0].prp_list = prp_list; iod->first_dma = prp_dma; i = 0; for (;;) { @@ -659,7 +635,7 @@ static blk_status_t nvme_pci_setup_prps(struct nvme_dev *dev, prp_list = dma_pool_alloc(pool, GFP_ATOMIC, &prp_dma); if (!prp_list) goto free_prps; - list[iod->nr_allocations++] = prp_list; + iod->list[iod->nr_allocations++].prp_list = prp_list; prp_list[0] = old_prp_list[i - 1]; old_prp_list[i - 1] = cpu_to_le64(prp_dma); i = 1; @@ -704,13 +680,8 @@ static void nvme_pci_sgl_set_seg(struct nvme_sgl_desc *sge, dma_addr_t dma_addr, int entries) { sge->addr = cpu_to_le64(dma_addr); - if (entries < SGES_PER_PAGE) { - sge->length = cpu_to_le32(entries * sizeof(*sge)); - sge->type = NVME_SGL_FMT_LAST_SEG_DESC << 4; - } else { - sge->length = cpu_to_le32(PAGE_SIZE); - sge->type = NVME_SGL_FMT_SEG_DESC << 4; - } + sge->length = cpu_to_le32(entries * sizeof(*sge)); + sge->type = NVME_SGL_FMT_LAST_SEG_DESC << 4; } static blk_status_t nvme_pci_setup_sgls(struct nvme_dev *dev, @@ -746,34 +717,16 @@ static blk_status_t nvme_pci_setup_sgls(struct nvme_dev *dev, return BLK_STS_RESOURCE; } - nvme_pci_iod_list(req)[0] = sg_list; + iod->list[0].sg_list = sg_list; iod->first_dma = sgl_dma; nvme_pci_sgl_set_seg(&cmd->dptr.sgl, sgl_dma, entries); - do { - if (i == SGES_PER_PAGE) { - struct nvme_sgl_desc *old_sg_desc = sg_list; - struct nvme_sgl_desc *link = &old_sg_desc[i - 1]; - - sg_list = dma_pool_alloc(pool, GFP_ATOMIC, &sgl_dma); - if (!sg_list) - goto free_sgls; - - i = 0; - nvme_pci_iod_list(req)[iod->nr_allocations++] = sg_list; - sg_list[i++] = *link; - nvme_pci_sgl_set_seg(link, sgl_dma, entries); - } - nvme_pci_sgl_set_data(&sg_list[i++], sg); sg = sg_next(sg); } while (--entries > 0); return BLK_STS_OK; -free_sgls: - nvme_free_sgls(dev, req); - return BLK_STS_RESOURCE; } static blk_status_t nvme_setup_prp_simple(struct nvme_dev *dev, @@ -855,8 +808,7 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req, goto out_free_sg; } - iod->use_sgl = nvme_pci_use_sgls(dev, req); - if (iod->use_sgl) + if (nvme_pci_use_sgls(dev, req, iod->sgt.nents)) ret = nvme_pci_setup_sgls(dev, req, &cmnd->rw); else ret = nvme_pci_setup_prps(dev, req, &cmnd->rw); @@ -1361,7 +1313,7 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req) else nvme_poll_irqdisable(nvmeq); - if (blk_mq_request_completed(req)) { + if (blk_mq_rq_state(req) != MQ_RQ_IN_FLIGHT) { dev_warn(dev->ctrl.device, "I/O %d QID %d timeout, completion polled\n", req->tag, nvmeq->qid); @@ -1922,6 +1874,8 @@ static void nvme_map_cmb(struct nvme_dev *dev) if ((dev->cmbsz & (NVME_CMBSZ_WDS | NVME_CMBSZ_RDS)) == (NVME_CMBSZ_WDS | NVME_CMBSZ_RDS)) pci_p2pmem_publish(pdev, true); + + nvme_update_attrs(dev); } static int nvme_set_host_mem(struct nvme_dev *dev, u32 bits) @@ -2208,6 +2162,11 @@ static const struct attribute_group *nvme_pci_dev_attr_groups[] = { NULL, }; +static void nvme_update_attrs(struct nvme_dev *dev) +{ + sysfs_update_group(&dev->ctrl.device->kobj, &nvme_pci_dev_attrs_group); +} + /* * nirqs is the number of interrupts available for write and read * queues. The core already reserved an interrupt for the admin queue. @@ -2332,10 +2291,12 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) if (dev->cmb_use_sqes) { result = nvme_cmb_qdepth(dev, nr_io_queues, sizeof(struct nvme_command)); - if (result > 0) + if (result > 0) { dev->q_depth = result; - else + dev->ctrl.sqsize = result - 1; + } else { dev->cmb_use_sqes = false; + } } do { @@ -2506,18 +2467,12 @@ static int nvme_pci_enable(struct nvme_dev *dev) { int result = -ENOMEM; struct pci_dev *pdev = to_pci_dev(dev->dev); - int dma_address_bits = 64; if (pci_enable_device_mem(pdev)) return result; pci_set_master(pdev); - if (dev->ctrl.quirks & NVME_QUIRK_DMA_ADDRESS_BITS_48) - dma_address_bits = 48; - if (dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(dma_address_bits))) - goto disable; - if (readl(dev->bar + NVME_REG_CSTS) == -1) { result = -ENODEV; goto disable; @@ -2530,13 +2485,12 @@ static int nvme_pci_enable(struct nvme_dev *dev) */ result = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); if (result < 0) - return result; + goto disable; dev->ctrl.cap = lo_hi_readq(dev->bar + NVME_REG_CAP); dev->q_depth = min_t(u32, NVME_CAP_MQES(dev->ctrl.cap) + 1, io_queue_depth); - dev->ctrl.sqsize = dev->q_depth - 1; /* 0's based queue depth */ dev->db_stride = 1 << NVME_CAP_STRIDE(dev->ctrl.cap); dev->dbs = dev->bar + 4096; @@ -2577,15 +2531,20 @@ static int nvme_pci_enable(struct nvme_dev *dev) dev_warn(dev->ctrl.device, "IO queue depth clamped to %d\n", dev->q_depth); } - + dev->ctrl.sqsize = dev->q_depth - 1; /* 0's based queue depth */ nvme_map_cmb(dev); pci_enable_pcie_error_reporting(pdev); pci_save_state(pdev); - return nvme_pci_configure_admin_queue(dev); + result = nvme_pci_configure_admin_queue(dev); + if (result) + goto free_irq; + return result; + free_irq: + pci_free_irq_vectors(pdev); disable: pci_disable_device(pdev); return result; @@ -2697,11 +2656,8 @@ static void nvme_release_prp_pools(struct nvme_dev *dev) static int nvme_pci_alloc_iod_mempool(struct nvme_dev *dev) { - size_t npages = max(nvme_pci_npages_prp(), nvme_pci_npages_sgl()); - size_t alloc_size = sizeof(__le64 *) * npages + - sizeof(struct scatterlist) * NVME_MAX_SEGS; + size_t alloc_size = sizeof(struct scatterlist) * NVME_MAX_SEGS; - WARN_ON_ONCE(alloc_size > PAGE_SIZE); dev->iod_mempool = mempool_create_node(1, mempool_kmalloc, mempool_kfree, (void *)alloc_size, GFP_KERNEL, @@ -2963,7 +2919,7 @@ static struct nvme_dev *nvme_pci_alloc_dev(struct pci_dev *pdev, dev = kzalloc_node(sizeof(*dev), GFP_KERNEL, node); if (!dev) - return NULL; + return ERR_PTR(-ENOMEM); INIT_WORK(&dev->ctrl.reset_work, nvme_reset_work); mutex_init(&dev->shutdown_lock); @@ -2991,7 +2947,11 @@ static struct nvme_dev *nvme_pci_alloc_dev(struct pci_dev *pdev, quirks); if (ret) goto out_put_device; - + + if (dev->ctrl.quirks & NVME_QUIRK_DMA_ADDRESS_BITS_48) + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); + else + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); dma_set_min_align_mask(&pdev->dev, NVME_CTRL_PAGE_SIZE - 1); dma_set_max_seg_size(&pdev->dev, 0xffffffff); @@ -3024,8 +2984,8 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) int result = -ENOMEM; dev = nvme_pci_alloc_dev(pdev, id); - if (!dev) - return -ENOMEM; + if (IS_ERR(dev)) + return PTR_ERR(dev); result = nvme_dev_map(dev); if (result) @@ -3095,6 +3055,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) nvme_start_ctrl(&dev->ctrl); nvme_put_ctrl(&dev->ctrl); + flush_work(&dev->ctrl.scan_work); return 0; out_disable: @@ -3415,6 +3376,8 @@ static const struct pci_device_id nvme_id_table[] = { { PCI_DEVICE(0x10ec, 0x5762), /* ADATA SX6000LNP */ .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN | NVME_QUIRK_BOGUS_NID, }, + { PCI_DEVICE(0x10ec, 0x5763), /* ADATA SX6000PNP */ + .driver_data = NVME_QUIRK_BOGUS_NID, }, { PCI_DEVICE(0x1cc1, 0x8201), /* ADATA SX8200PNP 512GB */ .driver_data = NVME_QUIRK_NO_DEEPEST_PS | NVME_QUIRK_IGNORE_DEV_SUBNQN, }, @@ -3493,7 +3456,8 @@ static const struct pci_device_id nvme_id_table[] = { .driver_data = NVME_QUIRK_SINGLE_VECTOR | NVME_QUIRK_128_BYTES_SQES | NVME_QUIRK_SHARED_TAGS | - NVME_QUIRK_SKIP_CID_GEN }, + NVME_QUIRK_SKIP_CID_GEN | + NVME_QUIRK_IDENTIFY_CNS }, { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) }, { 0, } }; @@ -3521,8 +3485,9 @@ static int __init nvme_init(void) BUILD_BUG_ON(sizeof(struct nvme_create_sq) != 64); BUILD_BUG_ON(sizeof(struct nvme_delete_queue) != 64); BUILD_BUG_ON(IRQ_AFFINITY_MAX_SETS < 2); - BUILD_BUG_ON(DIV_ROUND_UP(nvme_pci_npages_prp(), NVME_CTRL_PAGE_SIZE) > - S8_MAX); + BUILD_BUG_ON(NVME_MAX_SEGS > SGES_PER_PAGE); + BUILD_BUG_ON(sizeof(struct scatterlist) * NVME_MAX_SEGS > PAGE_SIZE); + BUILD_BUG_ON(nvme_pci_npages_prp() > NVME_MAX_NR_ALLOCATIONS); return pci_register_driver(&nvme_driver); } diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 8cedc1ef496c..d6100a787d39 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -2282,10 +2282,13 @@ static enum blk_eh_timer_return nvme_tcp_timeout(struct request *rq) struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq); struct nvme_ctrl *ctrl = &req->queue->ctrl->ctrl; struct nvme_tcp_cmd_pdu *pdu = req->pdu; + u8 opc = pdu->cmd.common.opcode, fctype = pdu->cmd.fabrics.fctype; + int qid = nvme_tcp_queue_id(req->queue); dev_warn(ctrl->device, - "queue %d: timeout request %#x type %d\n", - nvme_tcp_queue_id(req->queue), rq->tag, pdu->hdr.type); + "queue %d: timeout cid %#x type %d opcode %#x (%s)\n", + nvme_tcp_queue_id(req->queue), nvme_cid(rq), pdu->hdr.type, + opc, nvme_opcode_str(qid, opc, fctype)); if (ctrl->state != NVME_CTRL_LIVE) { /* diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index 53a004ea320c..80099df37314 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -164,26 +164,31 @@ out: static void nvmet_get_cmd_effects_nvm(struct nvme_effects_log *log) { - log->acs[nvme_admin_get_log_page] = cpu_to_le32(1 << 0); - log->acs[nvme_admin_identify] = cpu_to_le32(1 << 0); - log->acs[nvme_admin_abort_cmd] = cpu_to_le32(1 << 0); - log->acs[nvme_admin_set_features] = cpu_to_le32(1 << 0); - log->acs[nvme_admin_get_features] = cpu_to_le32(1 << 0); - log->acs[nvme_admin_async_event] = cpu_to_le32(1 << 0); - log->acs[nvme_admin_keep_alive] = cpu_to_le32(1 << 0); - - log->iocs[nvme_cmd_read] = cpu_to_le32(1 << 0); - log->iocs[nvme_cmd_write] = cpu_to_le32(1 << 0); - log->iocs[nvme_cmd_flush] = cpu_to_le32(1 << 0); - log->iocs[nvme_cmd_dsm] = cpu_to_le32(1 << 0); - log->iocs[nvme_cmd_write_zeroes] = cpu_to_le32(1 << 0); + log->acs[nvme_admin_get_log_page] = + log->acs[nvme_admin_identify] = + log->acs[nvme_admin_abort_cmd] = + log->acs[nvme_admin_set_features] = + log->acs[nvme_admin_get_features] = + log->acs[nvme_admin_async_event] = + log->acs[nvme_admin_keep_alive] = + cpu_to_le32(NVME_CMD_EFFECTS_CSUPP); + + log->iocs[nvme_cmd_read] = + log->iocs[nvme_cmd_flush] = + log->iocs[nvme_cmd_dsm] = + cpu_to_le32(NVME_CMD_EFFECTS_CSUPP); + log->iocs[nvme_cmd_write] = + log->iocs[nvme_cmd_write_zeroes] = + cpu_to_le32(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC); } static void nvmet_get_cmd_effects_zns(struct nvme_effects_log *log) { - log->iocs[nvme_cmd_zone_append] = cpu_to_le32(1 << 0); - log->iocs[nvme_cmd_zone_mgmt_send] = cpu_to_le32(1 << 0); - log->iocs[nvme_cmd_zone_mgmt_recv] = cpu_to_le32(1 << 0); + log->iocs[nvme_cmd_zone_append] = + log->iocs[nvme_cmd_zone_mgmt_send] = + cpu_to_le32(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC); + log->iocs[nvme_cmd_zone_mgmt_recv] = + cpu_to_le32(NVME_CMD_EFFECTS_CSUPP); } static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req) @@ -835,7 +840,7 @@ void nvmet_execute_set_features(struct nvmet_req *req) u16 nsqr; u16 ncqr; - if (!nvmet_check_transfer_len(req, 0)) + if (!nvmet_check_data_len_lte(req, 0)) return; switch (cdw10 & 0xff) { diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c index ab2627e17bb9..1ab6601fdd5c 100644 --- a/drivers/nvme/target/fc.c +++ b/drivers/nvme/target/fc.c @@ -1685,8 +1685,10 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, else { queue = nvmet_fc_alloc_target_queue(iod->assoc, 0, be16_to_cpu(rqst->assoc_cmd.sqsize)); - if (!queue) + if (!queue) { ret = VERR_QUEUE_ALLOC_FAIL; + nvmet_fc_tgt_a_put(iod->assoc); + } } } diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c index 871c4f32f443..2d068439b129 100644 --- a/drivers/nvme/target/io-cmd-file.c +++ b/drivers/nvme/target/io-cmd-file.c @@ -73,13 +73,6 @@ err: return ret; } -static void nvmet_file_init_bvec(struct bio_vec *bv, struct scatterlist *sg) -{ - bv->bv_page = sg_page(sg); - bv->bv_offset = sg->offset; - bv->bv_len = sg->length; -} - static ssize_t nvmet_file_submit_bvec(struct nvmet_req *req, loff_t pos, unsigned long nr_segs, size_t count, int ki_flags) { @@ -146,7 +139,8 @@ static bool nvmet_file_execute_io(struct nvmet_req *req, int ki_flags) memset(&req->f.iocb, 0, sizeof(struct kiocb)); for_each_sg(req->sg, sg, req->sg_cnt, i) { - nvmet_file_init_bvec(&req->f.bvec[bv_cnt], sg); + bvec_set_page(&req->f.bvec[bv_cnt], sg_page(sg), sg->length, + sg->offset); len += req->f.bvec[bv_cnt].bv_len; total_len += req->f.bvec[bv_cnt].bv_len; bv_cnt++; diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c index 79af5140af8b..511c980d538d 100644 --- a/drivers/nvme/target/passthru.c +++ b/drivers/nvme/target/passthru.c @@ -216,11 +216,12 @@ static void nvmet_passthru_execute_cmd_work(struct work_struct *w) struct nvmet_req *req = container_of(w, struct nvmet_req, p.work); struct request *rq = req->p.rq; struct nvme_ctrl *ctrl = nvme_req(rq)->ctrl; + struct nvme_ns *ns = rq->q->queuedata; u32 effects; int status; - status = nvme_execute_passthru_rq(rq, &effects); - + effects = nvme_passthru_start(ctrl, ns, req->cmd->common.opcode); + status = nvme_execute_rq(rq, false); if (status == NVME_SC_SUCCESS && req->cmd->common.opcode == nvme_admin_identify) { switch (req->cmd->identify.cns) { @@ -334,14 +335,13 @@ static void nvmet_passthru_execute_cmd(struct nvmet_req *req) } /* - * If there are effects for the command we are about to execute, or - * an end_req function we need to use nvme_execute_passthru_rq() - * synchronously in a work item seeing the end_req function and - * nvme_passthru_end() can't be called in the request done callback - * which is typically in interrupt context. + * If a command needs post-execution fixups, or there are any + * non-trivial effects, make sure to execute the command synchronously + * in a workqueue so that nvme_passthru_end gets called. */ effects = nvme_command_effects(ctrl, ns, req->cmd->common.opcode); - if (req->p.use_workqueue || effects) { + if (req->p.use_workqueue || + (effects & ~(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC))) { INIT_WORK(&req->p.work, nvmet_passthru_execute_cmd_work); req->p.rq = rq; queue_work(nvmet_wq, &req->p.work); diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index cc05c094de22..c5759eb503d0 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -321,9 +321,8 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) while (length) { u32 iov_len = min_t(u32, length, sg->length - sg_offset); - iov->bv_page = sg_page(sg); - iov->bv_len = sg->length; - iov->bv_offset = sg->offset + sg_offset; + bvec_set_page(iov, sg_page(sg), sg->length, + sg->offset + sg_offset); length -= iov_len; sg = sg_next(sg); diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c index 1254cf57e008..7e4292d88016 100644 --- a/drivers/nvme/target/zns.c +++ b/drivers/nvme/target/zns.c @@ -254,8 +254,7 @@ static unsigned long nvmet_req_nr_zones_from_slba(struct nvmet_req *req) { unsigned int sect = nvmet_lba_to_sect(req->ns, req->cmd->zmr.slba); - return bdev_nr_zones(req->ns->bdev) - - (sect >> ilog2(bdev_zone_sectors(req->ns->bdev))); + return bdev_nr_zones(req->ns->bdev) - bdev_zone_no(req->ns->bdev, sect); } static unsigned long get_nr_zones_from_buf(struct nvmet_req *req, u32 bufsize) diff --git a/drivers/nvmem/brcm_nvram.c b/drivers/nvmem/brcm_nvram.c index 34130449f2d2..39aa27942f28 100644 --- a/drivers/nvmem/brcm_nvram.c +++ b/drivers/nvmem/brcm_nvram.c @@ -98,6 +98,9 @@ static int brcm_nvram_parse(struct brcm_nvram *priv) len = le32_to_cpu(header.len); data = kzalloc(len, GFP_KERNEL); + if (!data) + return -ENOMEM; + memcpy_fromio(data, priv->base, len); data[len - 1] = '\0'; diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 321d7d63e068..34ee9d36ee7b 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -770,31 +770,32 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) return ERR_PTR(rval); } - if (config->wp_gpio) - nvmem->wp_gpio = config->wp_gpio; - else if (!config->ignore_wp) + nvmem->id = rval; + + nvmem->dev.type = &nvmem_provider_type; + nvmem->dev.bus = &nvmem_bus_type; + nvmem->dev.parent = config->dev; + + device_initialize(&nvmem->dev); + + if (!config->ignore_wp) nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp", GPIOD_OUT_HIGH); if (IS_ERR(nvmem->wp_gpio)) { - ida_free(&nvmem_ida, nvmem->id); rval = PTR_ERR(nvmem->wp_gpio); - kfree(nvmem); - return ERR_PTR(rval); + nvmem->wp_gpio = NULL; + goto err_put_device; } kref_init(&nvmem->refcnt); INIT_LIST_HEAD(&nvmem->cells); - nvmem->id = rval; nvmem->owner = config->owner; if (!nvmem->owner && config->dev->driver) nvmem->owner = config->dev->driver->owner; nvmem->stride = config->stride ?: 1; nvmem->word_size = config->word_size ?: 1; nvmem->size = config->size; - nvmem->dev.type = &nvmem_provider_type; - nvmem->dev.bus = &nvmem_bus_type; - nvmem->dev.parent = config->dev; nvmem->root_only = config->root_only; nvmem->priv = config->priv; nvmem->type = config->type; @@ -822,11 +823,8 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) break; } - if (rval) { - ida_free(&nvmem_ida, nvmem->id); - kfree(nvmem); - return ERR_PTR(rval); - } + if (rval) + goto err_put_device; nvmem->read_only = device_property_present(config->dev, "read-only") || config->read_only || !nvmem->reg_write; @@ -835,28 +833,22 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) nvmem->dev.groups = nvmem_dev_groups; #endif - dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); - - rval = device_register(&nvmem->dev); - if (rval) - goto err_put_device; - if (nvmem->nkeepout) { rval = nvmem_validate_keepouts(nvmem); if (rval) - goto err_device_del; + goto err_put_device; } if (config->compat) { rval = nvmem_sysfs_setup_compat(nvmem, config); if (rval) - goto err_device_del; + goto err_put_device; } if (config->cells) { rval = nvmem_add_cells(nvmem, config->cells, config->ncells); if (rval) - goto err_teardown_compat; + goto err_remove_cells; } rval = nvmem_add_cells_from_table(nvmem); @@ -867,17 +859,20 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) if (rval) goto err_remove_cells; + dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); + + rval = device_add(&nvmem->dev); + if (rval) + goto err_remove_cells; + blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); return nvmem; err_remove_cells: nvmem_device_remove_all_cells(nvmem); -err_teardown_compat: if (config->compat) nvmem_sysfs_remove_compat(nvmem, config); -err_device_del: - device_del(&nvmem->dev); err_put_device: put_device(&nvmem->dev); @@ -1242,16 +1237,21 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) if (!cell_np) return ERR_PTR(-ENOENT); - nvmem_np = of_get_next_parent(cell_np); - if (!nvmem_np) + nvmem_np = of_get_parent(cell_np); + if (!nvmem_np) { + of_node_put(cell_np); return ERR_PTR(-EINVAL); + } nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); of_node_put(nvmem_np); - if (IS_ERR(nvmem)) + if (IS_ERR(nvmem)) { + of_node_put(cell_np); return ERR_CAST(nvmem); + } cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np); + of_node_put(cell_np); if (!cell_entry) { __nvmem_device_put(nvmem); return ERR_PTR(-ENOENT); diff --git a/drivers/nvmem/qcom-spmi-sdam.c b/drivers/nvmem/qcom-spmi-sdam.c index 4fcb63507ecd..8499892044b7 100644 --- a/drivers/nvmem/qcom-spmi-sdam.c +++ b/drivers/nvmem/qcom-spmi-sdam.c @@ -166,6 +166,7 @@ static const struct of_device_id sdam_match_table[] = { { .compatible = "qcom,spmi-sdam" }, {}, }; +MODULE_DEVICE_TABLE(of, sdam_match_table); static struct platform_driver sdam_driver = { .driver = { diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c index 5750e1f4bcdb..92dfe4cb10e3 100644 --- a/drivers/nvmem/sunxi_sid.c +++ b/drivers/nvmem/sunxi_sid.c @@ -41,8 +41,21 @@ static int sunxi_sid_read(void *context, unsigned int offset, void *val, size_t bytes) { struct sunxi_sid *sid = context; + u32 word; + + /* .stride = 4 so offset is guaranteed to be aligned */ + __ioread32_copy(val, sid->base + sid->value_offset + offset, bytes / 4); - memcpy_fromio(val, sid->base + sid->value_offset + offset, bytes); + val += round_down(bytes, 4); + offset += round_down(bytes, 4); + bytes = bytes % 4; + + if (!bytes) + return 0; + + /* Handle any trailing bytes */ + word = readl_relaxed(sid->base + sid->value_offset + offset); + memcpy(val, &word, bytes); return 0; } diff --git a/drivers/of/address.c b/drivers/of/address.c index c34ac33b7338..67763e5b8c0e 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -965,8 +965,19 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map) } of_dma_range_parser_init(&parser, node); - for_each_of_range(&parser, &range) + for_each_of_range(&parser, &range) { + if (range.cpu_addr == OF_BAD_ADDR) { + pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n", + range.bus_addr, node); + continue; + } num_ranges++; + } + + if (!num_ranges) { + ret = -EINVAL; + goto out; + } r = kcalloc(num_ranges + 1, sizeof(*r), GFP_KERNEL); if (!r) { @@ -975,18 +986,16 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map) } /* - * Record all info in the generic DMA ranges array for struct device. + * Record all info in the generic DMA ranges array for struct device, + * returning an error if we don't find any parsable ranges. */ *map = r; of_dma_range_parser_init(&parser, node); for_each_of_range(&parser, &range) { pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n", range.bus_addr, range.cpu_addr, range.size); - if (range.cpu_addr == OF_BAD_ADDR) { - pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n", - range.bus_addr, node); + if (range.cpu_addr == OF_BAD_ADDR) continue; - } r->cpu_start = range.cpu_addr; r->dma_start = range.bus_addr; r->size = range.size; diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index b2272bccf85c..d1a68b6d03b3 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -26,7 +26,6 @@ #include <linux/serial_core.h> #include <linux/sysfs.h> #include <linux/random.h> -#include <linux/kmemleak.h> #include <asm/setup.h> /* for COMMAND_LINE_SIZE */ #include <asm/page.h> @@ -525,12 +524,9 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, size = dt_mem_next_cell(dt_root_size_cells, &prop); if (size && - early_init_dt_reserve_memory(base, size, nomap) == 0) { + early_init_dt_reserve_memory(base, size, nomap) == 0) pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n", uname, &base, (unsigned long)(size / SZ_1M)); - if (!nomap) - kmemleak_alloc_phys(base, size, 0); - } else pr_err("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n", uname, &base, (unsigned long)(size / SZ_1M)); @@ -1099,7 +1095,7 @@ u64 __init dt_mem_next_cell(int s, const __be32 **cellp) */ int __init early_init_dt_scan_memory(void) { - int node; + int node, found_memory = 0; const void *fdt = initial_boot_params; fdt_for_each_subnode(node, fdt, 0) { @@ -1139,6 +1135,8 @@ int __init early_init_dt_scan_memory(void) early_init_dt_add_memory_arch(base, size); + found_memory = 1; + if (!hotpluggable) continue; @@ -1147,7 +1145,7 @@ int __init early_init_dt_scan_memory(void) base, base + size); } } - return 0; + return found_memory; } int __init early_init_dt_scan_chosen(char *cmdline) @@ -1161,18 +1159,14 @@ int __init early_init_dt_scan_chosen(char *cmdline) if (node < 0) node = fdt_path_offset(fdt, "/chosen@0"); if (node < 0) - return -ENOENT; + /* Handle the cmdline config options even if no /chosen node */ + goto handle_cmdline; chosen_node_offset = node; early_init_dt_check_for_initrd(node); early_init_dt_check_for_elfcorehdr(node); - /* Retrieve command line */ - p = of_get_flat_dt_prop(node, "bootargs", &l); - if (p != NULL && l > 0) - strscpy(cmdline, p, min(l, COMMAND_LINE_SIZE)); - rng_seed = of_get_flat_dt_prop(node, "rng-seed", &l); if (rng_seed && l > 0) { add_bootloader_randomness(rng_seed, l); @@ -1185,6 +1179,32 @@ int __init early_init_dt_scan_chosen(char *cmdline) fdt_totalsize(initial_boot_params)); } + /* Retrieve command line */ + p = of_get_flat_dt_prop(node, "bootargs", &l); + if (p != NULL && l > 0) + strscpy(cmdline, p, min(l, COMMAND_LINE_SIZE)); + +handle_cmdline: + /* + * CONFIG_CMDLINE is meant to be a default in case nothing else + * managed to set the command line, unless CONFIG_CMDLINE_FORCE + * is set in which case we override whatever was found earlier. + */ +#ifdef CONFIG_CMDLINE +#if defined(CONFIG_CMDLINE_EXTEND) + strlcat(cmdline, " ", COMMAND_LINE_SIZE); + strlcat(cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE); +#elif defined(CONFIG_CMDLINE_FORCE) + strscpy(cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE); +#else + /* No arguments from boot loader, use kernel's cmdl*/ + if (!((char *)cmdline)[0]) + strscpy(cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE); +#endif +#endif /* CONFIG_CMDLINE */ + + pr_debug("Command line is: %s\n", (char *)cmdline); + return 0; } @@ -1277,26 +1297,6 @@ void __init early_init_dt_scan_nodes(void) if (rc) pr_warn("No chosen node found, continuing without\n"); - /* - * CONFIG_CMDLINE is meant to be a default in case nothing else - * managed to set the command line, unless CONFIG_CMDLINE_FORCE - * is set in which case we override whatever was found earlier. - */ -#ifdef CONFIG_CMDLINE -#if defined(CONFIG_CMDLINE_EXTEND) - strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); - strlcat(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); -#elif defined(CONFIG_CMDLINE_FORCE) - strscpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); -#else - /* No arguments from boot loader, use kernel's cmdl */ - if (!boot_command_line[0]) - strscpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); -#endif -#endif /* CONFIG_CMDLINE */ - - pr_debug("Command line is: %s\n", boot_command_line); - /* Setup memory, calling early_init_dt_add_memory_arch */ early_init_dt_scan_memory(); diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 65f3b02a0e4e..f90975e00446 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -48,9 +48,10 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size, err = memblock_mark_nomap(base, size); if (err) memblock_phys_free(base, size); - kmemleak_ignore_phys(base); } + kmemleak_ignore_phys(base); + return err; } diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 81c8c227ab6b..b3878a98d27f 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -525,6 +525,7 @@ static int __init of_platform_default_populate_init(void) if (IS_ENABLED(CONFIG_PPC)) { struct device_node *boot_display = NULL; struct platform_device *dev; + int display_number = 0; int ret; /* Check if we have a MacOS display without a node spec */ @@ -555,16 +556,23 @@ static int __init of_platform_default_populate_init(void) if (!of_get_property(node, "linux,opened", NULL) || !of_get_property(node, "linux,boot-display", NULL)) continue; - dev = of_platform_device_create(node, "of-display", NULL); + dev = of_platform_device_create(node, "of-display.0", NULL); + of_node_put(node); if (WARN_ON(!dev)) return -ENOMEM; boot_display = node; + display_number++; break; } for_each_node_by_type(node, "display") { + char buf[14]; + const char *of_display_format = "of-display.%d"; + if (!of_get_property(node, "linux,opened", NULL) || node == boot_display) continue; - of_platform_device_create(node, "of-display", NULL); + ret = snprintf(buf, sizeof(buf), of_display_format, display_number++); + if (ret < sizeof(buf)) + of_platform_device_create(node, buf, NULL); } } else { diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index d6af5726ddf3..2a18f7ba2398 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -274,8 +274,7 @@ pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t coun /* We'll use a local copy of buf */ count = min_t(size_t, count, sizeof(in)-1); - strncpy(in, buf, count); - in[count] = '\0'; + strscpy(in, buf, count + 1); /* Let's clean up the target. 0xff is a blank pattern */ memset(&hwpath, 0xff, sizeof(hwpath)); @@ -388,8 +387,7 @@ pdcspath_layer_write(struct pdcspath_entry *entry, const char *buf, size_t count /* We'll use a local copy of buf */ count = min_t(size_t, count, sizeof(in)-1); - strncpy(in, buf, count); - in[count] = '\0'; + strscpy(in, buf, count + 1); /* Let's clean up the target. 0 is a blank pattern */ memset(&layers, 0, sizeof(layers)); @@ -756,8 +754,7 @@ static ssize_t pdcs_auto_write(struct kobject *kobj, /* We'll use a local copy of buf */ count = min_t(size_t, count, sizeof(in)-1); - strncpy(in, buf, count); - in[count] = '\0'; + strscpy(in, buf, count + 1); /* Current flags are stored in primary boot path entry */ pathentry = &pdcspath_entry_primary; diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index 68a4fe4cd60b..5561362224e2 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -140,17 +140,6 @@ config PARPORT_SUNBPP found on many Sun machines. Note that many of the newer Ultras actually have pc style hardware instead. -config PARPORT_AX88796 - tristate "AX88796 Parallel Port" - select PARPORT_NOT_PC - help - Say Y here if you need support for the parallel port hardware on - the AX88796 network controller chip. This code is also available - as a module (say M), called parport_ax88796. - - The driver is not dependent on the AX88796 network driver, and - should not interfere with the networking functions of the chip. - config PARPORT_1284 bool "IEEE 1284 transfer modes" help diff --git a/drivers/parport/Makefile b/drivers/parport/Makefile index 022c566c0f32..d4a6b890852d 100644 --- a/drivers/parport/Makefile +++ b/drivers/parport/Makefile @@ -18,5 +18,4 @@ obj-$(CONFIG_PARPORT_MFC3) += parport_mfc3.o obj-$(CONFIG_PARPORT_ATARI) += parport_atari.o obj-$(CONFIG_PARPORT_SUNBPP) += parport_sunbpp.o obj-$(CONFIG_PARPORT_GSC) += parport_gsc.o -obj-$(CONFIG_PARPORT_AX88796) += parport_ax88796.o obj-$(CONFIG_PARPORT_IP32) += parport_ip32.o diff --git a/drivers/parport/parport_ax88796.c b/drivers/parport/parport_ax88796.c deleted file mode 100644 index 54b539809673..000000000000 --- a/drivers/parport/parport_ax88796.c +++ /dev/null @@ -1,418 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* linux/drivers/parport/parport_ax88796.c - * - * (c) 2005,2006 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> -*/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/parport.h> -#include <linux/interrupt.h> -#include <linux/errno.h> -#include <linux/platform_device.h> -#include <linux/slab.h> - -#include <asm/io.h> -#include <asm/irq.h> - -#define AX_SPR_BUSY (1<<7) -#define AX_SPR_ACK (1<<6) -#define AX_SPR_PE (1<<5) -#define AX_SPR_SLCT (1<<4) -#define AX_SPR_ERR (1<<3) - -#define AX_CPR_nDOE (1<<5) -#define AX_CPR_SLCTIN (1<<3) -#define AX_CPR_nINIT (1<<2) -#define AX_CPR_ATFD (1<<1) -#define AX_CPR_STRB (1<<0) - -struct ax_drvdata { - struct parport *parport; - struct parport_state suspend; - - struct device *dev; - struct resource *io; - - unsigned char irq_enabled; - - void __iomem *base; - void __iomem *spp_data; - void __iomem *spp_spr; - void __iomem *spp_cpr; -}; - -static inline struct ax_drvdata *pp_to_drv(struct parport *p) -{ - return p->private_data; -} - -static unsigned char -parport_ax88796_read_data(struct parport *p) -{ - struct ax_drvdata *dd = pp_to_drv(p); - - return readb(dd->spp_data); -} - -static void -parport_ax88796_write_data(struct parport *p, unsigned char data) -{ - struct ax_drvdata *dd = pp_to_drv(p); - - writeb(data, dd->spp_data); -} - -static unsigned char -parport_ax88796_read_control(struct parport *p) -{ - struct ax_drvdata *dd = pp_to_drv(p); - unsigned int cpr = readb(dd->spp_cpr); - unsigned int ret = 0; - - if (!(cpr & AX_CPR_STRB)) - ret |= PARPORT_CONTROL_STROBE; - - if (!(cpr & AX_CPR_ATFD)) - ret |= PARPORT_CONTROL_AUTOFD; - - if (cpr & AX_CPR_nINIT) - ret |= PARPORT_CONTROL_INIT; - - if (!(cpr & AX_CPR_SLCTIN)) - ret |= PARPORT_CONTROL_SELECT; - - return ret; -} - -static void -parport_ax88796_write_control(struct parport *p, unsigned char control) -{ - struct ax_drvdata *dd = pp_to_drv(p); - unsigned int cpr = readb(dd->spp_cpr); - - cpr &= AX_CPR_nDOE; - - if (!(control & PARPORT_CONTROL_STROBE)) - cpr |= AX_CPR_STRB; - - if (!(control & PARPORT_CONTROL_AUTOFD)) - cpr |= AX_CPR_ATFD; - - if (control & PARPORT_CONTROL_INIT) - cpr |= AX_CPR_nINIT; - - if (!(control & PARPORT_CONTROL_SELECT)) - cpr |= AX_CPR_SLCTIN; - - dev_dbg(dd->dev, "write_control: ctrl=%02x, cpr=%02x\n", control, cpr); - writeb(cpr, dd->spp_cpr); - - if (parport_ax88796_read_control(p) != control) { - dev_err(dd->dev, "write_control: read != set (%02x, %02x)\n", - parport_ax88796_read_control(p), control); - } -} - -static unsigned char -parport_ax88796_read_status(struct parport *p) -{ - struct ax_drvdata *dd = pp_to_drv(p); - unsigned int status = readb(dd->spp_spr); - unsigned int ret = 0; - - if (status & AX_SPR_BUSY) - ret |= PARPORT_STATUS_BUSY; - - if (status & AX_SPR_ACK) - ret |= PARPORT_STATUS_ACK; - - if (status & AX_SPR_ERR) - ret |= PARPORT_STATUS_ERROR; - - if (status & AX_SPR_SLCT) - ret |= PARPORT_STATUS_SELECT; - - if (status & AX_SPR_PE) - ret |= PARPORT_STATUS_PAPEROUT; - - return ret; -} - -static unsigned char -parport_ax88796_frob_control(struct parport *p, unsigned char mask, - unsigned char val) -{ - struct ax_drvdata *dd = pp_to_drv(p); - unsigned char old = parport_ax88796_read_control(p); - - dev_dbg(dd->dev, "frob: mask=%02x, val=%02x, old=%02x\n", - mask, val, old); - - parport_ax88796_write_control(p, (old & ~mask) | val); - return old; -} - -static void -parport_ax88796_enable_irq(struct parport *p) -{ - struct ax_drvdata *dd = pp_to_drv(p); - unsigned long flags; - - local_irq_save(flags); - if (!dd->irq_enabled) { - enable_irq(p->irq); - dd->irq_enabled = 1; - } - local_irq_restore(flags); -} - -static void -parport_ax88796_disable_irq(struct parport *p) -{ - struct ax_drvdata *dd = pp_to_drv(p); - unsigned long flags; - - local_irq_save(flags); - if (dd->irq_enabled) { - disable_irq(p->irq); - dd->irq_enabled = 0; - } - local_irq_restore(flags); -} - -static void -parport_ax88796_data_forward(struct parport *p) -{ - struct ax_drvdata *dd = pp_to_drv(p); - void __iomem *cpr = dd->spp_cpr; - - writeb((readb(cpr) & ~AX_CPR_nDOE), cpr); -} - -static void -parport_ax88796_data_reverse(struct parport *p) -{ - struct ax_drvdata *dd = pp_to_drv(p); - void __iomem *cpr = dd->spp_cpr; - - writeb(readb(cpr) | AX_CPR_nDOE, cpr); -} - -static void -parport_ax88796_init_state(struct pardevice *d, struct parport_state *s) -{ - struct ax_drvdata *dd = pp_to_drv(d->port); - - memset(s, 0, sizeof(struct parport_state)); - - dev_dbg(dd->dev, "init_state: %p: state=%p\n", d, s); - s->u.ax88796.cpr = readb(dd->spp_cpr); -} - -static void -parport_ax88796_save_state(struct parport *p, struct parport_state *s) -{ - struct ax_drvdata *dd = pp_to_drv(p); - - dev_dbg(dd->dev, "save_state: %p: state=%p\n", p, s); - s->u.ax88796.cpr = readb(dd->spp_cpr); -} - -static void -parport_ax88796_restore_state(struct parport *p, struct parport_state *s) -{ - struct ax_drvdata *dd = pp_to_drv(p); - - dev_dbg(dd->dev, "restore_state: %p: state=%p\n", p, s); - writeb(s->u.ax88796.cpr, dd->spp_cpr); -} - -static struct parport_operations parport_ax88796_ops = { - .write_data = parport_ax88796_write_data, - .read_data = parport_ax88796_read_data, - - .write_control = parport_ax88796_write_control, - .read_control = parport_ax88796_read_control, - .frob_control = parport_ax88796_frob_control, - - .read_status = parport_ax88796_read_status, - - .enable_irq = parport_ax88796_enable_irq, - .disable_irq = parport_ax88796_disable_irq, - - .data_forward = parport_ax88796_data_forward, - .data_reverse = parport_ax88796_data_reverse, - - .init_state = parport_ax88796_init_state, - .save_state = parport_ax88796_save_state, - .restore_state = parport_ax88796_restore_state, - - .epp_write_data = parport_ieee1284_epp_write_data, - .epp_read_data = parport_ieee1284_epp_read_data, - .epp_write_addr = parport_ieee1284_epp_write_addr, - .epp_read_addr = parport_ieee1284_epp_read_addr, - - .ecp_write_data = parport_ieee1284_ecp_write_data, - .ecp_read_data = parport_ieee1284_ecp_read_data, - .ecp_write_addr = parport_ieee1284_ecp_write_addr, - - .compat_write_data = parport_ieee1284_write_compat, - .nibble_read_data = parport_ieee1284_read_nibble, - .byte_read_data = parport_ieee1284_read_byte, - - .owner = THIS_MODULE, -}; - -static int parport_ax88796_probe(struct platform_device *pdev) -{ - struct device *_dev = &pdev->dev; - struct ax_drvdata *dd; - struct parport *pp; - struct resource *res; - unsigned long size; - int spacing; - int irq; - int ret; - - dd = kzalloc(sizeof(*dd), GFP_KERNEL); - if (!dd) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(_dev, "no MEM specified\n"); - ret = -ENXIO; - goto exit_mem; - } - - size = resource_size(res); - spacing = size / 3; - - dd->io = request_mem_region(res->start, size, pdev->name); - if (dd->io == NULL) { - dev_err(_dev, "cannot reserve memory\n"); - ret = -ENXIO; - goto exit_mem; - } - - dd->base = ioremap(res->start, size); - if (dd->base == NULL) { - dev_err(_dev, "cannot ioremap region\n"); - ret = -ENXIO; - goto exit_res; - } - - irq = platform_get_irq(pdev, 0); - if (irq <= 0) - irq = PARPORT_IRQ_NONE; - - pp = parport_register_port((unsigned long)dd->base, irq, - PARPORT_DMA_NONE, - &parport_ax88796_ops); - - if (pp == NULL) { - dev_err(_dev, "failed to register parallel port\n"); - ret = -ENOMEM; - goto exit_unmap; - } - - pp->private_data = dd; - dd->parport = pp; - dd->dev = _dev; - - dd->spp_data = dd->base; - dd->spp_spr = dd->base + (spacing * 1); - dd->spp_cpr = dd->base + (spacing * 2); - - /* initialise the port controls */ - writeb(AX_CPR_STRB, dd->spp_cpr); - - if (irq >= 0) { - /* request irq */ - ret = request_irq(irq, parport_irq_handler, - IRQF_TRIGGER_FALLING, pdev->name, pp); - - if (ret < 0) - goto exit_port; - - dd->irq_enabled = 1; - } - - platform_set_drvdata(pdev, pp); - - dev_info(_dev, "attached parallel port driver\n"); - parport_announce_port(pp); - - return 0; - - exit_port: - parport_remove_port(pp); - exit_unmap: - iounmap(dd->base); - exit_res: - release_mem_region(dd->io->start, size); - exit_mem: - kfree(dd); - return ret; -} - -static int parport_ax88796_remove(struct platform_device *pdev) -{ - struct parport *p = platform_get_drvdata(pdev); - struct ax_drvdata *dd = pp_to_drv(p); - - free_irq(p->irq, p); - parport_remove_port(p); - iounmap(dd->base); - release_mem_region(dd->io->start, resource_size(dd->io)); - kfree(dd); - - return 0; -} - -#ifdef CONFIG_PM - -static int parport_ax88796_suspend(struct platform_device *dev, - pm_message_t state) -{ - struct parport *p = platform_get_drvdata(dev); - struct ax_drvdata *dd = pp_to_drv(p); - - parport_ax88796_save_state(p, &dd->suspend); - writeb(AX_CPR_nDOE | AX_CPR_STRB, dd->spp_cpr); - return 0; -} - -static int parport_ax88796_resume(struct platform_device *dev) -{ - struct parport *p = platform_get_drvdata(dev); - struct ax_drvdata *dd = pp_to_drv(p); - - parport_ax88796_restore_state(p, &dd->suspend); - return 0; -} - -#else -#define parport_ax88796_suspend NULL -#define parport_ax88796_resume NULL -#endif - -MODULE_ALIAS("platform:ax88796-pp"); - -static struct platform_driver axdrv = { - .driver = { - .name = "ax88796-pp", - }, - .probe = parport_ax88796_probe, - .remove = parport_ax88796_remove, - .suspend = parport_ax88796_suspend, - .resume = parport_ax88796_resume, -}; - -module_platform_driver(axdrv); - -MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); -MODULE_DESCRIPTION("AX88796 Parport parallel port driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index a0d2713f0e88..99ec91e2a5cf 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -225,7 +225,7 @@ config PCIE_ARTPEC6_EP config PCIE_BT1 tristate "Baikal-T1 PCIe controller" depends on MIPS_BAIKAL_T1 || COMPILE_TEST - depends on PCI_MSI_IRQ_DOMAIN + depends on PCI_MSI select PCIE_DW_HOST help Enables support for the PCIe controller in the Baikal-T1 SoC to work diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index fba95486caaf..5641786bd020 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1665,7 +1665,6 @@ int pci_save_state(struct pci_dev *dev) return i; pci_save_ltr_state(dev); - pci_save_aspm_l1ss_state(dev); pci_save_dpc_state(dev); pci_save_aer_state(dev); pci_save_ptm_state(dev); @@ -1772,7 +1771,6 @@ void pci_restore_state(struct pci_dev *dev) * LTR itself (in the PCIe capability). */ pci_restore_ltr_state(dev); - pci_restore_aspm_l1ss_state(dev); pci_restore_pcie_state(dev); pci_restore_pasid_state(dev); @@ -3465,11 +3463,6 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev) if (error) pci_err(dev, "unable to allocate suspend buffer for LTR\n"); - error = pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_L1SS, - 2 * sizeof(u32)); - if (error) - pci_err(dev, "unable to allocate suspend buffer for ASPM-L1SS\n"); - pci_allocate_vc_save_buffers(dev); } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 9ed3b5550043..9049d07d3aae 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -566,14 +566,10 @@ bool pcie_wait_for_link(struct pci_dev *pdev, bool active); void pcie_aspm_init_link_state(struct pci_dev *pdev); void pcie_aspm_exit_link_state(struct pci_dev *pdev); void pcie_aspm_powersave_config_link(struct pci_dev *pdev); -void pci_save_aspm_l1ss_state(struct pci_dev *dev); -void pci_restore_aspm_l1ss_state(struct pci_dev *dev); #else static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { } static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { } static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { } -static inline void pci_save_aspm_l1ss_state(struct pci_dev *dev) { } -static inline void pci_restore_aspm_l1ss_state(struct pci_dev *dev) { } #endif #ifdef CONFIG_PCIE_ECRC diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 53a1fa306e1e..4b4184563a92 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -470,31 +470,6 @@ static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos, pci_write_config_dword(pdev, pos, val); } -static void aspm_program_l1ss(struct pci_dev *dev, u32 ctl1, u32 ctl2) -{ - u16 l1ss = dev->l1ss; - u32 l1_2_enable; - - /* - * Per PCIe r6.0, sec 5.5.4, T_POWER_ON in PCI_L1SS_CTL2 must be - * programmed prior to setting the L1.2 enable bits in PCI_L1SS_CTL1. - */ - pci_write_config_dword(dev, l1ss + PCI_L1SS_CTL2, ctl2); - - /* - * In addition, Common_Mode_Restore_Time and LTR_L1.2_THRESHOLD in - * PCI_L1SS_CTL1 must be programmed *before* setting the L1.2 - * enable bits, even though they're all in PCI_L1SS_CTL1. - */ - l1_2_enable = ctl1 & PCI_L1SS_CTL1_L1_2_MASK; - ctl1 &= ~PCI_L1SS_CTL1_L1_2_MASK; - - pci_write_config_dword(dev, l1ss + PCI_L1SS_CTL1, ctl1); - if (l1_2_enable) - pci_write_config_dword(dev, l1ss + PCI_L1SS_CTL1, - ctl1 | l1_2_enable); -} - /* Calculate L1.2 PM substate timing parameters */ static void aspm_calc_l1ss_info(struct pcie_link_state *link, u32 parent_l1ss_cap, u32 child_l1ss_cap) @@ -504,6 +479,7 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link, u32 t_common_mode, t_power_on, l1_2_threshold, scale, value; u32 ctl1 = 0, ctl2 = 0; u32 pctl1, pctl2, cctl1, cctl2; + u32 pl1_2_enables, cl1_2_enables; if (!(link->aspm_support & ASPM_STATE_L1_2_MASK)) return; @@ -552,21 +528,39 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link, ctl2 == pctl2 && ctl2 == cctl2) return; - pctl1 &= ~(PCI_L1SS_CTL1_CM_RESTORE_TIME | - PCI_L1SS_CTL1_LTR_L12_TH_VALUE | - PCI_L1SS_CTL1_LTR_L12_TH_SCALE); - pctl1 |= (ctl1 & (PCI_L1SS_CTL1_CM_RESTORE_TIME | - PCI_L1SS_CTL1_LTR_L12_TH_VALUE | - PCI_L1SS_CTL1_LTR_L12_TH_SCALE)); - aspm_program_l1ss(parent, pctl1, ctl2); - - cctl1 &= ~(PCI_L1SS_CTL1_CM_RESTORE_TIME | - PCI_L1SS_CTL1_LTR_L12_TH_VALUE | - PCI_L1SS_CTL1_LTR_L12_TH_SCALE); - cctl1 |= (ctl1 & (PCI_L1SS_CTL1_CM_RESTORE_TIME | - PCI_L1SS_CTL1_LTR_L12_TH_VALUE | - PCI_L1SS_CTL1_LTR_L12_TH_SCALE)); - aspm_program_l1ss(child, cctl1, ctl2); + /* Disable L1.2 while updating. See PCIe r5.0, sec 5.5.4, 7.8.3.3 */ + pl1_2_enables = pctl1 & PCI_L1SS_CTL1_L1_2_MASK; + cl1_2_enables = cctl1 & PCI_L1SS_CTL1_L1_2_MASK; + + if (pl1_2_enables || cl1_2_enables) { + pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, + PCI_L1SS_CTL1_L1_2_MASK, 0); + pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, + PCI_L1SS_CTL1_L1_2_MASK, 0); + } + + /* Program T_POWER_ON times in both ports */ + pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, ctl2); + pci_write_config_dword(child, child->l1ss + PCI_L1SS_CTL2, ctl2); + + /* Program Common_Mode_Restore_Time in upstream device */ + pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, + PCI_L1SS_CTL1_CM_RESTORE_TIME, ctl1); + + /* Program LTR_L1.2_THRESHOLD time in both ports */ + pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, + PCI_L1SS_CTL1_LTR_L12_TH_VALUE | + PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1); + pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, + PCI_L1SS_CTL1_LTR_L12_TH_VALUE | + PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1); + + if (pl1_2_enables || cl1_2_enables) { + pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 0, + pl1_2_enables); + pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 0, + cl1_2_enables); + } } static void aspm_l1ss_init(struct pcie_link_state *link) @@ -757,43 +751,6 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state) PCI_L1SS_CTL1_L1SS_MASK, val); } -void pci_save_aspm_l1ss_state(struct pci_dev *dev) -{ - struct pci_cap_saved_state *save_state; - u16 l1ss = dev->l1ss; - u32 *cap; - - if (!l1ss) - return; - - save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS); - if (!save_state) - return; - - cap = (u32 *)&save_state->cap.data[0]; - pci_read_config_dword(dev, l1ss + PCI_L1SS_CTL2, cap++); - pci_read_config_dword(dev, l1ss + PCI_L1SS_CTL1, cap++); -} - -void pci_restore_aspm_l1ss_state(struct pci_dev *dev) -{ - struct pci_cap_saved_state *save_state; - u32 *cap, ctl1, ctl2; - u16 l1ss = dev->l1ss; - - if (!l1ss) - return; - - save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS); - if (!save_state) - return; - - cap = (u32 *)&save_state->cap.data[0]; - ctl2 = *cap++; - ctl1 = *cap; - aspm_program_l1ss(dev, ctl1, ctl2); -} - static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val) { pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL, diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 7378e2f3e525..fcd029ca2eb1 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -1055,14 +1055,12 @@ out: return err; } -static int pcifront_xenbus_remove(struct xenbus_device *xdev) +static void pcifront_xenbus_remove(struct xenbus_device *xdev) { struct pcifront_device *pdev = dev_get_drvdata(&xdev->dev); if (pdev) free_pdev(pdev); - - return 0; } static const struct xenbus_device_id xenpci_ids[] = { diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 1525023e49b6..44c16508ef14 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -194,10 +194,8 @@ config PCMCIA_SA1111 tristate "SA1111 support" depends on ARM && SA1111 && PCMCIA select PCMCIA_SOC_COMMON - select PCMCIA_SA11XX_BASE if ARCH_SA1100 - select PCMCIA_PXA2XX if ARCH_LUBBOCK && SA1111 + select PCMCIA_SA11XX_BASE select PCMCIA_MAX1600 if ASSABET_NEPONSET - select PCMCIA_MAX1600 if ARCH_LUBBOCK && SA1111 help Say Y here to include support for SA1111-based PCMCIA or CF sockets, found on the Jornada 720, Graphicsmaster and other @@ -207,14 +205,8 @@ config PCMCIA_SA1111 config PCMCIA_PXA2XX tristate "PXA2xx support" - depends on ARM && ARCH_PXA && PCMCIA - depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \ - || ARCH_PXA_PALM || TRIZEPS_PCMCIA \ - || ARCOM_PCMCIA || ARCH_PXA_ESERIES \ - || MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \ - || MACH_COLIBRI320 || MACH_H4700) + depends on ARM && ARCH_PXA && PCMCIA && PXA_SHARPSL select PCMCIA_SOC_COMMON - select PCMCIA_MAX1600 if MACH_MAINSTONE help Say Y here to include support for the PXA2xx PCMCIA controller diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index b3a2accf47af..c9d51b150682 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -36,17 +36,12 @@ obj-$(CONFIG_PCMCIA_MAX1600) += max1600.o sa1111_cs-y += sa1111_generic.o sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1111_neponset.o -sa1111_cs-$(CONFIG_SA1100_BADGE4) += sa1111_badge4.o sa1111_cs-$(CONFIG_SA1100_JORNADA720) += sa1111_jornada720.o -sa1111_cs-$(CONFIG_ARCH_LUBBOCK) += sa1111_lubbock.o sa1100_cs-y += sa1100_generic.o sa1100_cs-$(CONFIG_SA1100_COLLIE) += pxa2xx_sharpsl.o -sa1100_cs-$(CONFIG_SA1100_H3100) += sa1100_h3600.o sa1100_cs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o -sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o -pxa2xx-obj-$(CONFIG_MACH_MAINSTONE) += pxa2xx_mainstone.o pxa2xx-obj-$(CONFIG_PXA_SHARPSL) += pxa2xx_sharpsl.o obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y) obj-$(CONFIG_PCMCIA_XXS1500) += xxs1500_ss.o diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 0ea41f1411e5..5254028354f4 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -206,13 +206,7 @@ pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, void pxa2xx_configure_sockets(struct device *dev, struct pcmcia_low_level *ops) { - int nr = 1; - - if ((ops->first + ops->nr) > 1 || - machine_is_viper() || machine_is_arcom_zeus()) - nr = 2; - - pxa_smemc_set_pcmcia_socket(nr); + pxa_smemc_set_pcmcia_socket(1); } EXPORT_SYMBOL(pxa2xx_configure_sockets); diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c deleted file mode 100644 index a076e4108452..000000000000 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/drivers/pcmcia/pxa2xx_mainstone.c - * - * Mainstone PCMCIA specific routines. - * - * Created: May 12, 2004 - * Author: Nicolas Pitre - * Copyright: MontaVista Software Inc. - */ -#include <linux/gpio/consumer.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/platform_device.h> - -#include <pcmcia/ss.h> - -#include <asm/mach-types.h> - -#include "soc_common.h" -#include "max1600.h" - -static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt) -{ - struct device *dev = skt->socket.dev.parent; - struct max1600 *m; - int ret; - - skt->stat[SOC_STAT_CD].name = skt->nr ? "bdetect" : "adetect"; - skt->stat[SOC_STAT_BVD1].name = skt->nr ? "bbvd1" : "abvd1"; - skt->stat[SOC_STAT_BVD2].name = skt->nr ? "bbvd2" : "abvd2"; - skt->stat[SOC_STAT_RDY].name = skt->nr ? "bready" : "aready"; - skt->stat[SOC_STAT_VS1].name = skt->nr ? "bvs1" : "avs1"; - skt->stat[SOC_STAT_VS2].name = skt->nr ? "bvs2" : "avs2"; - - skt->gpio_reset = devm_gpiod_get(dev, skt->nr ? "breset" : "areset", - GPIOD_OUT_HIGH); - if (IS_ERR(skt->gpio_reset)) - return PTR_ERR(skt->gpio_reset); - - ret = max1600_init(dev, &m, skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A, - MAX1600_CODE_HIGH); - if (ret) - return ret; - - skt->driver_data = m; - - return soc_pcmcia_request_gpiods(skt); -} - -static unsigned int mst_pcmcia_bvd1_status[2]; - -static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt, - struct pcmcia_state *state) -{ - unsigned int flip = mst_pcmcia_bvd1_status[skt->nr] ^ state->bvd1; - - /* - * Workaround for STSCHG which can't be deasserted: - * We therefore disable/enable corresponding IRQs - * as needed to avoid IRQ locks. - */ - if (flip) { - mst_pcmcia_bvd1_status[skt->nr] = state->bvd1; - if (state->bvd1) - enable_irq(skt->stat[SOC_STAT_BVD1].irq); - else - disable_irq(skt->stat[SOC_STAT_BVD2].irq); - } -} - -static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, - const socket_state_t *state) -{ - return max1600_configure(skt->driver_data, state->Vcc, state->Vpp); -} - -static struct pcmcia_low_level mst_pcmcia_ops __initdata = { - .owner = THIS_MODULE, - .hw_init = mst_pcmcia_hw_init, - .socket_state = mst_pcmcia_socket_state, - .configure_socket = mst_pcmcia_configure_socket, - .nr = 2, -}; - -static struct platform_device *mst_pcmcia_device; - -static int __init mst_pcmcia_init(void) -{ - int ret; - - if (!machine_is_mainstone()) - return -ENODEV; - - mst_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); - if (!mst_pcmcia_device) - return -ENOMEM; - - ret = platform_device_add_data(mst_pcmcia_device, &mst_pcmcia_ops, - sizeof(mst_pcmcia_ops)); - if (ret == 0) - ret = platform_device_add(mst_pcmcia_device); - - if (ret) - platform_device_put(mst_pcmcia_device); - - return ret; -} - -static void __exit mst_pcmcia_exit(void) -{ - platform_device_unregister(mst_pcmcia_device); -} - -fs_initcall(mst_pcmcia_init); -module_exit(mst_pcmcia_exit); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pxa2xx-pcmcia"); diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index c2b6e828c2c6..89d4ba58c891 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -98,12 +98,9 @@ static struct pcmcia_low_level sa11x0_cf_ops = { int __init pcmcia_collie_init(struct device *dev); static int (*sa11x0_pcmcia_legacy_hw_init[])(struct device *dev) = { -#if defined(CONFIG_SA1100_H3100) || defined(CONFIG_SA1100_H3600) +#ifdef CONFIG_SA1100_H3600 pcmcia_h3600_init, #endif -#ifdef CONFIG_SA1100_SIMPAD - pcmcia_simpad_init, -#endif #ifdef CONFIG_SA1100_COLLIE pcmcia_collie_init, #endif diff --git a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c index a91222bc3824..10cb99c20a7f 100644 --- a/drivers/pcmcia/sa1100_h3600.c +++ b/drivers/pcmcia/sa1100_h3600.c @@ -156,7 +156,7 @@ int pcmcia_h3600_init(struct device *dev) { int ret = -ENODEV; - if (machine_is_h3600() || machine_is_h3100()) + if (machine_is_h3600()) ret = sa11xx_drv_pcmcia_probe(dev, &h3600_pcmcia_ops, 0, 2); return ret; diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c deleted file mode 100644 index 784ada5b8c4f..000000000000 --- a/drivers/pcmcia/sa1100_simpad.c +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * drivers/pcmcia/sa1100_simpad.c - * - * PCMCIA implementation routines for simpad - * - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/init.h> - -#include <mach/hardware.h> -#include <asm/mach-types.h> -#include <mach/simpad.h> -#include "sa1100_generic.h" - -static int simpad_pcmcia_hw_init(struct soc_pcmcia_socket *skt) -{ - - simpad_clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); - - skt->stat[SOC_STAT_CD].name = "cf-detect"; - skt->stat[SOC_STAT_RDY].name = "cf-ready"; - - return soc_pcmcia_request_gpiods(skt); -} - -static void simpad_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) -{ - /* Disable CF bus: */ - /*simpad_set_cs3_bit(PCMCIA_BUFF_DIS);*/ - simpad_clear_cs3_bit(PCMCIA_RESET); -} - -static void -simpad_pcmcia_socket_state(struct soc_pcmcia_socket *skt, - struct pcmcia_state *state) -{ - long cs3reg = simpad_get_cs3_ro(); - - /* bvd1 might be cs3reg & PCMCIA_BVD1 */ - /* bvd2 might be cs3reg & PCMCIA_BVD2 */ - - if ((cs3reg & (PCMCIA_VS1|PCMCIA_VS2)) == - (PCMCIA_VS1|PCMCIA_VS2)) { - state->vs_3v=0; - state->vs_Xv=0; - } else { - state->vs_3v=1; - state->vs_Xv=0; - } -} - -static int -simpad_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, - const socket_state_t *state) -{ - unsigned long flags; - - local_irq_save(flags); - - /* Murphy: see table of MIC2562a-1 */ - switch (state->Vcc) { - case 0: - simpad_clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); - break; - - case 33: - simpad_clear_cs3_bit(VCC_3V_EN|EN1); - simpad_set_cs3_bit(VCC_5V_EN|EN0); - break; - - case 50: - simpad_clear_cs3_bit(VCC_5V_EN|EN1); - simpad_set_cs3_bit(VCC_3V_EN|EN0); - break; - - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", - __func__, state->Vcc); - simpad_clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); - local_irq_restore(flags); - return -1; - } - - - local_irq_restore(flags); - - return 0; -} - -static void simpad_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) -{ - simpad_set_cs3_bit(PCMCIA_RESET); -} - -static struct pcmcia_low_level simpad_pcmcia_ops = { - .owner = THIS_MODULE, - .hw_init = simpad_pcmcia_hw_init, - .hw_shutdown = simpad_pcmcia_hw_shutdown, - .socket_state = simpad_pcmcia_socket_state, - .configure_socket = simpad_pcmcia_configure_socket, - .socket_suspend = simpad_pcmcia_socket_suspend, -}; - -int pcmcia_simpad_init(struct device *dev) -{ - int ret = -ENODEV; - - if (machine_is_simpad()) - ret = sa11xx_drv_pcmcia_probe(dev, &simpad_pcmcia_ops, 1, 1); - - return ret; -} diff --git a/drivers/pcmcia/sa1111_badge4.c b/drivers/pcmcia/sa1111_badge4.c deleted file mode 100644 index e76d5ba921dd..000000000000 --- a/drivers/pcmcia/sa1111_badge4.c +++ /dev/null @@ -1,158 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/drivers/pcmcia/sa1100_badge4.c - * - * BadgePAD 4 PCMCIA specific routines - * - * Christopher Hoover <ch@hpl.hp.com> - * - * Copyright (C) 2002 Hewlett-Packard Company - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/init.h> - -#include <mach/hardware.h> -#include <asm/mach-types.h> -#include <mach/badge4.h> -#include <asm/hardware/sa1111.h> - -#include "sa1111_generic.h" - -/* - * BadgePAD 4 Details - * - * PCM Vcc: - * - * PCM Vcc on BadgePAD 4 can be jumpered for 3v3 (short pins 1 and 3 - * on JP6) or 5v0 (short pins 3 and 5 on JP6). - * - * PCM Vpp: - * - * PCM Vpp on BadgePAD 4 can be jumpered for 12v0 (short pins 4 and 6 - * on JP6) or tied to PCM Vcc (short pins 2 and 4 on JP6). N.B., - * 12v0 operation requires that the power supply actually supply 12v0 - * via pin 7 of JP7. - * - * CF Vcc: - * - * CF Vcc on BadgePAD 4 can be jumpered either for 3v3 (short pins 1 - * and 2 on JP10) or 5v0 (short pins 2 and 3 on JP10). - * - * Unfortunately there's no way programmatically to determine how a - * given board is jumpered. This code assumes a default jumpering - * as described below. - * - * If the defaults aren't correct, you may override them with a pcmv - * setup argument: pcmv=<pcm vcc>,<pcm vpp>,<cf vcc>. The units are - * tenths of volts; e.g. pcmv=33,120,50 indicates 3v3 PCM Vcc, 12v0 - * PCM Vpp, and 5v0 CF Vcc. - * - */ - -static int badge4_pcmvcc = 50; /* pins 3 and 5 jumpered on JP6 */ -static int badge4_pcmvpp = 50; /* pins 2 and 4 jumpered on JP6 */ -static int badge4_cfvcc = 33; /* pins 1 and 2 jumpered on JP10 */ - -static void complain_about_jumpering(const char *whom, - const char *supply, - int given, int wanted) -{ - printk(KERN_ERR - "%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation" - "; re-jumper the board and/or use pcmv=xx,xx,xx\n", - whom, supply, - wanted / 10, wanted % 10, - supply, - given / 10, given % 10); -} - -static int -badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) -{ - int ret; - - switch (skt->nr) { - case 0: - if ((state->Vcc != 0) && - (state->Vcc != badge4_pcmvcc)) { - complain_about_jumpering(__func__, "pcmvcc", - badge4_pcmvcc, state->Vcc); - // Apply power regardless of the jumpering. - // return -1; - } - if ((state->Vpp != 0) && - (state->Vpp != badge4_pcmvpp)) { - complain_about_jumpering(__func__, "pcmvpp", - badge4_pcmvpp, state->Vpp); - return -1; - } - break; - - case 1: - if ((state->Vcc != 0) && - (state->Vcc != badge4_cfvcc)) { - complain_about_jumpering(__func__, "cfvcc", - badge4_cfvcc, state->Vcc); - return -1; - } - break; - - default: - return -1; - } - - ret = sa1111_pcmcia_configure_socket(skt, state); - if (ret == 0) { - unsigned long flags; - int need5V; - - local_irq_save(flags); - - need5V = ((state->Vcc == 50) || (state->Vpp == 50)); - - badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(skt->nr), need5V); - - local_irq_restore(flags); - } - - return ret; -} - -static struct pcmcia_low_level badge4_pcmcia_ops = { - .owner = THIS_MODULE, - .configure_socket = badge4_pcmcia_configure_socket, - .first = 0, - .nr = 2, -}; - -int pcmcia_badge4_init(struct sa1111_dev *dev) -{ - printk(KERN_INFO - "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n", - __func__, - badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc); - - sa11xx_drv_pcmcia_ops(&badge4_pcmcia_ops); - return sa1111_pcmcia_add(dev, &badge4_pcmcia_ops, - sa11xx_drv_pcmcia_add_one); -} - -#ifndef MODULE -static int __init pcmv_setup(char *s) -{ - int v[4]; - - s = get_options(s, ARRAY_SIZE(v), v); - - if (v[0] >= 1) badge4_pcmvcc = v[1]; - if (v[0] >= 2) badge4_pcmvpp = v[2]; - if (v[0] >= 3) badge4_cfvcc = v[3]; - - return 1; -} - -__setup("pcmv=", pcmv_setup); -#endif diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index bce664bbdc98..2a67e33fb5f0 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -212,18 +212,10 @@ static int pcmcia_probe(struct sa1111_dev *dev) writel_relaxed(PCCR_S0_FLT | PCCR_S1_FLT, base + PCCR); ret = -ENODEV; -#ifdef CONFIG_SA1100_BADGE4 - if (machine_is_badge4()) - ret = pcmcia_badge4_init(dev); -#endif #ifdef CONFIG_SA1100_JORNADA720 if (machine_is_jornada720()) ret = pcmcia_jornada720_init(dev); #endif -#ifdef CONFIG_ARCH_LUBBOCK - if (machine_is_lubbock()) - ret = pcmcia_lubbock_init(dev); -#endif #ifdef CONFIG_ASSABET_NEPONSET if (machine_is_assabet()) ret = pcmcia_neponset_init(dev); diff --git a/drivers/pcmcia/sa1111_lubbock.c b/drivers/pcmcia/sa1111_lubbock.c deleted file mode 100644 index f1b5160cb8fa..000000000000 --- a/drivers/pcmcia/sa1111_lubbock.c +++ /dev/null @@ -1,155 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/drivers/pcmcia/pxa2xx_lubbock.c - * - * Author: George Davis - * Created: Jan 10, 2002 - * Copyright: MontaVista Software Inc. - * - * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c - * - * Lubbock PCMCIA specific routines. - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/delay.h> - -#include <asm/hardware/sa1111.h> -#include <asm/mach-types.h> - -#include "sa1111_generic.h" -#include "max1600.h" - -static int lubbock_pcmcia_hw_init(struct soc_pcmcia_socket *skt) -{ - struct max1600 *m; - int ret; - - ret = max1600_init(skt->socket.dev.parent, &m, - skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A, - MAX1600_CODE_HIGH); - if (ret == 0) - skt->driver_data = m; - - return ret; -} - -static int -lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, - const socket_state_t *state) -{ - struct max1600 *m = skt->driver_data; - int ret = 0; - - /* Lubbock uses the Maxim MAX1602, with the following connections: - * - * Socket 0 (PCMCIA): - * MAX1602 Lubbock Register - * Pin Signal - * ----- ------- ---------------------- - * A0VPP S0_PWR0 SA-1111 GPIO A<0> - * A1VPP S0_PWR1 SA-1111 GPIO A<1> - * A0VCC S0_PWR2 SA-1111 GPIO A<2> - * A1VCC S0_PWR3 SA-1111 GPIO A<3> - * VX VCC - * VY +3.3V - * 12IN +12V - * CODE +3.3V Cirrus Code, CODE = High (VY) - * - * Socket 1 (CF): - * MAX1602 Lubbock Register - * Pin Signal - * ----- ------- ---------------------- - * A0VPP GND VPP is not connected - * A1VPP GND VPP is not connected - * A0VCC S1_PWR0 MISC_WR<14> - * A1VCC S1_PWR1 MISC_WR<15> - * VX VCC - * VY +3.3V - * 12IN GND VPP is not connected - * CODE +3.3V Cirrus Code, CODE = High (VY) - * - */ - - again: - switch (skt->nr) { - case 0: - case 1: - break; - - default: - ret = -1; - } - - if (ret == 0) - ret = sa1111_pcmcia_configure_socket(skt, state); - if (ret == 0) - ret = max1600_configure(m, state->Vcc, state->Vpp); - -#if 1 - if (ret == 0 && state->Vcc == 33) { - struct pcmcia_state new_state; - - /* - * HACK ALERT: - * We can't sense the voltage properly on Lubbock before - * actually applying some power to the socket (catch 22). - * Resense the socket Voltage Sense pins after applying - * socket power. - * - * Note: It takes about 2.5ms for the MAX1602 VCC output - * to rise. - */ - mdelay(3); - - sa1111_pcmcia_socket_state(skt, &new_state); - - if (!new_state.vs_3v && !new_state.vs_Xv) { - /* - * Switch to 5V, Configure socket with 5V voltage - */ - max1600_configure(m, 0, 0); - - /* - * It takes about 100ms to turn off Vcc. - */ - mdelay(100); - - /* - * We need to hack around the const qualifier as - * well to keep this ugly workaround localized and - * not force it to the rest of the code. Barf bags - * available in the seat pocket in front of you! - */ - ((socket_state_t *)state)->Vcc = 50; - ((socket_state_t *)state)->Vpp = 50; - goto again; - } - } -#endif - - return ret; -} - -static struct pcmcia_low_level lubbock_pcmcia_ops = { - .owner = THIS_MODULE, - .hw_init = lubbock_pcmcia_hw_init, - .configure_socket = lubbock_pcmcia_configure_socket, - .first = 0, - .nr = 2, -}; - -#include "pxa2xx_base.h" - -int pcmcia_lubbock_init(struct sa1111_dev *sadev) -{ - pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops); - pxa2xx_configure_sockets(&sadev->dev, &lubbock_pcmcia_ops); - return sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops, - pxa2xx_drv_pcmcia_add_one); -} - -MODULE_LICENSE("GPL"); diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c index b80a9b74662b..1deb61b22bc7 100644 --- a/drivers/perf/arm-cmn.c +++ b/drivers/perf/arm-cmn.c @@ -1576,7 +1576,6 @@ static int arm_cmn_event_init(struct perf_event *event) hw->dn++; continue; } - hw->dtcs_used |= arm_cmn_node_to_xp(cmn, dn)->dtc; hw->num_dns++; if (bynodeid) break; @@ -1589,6 +1588,12 @@ static int arm_cmn_event_init(struct perf_event *event) nodeid, nid.x, nid.y, nid.port, nid.dev, type); return -EINVAL; } + /* + * Keep assuming non-cycles events count in all DTC domains; turns out + * it's hard to make a worthwhile optimisation around this, short of + * going all-in with domain-local counter allocation as well. + */ + hw->dtcs_used = (1U << cmn->num_dtcs) - 1; return arm_cmn_validate_group(cmn, event); } diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 9b593f985805..15bd1e34a88e 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -550,13 +550,7 @@ static void armpmu_disable(struct pmu *pmu) static bool armpmu_filter(struct pmu *pmu, int cpu) { struct arm_pmu *armpmu = to_arm_pmu(pmu); - bool ret; - - ret = cpumask_test_cpu(cpu, &armpmu->supported_cpus); - if (ret && armpmu->filter) - return armpmu->filter(pmu, cpu); - - return ret; + return !cpumask_test_cpu(cpu, &armpmu->supported_cpus); } static ssize_t cpus_show(struct device *dev, @@ -758,17 +752,8 @@ static void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd) case CPU_PM_ENTER_FAILED: /* * Restore and enable the counter. - * armpmu_start() indirectly calls - * - * perf_event_update_userpage() - * - * that requires RCU read locking to be functional, - * wrap the call within RCU_NONIDLE to make the - * RCU subsystem aware this cpu is not idle from - * an RCU perspective for the armpmu_start() call - * duration. */ - RCU_NONIDLE(armpmu_start(event, PERF_EF_RELOAD)); + armpmu_start(event, PERF_EF_RELOAD); break; default: break; diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index f6507efe2a58..7b2288d4b1ec 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -771,14 +771,8 @@ static int riscv_pm_pmu_notify(struct notifier_block *b, unsigned long cmd, case CPU_PM_ENTER_FAILED: /* * Restore and enable the counter. - * - * Requires RCU read locking to be functional, - * wrap the call within RCU_NONIDLE to make the - * RCU subsystem aware this cpu is not idle from - * an RCU perspective for the riscv_pmu_start() call - * duration. */ - RCU_NONIDLE(riscv_pmu_start(event, PERF_EF_RELOAD)); + riscv_pmu_start(event, PERF_EF_RELOAD); break; default: break; diff --git a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c index 7585e8080b77..afc63552ecaf 100644 --- a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c +++ b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c @@ -255,7 +255,7 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev) imx8_phy->perst = devm_reset_control_get_exclusive(dev, "perst"); if (IS_ERR(imx8_phy->perst)) - dev_err_probe(dev, PTR_ERR(imx8_phy->perst), + return dev_err_probe(dev, PTR_ERR(imx8_phy->perst), "Failed to get PCIE PHY PERST control\n"); } diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c index 95c6dbb52da7..ce511ad5d369 100644 --- a/drivers/phy/phy-can-transceiver.c +++ b/drivers/phy/phy-can-transceiver.c @@ -99,6 +99,7 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) struct gpio_desc *standby_gpio; struct gpio_desc *enable_gpio; u32 max_bitrate = 0; + int err; can_transceiver_phy = devm_kzalloc(dev, sizeof(struct can_transceiver_phy), GFP_KERNEL); if (!can_transceiver_phy) @@ -124,8 +125,8 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) return PTR_ERR(phy); } - device_property_read_u32(dev, "max-bitrate", &max_bitrate); - if (!max_bitrate) + err = device_property_read_u32(dev, "max-bitrate", &max_bitrate); + if ((err != -EINVAL) && !max_bitrate) dev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit\n"); phy->attrs.max_link_rate = max_bitrate; diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c b/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c index 8807e59a1162..a52a9bf13b75 100644 --- a/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c +++ b/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c @@ -401,26 +401,13 @@ static const struct hsphy_init_seq init_seq_femtophy[] = { HSPHY_INIT_CFG(0x90, 0x60, 0), }; -static const struct hsphy_init_seq init_seq_mdm9607[] = { - HSPHY_INIT_CFG(0x80, 0x44, 0), - HSPHY_INIT_CFG(0x81, 0x38, 0), - HSPHY_INIT_CFG(0x82, 0x24, 0), - HSPHY_INIT_CFG(0x83, 0x13, 0), -}; - static const struct hsphy_data hsphy_data_femtophy = { .init_seq = init_seq_femtophy, .init_seq_num = ARRAY_SIZE(init_seq_femtophy), }; -static const struct hsphy_data hsphy_data_mdm9607 = { - .init_seq = init_seq_mdm9607, - .init_seq_num = ARRAY_SIZE(init_seq_mdm9607), -}; - static const struct of_device_id qcom_snps_hsphy_match[] = { { .compatible = "qcom,usb-hs-28nm-femtophy", .data = &hsphy_data_femtophy, }, - { .compatible = "qcom,usb-hs-28nm-mdm9607", .data = &hsphy_data_mdm9607, }, { }, }; MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_match); diff --git a/drivers/phy/renesas/r8a779f0-ether-serdes.c b/drivers/phy/renesas/r8a779f0-ether-serdes.c index ec6594e6dc27..e7588a940d69 100644 --- a/drivers/phy/renesas/r8a779f0-ether-serdes.c +++ b/drivers/phy/renesas/r8a779f0-ether-serdes.c @@ -126,7 +126,7 @@ r8a779f0_eth_serdes_chan_setting(struct r8a779f0_eth_serdes_channel *channel) r8a779f0_eth_serdes_write32(channel->addr, 0x0160, 0x180, 0x0007); r8a779f0_eth_serdes_write32(channel->addr, 0x01ac, 0x180, 0x0000); r8a779f0_eth_serdes_write32(channel->addr, 0x00c4, 0x180, 0x0310); - r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x380, 0x0101); + r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x180, 0x0101); ret = r8a779f0_eth_serdes_reg_wait(channel, 0x00c8, 0x0180, BIT(0), 0); if (ret) return ret; diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index e6ededc51523..a0bc10aa7961 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -485,8 +485,10 @@ static int rockchip_usb2phy_power_on(struct phy *phy) return ret; ret = property_enable(base, &rport->port_cfg->phy_sus, false); - if (ret) + if (ret) { + clk_disable_unprepare(rphy->clk480m); return ret; + } /* waiting for the utmi_clk to become stable */ usleep_range(1500, 2000); diff --git a/drivers/phy/sunplus/phy-sunplus-usb2.c b/drivers/phy/sunplus/phy-sunplus-usb2.c index e827b79f6d49..56de41091d63 100644 --- a/drivers/phy/sunplus/phy-sunplus-usb2.c +++ b/drivers/phy/sunplus/phy-sunplus-usb2.c @@ -254,6 +254,9 @@ static int sp_usb_phy_probe(struct platform_device *pdev) return PTR_ERR(usbphy->phy_regs); usbphy->moon4_res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "moon4"); + if (!usbphy->moon4_res_mem) + return -EINVAL; + usbphy->moon4_regs = devm_ioremap(&pdev->dev, usbphy->moon4_res_mem->start, resource_size(usbphy->moon4_res_mem)); if (!usbphy->moon4_regs) diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig index 15a3bcf32308..b905902d5750 100644 --- a/drivers/phy/ti/Kconfig +++ b/drivers/phy/ti/Kconfig @@ -23,7 +23,7 @@ config PHY_DM816X_USB config PHY_AM654_SERDES tristate "TI AM654 SERDES support" - depends on OF && ARCH_K3 || COMPILE_TEST + depends on OF && (ARCH_K3 || COMPILE_TEST) depends on COMMON_CLK select GENERIC_PHY select MULTIPLEXER @@ -35,7 +35,7 @@ config PHY_AM654_SERDES config PHY_J721E_WIZ tristate "TI J721E WIZ (SERDES Wrapper) support" - depends on OF && ARCH_K3 || COMPILE_TEST + depends on OF && (ARCH_K3 || COMPILE_TEST) depends on HAS_IOMEM && OF_ADDRESS depends on COMMON_CLK select GENERIC_PHY diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c index 3945612900e6..9c6ee46ac7a0 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c @@ -93,10 +93,19 @@ static int aspeed_sig_expr_enable(struct aspeed_pinmux_data *ctx, static int aspeed_sig_expr_disable(struct aspeed_pinmux_data *ctx, const struct aspeed_sig_expr *expr) { + int ret; + pr_debug("Disabling signal %s for %s\n", expr->signal, expr->function); - return aspeed_sig_expr_set(ctx, expr, false); + ret = aspeed_sig_expr_eval(ctx, expr, true); + if (ret < 0) + return ret; + + if (ret) + return aspeed_sig_expr_set(ctx, expr, false); + + return 0; } /** @@ -114,7 +123,7 @@ static int aspeed_disable_sig(struct aspeed_pinmux_data *ctx, int ret = 0; if (!exprs) - return true; + return -EINVAL; while (*exprs && !ret) { ret = aspeed_sig_expr_disable(ctx, *exprs); diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index cc3aaba24188..e49f271de936 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -1709,6 +1709,12 @@ const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_ EXPORT_SYMBOL_GPL(intel_pinctrl_get_soc_data); #ifdef CONFIG_PM_SLEEP +static bool __intel_gpio_is_direct_irq(u32 value) +{ + return (value & PADCFG0_GPIROUTIOXAPIC) && (value & PADCFG0_GPIOTXDIS) && + (__intel_gpio_get_gpio_mode(value) == PADCFG0_PMODE_GPIO); +} + static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin) { const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin); @@ -1742,8 +1748,7 @@ static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int * See https://bugzilla.kernel.org/show_bug.cgi?id=214749. */ value = readl(intel_get_padcfg(pctrl, pin, PADCFG0)); - if ((value & PADCFG0_GPIROUTIOXAPIC) && (value & PADCFG0_GPIOTXDIS) && - (__intel_gpio_get_gpio_mode(value) == PADCFG0_PMODE_GPIO)) + if (__intel_gpio_is_direct_irq(value)) return true; return false; @@ -1873,7 +1878,12 @@ int intel_pinctrl_resume_noirq(struct device *dev) for (i = 0; i < pctrl->soc->npins; i++) { const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i]; - if (!intel_pinctrl_should_save(pctrl, desc->number)) + if (!(intel_pinctrl_should_save(pctrl, desc->number) || + /* + * If the firmware mangled the register contents too much, + * check the saved value for the Direct IRQ mode. + */ + __intel_gpio_is_direct_irq(pads[i].padcfg0))) continue; intel_restore_padcfg(pctrl, desc->number, PADCFG0, pads[i].padcfg0); diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8195.c b/drivers/pinctrl/mediatek/pinctrl-mt8195.c index 89557c7ed2ab..09c4dcef9338 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt8195.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt8195.c @@ -659,7 +659,7 @@ static const struct mtk_pin_field_calc mt8195_pin_drv_range[] = { PIN_FIELD_BASE(10, 10, 4, 0x010, 0x10, 9, 3), PIN_FIELD_BASE(11, 11, 4, 0x000, 0x10, 24, 3), PIN_FIELD_BASE(12, 12, 4, 0x010, 0x10, 12, 3), - PIN_FIELD_BASE(13, 13, 4, 0x010, 0x10, 27, 3), + PIN_FIELD_BASE(13, 13, 4, 0x000, 0x10, 27, 3), PIN_FIELD_BASE(14, 14, 4, 0x010, 0x10, 15, 3), PIN_FIELD_BASE(15, 15, 4, 0x010, 0x10, 0, 3), PIN_FIELD_BASE(16, 16, 4, 0x010, 0x10, 18, 3), @@ -708,7 +708,7 @@ static const struct mtk_pin_field_calc mt8195_pin_drv_range[] = { PIN_FIELD_BASE(78, 78, 3, 0x000, 0x10, 15, 3), PIN_FIELD_BASE(79, 79, 3, 0x000, 0x10, 18, 3), PIN_FIELD_BASE(80, 80, 3, 0x000, 0x10, 21, 3), - PIN_FIELD_BASE(81, 81, 3, 0x000, 0x10, 28, 3), + PIN_FIELD_BASE(81, 81, 3, 0x000, 0x10, 24, 3), PIN_FIELD_BASE(82, 82, 3, 0x000, 0x10, 27, 3), PIN_FIELD_BASE(83, 83, 3, 0x010, 0x10, 0, 3), PIN_FIELD_BASE(84, 84, 3, 0x010, 0x10, 3, 3), diff --git a/drivers/pinctrl/nomadik/pinctrl-ab8500.c b/drivers/pinctrl/nomadik/pinctrl-ab8500.c index 3106a21cd277..d7b244df058f 100644 --- a/drivers/pinctrl/nomadik/pinctrl-ab8500.c +++ b/drivers/pinctrl/nomadik/pinctrl-ab8500.c @@ -6,9 +6,10 @@ */ #include <linux/kernel.h> -#include <linux/gpio/driver.h> #include <linux/pinctrl/pinctrl.h> + #include <linux/mfd/abx500/ab8500.h> + #include "pinctrl-abx500.h" /* All the pins that can be used for GPIO and some other functions */ diff --git a/drivers/pinctrl/nomadik/pinctrl-ab8505.c b/drivers/pinctrl/nomadik/pinctrl-ab8505.c index b93af1fb37f0..45aa958b573e 100644 --- a/drivers/pinctrl/nomadik/pinctrl-ab8505.c +++ b/drivers/pinctrl/nomadik/pinctrl-ab8505.c @@ -6,9 +6,10 @@ */ #include <linux/kernel.h> -#include <linux/gpio/driver.h> #include <linux/pinctrl/pinctrl.h> + #include <linux/mfd/abx500/ab8500.h> + #include "pinctrl-abx500.h" /* All the pins that can be used for GPIO and some other functions */ diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index 7aa534576a45..28c3403df1b0 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -6,33 +6,37 @@ * * Driver allows to use AxB5xx unused pins to be used as GPIO */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/init.h> +#include <linux/bitops.h> #include <linux/err.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/platform_device.h> #include <linux/gpio/driver.h> +#include <linux/init.h> +#include <linux/interrupt.h> #include <linux/irq.h> #include <linux/irqdomain.h> -#include <linux/interrupt.h> -#include <linux/bitops.h> +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <linux/types.h> + #include <linux/mfd/abx500.h> #include <linux/mfd/abx500/ab8500.h> -#include <linux/pinctrl/pinctrl.h> + #include <linux/pinctrl/consumer.h> -#include <linux/pinctrl/pinmux.h> -#include <linux/pinctrl/pinconf.h> -#include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> -#include "pinctrl-abx500.h" #include "../core.h" #include "../pinconf.h" #include "../pinctrl-utils.h" +#include "pinctrl-abx500.h" + /* * GPIO registers offset * Bank: 0x10 diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.h b/drivers/pinctrl/nomadik/pinctrl-abx500.h index 90bb12fe8073..d67522084675 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.h +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.h @@ -2,6 +2,10 @@ #ifndef PINCTRL_PINCTRL_ABx500_H #define PINCTRL_PINCTRL_ABx500_H +#include <linux/types.h> + +struct pinctrl_pin_desc; + /* Package definitions */ #define PINCTRL_AB8500 0 #define PINCTRL_AB8505 1 diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c index 758d21f0a850..490e0959e8be 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/kernel.h> +#include <linux/types.h> + #include <linux/pinctrl/pinctrl.h> + #include "pinctrl-nomadik.h" /* All the pins that can be used for GPIO and some other functions */ diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c index c0d7c86d0939..1552222ac68e 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/kernel.h> +#include <linux/types.h> + #include <linux/pinctrl/pinctrl.h> + #include "pinctrl-nomadik.h" /* All the pins that can be used for GPIO and some other functions */ diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index f7d02513d8cc..86a638077a69 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -7,30 +7,34 @@ * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com> * Copyright (C) 2011-2013 Linus Walleij <linus.walleij@linaro.org> */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/io.h> +#include <linux/bitops.h> #include <linux/clk.h> +#include <linux/device.h> #include <linux/err.h> #include <linux/gpio/driver.h> -#include <linux/spinlock.h> +#include <linux/init.h> #include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/of_device.h> +#include <linux/io.h> +#include <linux/kernel.h> #include <linux/of_address.h> -#include <linux/bitops.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +/* Since we request GPIOs from ourself */ +#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinmux.h> -#include <linux/pinctrl/pinconf.h> -/* Since we request GPIOs from ourself */ -#include <linux/pinctrl/consumer.h> -#include "pinctrl-nomadik.h" + #include "../core.h" #include "../pinctrl-utils.h" +#include "pinctrl-nomadik.h" + /* * The GPIO module in the Nomadik family of Systems-on-Chip is an * AMBA device, managing 32 pins and alternate functions. The logic block @@ -907,8 +911,6 @@ static int nmk_gpio_get_mode(struct nmk_gpio_chip *nmk_chip, int offset) return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0); } -#include <linux/seq_file.h> - static void nmk_gpio_dbg_show_one(struct seq_file *s, struct pinctrl_dev *pctldev, struct gpio_chip *chip, unsigned offset, unsigned gpio) diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.h b/drivers/pinctrl/nomadik/pinctrl-nomadik.h index 84e297757335..1ef2559bc571 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.h +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.h @@ -2,6 +2,11 @@ #ifndef PINCTRL_PINCTRL_NOMADIK_H #define PINCTRL_PINCTRL_NOMADIK_H +#include <linux/kernel.h> +#include <linux/types.h> + +#include <linux/pinctrl/pinctrl.h> + /* Package definitions */ #define PINCTRL_NMK_STN8815 0 #define PINCTRL_NMK_DB8500 1 diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index 9bc6e3922e78..32c3edaf9038 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -365,6 +365,7 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) } else { debounce_enable = " ∅"; + time = 0; } snprintf(debounce_value, sizeof(debounce_value), "%u", time * unit); seq_printf(s, "debounce %s (🕑 %sus)| ", debounce_enable, debounce_value); diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index da974ff2d75d..5eeac92f610a 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -926,19 +926,19 @@ static struct rockchip_mux_route_data rk3568_mux_route_data[] = { RK_MUXROUTE_PMU(0, RK_PB5, 4, 0x0110, WRITE_MASK_VAL(3, 2, 1)), /* PWM1 IO mux M1 */ RK_MUXROUTE_PMU(0, RK_PC1, 1, 0x0110, WRITE_MASK_VAL(5, 4, 0)), /* PWM2 IO mux M0 */ RK_MUXROUTE_PMU(0, RK_PB6, 4, 0x0110, WRITE_MASK_VAL(5, 4, 1)), /* PWM2 IO mux M1 */ - RK_MUXROUTE_PMU(0, RK_PB3, 2, 0x0300, WRITE_MASK_VAL(0, 0, 0)), /* CAN0 IO mux M0 */ + RK_MUXROUTE_GRF(0, RK_PB3, 2, 0x0300, WRITE_MASK_VAL(0, 0, 0)), /* CAN0 IO mux M0 */ RK_MUXROUTE_GRF(2, RK_PA1, 4, 0x0300, WRITE_MASK_VAL(0, 0, 1)), /* CAN0 IO mux M1 */ RK_MUXROUTE_GRF(1, RK_PA1, 3, 0x0300, WRITE_MASK_VAL(2, 2, 0)), /* CAN1 IO mux M0 */ RK_MUXROUTE_GRF(4, RK_PC3, 3, 0x0300, WRITE_MASK_VAL(2, 2, 1)), /* CAN1 IO mux M1 */ RK_MUXROUTE_GRF(4, RK_PB5, 3, 0x0300, WRITE_MASK_VAL(4, 4, 0)), /* CAN2 IO mux M0 */ RK_MUXROUTE_GRF(2, RK_PB2, 4, 0x0300, WRITE_MASK_VAL(4, 4, 1)), /* CAN2 IO mux M1 */ RK_MUXROUTE_GRF(4, RK_PC4, 1, 0x0300, WRITE_MASK_VAL(6, 6, 0)), /* HPDIN IO mux M0 */ - RK_MUXROUTE_PMU(0, RK_PC2, 2, 0x0300, WRITE_MASK_VAL(6, 6, 1)), /* HPDIN IO mux M1 */ + RK_MUXROUTE_GRF(0, RK_PC2, 2, 0x0300, WRITE_MASK_VAL(6, 6, 1)), /* HPDIN IO mux M1 */ RK_MUXROUTE_GRF(3, RK_PB1, 3, 0x0300, WRITE_MASK_VAL(8, 8, 0)), /* GMAC1 IO mux M0 */ RK_MUXROUTE_GRF(4, RK_PA7, 3, 0x0300, WRITE_MASK_VAL(8, 8, 1)), /* GMAC1 IO mux M1 */ RK_MUXROUTE_GRF(4, RK_PD1, 1, 0x0300, WRITE_MASK_VAL(10, 10, 0)), /* HDMITX IO mux M0 */ - RK_MUXROUTE_PMU(0, RK_PC7, 1, 0x0300, WRITE_MASK_VAL(10, 10, 1)), /* HDMITX IO mux M1 */ - RK_MUXROUTE_PMU(0, RK_PB6, 1, 0x0300, WRITE_MASK_VAL(14, 14, 0)), /* I2C2 IO mux M0 */ + RK_MUXROUTE_GRF(0, RK_PC7, 1, 0x0300, WRITE_MASK_VAL(10, 10, 1)), /* HDMITX IO mux M1 */ + RK_MUXROUTE_GRF(0, RK_PB6, 1, 0x0300, WRITE_MASK_VAL(14, 14, 0)), /* I2C2 IO mux M0 */ RK_MUXROUTE_GRF(4, RK_PB4, 1, 0x0300, WRITE_MASK_VAL(14, 14, 1)), /* I2C2 IO mux M1 */ RK_MUXROUTE_GRF(1, RK_PA0, 1, 0x0304, WRITE_MASK_VAL(0, 0, 0)), /* I2C3 IO mux M0 */ RK_MUXROUTE_GRF(3, RK_PB6, 4, 0x0304, WRITE_MASK_VAL(0, 0, 1)), /* I2C3 IO mux M1 */ @@ -964,7 +964,7 @@ static struct rockchip_mux_route_data rk3568_mux_route_data[] = { RK_MUXROUTE_GRF(4, RK_PC3, 1, 0x0308, WRITE_MASK_VAL(12, 12, 1)), /* PWM15 IO mux M1 */ RK_MUXROUTE_GRF(3, RK_PD2, 3, 0x0308, WRITE_MASK_VAL(14, 14, 0)), /* SDMMC2 IO mux M0 */ RK_MUXROUTE_GRF(3, RK_PA5, 5, 0x0308, WRITE_MASK_VAL(14, 14, 1)), /* SDMMC2 IO mux M1 */ - RK_MUXROUTE_PMU(0, RK_PB5, 2, 0x030c, WRITE_MASK_VAL(0, 0, 0)), /* SPI0 IO mux M0 */ + RK_MUXROUTE_GRF(0, RK_PB5, 2, 0x030c, WRITE_MASK_VAL(0, 0, 0)), /* SPI0 IO mux M0 */ RK_MUXROUTE_GRF(2, RK_PD3, 3, 0x030c, WRITE_MASK_VAL(0, 0, 1)), /* SPI0 IO mux M1 */ RK_MUXROUTE_GRF(2, RK_PB5, 3, 0x030c, WRITE_MASK_VAL(2, 2, 0)), /* SPI1 IO mux M0 */ RK_MUXROUTE_GRF(3, RK_PC3, 3, 0x030c, WRITE_MASK_VAL(2, 2, 1)), /* SPI1 IO mux M1 */ @@ -973,8 +973,8 @@ static struct rockchip_mux_route_data rk3568_mux_route_data[] = { RK_MUXROUTE_GRF(4, RK_PB3, 4, 0x030c, WRITE_MASK_VAL(6, 6, 0)), /* SPI3 IO mux M0 */ RK_MUXROUTE_GRF(4, RK_PC2, 2, 0x030c, WRITE_MASK_VAL(6, 6, 1)), /* SPI3 IO mux M1 */ RK_MUXROUTE_GRF(2, RK_PB4, 2, 0x030c, WRITE_MASK_VAL(8, 8, 0)), /* UART1 IO mux M0 */ - RK_MUXROUTE_PMU(0, RK_PD1, 1, 0x030c, WRITE_MASK_VAL(8, 8, 1)), /* UART1 IO mux M1 */ - RK_MUXROUTE_PMU(0, RK_PD1, 1, 0x030c, WRITE_MASK_VAL(10, 10, 0)), /* UART2 IO mux M0 */ + RK_MUXROUTE_GRF(3, RK_PD6, 4, 0x030c, WRITE_MASK_VAL(8, 8, 1)), /* UART1 IO mux M1 */ + RK_MUXROUTE_GRF(0, RK_PD1, 1, 0x030c, WRITE_MASK_VAL(10, 10, 0)), /* UART2 IO mux M0 */ RK_MUXROUTE_GRF(1, RK_PD5, 2, 0x030c, WRITE_MASK_VAL(10, 10, 1)), /* UART2 IO mux M1 */ RK_MUXROUTE_GRF(1, RK_PA1, 2, 0x030c, WRITE_MASK_VAL(12, 12, 0)), /* UART3 IO mux M0 */ RK_MUXROUTE_GRF(3, RK_PB7, 4, 0x030c, WRITE_MASK_VAL(12, 12, 1)), /* UART3 IO mux M1 */ @@ -1004,13 +1004,13 @@ static struct rockchip_mux_route_data rk3568_mux_route_data[] = { RK_MUXROUTE_GRF(3, RK_PD6, 5, 0x0314, WRITE_MASK_VAL(1, 0, 1)), /* PDM IO mux M1 */ RK_MUXROUTE_GRF(4, RK_PA0, 4, 0x0314, WRITE_MASK_VAL(1, 0, 1)), /* PDM IO mux M1 */ RK_MUXROUTE_GRF(3, RK_PC4, 5, 0x0314, WRITE_MASK_VAL(1, 0, 2)), /* PDM IO mux M2 */ - RK_MUXROUTE_PMU(0, RK_PA5, 3, 0x0314, WRITE_MASK_VAL(3, 2, 0)), /* PCIE20 IO mux M0 */ + RK_MUXROUTE_GRF(0, RK_PA5, 3, 0x0314, WRITE_MASK_VAL(3, 2, 0)), /* PCIE20 IO mux M0 */ RK_MUXROUTE_GRF(2, RK_PD0, 4, 0x0314, WRITE_MASK_VAL(3, 2, 1)), /* PCIE20 IO mux M1 */ RK_MUXROUTE_GRF(1, RK_PB0, 4, 0x0314, WRITE_MASK_VAL(3, 2, 2)), /* PCIE20 IO mux M2 */ - RK_MUXROUTE_PMU(0, RK_PA4, 3, 0x0314, WRITE_MASK_VAL(5, 4, 0)), /* PCIE30X1 IO mux M0 */ + RK_MUXROUTE_GRF(0, RK_PA4, 3, 0x0314, WRITE_MASK_VAL(5, 4, 0)), /* PCIE30X1 IO mux M0 */ RK_MUXROUTE_GRF(2, RK_PD2, 4, 0x0314, WRITE_MASK_VAL(5, 4, 1)), /* PCIE30X1 IO mux M1 */ RK_MUXROUTE_GRF(1, RK_PA5, 4, 0x0314, WRITE_MASK_VAL(5, 4, 2)), /* PCIE30X1 IO mux M2 */ - RK_MUXROUTE_PMU(0, RK_PA6, 2, 0x0314, WRITE_MASK_VAL(7, 6, 0)), /* PCIE30X2 IO mux M0 */ + RK_MUXROUTE_GRF(0, RK_PA6, 2, 0x0314, WRITE_MASK_VAL(7, 6, 0)), /* PCIE30X2 IO mux M0 */ RK_MUXROUTE_GRF(2, RK_PD4, 4, 0x0314, WRITE_MASK_VAL(7, 6, 1)), /* PCIE30X2 IO mux M1 */ RK_MUXROUTE_GRF(4, RK_PC2, 4, 0x0314, WRITE_MASK_VAL(7, 6, 2)), /* PCIE30X2 IO mux M2 */ }; @@ -2436,10 +2436,19 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num) case RK3308: case RK3368: case RK3399: + case RK3568: case RK3588: pull_type = bank->pull_type[pin_num / 8]; data >>= bit; data &= (1 << RK3188_PULL_BITS_PER_PIN) - 1; + /* + * In the TRM, pull-up being 1 for everything except the GPIO0_D3-D6, + * where that pull up value becomes 3. + */ + if (ctrl->type == RK3568 && bank->bank_num == 0 && pin_num >= 27 && pin_num <= 30) { + if (data == 3) + data = 1; + } return rockchip_pull_list[pull_type][data]; default: @@ -2497,7 +2506,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, } } /* - * In the TRM, pull-up being 1 for everything except the GPIO0_D0-D6, + * In the TRM, pull-up being 1 for everything except the GPIO0_D3-D6, * where that pull up value becomes 3. */ if (ctrl->type == RK3568 && bank->bank_num == 0 && pin_num >= 27 && pin_num <= 30) { diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 99c3745da456..190923757cda 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -372,6 +372,8 @@ static int pcs_set_mux(struct pinctrl_dev *pctldev, unsigned fselector, if (!pcs->fmask) return 0; function = pinmux_generic_get_function(pctldev, fselector); + if (!function) + return -EINVAL; func = function->data; if (!func) return -EINVAL; diff --git a/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c index c3c8c34148f1..e22d03ce292e 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c @@ -105,7 +105,7 @@ static const struct pinctrl_pin_desc sm8450_lpi_pins[] = { static const char * const swr_tx_clk_groups[] = { "gpio0" }; static const char * const swr_tx_data_groups[] = { "gpio1", "gpio2", "gpio14" }; static const char * const swr_rx_clk_groups[] = { "gpio3" }; -static const char * const swr_rx_data_groups[] = { "gpio4", "gpio5", "gpio15" }; +static const char * const swr_rx_data_groups[] = { "gpio4", "gpio5" }; static const char * const dmic1_clk_groups[] = { "gpio6" }; static const char * const dmic1_data_groups[] = { "gpio7" }; static const char * const dmic2_clk_groups[] = { "gpio8" }; diff --git a/drivers/pinctrl/samsung/Kconfig b/drivers/pinctrl/samsung/Kconfig index 7b0576f71376..697ff7812d8e 100644 --- a/drivers/pinctrl/samsung/Kconfig +++ b/drivers/pinctrl/samsung/Kconfig @@ -23,11 +23,6 @@ config PINCTRL_EXYNOS_ARM64 bool "ARMv8-specific pinctrl driver for Samsung Exynos SoCs" if COMPILE_TEST depends on PINCTRL_EXYNOS -config PINCTRL_S3C24XX - bool "Samsung S3C24XX SoC pinctrl driver" - depends on ARCH_S3C24XX || (COMPILE_TEST && OF) - select PINCTRL_SAMSUNG - config PINCTRL_S3C64XX bool "Samsung S3C64XX SoC pinctrl driver" depends on ARCH_S3C64XX || (COMPILE_TEST && OF) diff --git a/drivers/pinctrl/samsung/Makefile b/drivers/pinctrl/samsung/Makefile index ed951df6a112..4dd4a92ab6cc 100644 --- a/drivers/pinctrl/samsung/Makefile +++ b/drivers/pinctrl/samsung/Makefile @@ -5,5 +5,4 @@ obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o obj-$(CONFIG_PINCTRL_EXYNOS) += pinctrl-exynos.o obj-$(CONFIG_PINCTRL_EXYNOS_ARM) += pinctrl-exynos-arm.o obj-$(CONFIG_PINCTRL_EXYNOS_ARM64) += pinctrl-exynos-arm64.o -obj-$(CONFIG_PINCTRL_S3C24XX) += pinctrl-s3c24xx.o obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c deleted file mode 100644 index 625cb1065eaf..000000000000 --- a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c +++ /dev/null @@ -1,653 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// S3C24XX specific support for Samsung pinctrl/gpiolib driver. -// -// Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de> -// -// This file contains the SamsungS3C24XX specific information required by the -// Samsung pinctrl/gpiolib driver. It also includes the implementation of -// external gpio and wakeup interrupt support. - -#include <linux/init.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/irqdomain.h> -#include <linux/irq.h> -#include <linux/of_irq.h> -#include <linux/irqchip/chained_irq.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/err.h> - -#include "pinctrl-samsung.h" - -#define NUM_EINT 24 -#define NUM_EINT_IRQ 6 -#define EINT_MAX_PER_GROUP 8 - -#define EINTPEND_REG 0xa8 -#define EINTMASK_REG 0xa4 - -#define EINT_GROUP(i) ((int)((i) / EINT_MAX_PER_GROUP)) -#define EINT_REG(i) ((EINT_GROUP(i) * 4) + 0x88) -#define EINT_OFFS(i) ((i) % EINT_MAX_PER_GROUP * 4) - -#define EINT_LEVEL_LOW 0 -#define EINT_LEVEL_HIGH 1 -#define EINT_EDGE_FALLING 2 -#define EINT_EDGE_RISING 4 -#define EINT_EDGE_BOTH 6 -#define EINT_MASK 0xf - -static const struct samsung_pin_bank_type bank_type_1bit = { - .fld_width = { 1, 1, }, - .reg_offset = { 0x00, 0x04, }, -}; - -static const struct samsung_pin_bank_type bank_type_2bit = { - .fld_width = { 2, 1, 2, }, - .reg_offset = { 0x00, 0x04, 0x08, }, -}; - -#define PIN_BANK_A(pins, reg, id) \ - { \ - .type = &bank_type_1bit, \ - .pctl_offset = reg, \ - .nr_pins = pins, \ - .eint_type = EINT_TYPE_NONE, \ - .name = id \ - } - -#define PIN_BANK_2BIT(pins, reg, id) \ - { \ - .type = &bank_type_2bit, \ - .pctl_offset = reg, \ - .nr_pins = pins, \ - .eint_type = EINT_TYPE_NONE, \ - .name = id \ - } - -#define PIN_BANK_2BIT_EINTW(pins, reg, id, eoffs, emask)\ - { \ - .type = &bank_type_2bit, \ - .pctl_offset = reg, \ - .nr_pins = pins, \ - .eint_type = EINT_TYPE_WKUP, \ - .eint_func = 2, \ - .eint_mask = emask, \ - .eint_offset = eoffs, \ - .name = id \ - } - -/** - * struct s3c24xx_eint_data - EINT common data - * @drvdata: pin controller driver data - * @domains: IRQ domains of particular EINT interrupts - * @parents: mapped parent irqs in the main interrupt controller - */ -struct s3c24xx_eint_data { - struct samsung_pinctrl_drv_data *drvdata; - struct irq_domain *domains[NUM_EINT]; - int parents[NUM_EINT_IRQ]; -}; - -/** - * struct s3c24xx_eint_domain_data - per irq-domain data - * @bank: pin bank related to the domain - * @eint_data: common data - * @eint0_3_parent_only: live eints 0-3 only in the main intc - */ -struct s3c24xx_eint_domain_data { - struct samsung_pin_bank *bank; - struct s3c24xx_eint_data *eint_data; - bool eint0_3_parent_only; -}; - -static int s3c24xx_eint_get_trigger(unsigned int type) -{ - switch (type) { - case IRQ_TYPE_EDGE_RISING: - return EINT_EDGE_RISING; - case IRQ_TYPE_EDGE_FALLING: - return EINT_EDGE_FALLING; - case IRQ_TYPE_EDGE_BOTH: - return EINT_EDGE_BOTH; - case IRQ_TYPE_LEVEL_HIGH: - return EINT_LEVEL_HIGH; - case IRQ_TYPE_LEVEL_LOW: - return EINT_LEVEL_LOW; - default: - return -EINVAL; - } -} - -static void s3c24xx_eint_set_handler(struct irq_data *d, unsigned int type) -{ - /* Edge- and level-triggered interrupts need different handlers */ - if (type & IRQ_TYPE_EDGE_BOTH) - irq_set_handler_locked(d, handle_edge_irq); - else - irq_set_handler_locked(d, handle_level_irq); -} - -static void s3c24xx_eint_set_function(struct samsung_pinctrl_drv_data *d, - struct samsung_pin_bank *bank, int pin) -{ - const struct samsung_pin_bank_type *bank_type = bank->type; - unsigned long flags; - void __iomem *reg; - u8 shift; - u32 mask; - u32 val; - - /* Make sure that pin is configured as interrupt */ - reg = d->virt_base + bank->pctl_offset; - shift = pin * bank_type->fld_width[PINCFG_TYPE_FUNC]; - mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1; - - raw_spin_lock_irqsave(&bank->slock, flags); - - val = readl(reg); - val &= ~(mask << shift); - val |= bank->eint_func << shift; - writel(val, reg); - - raw_spin_unlock_irqrestore(&bank->slock, flags); -} - -static int s3c24xx_eint_type(struct irq_data *data, unsigned int type) -{ - struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct samsung_pinctrl_drv_data *d = bank->drvdata; - int index = bank->eint_offset + data->hwirq; - void __iomem *reg; - int trigger; - u8 shift; - u32 val; - - trigger = s3c24xx_eint_get_trigger(type); - if (trigger < 0) { - dev_err(d->dev, "unsupported external interrupt type\n"); - return -EINVAL; - } - - s3c24xx_eint_set_handler(data, type); - - /* Set up interrupt trigger */ - reg = d->virt_base + EINT_REG(index); - shift = EINT_OFFS(index); - - val = readl(reg); - val &= ~(EINT_MASK << shift); - val |= trigger << shift; - writel(val, reg); - - s3c24xx_eint_set_function(d, bank, data->hwirq); - - return 0; -} - -/* Handling of EINTs 0-3 on all except S3C2412 and S3C2413 */ - -static void s3c2410_eint0_3_ack(struct irq_data *data) -{ - struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct s3c24xx_eint_domain_data *ddata = bank->irq_domain->host_data; - struct s3c24xx_eint_data *eint_data = ddata->eint_data; - int parent_irq = eint_data->parents[data->hwirq]; - struct irq_chip *parent_chip = irq_get_chip(parent_irq); - - parent_chip->irq_ack(irq_get_irq_data(parent_irq)); -} - -static void s3c2410_eint0_3_mask(struct irq_data *data) -{ - struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct s3c24xx_eint_domain_data *ddata = bank->irq_domain->host_data; - struct s3c24xx_eint_data *eint_data = ddata->eint_data; - int parent_irq = eint_data->parents[data->hwirq]; - struct irq_chip *parent_chip = irq_get_chip(parent_irq); - - parent_chip->irq_mask(irq_get_irq_data(parent_irq)); -} - -static void s3c2410_eint0_3_unmask(struct irq_data *data) -{ - struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct s3c24xx_eint_domain_data *ddata = bank->irq_domain->host_data; - struct s3c24xx_eint_data *eint_data = ddata->eint_data; - int parent_irq = eint_data->parents[data->hwirq]; - struct irq_chip *parent_chip = irq_get_chip(parent_irq); - - parent_chip->irq_unmask(irq_get_irq_data(parent_irq)); -} - -static struct irq_chip s3c2410_eint0_3_chip = { - .name = "s3c2410-eint0_3", - .irq_ack = s3c2410_eint0_3_ack, - .irq_mask = s3c2410_eint0_3_mask, - .irq_unmask = s3c2410_eint0_3_unmask, - .irq_set_type = s3c24xx_eint_type, -}; - -static void s3c2410_demux_eint0_3(struct irq_desc *desc) -{ - struct irq_data *data = irq_desc_get_irq_data(desc); - struct s3c24xx_eint_data *eint_data = irq_desc_get_handler_data(desc); - int ret; - - /* the first 4 eints have a simple 1 to 1 mapping */ - ret = generic_handle_domain_irq(eint_data->domains[data->hwirq], data->hwirq); - /* Something must be really wrong if an unmapped EINT is unmasked */ - BUG_ON(ret); -} - -/* Handling of EINTs 0-3 on S3C2412 and S3C2413 */ - -static void s3c2412_eint0_3_ack(struct irq_data *data) -{ - struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct samsung_pinctrl_drv_data *d = bank->drvdata; - - unsigned long bitval = 1UL << data->hwirq; - writel(bitval, d->virt_base + EINTPEND_REG); -} - -static void s3c2412_eint0_3_mask(struct irq_data *data) -{ - struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct samsung_pinctrl_drv_data *d = bank->drvdata; - unsigned long mask; - - mask = readl(d->virt_base + EINTMASK_REG); - mask |= (1UL << data->hwirq); - writel(mask, d->virt_base + EINTMASK_REG); -} - -static void s3c2412_eint0_3_unmask(struct irq_data *data) -{ - struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct samsung_pinctrl_drv_data *d = bank->drvdata; - unsigned long mask; - - mask = readl(d->virt_base + EINTMASK_REG); - mask &= ~(1UL << data->hwirq); - writel(mask, d->virt_base + EINTMASK_REG); -} - -static struct irq_chip s3c2412_eint0_3_chip = { - .name = "s3c2412-eint0_3", - .irq_ack = s3c2412_eint0_3_ack, - .irq_mask = s3c2412_eint0_3_mask, - .irq_unmask = s3c2412_eint0_3_unmask, - .irq_set_type = s3c24xx_eint_type, -}; - -static void s3c2412_demux_eint0_3(struct irq_desc *desc) -{ - struct s3c24xx_eint_data *eint_data = irq_desc_get_handler_data(desc); - struct irq_data *data = irq_desc_get_irq_data(desc); - struct irq_chip *chip = irq_data_get_irq_chip(data); - int ret; - - chained_irq_enter(chip, desc); - - /* the first 4 eints have a simple 1 to 1 mapping */ - ret = generic_handle_domain_irq(eint_data->domains[data->hwirq], data->hwirq); - /* Something must be really wrong if an unmapped EINT is unmasked */ - BUG_ON(ret); - - chained_irq_exit(chip, desc); -} - -/* Handling of all other eints */ - -static void s3c24xx_eint_ack(struct irq_data *data) -{ - struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct samsung_pinctrl_drv_data *d = bank->drvdata; - unsigned char index = bank->eint_offset + data->hwirq; - - writel(1UL << index, d->virt_base + EINTPEND_REG); -} - -static void s3c24xx_eint_mask(struct irq_data *data) -{ - struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct samsung_pinctrl_drv_data *d = bank->drvdata; - unsigned char index = bank->eint_offset + data->hwirq; - unsigned long mask; - - mask = readl(d->virt_base + EINTMASK_REG); - mask |= (1UL << index); - writel(mask, d->virt_base + EINTMASK_REG); -} - -static void s3c24xx_eint_unmask(struct irq_data *data) -{ - struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct samsung_pinctrl_drv_data *d = bank->drvdata; - unsigned char index = bank->eint_offset + data->hwirq; - unsigned long mask; - - mask = readl(d->virt_base + EINTMASK_REG); - mask &= ~(1UL << index); - writel(mask, d->virt_base + EINTMASK_REG); -} - -static struct irq_chip s3c24xx_eint_chip = { - .name = "s3c-eint", - .irq_ack = s3c24xx_eint_ack, - .irq_mask = s3c24xx_eint_mask, - .irq_unmask = s3c24xx_eint_unmask, - .irq_set_type = s3c24xx_eint_type, -}; - -static inline void s3c24xx_demux_eint(struct irq_desc *desc, - u32 offset, u32 range) -{ - struct s3c24xx_eint_data *data = irq_desc_get_handler_data(desc); - struct irq_chip *chip = irq_desc_get_chip(desc); - struct samsung_pinctrl_drv_data *d = data->drvdata; - unsigned int pend, mask; - - chained_irq_enter(chip, desc); - - pend = readl(d->virt_base + EINTPEND_REG); - mask = readl(d->virt_base + EINTMASK_REG); - - pend &= ~mask; - pend &= range; - - while (pend) { - unsigned int irq; - int ret; - - irq = __ffs(pend); - pend &= ~(1 << irq); - ret = generic_handle_domain_irq(data->domains[irq], irq - offset); - /* Something is really wrong if an unmapped EINT is unmasked */ - BUG_ON(ret); - } - - chained_irq_exit(chip, desc); -} - -static void s3c24xx_demux_eint4_7(struct irq_desc *desc) -{ - s3c24xx_demux_eint(desc, 0, 0xf0); -} - -static void s3c24xx_demux_eint8_23(struct irq_desc *desc) -{ - s3c24xx_demux_eint(desc, 8, 0xffff00); -} - -static irq_flow_handler_t s3c2410_eint_handlers[NUM_EINT_IRQ] = { - s3c2410_demux_eint0_3, - s3c2410_demux_eint0_3, - s3c2410_demux_eint0_3, - s3c2410_demux_eint0_3, - s3c24xx_demux_eint4_7, - s3c24xx_demux_eint8_23, -}; - -static irq_flow_handler_t s3c2412_eint_handlers[NUM_EINT_IRQ] = { - s3c2412_demux_eint0_3, - s3c2412_demux_eint0_3, - s3c2412_demux_eint0_3, - s3c2412_demux_eint0_3, - s3c24xx_demux_eint4_7, - s3c24xx_demux_eint8_23, -}; - -static int s3c24xx_gpf_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - struct s3c24xx_eint_domain_data *ddata = h->host_data; - struct samsung_pin_bank *bank = ddata->bank; - - if (!(bank->eint_mask & (1 << (bank->eint_offset + hw)))) - return -EINVAL; - - if (hw <= 3) { - if (ddata->eint0_3_parent_only) - irq_set_chip_and_handler(virq, &s3c2410_eint0_3_chip, - handle_edge_irq); - else - irq_set_chip_and_handler(virq, &s3c2412_eint0_3_chip, - handle_edge_irq); - } else { - irq_set_chip_and_handler(virq, &s3c24xx_eint_chip, - handle_edge_irq); - } - irq_set_chip_data(virq, bank); - return 0; -} - -static const struct irq_domain_ops s3c24xx_gpf_irq_ops = { - .map = s3c24xx_gpf_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -static int s3c24xx_gpg_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - struct s3c24xx_eint_domain_data *ddata = h->host_data; - struct samsung_pin_bank *bank = ddata->bank; - - if (!(bank->eint_mask & (1 << (bank->eint_offset + hw)))) - return -EINVAL; - - irq_set_chip_and_handler(virq, &s3c24xx_eint_chip, handle_edge_irq); - irq_set_chip_data(virq, bank); - return 0; -} - -static const struct irq_domain_ops s3c24xx_gpg_irq_ops = { - .map = s3c24xx_gpg_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -static const struct of_device_id s3c24xx_eint_irq_ids[] = { - { .compatible = "samsung,s3c2410-wakeup-eint", .data = (void *)1 }, - { .compatible = "samsung,s3c2412-wakeup-eint", .data = (void *)0 }, - { } -}; - -static int s3c24xx_eint_init(struct samsung_pinctrl_drv_data *d) -{ - struct device *dev = d->dev; - const struct of_device_id *match; - struct device_node *eint_np = NULL; - struct device_node *np; - struct samsung_pin_bank *bank; - struct s3c24xx_eint_data *eint_data; - const struct irq_domain_ops *ops; - unsigned int i; - bool eint0_3_parent_only; - irq_flow_handler_t *handlers; - - for_each_child_of_node(dev->of_node, np) { - match = of_match_node(s3c24xx_eint_irq_ids, np); - if (match) { - eint_np = np; - eint0_3_parent_only = (bool)match->data; - break; - } - } - if (!eint_np) - return -ENODEV; - - eint_data = devm_kzalloc(dev, sizeof(*eint_data), GFP_KERNEL); - if (!eint_data) { - of_node_put(eint_np); - return -ENOMEM; - } - - eint_data->drvdata = d; - - handlers = eint0_3_parent_only ? s3c2410_eint_handlers - : s3c2412_eint_handlers; - for (i = 0; i < NUM_EINT_IRQ; ++i) { - unsigned int irq; - - irq = irq_of_parse_and_map(eint_np, i); - if (!irq) { - dev_err(dev, "failed to get wakeup EINT IRQ %d\n", i); - of_node_put(eint_np); - return -ENXIO; - } - - eint_data->parents[i] = irq; - irq_set_chained_handler_and_data(irq, handlers[i], eint_data); - } - of_node_put(eint_np); - - bank = d->pin_banks; - for (i = 0; i < d->nr_banks; ++i, ++bank) { - struct s3c24xx_eint_domain_data *ddata; - unsigned int mask; - unsigned int irq; - unsigned int pin; - - if (bank->eint_type != EINT_TYPE_WKUP) - continue; - - ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); - if (!ddata) - return -ENOMEM; - - ddata->bank = bank; - ddata->eint_data = eint_data; - ddata->eint0_3_parent_only = eint0_3_parent_only; - - ops = (bank->eint_offset == 0) ? &s3c24xx_gpf_irq_ops - : &s3c24xx_gpg_irq_ops; - - bank->irq_domain = irq_domain_create_linear(bank->fwnode, - bank->nr_pins, ops, ddata); - if (!bank->irq_domain) { - dev_err(dev, "wkup irq domain add failed\n"); - return -ENXIO; - } - - irq = bank->eint_offset; - mask = bank->eint_mask; - for (pin = 0; mask; ++pin, mask >>= 1) { - if (irq >= NUM_EINT) - break; - if (!(mask & 1)) - continue; - eint_data->domains[irq] = bank->irq_domain; - ++irq; - } - } - - return 0; -} - -static const struct samsung_pin_bank_data s3c2412_pin_banks[] __initconst = { - PIN_BANK_A(23, 0x000, "gpa"), - PIN_BANK_2BIT(11, 0x010, "gpb"), - PIN_BANK_2BIT(16, 0x020, "gpc"), - PIN_BANK_2BIT(16, 0x030, "gpd"), - PIN_BANK_2BIT(16, 0x040, "gpe"), - PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff), - PIN_BANK_2BIT_EINTW(16, 0x060, "gpg", 8, 0xffff00), - PIN_BANK_2BIT(11, 0x070, "gph"), - PIN_BANK_2BIT(13, 0x080, "gpj"), -}; - -static const struct samsung_pin_ctrl s3c2412_pin_ctrl[] __initconst = { - { - .pin_banks = s3c2412_pin_banks, - .nr_banks = ARRAY_SIZE(s3c2412_pin_banks), - .eint_wkup_init = s3c24xx_eint_init, - }, -}; - -const struct samsung_pinctrl_of_match_data s3c2412_of_data __initconst = { - .ctrl = s3c2412_pin_ctrl, - .num_ctrl = ARRAY_SIZE(s3c2412_pin_ctrl), -}; - -static const struct samsung_pin_bank_data s3c2416_pin_banks[] __initconst = { - PIN_BANK_A(27, 0x000, "gpa"), - PIN_BANK_2BIT(11, 0x010, "gpb"), - PIN_BANK_2BIT(16, 0x020, "gpc"), - PIN_BANK_2BIT(16, 0x030, "gpd"), - PIN_BANK_2BIT(16, 0x040, "gpe"), - PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff), - PIN_BANK_2BIT_EINTW(8, 0x060, "gpg", 8, 0xff00), - PIN_BANK_2BIT(15, 0x070, "gph"), - PIN_BANK_2BIT(16, 0x0e0, "gpk"), - PIN_BANK_2BIT(14, 0x0f0, "gpl"), - PIN_BANK_2BIT(2, 0x100, "gpm"), -}; - -static const struct samsung_pin_ctrl s3c2416_pin_ctrl[] __initconst = { - { - .pin_banks = s3c2416_pin_banks, - .nr_banks = ARRAY_SIZE(s3c2416_pin_banks), - .eint_wkup_init = s3c24xx_eint_init, - }, -}; - -const struct samsung_pinctrl_of_match_data s3c2416_of_data __initconst = { - .ctrl = s3c2416_pin_ctrl, - .num_ctrl = ARRAY_SIZE(s3c2416_pin_ctrl), -}; - -static const struct samsung_pin_bank_data s3c2440_pin_banks[] __initconst = { - PIN_BANK_A(25, 0x000, "gpa"), - PIN_BANK_2BIT(11, 0x010, "gpb"), - PIN_BANK_2BIT(16, 0x020, "gpc"), - PIN_BANK_2BIT(16, 0x030, "gpd"), - PIN_BANK_2BIT(16, 0x040, "gpe"), - PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff), - PIN_BANK_2BIT_EINTW(16, 0x060, "gpg", 8, 0xffff00), - PIN_BANK_2BIT(11, 0x070, "gph"), - PIN_BANK_2BIT(13, 0x0d0, "gpj"), -}; - -static const struct samsung_pin_ctrl s3c2440_pin_ctrl[] __initconst = { - { - .pin_banks = s3c2440_pin_banks, - .nr_banks = ARRAY_SIZE(s3c2440_pin_banks), - .eint_wkup_init = s3c24xx_eint_init, - }, -}; - -const struct samsung_pinctrl_of_match_data s3c2440_of_data __initconst = { - .ctrl = s3c2440_pin_ctrl, - .num_ctrl = ARRAY_SIZE(s3c2440_pin_ctrl), -}; - -static const struct samsung_pin_bank_data s3c2450_pin_banks[] __initconst = { - PIN_BANK_A(28, 0x000, "gpa"), - PIN_BANK_2BIT(11, 0x010, "gpb"), - PIN_BANK_2BIT(16, 0x020, "gpc"), - PIN_BANK_2BIT(16, 0x030, "gpd"), - PIN_BANK_2BIT(16, 0x040, "gpe"), - PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff), - PIN_BANK_2BIT_EINTW(16, 0x060, "gpg", 8, 0xffff00), - PIN_BANK_2BIT(15, 0x070, "gph"), - PIN_BANK_2BIT(16, 0x0d0, "gpj"), - PIN_BANK_2BIT(16, 0x0e0, "gpk"), - PIN_BANK_2BIT(15, 0x0f0, "gpl"), - PIN_BANK_2BIT(2, 0x100, "gpm"), -}; - -static const struct samsung_pin_ctrl s3c2450_pin_ctrl[] __initconst = { - { - .pin_banks = s3c2450_pin_banks, - .nr_banks = ARRAY_SIZE(s3c2450_pin_banks), - .eint_wkup_init = s3c24xx_eint_init, - }, -}; - -const struct samsung_pinctrl_of_match_data s3c2450_of_data __initconst = { - .ctrl = s3c2450_pin_ctrl, - .num_ctrl = ARRAY_SIZE(s3c2450_pin_ctrl), -}; diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 5736761927cb..514001e448b9 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -1324,16 +1324,6 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { { .compatible = "samsung,s3c64xx-pinctrl", .data = &s3c64xx_of_data }, #endif -#ifdef CONFIG_PINCTRL_S3C24XX - { .compatible = "samsung,s3c2412-pinctrl", - .data = &s3c2412_of_data }, - { .compatible = "samsung,s3c2416-pinctrl", - .data = &s3c2416_of_data }, - { .compatible = "samsung,s3c2440-pinctrl", - .data = &s3c2440_of_data }, - { .compatible = "samsung,s3c2450-pinctrl", - .data = &s3c2450_of_data }, -#endif {}, }; diff --git a/drivers/pinctrl/sunplus/sppctl.c b/drivers/pinctrl/sunplus/sppctl.c index 2b3335ab56c6..25101293268f 100644 --- a/drivers/pinctrl/sunplus/sppctl.c +++ b/drivers/pinctrl/sunplus/sppctl.c @@ -499,7 +499,6 @@ static int sppctl_gpio_set_config(struct gpio_chip *chip, unsigned int offset, return 0; } -#ifdef CONFIG_DEBUG_FS static void sppctl_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) { const char *label; @@ -521,7 +520,6 @@ static void sppctl_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) seq_puts(s, "\n"); } } -#endif static int sppctl_gpio_new(struct platform_device *pdev, struct sppctl_pdata *pctl) { @@ -550,9 +548,8 @@ static int sppctl_gpio_new(struct platform_device *pdev, struct sppctl_pdata *pc gchip->get = sppctl_gpio_get; gchip->set = sppctl_gpio_set; gchip->set_config = sppctl_gpio_set_config; -#ifdef CONFIG_DEBUG_FS - gchip->dbg_show = sppctl_gpio_dbg_show; -#endif + gchip->dbg_show = IS_ENABLED(CONFIG_DEBUG_FS) ? + sppctl_gpio_dbg_show : NULL; gchip->base = -1; gchip->ngpio = sppctl_gpio_list_sz; gchip->names = sppctl_gpio_list_s; diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c index 43e765199137..c6537a1b3a2e 100644 --- a/drivers/platform/surface/aggregator/controller.c +++ b/drivers/platform/surface/aggregator/controller.c @@ -1700,8 +1700,10 @@ int ssam_request_sync(struct ssam_controller *ctrl, return status; status = ssam_request_sync_init(rqst, spec->flags); - if (status) + if (status) { + ssam_request_sync_free(rqst); return status; + } ssam_request_sync_set_resp(rqst, rsp); diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c index f5565570f16c..69132976d297 100644 --- a/drivers/platform/surface/aggregator/ssh_request_layer.c +++ b/drivers/platform/surface/aggregator/ssh_request_layer.c @@ -916,6 +916,20 @@ static void ssh_rtl_rx_command(struct ssh_ptl *p, const struct ssam_span *data) if (sshp_parse_command(dev, data, &command, &command_data)) return; + /* + * Check if the message was intended for us. If not, drop it. + * + * Note: We will need to change this to handle debug messages. On newer + * generation devices, these seem to be sent to tid_out=0x03. We as + * host can still receive them as they can be forwarded via an override + * option on SAM, but doing so does not change tid_out=0x00. + */ + if (command->tid_out != 0x00) { + rtl_warn(rtl, "rtl: dropping message not intended for us (tid = %#04x)\n", + command->tid_out); + return; + } + if (ssh_rqid_is_event(get_unaligned_le16(&command->rqid))) ssh_rtl_rx_event(rtl, command, &command_data); else diff --git a/drivers/platform/x86/amd/Kconfig b/drivers/platform/x86/amd/Kconfig index a825af8126c8..2ce8cb2170df 100644 --- a/drivers/platform/x86/amd/Kconfig +++ b/drivers/platform/x86/amd/Kconfig @@ -8,6 +8,7 @@ source "drivers/platform/x86/amd/pmf/Kconfig" config AMD_PMC tristate "AMD SoC PMC driver" depends on ACPI && PCI && RTC_CLASS + select SERIO help The driver provides support for AMD Power Management Controller primarily responsible for S2Idle transactions that are driven from diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index 439d282aafd1..3cbb01ec10e3 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -22,6 +22,7 @@ #include <linux/pci.h> #include <linux/platform_device.h> #include <linux/rtc.h> +#include <linux/serio.h> #include <linux/suspend.h> #include <linux/seq_file.h> #include <linux/uaccess.h> @@ -160,6 +161,10 @@ static bool enable_stb; module_param(enable_stb, bool, 0644); MODULE_PARM_DESC(enable_stb, "Enable the STB debug mechanism"); +static bool disable_workarounds; +module_param(disable_workarounds, bool, 0644); +MODULE_PARM_DESC(disable_workarounds, "Disable workarounds for platform bugs"); + static struct amd_pmc_dev pmc; static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret); static int amd_pmc_read_stb(struct amd_pmc_dev *dev, u32 *buf); @@ -653,6 +658,33 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev) return -EINVAL; } +static int amd_pmc_czn_wa_irq1(struct amd_pmc_dev *pdev) +{ + struct device *d; + int rc; + + if (!pdev->major) { + rc = amd_pmc_get_smu_version(pdev); + if (rc) + return rc; + } + + if (pdev->major > 64 || (pdev->major == 64 && pdev->minor > 65)) + return 0; + + d = bus_find_device_by_name(&serio_bus, NULL, "serio0"); + if (!d) + return 0; + if (device_may_wakeup(d)) { + dev_info_once(d, "Disabling IRQ1 wakeup source to avoid platform firmware bug\n"); + disable_irq_wake(1); + device_set_wakeup_enable(d, false); + } + put_device(d); + + return 0; +} + static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg) { struct rtc_device *rtc_device; @@ -715,8 +747,8 @@ static void amd_pmc_s2idle_prepare(void) /* Reset and Start SMU logging - to monitor the s0i3 stats */ amd_pmc_setup_smu_logging(pdev); - /* Activate CZN specific RTC functionality */ - if (pdev->cpu_id == AMD_CPU_ID_CZN) { + /* Activate CZN specific platform bug workarounds */ + if (pdev->cpu_id == AMD_CPU_ID_CZN && !disable_workarounds) { rc = amd_pmc_verify_czn_rtc(pdev, &arg); if (rc) { dev_err(pdev->dev, "failed to set RTC: %d\n", rc); @@ -782,6 +814,25 @@ static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = { .check = amd_pmc_s2idle_check, .restore = amd_pmc_s2idle_restore, }; + +static int __maybe_unused amd_pmc_suspend_handler(struct device *dev) +{ + struct amd_pmc_dev *pdev = dev_get_drvdata(dev); + + if (pdev->cpu_id == AMD_CPU_ID_CZN && !disable_workarounds) { + int rc = amd_pmc_czn_wa_irq1(pdev); + + if (rc) { + dev_err(pdev->dev, "failed to adjust keyboard wakeup: %d\n", rc); + return rc; + } + } + + return 0; +} + +static SIMPLE_DEV_PM_OPS(amd_pmc_pm, amd_pmc_suspend_handler, NULL); + #endif static const struct pci_device_id pmc_pci_ids[] = { @@ -932,7 +983,7 @@ static int amd_pmc_probe(struct platform_device *pdev) if (enable_stb && (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB)) { err = amd_pmc_s2d_init(dev); if (err) - return err; + goto err_pci_dev_put; } platform_set_drvdata(pdev, dev); @@ -980,6 +1031,9 @@ static struct platform_driver amd_pmc_driver = { .name = "amd_pmc", .acpi_match_table = amd_pmc_acpi_ids, .dev_groups = pmc_groups, +#ifdef CONFIG_SUSPEND + .pm = &amd_pmc_pm, +#endif }, .probe = amd_pmc_probe, .remove = amd_pmc_remove, diff --git a/drivers/platform/x86/amd/pmf/auto-mode.c b/drivers/platform/x86/amd/pmf/auto-mode.c index 644af42e07cf..96a8e1832c05 100644 --- a/drivers/platform/x86/amd/pmf/auto-mode.c +++ b/drivers/platform/x86/amd/pmf/auto-mode.c @@ -275,13 +275,8 @@ int amd_pmf_reset_amt(struct amd_pmf_dev *dev) */ if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { - int mode = amd_pmf_get_pprof_modes(dev); - - if (mode < 0) - return mode; - dev_dbg(dev->dev, "resetting AMT thermals\n"); - amd_pmf_update_slider(dev, SLIDER_OP_SET, mode, NULL); + amd_pmf_set_sps_power_limits(dev); } return 0; } @@ -299,7 +294,5 @@ void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev) void amd_pmf_init_auto_mode(struct amd_pmf_dev *dev) { amd_pmf_load_defaults_auto_mode(dev); - /* update the thermal limits for Automode */ - amd_pmf_set_automode(dev, config_store.current_mode, NULL); amd_pmf_init_metrics_table(dev); } diff --git a/drivers/platform/x86/amd/pmf/cnqf.c b/drivers/platform/x86/amd/pmf/cnqf.c index 3f9731a2ac28..4beb22a19466 100644 --- a/drivers/platform/x86/amd/pmf/cnqf.c +++ b/drivers/platform/x86/amd/pmf/cnqf.c @@ -103,7 +103,7 @@ int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_l src = amd_pmf_cnqf_get_power_source(dev); - if (dev->current_profile == PLATFORM_PROFILE_BALANCED) { + if (is_pprof_balanced(dev)) { amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL); } else { /* @@ -307,13 +307,9 @@ static ssize_t cnqf_enable_store(struct device *dev, const char *buf, size_t count) { struct amd_pmf_dev *pdev = dev_get_drvdata(dev); - int mode, result, src; + int result, src; bool input; - mode = amd_pmf_get_pprof_modes(pdev); - if (mode < 0) - return mode; - result = kstrtobool(buf, &input); if (result) return result; @@ -321,11 +317,11 @@ static ssize_t cnqf_enable_store(struct device *dev, src = amd_pmf_cnqf_get_power_source(pdev); pdev->cnqf_enabled = input; - if (pdev->cnqf_enabled && pdev->current_profile == PLATFORM_PROFILE_BALANCED) { + if (pdev->cnqf_enabled && is_pprof_balanced(pdev)) { amd_pmf_set_cnqf(pdev, src, config_store.current_mode, NULL); } else { if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) - amd_pmf_update_slider(pdev, SLIDER_OP_SET, mode, NULL); + amd_pmf_set_sps_power_limits(pdev); } dev_dbg(pdev->dev, "Received CnQF %s\n", input ? "on" : "off"); @@ -386,7 +382,7 @@ int amd_pmf_init_cnqf(struct amd_pmf_dev *dev) dev->cnqf_enabled = amd_pmf_check_flags(dev); /* update the thermal for CnQF */ - if (dev->cnqf_enabled && dev->current_profile == PLATFORM_PROFILE_BALANCED) { + if (dev->cnqf_enabled && is_pprof_balanced(dev)) { src = amd_pmf_cnqf_get_power_source(dev); amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL); } diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index a5f5a4bcff6d..da23639071d7 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -58,6 +58,25 @@ static bool force_load; module_param(force_load, bool, 0444); MODULE_PARM_DESC(force_load, "Force load this driver on supported older platforms (experimental)"); +static int amd_pmf_pwr_src_notify_call(struct notifier_block *nb, unsigned long event, void *data) +{ + struct amd_pmf_dev *pmf = container_of(nb, struct amd_pmf_dev, pwr_src_notifier); + + if (event != PSY_EVENT_PROP_CHANGED) + return NOTIFY_OK; + + if (is_apmf_func_supported(pmf, APMF_FUNC_AUTO_MODE) || + is_apmf_func_supported(pmf, APMF_FUNC_DYN_SLIDER_DC) || + is_apmf_func_supported(pmf, APMF_FUNC_DYN_SLIDER_AC)) { + if ((pmf->amt_enabled || pmf->cnqf_enabled) && is_pprof_balanced(pmf)) + return NOTIFY_DONE; + } + + amd_pmf_set_sps_power_limits(pmf); + + return NOTIFY_OK; +} + static int current_power_limits_show(struct seq_file *seq, void *unused) { struct amd_pmf_dev *dev = seq->private; @@ -366,14 +385,18 @@ static int amd_pmf_probe(struct platform_device *pdev) if (!dev->regbase) return -ENOMEM; + mutex_init(&dev->lock); + mutex_init(&dev->update_mutex); + apmf_acpi_init(dev); platform_set_drvdata(pdev, dev); amd_pmf_init_features(dev); apmf_install_handler(dev); amd_pmf_dbgfs_register(dev); - mutex_init(&dev->lock); - mutex_init(&dev->update_mutex); + dev->pwr_src_notifier.notifier_call = amd_pmf_pwr_src_notify_call; + power_supply_reg_notifier(&dev->pwr_src_notifier); + dev_info(dev->dev, "registered PMF device successfully\n"); return 0; @@ -383,11 +406,12 @@ static int amd_pmf_remove(struct platform_device *pdev) { struct amd_pmf_dev *dev = platform_get_drvdata(pdev); - mutex_destroy(&dev->lock); - mutex_destroy(&dev->update_mutex); + power_supply_unreg_notifier(&dev->pwr_src_notifier); amd_pmf_deinit_features(dev); apmf_acpi_deinit(dev); amd_pmf_dbgfs_unregister(dev); + mutex_destroy(&dev->lock); + mutex_destroy(&dev->update_mutex); kfree(dev->buf); return 0; } diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index 84bbe2c6ea61..06c30cdc0573 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -169,6 +169,7 @@ struct amd_pmf_dev { struct mutex update_mutex; /* protects race between ACPI handler and metrics thread */ bool cnqf_enabled; bool cnqf_supported; + struct notifier_block pwr_src_notifier; }; struct apmf_sps_prop_granular { @@ -391,9 +392,11 @@ int amd_pmf_init_sps(struct amd_pmf_dev *dev); void amd_pmf_deinit_sps(struct amd_pmf_dev *dev); int apmf_get_static_slider_granular(struct amd_pmf_dev *pdev, struct apmf_static_slider_granular_output *output); +bool is_pprof_balanced(struct amd_pmf_dev *pmf); int apmf_update_fan_idx(struct amd_pmf_dev *pdev, bool manual, u32 idx); +int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf); /* Auto Mode Layer */ int apmf_get_auto_mode_def(struct amd_pmf_dev *pdev, struct apmf_auto_mode *data); diff --git a/drivers/platform/x86/amd/pmf/sps.c b/drivers/platform/x86/amd/pmf/sps.c index dba7e36962dc..bed762d47a14 100644 --- a/drivers/platform/x86/amd/pmf/sps.c +++ b/drivers/platform/x86/amd/pmf/sps.c @@ -70,6 +70,24 @@ void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx, } } +int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf) +{ + int mode; + + mode = amd_pmf_get_pprof_modes(pmf); + if (mode < 0) + return mode; + + amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL); + + return 0; +} + +bool is_pprof_balanced(struct amd_pmf_dev *pmf) +{ + return (pmf->current_profile == PLATFORM_PROFILE_BALANCED) ? true : false; +} + static int amd_pmf_profile_get(struct platform_profile_handler *pprof, enum platform_profile_option *profile) { @@ -105,15 +123,10 @@ static int amd_pmf_profile_set(struct platform_profile_handler *pprof, enum platform_profile_option profile) { struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); - int mode; pmf->current_profile = profile; - mode = amd_pmf_get_pprof_modes(pmf); - if (mode < 0) - return mode; - amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL); - return 0; + return amd_pmf_set_sps_power_limits(pmf); } int amd_pmf_init_sps(struct amd_pmf_dev *dev) @@ -123,6 +136,9 @@ int amd_pmf_init_sps(struct amd_pmf_dev *dev) dev->current_profile = PLATFORM_PROFILE_BALANCED; amd_pmf_load_defaults_sps(dev); + /* update SPS balanced power mode thermals */ + amd_pmf_set_sps_power_limits(dev); + dev->pprof.profile_get = amd_pmf_profile_get; dev->pprof.profile_set = amd_pmf_profile_set; diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index ca33df7ea550..9333f82cfa8a 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c @@ -64,29 +64,6 @@ struct apple_gmux_data { static struct apple_gmux_data *apple_gmux_data; -/* - * gmux port offsets. Many of these are not yet used, but may be in the - * future, and it's useful to have them documented here anyhow. - */ -#define GMUX_PORT_VERSION_MAJOR 0x04 -#define GMUX_PORT_VERSION_MINOR 0x05 -#define GMUX_PORT_VERSION_RELEASE 0x06 -#define GMUX_PORT_SWITCH_DISPLAY 0x10 -#define GMUX_PORT_SWITCH_GET_DISPLAY 0x11 -#define GMUX_PORT_INTERRUPT_ENABLE 0x14 -#define GMUX_PORT_INTERRUPT_STATUS 0x16 -#define GMUX_PORT_SWITCH_DDC 0x28 -#define GMUX_PORT_SWITCH_EXTERNAL 0x40 -#define GMUX_PORT_SWITCH_GET_EXTERNAL 0x41 -#define GMUX_PORT_DISCRETE_POWER 0x50 -#define GMUX_PORT_MAX_BRIGHTNESS 0x70 -#define GMUX_PORT_BRIGHTNESS 0x74 -#define GMUX_PORT_VALUE 0xc2 -#define GMUX_PORT_READ 0xd0 -#define GMUX_PORT_WRITE 0xd4 - -#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4) - #define GMUX_INTERRUPT_ENABLE 0xff #define GMUX_INTERRUPT_DISABLE 0x00 @@ -249,23 +226,6 @@ static void gmux_write32(struct apple_gmux_data *gmux_data, int port, gmux_pio_write32(gmux_data, port, val); } -static bool gmux_is_indexed(struct apple_gmux_data *gmux_data) -{ - u16 val; - - outb(0xaa, gmux_data->iostart + 0xcc); - outb(0x55, gmux_data->iostart + 0xcd); - outb(0x00, gmux_data->iostart + 0xce); - - val = inb(gmux_data->iostart + 0xcc) | - (inb(gmux_data->iostart + 0xcd) << 8); - - if (val == 0x55aa) - return true; - - return false; -} - /** * DOC: Backlight control * @@ -605,60 +565,43 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) int ret = -ENXIO; acpi_status status; unsigned long long gpe; + bool indexed = false; + u32 version; if (apple_gmux_data) return -EBUSY; + if (!apple_gmux_detect(pnp, &indexed)) { + pr_info("gmux device not present\n"); + return -ENODEV; + } + gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL); if (!gmux_data) return -ENOMEM; pnp_set_drvdata(pnp, gmux_data); res = pnp_get_resource(pnp, IORESOURCE_IO, 0); - if (!res) { - pr_err("Failed to find gmux I/O resource\n"); - goto err_free; - } - gmux_data->iostart = res->start; gmux_data->iolen = resource_size(res); - if (gmux_data->iolen < GMUX_MIN_IO_LEN) { - pr_err("gmux I/O region too small (%lu < %u)\n", - gmux_data->iolen, GMUX_MIN_IO_LEN); - goto err_free; - } - if (!request_region(gmux_data->iostart, gmux_data->iolen, "Apple gmux")) { pr_err("gmux I/O already in use\n"); goto err_free; } - /* - * Invalid version information may indicate either that the gmux - * device isn't present or that it's a new one that uses indexed - * io - */ - - ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR); - ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR); - ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE); - if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) { - if (gmux_is_indexed(gmux_data)) { - u32 version; - mutex_init(&gmux_data->index_lock); - gmux_data->indexed = true; - version = gmux_read32(gmux_data, - GMUX_PORT_VERSION_MAJOR); - ver_major = (version >> 24) & 0xff; - ver_minor = (version >> 16) & 0xff; - ver_release = (version >> 8) & 0xff; - } else { - pr_info("gmux device not present\n"); - ret = -ENODEV; - goto err_release; - } + if (indexed) { + mutex_init(&gmux_data->index_lock); + gmux_data->indexed = true; + version = gmux_read32(gmux_data, GMUX_PORT_VERSION_MAJOR); + ver_major = (version >> 24) & 0xff; + ver_minor = (version >> 16) & 0xff; + ver_release = (version >> 8) & 0xff; + } else { + ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR); + ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR); + ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE); } pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor, ver_release, (gmux_data->indexed ? "indexed" : "classic")); diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index c685a705b73d..cb15acdf14a3 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -121,6 +121,10 @@ static struct quirk_entry quirk_asus_tablet_mode = { .tablet_switch_mode = asus_wmi_lid_flip_rog_devid, }; +static struct quirk_entry quirk_asus_ignore_fan = { + .wmi_ignore_fan = true, +}; + static int dmi_matched(const struct dmi_system_id *dmi) { pr_info("Identified laptop model '%s'\n", dmi->ident); @@ -473,6 +477,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_tablet_mode, }, + { + .callback = dmi_matched, + .ident = "ASUS VivoBook E410MA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "E410MA"), + }, + .driver_data = &quirk_asus_ignore_fan, + }, {}, }; @@ -511,6 +524,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0x30, { KEY_VOLUMEUP } }, { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, { KE_KEY, 0x32, { KEY_MUTE } }, + { KE_KEY, 0x33, { KEY_SCREENLOCK } }, { KE_KEY, 0x35, { KEY_SCREENLOCK } }, { KE_KEY, 0x38, { KEY_PROG3 } }, /* Armoury Crate */ { KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, @@ -544,6 +558,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */ { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */ { KE_KEY, 0x82, { KEY_CAMERA } }, + { KE_KEY, 0x85, { KEY_CAMERA } }, { KE_KEY, 0x86, { KEY_PROG1 } }, /* MyASUS Key */ { KE_KEY, 0x88, { KEY_RFKILL } }, /* Radio Toggle Key */ { KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */ diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 6f81b2844dcb..1038dfdcdd32 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -225,6 +225,7 @@ struct asus_wmi { int tablet_switch_event_code; u32 tablet_switch_dev_id; + bool tablet_switch_inverted; enum fan_type fan_type; enum fan_type gpu_fan_type; @@ -493,6 +494,13 @@ static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id) } /* Input **********************************************************************/ +static void asus_wmi_tablet_sw_report(struct asus_wmi *asus, bool value) +{ + input_report_switch(asus->inputdev, SW_TABLET_MODE, + asus->tablet_switch_inverted ? !value : value); + input_sync(asus->inputdev); +} + static void asus_wmi_tablet_sw_init(struct asus_wmi *asus, u32 dev_id, int event_code) { struct device *dev = &asus->platform_device->dev; @@ -501,7 +509,7 @@ static void asus_wmi_tablet_sw_init(struct asus_wmi *asus, u32 dev_id, int event result = asus_wmi_get_devstate_simple(asus, dev_id); if (result >= 0) { input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE); - input_report_switch(asus->inputdev, SW_TABLET_MODE, result); + asus_wmi_tablet_sw_report(asus, result); asus->tablet_switch_dev_id = dev_id; asus->tablet_switch_event_code = event_code; } else if (result == -ENODEV) { @@ -534,6 +542,7 @@ static int asus_wmi_input_init(struct asus_wmi *asus) case asus_wmi_no_tablet_switch: break; case asus_wmi_kbd_dock_devid: + asus->tablet_switch_inverted = true; asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_KBD_DOCK, NOTIFY_KBD_DOCK_CHANGE); break; case asus_wmi_lid_flip_devid: @@ -573,10 +582,8 @@ static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus) return; result = asus_wmi_get_devstate_simple(asus, asus->tablet_switch_dev_id); - if (result >= 0) { - input_report_switch(asus->inputdev, SW_TABLET_MODE, result); - input_sync(asus->inputdev); - } + if (result >= 0) + asus_wmi_tablet_sw_report(asus, result); } /* dGPU ********************************************************************/ @@ -2243,7 +2250,9 @@ static int asus_wmi_fan_init(struct asus_wmi *asus) asus->fan_type = FAN_TYPE_NONE; asus->agfn_pwm = -1; - if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL)) + if (asus->driver->quirks->wmi_ignore_fan) + asus->fan_type = FAN_TYPE_NONE; + else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL)) asus->fan_type = FAN_TYPE_SPEC83; else if (asus_wmi_has_agfn_fan(asus)) asus->fan_type = FAN_TYPE_AGFN; @@ -2436,6 +2445,9 @@ static int fan_curve_check_present(struct asus_wmi *asus, bool *available, *available = false; + if (asus->fan_type == FAN_TYPE_NONE) + return 0; + err = fan_curve_get_factory_default(asus, fan_dev); if (err) { return 0; diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 65316998b898..a478ebfd34df 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -38,6 +38,7 @@ struct quirk_entry { bool store_backlight_power; bool wmi_backlight_set_devstate; bool wmi_force_als_set; + bool wmi_ignore_fan; enum asus_wmi_tablet_switch_mode tablet_switch_mode; int wapf; /* diff --git a/drivers/platform/x86/dell/dell-wmi-base.c b/drivers/platform/x86/dell/dell-wmi-base.c index 0a259a27459f..502783a7adb1 100644 --- a/drivers/platform/x86/dell/dell-wmi-base.c +++ b/drivers/platform/x86/dell/dell-wmi-base.c @@ -261,6 +261,9 @@ static const struct key_entry dell_wmi_keymap_type_0010[] = { { KE_KEY, 0x57, { KEY_BRIGHTNESSDOWN } }, { KE_KEY, 0x58, { KEY_BRIGHTNESSUP } }, + /*Speaker Mute*/ + { KE_KEY, 0x109, { KEY_MUTE} }, + /* Mic mute */ { KE_KEY, 0x150, { KEY_MICMUTE } }, diff --git a/drivers/platform/x86/dell/dell-wmi-privacy.c b/drivers/platform/x86/dell/dell-wmi-privacy.c index c82b3d6867c5..c517bd45dd32 100644 --- a/drivers/platform/x86/dell/dell-wmi-privacy.c +++ b/drivers/platform/x86/dell/dell-wmi-privacy.c @@ -61,7 +61,7 @@ static const struct key_entry dell_wmi_keymap_type_0012[] = { /* privacy mic mute */ { KE_KEY, 0x0001, { KEY_MICMUTE } }, /* privacy camera mute */ - { KE_SW, 0x0002, { SW_CAMERA_LENS_COVER } }, + { KE_VSW, 0x0002, { SW_CAMERA_LENS_COVER } }, { KE_END, 0}, }; @@ -115,11 +115,15 @@ bool dell_privacy_process_event(int type, int code, int status) switch (code) { case DELL_PRIVACY_AUDIO_EVENT: /* Mic mute */ - case DELL_PRIVACY_CAMERA_EVENT: /* Camera mute */ priv->last_status = status; sparse_keymap_report_entry(priv->input_dev, key, 1, true); ret = true; break; + case DELL_PRIVACY_CAMERA_EVENT: /* Camera mute */ + priv->last_status = status; + sparse_keymap_report_entry(priv->input_dev, key, !(status & CAMERA_STATUS), false); + ret = true; + break; default: dev_dbg(&priv->wdev->dev, "unknown event type 0x%04x 0x%04x\n", type, code); } @@ -292,7 +296,7 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context) { struct privacy_wmi_data *priv; struct key_entry *keymap; - int ret, i; + int ret, i, j; ret = wmi_has_guid(DELL_PRIVACY_GUID); if (!ret) @@ -304,6 +308,11 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context) dev_set_drvdata(&wdev->dev, priv); priv->wdev = wdev; + + ret = get_current_status(priv->wdev); + if (ret) + return ret; + /* create evdev passing interface */ priv->input_dev = devm_input_allocate_device(&wdev->dev); if (!priv->input_dev) @@ -318,9 +327,20 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context) /* remap the keymap code with Dell privacy key type 0x12 as prefix * KEY_MICMUTE scancode will be reported as 0x120001 */ - for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) { - keymap[i] = dell_wmi_keymap_type_0012[i]; - keymap[i].code |= (0x0012 << 16); + for (i = 0, j = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) { + /* + * Unlike keys where only presses matter, userspace may act + * on switches in both of their positions. Only register + * SW_CAMERA_LENS_COVER if it is actually there. + */ + if (dell_wmi_keymap_type_0012[i].type == KE_VSW && + dell_wmi_keymap_type_0012[i].sw.code == SW_CAMERA_LENS_COVER && + !(priv->features_present & BIT(DELL_PRIVACY_TYPE_CAMERA))) + continue; + + keymap[j] = dell_wmi_keymap_type_0012[i]; + keymap[j].code |= (0x0012 << 16); + j++; } ret = sparse_keymap_setup(priv->input_dev, keymap, NULL); kfree(keymap); @@ -331,11 +351,12 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context) priv->input_dev->name = "Dell Privacy Driver"; priv->input_dev->id.bustype = BUS_HOST; - ret = input_register_device(priv->input_dev); - if (ret) - return ret; + /* Report initial camera-cover status */ + if (priv->features_present & BIT(DELL_PRIVACY_TYPE_CAMERA)) + input_report_switch(priv->input_dev, SW_CAMERA_LENS_COVER, + !(priv->last_status & CAMERA_STATUS)); - ret = get_current_status(priv->wdev); + ret = input_register_device(priv->input_dev); if (ret) return ret; diff --git a/drivers/platform/x86/gigabyte-wmi.c b/drivers/platform/x86/gigabyte-wmi.c index 5e7e6659a849..322cfaeda17b 100644 --- a/drivers/platform/x86/gigabyte-wmi.c +++ b/drivers/platform/x86/gigabyte-wmi.c @@ -141,6 +141,7 @@ static u8 gigabyte_wmi_detect_sensor_usability(struct wmi_device *wdev) static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = { DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M DS3H-CF"), + DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M DS3H WIFI-CF"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M S2H V2"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE AX V2"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE"), diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c index 0a99058be813..2ef201b625b3 100644 --- a/drivers/platform/x86/hp/hp-wmi.c +++ b/drivers/platform/x86/hp/hp-wmi.c @@ -90,6 +90,7 @@ enum hp_wmi_event_ids { HPWMI_PEAKSHIFT_PERIOD = 0x0F, HPWMI_BATTERY_CHARGE_PERIOD = 0x10, HPWMI_SANITIZATION_MODE = 0x17, + HPWMI_OMEN_KEY = 0x1D, HPWMI_SMART_EXPERIENCE_APP = 0x21, }; @@ -216,6 +217,8 @@ static const struct key_entry hp_wmi_keymap[] = { { KE_KEY, 0x213b, { KEY_INFO } }, { KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } }, { KE_KEY, 0x216a, { KEY_SETUP } }, + { KE_KEY, 0x21a5, { KEY_PROG2 } }, /* HP Omen Key */ + { KE_KEY, 0x21a7, { KEY_FN_ESC } }, { KE_KEY, 0x21a9, { KEY_TOUCHPAD_OFF } }, { KE_KEY, 0x121a9, { KEY_TOUCHPAD_ON } }, { KE_KEY, 0x231b, { KEY_HELP } }, @@ -548,7 +551,7 @@ static int __init hp_wmi_enable_hotkeys(void) static int hp_wmi_set_block(void *data, bool blocked) { - enum hp_wmi_radio r = (enum hp_wmi_radio) data; + enum hp_wmi_radio r = (long)data; int query = BIT(r + 8) | ((!blocked) << r); int ret; @@ -810,6 +813,7 @@ static void hp_wmi_notify(u32 value, void *context) case HPWMI_SMART_ADAPTER: break; case HPWMI_BEZEL_BUTTON: + case HPWMI_OMEN_KEY: key_code = hp_wmi_read_int(HPWMI_HOTKEY_QUERY); if (key_code < 0) break; diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 435d2d3d903b..0eb5bfdd823a 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -1621,6 +1621,12 @@ static const struct dmi_system_id set_fn_lock_led_list[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion R7000P2020H"), } }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion 5 15ARH05"), + } + }, {} }; diff --git a/drivers/platform/x86/intel/int3472/clk_and_regulator.c b/drivers/platform/x86/intel/int3472/clk_and_regulator.c index b2342b3d78c7..74dc2cff799e 100644 --- a/drivers/platform/x86/intel/int3472/clk_and_regulator.c +++ b/drivers/platform/x86/intel/int3472/clk_and_regulator.c @@ -181,6 +181,9 @@ int skl_int3472_register_regulator(struct int3472_discrete_device *int3472, return PTR_ERR(int3472->regulator.gpio); } + /* Ensure the pin is in output mode and non-active state */ + gpiod_direction_output(int3472->regulator.gpio, 0); + cfg.dev = &int3472->adev->dev; cfg.init_data = &init_data; cfg.ena_gpiod = int3472->regulator.gpio; diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index 974a132db651..c42c3faa2c32 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -168,6 +168,8 @@ static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472, return (PTR_ERR(gpio)); int3472->clock.ena_gpio = gpio; + /* Ensure the pin is in output mode and non-active state */ + gpiod_direction_output(int3472->clock.ena_gpio, 0); break; case INT3472_GPIO_TYPE_PRIVACY_LED: gpio = acpi_get_and_request_gpiod(path, pin, "int3472,privacy-led"); @@ -175,6 +177,8 @@ static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472, return (PTR_ERR(gpio)); int3472->clock.led_gpio = gpio; + /* Ensure the pin is in output mode and non-active state */ + gpiod_direction_output(int3472->clock.led_gpio, 0); break; default: dev_err(int3472->dev, "Invalid GPIO type 0x%02x for clock\n", type); diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c index f1d802f6ec3f..3a15d32d7644 100644 --- a/drivers/platform/x86/intel/pmc/core.c +++ b/drivers/platform/x86/intel/pmc/core.c @@ -1029,6 +1029,7 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = { X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, adl_core_init), X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, adl_core_init), X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE, mtl_core_init), + X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE_L, mtl_core_init), {} }; diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index bb81b8b1f7e9..89c5374e33b3 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -408,14 +408,23 @@ static const struct intel_vsec_platform_info dg1_info = { .quirks = VSEC_QUIRK_NO_DVSEC | VSEC_QUIRK_EARLY_HW, }; +/* MTL info */ +static const struct intel_vsec_platform_info mtl_info = { + .quirks = VSEC_QUIRK_NO_WATCHER | VSEC_QUIRK_NO_CRASHLOG, +}; + #define PCI_DEVICE_ID_INTEL_VSEC_ADL 0x467d #define PCI_DEVICE_ID_INTEL_VSEC_DG1 0x490e +#define PCI_DEVICE_ID_INTEL_VSEC_MTL_M 0x7d0d +#define PCI_DEVICE_ID_INTEL_VSEC_MTL_S 0xad0d #define PCI_DEVICE_ID_INTEL_VSEC_OOBMSM 0x09a7 #define PCI_DEVICE_ID_INTEL_VSEC_RPL 0xa77d #define PCI_DEVICE_ID_INTEL_VSEC_TGL 0x9a0d static const struct pci_device_id intel_vsec_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, VSEC_ADL, &tgl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_DG1, &dg1_info) }, + { PCI_DEVICE_DATA(INTEL, VSEC_MTL_M, &mtl_info) }, + { PCI_DEVICE_DATA(INTEL, VSEC_MTL_S, &mtl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM, &(struct intel_vsec_platform_info) {}) }, { PCI_DEVICE_DATA(INTEL, VSEC_RPL, &tgl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_TGL, &tgl_info) }, diff --git a/drivers/platform/x86/simatic-ipc.c b/drivers/platform/x86/simatic-ipc.c index ca76076fc706..b3622419cd1a 100644 --- a/drivers/platform/x86/simatic-ipc.c +++ b/drivers/platform/x86/simatic-ipc.c @@ -46,7 +46,8 @@ static struct { {SIMATIC_IPC_IPC427D, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE}, {SIMATIC_IPC_IPC427E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_427E}, {SIMATIC_IPC_IPC477E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_427E}, - {SIMATIC_IPC_IPC427G, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G}, + {SIMATIC_IPC_IPCBX_39A, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G}, + {SIMATIC_IPC_IPCPX_39A, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227G}, }; static int register_platform_devices(u32 station_id) diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 7156ae2ad196..537d6a2d0781 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1887,14 +1887,21 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd, break; } - ret = sony_call_snc_handle(handle, probe_base, &result); - if (ret) - return ret; + /* + * Only probe if there is a separate probe_base, otherwise the probe call + * is equivalent to __sony_nc_kbd_backlight_mode_set(0), resulting in + * the keyboard backlight being turned off. + */ + if (probe_base) { + ret = sony_call_snc_handle(handle, probe_base, &result); + if (ret) + return ret; - if ((handle == 0x0137 && !(result & 0x02)) || - !(result & 0x01)) { - dprintk("no backlight keyboard found\n"); - return 0; + if ((handle == 0x0137 && !(result & 0x02)) || + !(result & 0x01)) { + dprintk("no backlight keyboard found\n"); + return 0; + } } kbdbl_ctl = kzalloc(sizeof(*kbdbl_ctl), GFP_KERNEL); diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 1195293b22fd..32c10457399e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -5563,7 +5563,7 @@ static int light_sysfs_set(struct led_classdev *led_cdev, static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev) { - return (light_get_status() == 1) ? LED_FULL : LED_OFF; + return (light_get_status() == 1) ? LED_ON : LED_OFF; } static struct tpacpi_led_classdev tpacpi_led_thinklight = { @@ -10311,9 +10311,11 @@ static DEFINE_MUTEX(dytc_mutex); static int dytc_capabilities; static bool dytc_mmc_get_available; -static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile) +static int convert_dytc_to_profile(int funcmode, int dytcmode, + enum platform_profile_option *profile) { - if (dytc_capabilities & BIT(DYTC_FC_MMC)) { + switch (funcmode) { + case DYTC_FUNCTION_MMC: switch (dytcmode) { case DYTC_MODE_MMC_LOWPOWER: *profile = PLATFORM_PROFILE_LOW_POWER; @@ -10329,8 +10331,7 @@ static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *p return -EINVAL; } return 0; - } - if (dytc_capabilities & BIT(DYTC_FC_PSC)) { + case DYTC_FUNCTION_PSC: switch (dytcmode) { case DYTC_MODE_PSC_LOWPOWER: *profile = PLATFORM_PROFILE_LOW_POWER; @@ -10344,6 +10345,14 @@ static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *p default: /* Unknown mode */ return -EINVAL; } + return 0; + case DYTC_FUNCTION_AMT: + /* For now return balanced. It's the closest we have to 'auto' */ + *profile = PLATFORM_PROFILE_BALANCED; + return 0; + default: + /* Unknown function */ + return -EOPNOTSUPP; } return 0; } @@ -10487,11 +10496,11 @@ static int dytc_profile_set(struct platform_profile_handler *pprof, if (err) goto unlock; } - } - if (dytc_capabilities & BIT(DYTC_FC_PSC)) { + } else if (dytc_capabilities & BIT(DYTC_FC_PSC)) { err = dytc_command(DYTC_SET_COMMAND(DYTC_FUNCTION_PSC, perfmode, 1), &output); if (err) goto unlock; + /* system supports AMT, activate it when on balanced */ if (dytc_capabilities & BIT(DYTC_FC_AMT)) dytc_control_amt(profile == PLATFORM_PROFILE_BALANCED); @@ -10507,7 +10516,7 @@ static void dytc_profile_refresh(void) { enum platform_profile_option profile; int output, err = 0; - int perfmode; + int perfmode, funcmode; mutex_lock(&dytc_mutex); if (dytc_capabilities & BIT(DYTC_FC_MMC)) { @@ -10515,15 +10524,18 @@ static void dytc_profile_refresh(void) err = dytc_command(DYTC_CMD_MMC_GET, &output); else err = dytc_cql_command(DYTC_CMD_GET, &output); - } else if (dytc_capabilities & BIT(DYTC_FC_PSC)) + funcmode = DYTC_FUNCTION_MMC; + } else if (dytc_capabilities & BIT(DYTC_FC_PSC)) { err = dytc_command(DYTC_CMD_GET, &output); - + /* Check if we are PSC mode, or have AMT enabled */ + funcmode = (output >> DYTC_GET_FUNCTION_BIT) & 0xF; + } mutex_unlock(&dytc_mutex); if (err) return; perfmode = (output >> DYTC_GET_MODE_BIT) & 0xF; - convert_dytc_to_profile(perfmode, &profile); + convert_dytc_to_profile(funcmode, perfmode, &profile); if (profile != dytc_current_profile) { dytc_current_profile = profile; platform_profile_notify(); diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index baae3120efd0..13802a3c3591 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -264,6 +264,23 @@ static const struct ts_dmi_data connect_tablet9_data = { .properties = connect_tablet9_props, }; +static const struct property_entry csl_panther_tab_hd_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 1), + PROPERTY_ENTRY_U32("touchscreen-min-y", 20), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1526), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-csl-panther-tab-hd.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + { } +}; + +static const struct ts_dmi_data csl_panther_tab_hd_data = { + .acpi_name = "MSSL1680:00", + .properties = csl_panther_tab_hd_props, +}; + static const struct property_entry cube_iwork8_air_props[] = { PROPERTY_ENTRY_U32("touchscreen-min-x", 1), PROPERTY_ENTRY_U32("touchscreen-min-y", 3), @@ -1081,6 +1098,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = { }, }, { + /* Chuwi Vi8 (CWI501) */ + .driver_data = (void *)&chuwi_vi8_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "i86"), + DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.W86JLBNR01"), + }, + }, + { /* Chuwi Vi8 (CWI506) */ .driver_data = (void *)&chuwi_vi8_data, .matches = { @@ -1125,6 +1151,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = { }, }, { + /* CSL Panther Tab HD */ + .driver_data = (void *)&csl_panther_tab_hd_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "CSL Computer GmbH & Co. KG"), + DMI_MATCH(DMI_PRODUCT_NAME, "CSL Panther Tab HD"), + }, + }, + { /* CUBE iwork8 Air */ .driver_data = (void *)&cube_iwork8_air_data, .matches = { diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 0bbfe6a7ce4d..e2f8dfcdd2a9 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -28,15 +28,6 @@ config POWER_SUPPLY_HWMON Say 'Y' here if you want power supplies to have hwmon sysfs interface too. - -config PDA_POWER - tristate "Generic PDA/phone power driver" - depends on !S390 - help - Say Y here to enable generic 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. - config APM_POWER tristate "APM emulation for class batteries" depends on APM_EMULATION @@ -195,13 +186,6 @@ config BATTERY_SAMSUNG_SDI Say Y to enable support for Samsung SDI battery data. These batteries are used in Samsung mobile phones. -config BATTERY_TOSA - tristate "Sharp SL-6000 (tosa) battery" - depends on MACH_TOSA && MFD_TC6393XB && TOUCHSCREEN_WM97XX - help - Say Y to enable support for the battery on the Sharp Zaurus - SL-6000 (tosa) models. - config BATTERY_COLLIE tristate "Sharp SL-5500 (collie) battery" depends on SA1100_COLLIE && MCP_UCB1200 @@ -422,18 +406,6 @@ config BATTERY_MAX1721X Say Y here to enable support for the MAX17211/MAX17215 standalone battery gas-gauge. -config BATTERY_Z2 - tristate "Z2 battery driver" - depends on I2C && MACH_ZIPIT2 - help - Say Y to include support for the battery on the Zipit Z2. - -config BATTERY_S3C_ADC - tristate "Battery driver for Samsung ADC based monitoring" - depends on S3C_ADC - help - Say Y here to enable support for iPAQ h1930/h1940/rx1950 battery - config BATTERY_TWL4030_MADC tristate "TWL4030 MADC battery driver" depends on TWL4030_MADC diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 0ee8653e882e..8cb3c7f5c111 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_POWER_SUPPLY) += power_supply.o obj-$(CONFIG_POWER_SUPPLY_HWMON) += power_supply_hwmon.o obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o -obj-$(CONFIG_PDA_POWER) += pda_power.o obj-$(CONFIG_APM_POWER) += apm_power.o obj-$(CONFIG_AXP20X_POWER) += axp20x_usb_power.o obj-$(CONFIG_IP5XXX_POWER) += ip5xxx_power.o @@ -36,7 +35,6 @@ obj-$(CONFIG_BATTERY_LEGO_EV3) += lego_ev3_battery.o obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o obj-$(CONFIG_BATTERY_SAMSUNG_SDI) += samsung-sdi-battery.o -obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o obj-$(CONFIG_BATTERY_INGENIC) += ingenic-battery.o obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o @@ -54,10 +52,8 @@ obj-$(CONFIG_BATTERY_DA9150) += da9150-fg.o obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o obj-$(CONFIG_BATTERY_MAX1721X) += max1721x_battery.o -obj-$(CONFIG_BATTERY_Z2) += z2_battery.o obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o obj-$(CONFIG_CHARGER_RT9455) += rt9455_charger.o -obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o diff --git a/drivers/power/supply/ds2760_battery.c b/drivers/power/supply/ds2760_battery.c index 5f50da524f41..40fba31be174 100644 --- a/drivers/power/supply/ds2760_battery.c +++ b/drivers/power/supply/ds2760_battery.c @@ -227,20 +227,12 @@ static int rated_capacities[] = { 920, /* NEC */ 1440, /* Samsung */ 1440, /* BYD */ -#ifdef CONFIG_MACH_H4700 - 1800, /* HP iPAQ hx4700 3.7V 1800mAh (359113-001) */ -#else 1440, /* Lishen */ -#endif 1440, /* NEC */ 2880, /* Samsung */ 2880, /* BYD */ 2880, /* Lishen */ 2880, /* NEC */ -#ifdef CONFIG_MACH_H4700 - 0, - 3600, /* HP iPAQ hx4700 3.7V 3600mAh (359114-001) */ -#endif }; /* array is level at temps 0°C, 10°C, 20°C, 30°C, 40°C diff --git a/drivers/power/supply/pda_power.c b/drivers/power/supply/pda_power.c deleted file mode 100644 index 03a37fd6be27..000000000000 --- a/drivers/power/supply/pda_power.c +++ /dev/null @@ -1,520 +0,0 @@ -// 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> - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/err.h> -#include <linux/interrupt.h> -#include <linux/notifier.h> -#include <linux/power_supply.h> -#include <linux/pda_power.h> -#include <linux/regulator/consumer.h> -#include <linux/timer.h> -#include <linux/jiffies.h> -#include <linux/usb/otg.h> - -static inline unsigned int get_irq_flags(struct resource *res) -{ - return IRQF_SHARED | (res->flags & IRQF_TRIGGER_MASK); -} - -static struct device *dev; -static struct pda_power_pdata *pdata; -static struct resource *ac_irq, *usb_irq; -static struct delayed_work charger_work; -static struct delayed_work polling_work; -static struct delayed_work supply_work; -static int polling; -static struct power_supply *pda_psy_ac, *pda_psy_usb; - -#if IS_ENABLED(CONFIG_USB_PHY) -static struct usb_phy *transceiver; -static struct notifier_block otg_nb; -#endif - -static struct regulator *ac_draw; - -enum { - PDA_PSY_OFFLINE = 0, - PDA_PSY_ONLINE = 1, - PDA_PSY_TO_CHANGE, -}; -static int new_ac_status = -1; -static int new_usb_status = -1; -static int ac_status = -1; -static int usb_status = -1; - -static int pda_power_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ - switch (psp) { - case POWER_SUPPLY_PROP_ONLINE: - if (psy->desc->type == POWER_SUPPLY_TYPE_MAINS) - val->intval = pdata->is_ac_online ? - pdata->is_ac_online() : 0; - else - val->intval = pdata->is_usb_online ? - pdata->is_usb_online() : 0; - break; - default: - return -EINVAL; - } - return 0; -} - -static enum power_supply_property pda_power_props[] = { - POWER_SUPPLY_PROP_ONLINE, -}; - -static char *pda_power_supplied_to[] = { - "main-battery", - "backup-battery", -}; - -static const struct power_supply_desc pda_psy_ac_desc = { - .name = "ac", - .type = POWER_SUPPLY_TYPE_MAINS, - .properties = pda_power_props, - .num_properties = ARRAY_SIZE(pda_power_props), - .get_property = pda_power_get_property, -}; - -static const struct power_supply_desc pda_psy_usb_desc = { - .name = "usb", - .type = POWER_SUPPLY_TYPE_USB, - .properties = pda_power_props, - .num_properties = ARRAY_SIZE(pda_power_props), - .get_property = pda_power_get_property, -}; - -static void update_status(void) -{ - if (pdata->is_ac_online) - new_ac_status = !!pdata->is_ac_online(); - - if (pdata->is_usb_online) - new_usb_status = !!pdata->is_usb_online(); -} - -static void update_charger(void) -{ - static int regulator_enabled; - int max_uA = pdata->ac_max_uA; - - if (pdata->set_charge) { - if (new_ac_status > 0) { - dev_dbg(dev, "charger on (AC)\n"); - pdata->set_charge(PDA_POWER_CHARGE_AC); - } else if (new_usb_status > 0) { - dev_dbg(dev, "charger on (USB)\n"); - pdata->set_charge(PDA_POWER_CHARGE_USB); - } else { - dev_dbg(dev, "charger off\n"); - pdata->set_charge(0); - } - } else if (ac_draw) { - if (new_ac_status > 0) { - regulator_set_current_limit(ac_draw, max_uA, max_uA); - if (!regulator_enabled) { - dev_dbg(dev, "charger on (AC)\n"); - WARN_ON(regulator_enable(ac_draw)); - regulator_enabled = 1; - } - } else { - if (regulator_enabled) { - dev_dbg(dev, "charger off\n"); - WARN_ON(regulator_disable(ac_draw)); - regulator_enabled = 0; - } - } - } -} - -static void supply_work_func(struct work_struct *work) -{ - if (ac_status == PDA_PSY_TO_CHANGE) { - ac_status = new_ac_status; - power_supply_changed(pda_psy_ac); - } - - if (usb_status == PDA_PSY_TO_CHANGE) { - usb_status = new_usb_status; - power_supply_changed(pda_psy_usb); - } -} - -static void psy_changed(void) -{ - update_charger(); - - /* - * Okay, charger set. Now wait a bit before notifying supplicants, - * charge power should stabilize. - */ - cancel_delayed_work(&supply_work); - schedule_delayed_work(&supply_work, - msecs_to_jiffies(pdata->wait_for_charger)); -} - -static void charger_work_func(struct work_struct *work) -{ - update_status(); - psy_changed(); -} - -static irqreturn_t power_changed_isr(int irq, void *power_supply) -{ - if (power_supply == pda_psy_ac) - ac_status = PDA_PSY_TO_CHANGE; - else if (power_supply == pda_psy_usb) - usb_status = PDA_PSY_TO_CHANGE; - else - return IRQ_NONE; - - /* - * Wait a bit before reading ac/usb line status and setting charger, - * because ac/usb status readings may lag from irq. - */ - cancel_delayed_work(&charger_work); - schedule_delayed_work(&charger_work, - msecs_to_jiffies(pdata->wait_for_status)); - - return IRQ_HANDLED; -} - -static void polling_work_func(struct work_struct *work) -{ - int changed = 0; - - dev_dbg(dev, "polling...\n"); - - update_status(); - - if (!ac_irq && new_ac_status != ac_status) { - ac_status = PDA_PSY_TO_CHANGE; - changed = 1; - } - - if (!usb_irq && new_usb_status != usb_status) { - usb_status = PDA_PSY_TO_CHANGE; - changed = 1; - } - - if (changed) - psy_changed(); - - cancel_delayed_work(&polling_work); - schedule_delayed_work(&polling_work, - msecs_to_jiffies(pdata->polling_interval)); -} - -#if IS_ENABLED(CONFIG_USB_PHY) -static int otg_is_usb_online(void) -{ - return (transceiver->last_event == USB_EVENT_VBUS || - transceiver->last_event == USB_EVENT_ENUMERATED); -} - -static int otg_is_ac_online(void) -{ - return (transceiver->last_event == USB_EVENT_CHARGER); -} - -static int otg_handle_notification(struct notifier_block *nb, - unsigned long event, void *unused) -{ - switch (event) { - case USB_EVENT_CHARGER: - ac_status = PDA_PSY_TO_CHANGE; - break; - case USB_EVENT_VBUS: - case USB_EVENT_ENUMERATED: - usb_status = PDA_PSY_TO_CHANGE; - break; - case USB_EVENT_NONE: - ac_status = PDA_PSY_TO_CHANGE; - usb_status = PDA_PSY_TO_CHANGE; - break; - default: - return NOTIFY_OK; - } - - /* - * Wait a bit before reading ac/usb line status and setting charger, - * because ac/usb status readings may lag from irq. - */ - cancel_delayed_work(&charger_work); - schedule_delayed_work(&charger_work, - msecs_to_jiffies(pdata->wait_for_status)); - - return NOTIFY_OK; -} -#endif - -static int pda_power_probe(struct platform_device *pdev) -{ - struct power_supply_config psy_cfg = {}; - int ret = 0; - - dev = &pdev->dev; - - if (pdev->id != -1) { - dev_err(dev, "it's meaningless to register several " - "pda_powers; use id = -1\n"); - ret = -EINVAL; - goto wrongid; - } - - pdata = pdev->dev.platform_data; - - if (pdata->init) { - ret = pdata->init(dev); - if (ret < 0) - goto init_failed; - } - - ac_draw = regulator_get(dev, "ac_draw"); - if (IS_ERR(ac_draw)) { - dev_dbg(dev, "couldn't get ac_draw regulator\n"); - ac_draw = NULL; - } - - update_status(); - update_charger(); - - if (!pdata->wait_for_status) - pdata->wait_for_status = 500; - - if (!pdata->wait_for_charger) - pdata->wait_for_charger = 500; - - if (!pdata->polling_interval) - pdata->polling_interval = 2000; - - if (!pdata->ac_max_uA) - pdata->ac_max_uA = 500000; - - INIT_DELAYED_WORK(&charger_work, charger_work_func); - INIT_DELAYED_WORK(&supply_work, supply_work_func); - - ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac"); - usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb"); - - if (pdata->supplied_to) { - psy_cfg.supplied_to = pdata->supplied_to; - psy_cfg.num_supplicants = pdata->num_supplicants; - } else { - psy_cfg.supplied_to = pda_power_supplied_to; - psy_cfg.num_supplicants = ARRAY_SIZE(pda_power_supplied_to); - } - -#if IS_ENABLED(CONFIG_USB_PHY) - transceiver = usb_get_phy(USB_PHY_TYPE_USB2); - if (!IS_ERR_OR_NULL(transceiver)) { - if (!pdata->is_usb_online) - pdata->is_usb_online = otg_is_usb_online; - if (!pdata->is_ac_online) - pdata->is_ac_online = otg_is_ac_online; - } -#endif - - if (pdata->is_ac_online) { - pda_psy_ac = power_supply_register(&pdev->dev, - &pda_psy_ac_desc, &psy_cfg); - if (IS_ERR(pda_psy_ac)) { - dev_err(dev, "failed to register %s power supply\n", - pda_psy_ac_desc.name); - ret = PTR_ERR(pda_psy_ac); - goto ac_supply_failed; - } - - if (ac_irq) { - ret = request_irq(ac_irq->start, power_changed_isr, - get_irq_flags(ac_irq), ac_irq->name, - pda_psy_ac); - if (ret) { - dev_err(dev, "request ac irq failed\n"); - goto ac_irq_failed; - } - } else { - polling = 1; - } - } - - if (pdata->is_usb_online) { - pda_psy_usb = power_supply_register(&pdev->dev, - &pda_psy_usb_desc, - &psy_cfg); - if (IS_ERR(pda_psy_usb)) { - dev_err(dev, "failed to register %s power supply\n", - pda_psy_usb_desc.name); - ret = PTR_ERR(pda_psy_usb); - goto usb_supply_failed; - } - - if (usb_irq) { - ret = request_irq(usb_irq->start, power_changed_isr, - get_irq_flags(usb_irq), - usb_irq->name, pda_psy_usb); - if (ret) { - dev_err(dev, "request usb irq failed\n"); - goto usb_irq_failed; - } - } else { - polling = 1; - } - } - -#if IS_ENABLED(CONFIG_USB_PHY) - if (!IS_ERR_OR_NULL(transceiver) && pdata->use_otg_notifier) { - otg_nb.notifier_call = otg_handle_notification; - ret = usb_register_notifier(transceiver, &otg_nb); - if (ret) { - dev_err(dev, "failure to register otg notifier\n"); - goto otg_reg_notifier_failed; - } - polling = 0; - } -#endif - - if (polling) { - dev_dbg(dev, "will poll for status\n"); - INIT_DELAYED_WORK(&polling_work, polling_work_func); - cancel_delayed_work(&polling_work); - schedule_delayed_work(&polling_work, - msecs_to_jiffies(pdata->polling_interval)); - } - - if (ac_irq || usb_irq) - device_init_wakeup(&pdev->dev, 1); - - return 0; - -#if IS_ENABLED(CONFIG_USB_PHY) -otg_reg_notifier_failed: - if (pdata->is_usb_online && usb_irq) - free_irq(usb_irq->start, pda_psy_usb); -#endif -usb_irq_failed: - if (pdata->is_usb_online) - power_supply_unregister(pda_psy_usb); -usb_supply_failed: - if (pdata->is_ac_online && ac_irq) - free_irq(ac_irq->start, pda_psy_ac); -#if IS_ENABLED(CONFIG_USB_PHY) - if (!IS_ERR_OR_NULL(transceiver)) - usb_put_phy(transceiver); -#endif -ac_irq_failed: - if (pdata->is_ac_online) - power_supply_unregister(pda_psy_ac); -ac_supply_failed: - if (ac_draw) { - regulator_put(ac_draw); - ac_draw = NULL; - } - if (pdata->exit) - pdata->exit(dev); -init_failed: -wrongid: - return ret; -} - -static int pda_power_remove(struct platform_device *pdev) -{ -#if IS_ENABLED(CONFIG_USB_PHY) - if (!IS_ERR_OR_NULL(transceiver) && pdata->use_otg_notifier) - usb_unregister_notifier(transceiver, &otg_nb); -#endif - if (pdata->is_usb_online && usb_irq) - free_irq(usb_irq->start, pda_psy_usb); - if (pdata->is_ac_online && ac_irq) - free_irq(ac_irq->start, pda_psy_ac); - - if (polling) - cancel_delayed_work_sync(&polling_work); - cancel_delayed_work_sync(&charger_work); - cancel_delayed_work_sync(&supply_work); - - if (pdata->is_usb_online) - power_supply_unregister(pda_psy_usb); - if (pdata->is_ac_online) - power_supply_unregister(pda_psy_ac); -#if IS_ENABLED(CONFIG_USB_PHY) - if (!IS_ERR_OR_NULL(transceiver)) - usb_put_phy(transceiver); -#endif - if (ac_draw) { - regulator_put(ac_draw); - ac_draw = NULL; - } - if (pdata->exit) - pdata->exit(dev); - - return 0; -} - -#ifdef CONFIG_PM -static int ac_wakeup_enabled; -static int usb_wakeup_enabled; - -static int pda_power_suspend(struct platform_device *pdev, pm_message_t state) -{ - if (pdata->suspend) { - int ret = pdata->suspend(state); - - if (ret) - return ret; - } - - if (device_may_wakeup(&pdev->dev)) { - if (ac_irq) - ac_wakeup_enabled = !enable_irq_wake(ac_irq->start); - if (usb_irq) - usb_wakeup_enabled = !enable_irq_wake(usb_irq->start); - } - - return 0; -} - -static int pda_power_resume(struct platform_device *pdev) -{ - if (device_may_wakeup(&pdev->dev)) { - if (usb_irq && usb_wakeup_enabled) - disable_irq_wake(usb_irq->start); - if (ac_irq && ac_wakeup_enabled) - disable_irq_wake(ac_irq->start); - } - - if (pdata->resume) - return pdata->resume(); - - return 0; -} -#else -#define pda_power_suspend NULL -#define pda_power_resume NULL -#endif /* CONFIG_PM */ - -static struct platform_driver pda_power_pdrv = { - .driver = { - .name = "pda-power", - }, - .probe = pda_power_probe, - .remove = pda_power_remove, - .suspend = pda_power_suspend, - .resume = pda_power_resume, -}; - -module_platform_driver(pda_power_pdrv); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>"); -MODULE_ALIAS("platform:pda-power"); diff --git a/drivers/power/supply/s3c_adc_battery.c b/drivers/power/supply/s3c_adc_battery.c deleted file mode 100644 index 68d31a3bee48..000000000000 --- a/drivers/power/supply/s3c_adc_battery.c +++ /dev/null @@ -1,453 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// iPAQ h1930/h1940/rx1950 battery controller driver -// Copyright (c) Vasily Khoruzhick -// Based on h1940_battery.c by Arnaud Patard - -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/power_supply.h> -#include <linux/leds.h> -#include <linux/gpio/consumer.h> -#include <linux/err.h> -#include <linux/timer.h> -#include <linux/jiffies.h> -#include <linux/s3c_adc_battery.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/module.h> - -#include <linux/soc/samsung/s3c-adc.h> - -#define BAT_POLL_INTERVAL 10000 /* ms */ -#define JITTER_DELAY 500 /* ms */ - -struct s3c_adc_bat { - struct power_supply *psy; - struct s3c_adc_client *client; - struct s3c_adc_bat_pdata *pdata; - struct gpio_desc *charge_finished; - int volt_value; - int cur_value; - unsigned int timestamp; - int level; - int status; - int cable_plugged:1; -}; - -static struct delayed_work bat_work; - -static void s3c_adc_bat_ext_power_changed(struct power_supply *psy) -{ - schedule_delayed_work(&bat_work, - msecs_to_jiffies(JITTER_DELAY)); -} - -static int gather_samples(struct s3c_adc_client *client, int num, int channel) -{ - int value, i; - - /* default to 1 if nothing is set */ - if (num < 1) - num = 1; - - value = 0; - for (i = 0; i < num; i++) - value += s3c_adc_read(client, channel); - value /= num; - - return value; -} - -static enum power_supply_property s3c_adc_backup_bat_props[] = { - POWER_SUPPLY_PROP_VOLTAGE_NOW, - POWER_SUPPLY_PROP_VOLTAGE_MIN, - POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, -}; - -static int s3c_adc_backup_bat_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ - struct s3c_adc_bat *bat = power_supply_get_drvdata(psy); - - if (!bat) { - dev_err(&psy->dev, "%s: no battery infos ?!\n", __func__); - return -EINVAL; - } - - if (bat->volt_value < 0 || - jiffies_to_msecs(jiffies - bat->timestamp) > - BAT_POLL_INTERVAL) { - bat->volt_value = gather_samples(bat->client, - bat->pdata->backup_volt_samples, - bat->pdata->backup_volt_channel); - bat->volt_value *= bat->pdata->backup_volt_mult; - bat->timestamp = jiffies; - } - - switch (psp) { - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - val->intval = bat->volt_value; - return 0; - case POWER_SUPPLY_PROP_VOLTAGE_MIN: - val->intval = bat->pdata->backup_volt_min; - return 0; - case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: - val->intval = bat->pdata->backup_volt_max; - return 0; - default: - return -EINVAL; - } -} - -static const struct power_supply_desc backup_bat_desc = { - .name = "backup-battery", - .type = POWER_SUPPLY_TYPE_BATTERY, - .properties = s3c_adc_backup_bat_props, - .num_properties = ARRAY_SIZE(s3c_adc_backup_bat_props), - .get_property = s3c_adc_backup_bat_get_property, - .use_for_apm = 1, -}; - -static struct s3c_adc_bat backup_bat; - -static enum power_supply_property s3c_adc_main_bat_props[] = { - POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, - POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN, - POWER_SUPPLY_PROP_CHARGE_NOW, - POWER_SUPPLY_PROP_VOLTAGE_NOW, - POWER_SUPPLY_PROP_CURRENT_NOW, -}; - -static int calc_full_volt(int volt_val, int cur_val, int impedance) -{ - return volt_val + cur_val * impedance / 1000; -} - -static int charge_finished(struct s3c_adc_bat *bat) -{ - return gpiod_get_value(bat->charge_finished); -} - -static int s3c_adc_bat_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ - struct s3c_adc_bat *bat = power_supply_get_drvdata(psy); - - int new_level; - int full_volt; - const struct s3c_adc_bat_thresh *lut; - unsigned int lut_size; - - if (!bat) { - dev_err(&psy->dev, "no battery infos ?!\n"); - return -EINVAL; - } - - lut = bat->pdata->lut_noac; - lut_size = bat->pdata->lut_noac_cnt; - - if (bat->volt_value < 0 || bat->cur_value < 0 || - jiffies_to_msecs(jiffies - bat->timestamp) > - BAT_POLL_INTERVAL) { - bat->volt_value = gather_samples(bat->client, - bat->pdata->volt_samples, - bat->pdata->volt_channel) * bat->pdata->volt_mult; - bat->cur_value = gather_samples(bat->client, - bat->pdata->current_samples, - bat->pdata->current_channel) * bat->pdata->current_mult; - bat->timestamp = jiffies; - } - - if (bat->cable_plugged && - (!bat->charge_finished || - !charge_finished(bat))) { - lut = bat->pdata->lut_acin; - lut_size = bat->pdata->lut_acin_cnt; - } - - new_level = 100000; - full_volt = calc_full_volt((bat->volt_value / 1000), - (bat->cur_value / 1000), bat->pdata->internal_impedance); - - if (full_volt < calc_full_volt(lut->volt, lut->cur, - bat->pdata->internal_impedance)) { - lut_size--; - while (lut_size--) { - int lut_volt1; - int lut_volt2; - - lut_volt1 = calc_full_volt(lut[0].volt, lut[0].cur, - bat->pdata->internal_impedance); - lut_volt2 = calc_full_volt(lut[1].volt, lut[1].cur, - bat->pdata->internal_impedance); - if (full_volt < lut_volt1 && full_volt >= lut_volt2) { - new_level = (lut[1].level + - (lut[0].level - lut[1].level) * - (full_volt - lut_volt2) / - (lut_volt1 - lut_volt2)) * 1000; - break; - } - new_level = lut[1].level * 1000; - lut++; - } - } - - bat->level = new_level; - - switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - if (!bat->charge_finished) - val->intval = bat->level == 100000 ? - POWER_SUPPLY_STATUS_FULL : bat->status; - else - val->intval = bat->status; - return 0; - case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: - val->intval = 100000; - return 0; - case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN: - val->intval = 0; - return 0; - case POWER_SUPPLY_PROP_CHARGE_NOW: - val->intval = bat->level; - return 0; - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - val->intval = bat->volt_value; - return 0; - case POWER_SUPPLY_PROP_CURRENT_NOW: - val->intval = bat->cur_value; - return 0; - default: - return -EINVAL; - } -} - -static const struct power_supply_desc main_bat_desc = { - .name = "main-battery", - .type = POWER_SUPPLY_TYPE_BATTERY, - .properties = s3c_adc_main_bat_props, - .num_properties = ARRAY_SIZE(s3c_adc_main_bat_props), - .get_property = s3c_adc_bat_get_property, - .external_power_changed = s3c_adc_bat_ext_power_changed, - .use_for_apm = 1, -}; - -static struct s3c_adc_bat main_bat; - -static void s3c_adc_bat_work(struct work_struct *work) -{ - struct s3c_adc_bat *bat = &main_bat; - int is_charged; - int is_plugged; - static int was_plugged; - - is_plugged = power_supply_am_i_supplied(bat->psy); - bat->cable_plugged = is_plugged; - if (is_plugged != was_plugged) { - was_plugged = is_plugged; - if (is_plugged) { - if (bat->pdata->enable_charger) - bat->pdata->enable_charger(); - bat->status = POWER_SUPPLY_STATUS_CHARGING; - } else { - if (bat->pdata->disable_charger) - bat->pdata->disable_charger(); - bat->status = POWER_SUPPLY_STATUS_DISCHARGING; - } - } else { - if (bat->charge_finished && is_plugged) { - is_charged = charge_finished(&main_bat); - if (is_charged) { - if (bat->pdata->disable_charger) - bat->pdata->disable_charger(); - bat->status = POWER_SUPPLY_STATUS_FULL; - } else { - if (bat->pdata->enable_charger) - bat->pdata->enable_charger(); - bat->status = POWER_SUPPLY_STATUS_CHARGING; - } - } - } - - power_supply_changed(bat->psy); -} - -static irqreturn_t s3c_adc_bat_charged(int irq, void *dev_id) -{ - schedule_delayed_work(&bat_work, - msecs_to_jiffies(JITTER_DELAY)); - return IRQ_HANDLED; -} - -static int s3c_adc_bat_probe(struct platform_device *pdev) -{ - struct s3c_adc_client *client; - struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data; - struct power_supply_config psy_cfg = {}; - struct gpio_desc *gpiod; - int ret; - - client = s3c_adc_register(pdev, NULL, NULL, 0); - if (IS_ERR(client)) { - dev_err(&pdev->dev, "cannot register adc\n"); - return PTR_ERR(client); - } - - platform_set_drvdata(pdev, client); - - gpiod = devm_gpiod_get_optional(&pdev->dev, "charge-status", GPIOD_IN); - if (IS_ERR(gpiod)) { - /* Could be probe deferral etc */ - ret = PTR_ERR(gpiod); - dev_err(&pdev->dev, "no GPIO %d\n", ret); - return ret; - } - - main_bat.client = client; - main_bat.pdata = pdata; - main_bat.charge_finished = gpiod; - main_bat.volt_value = -1; - main_bat.cur_value = -1; - main_bat.cable_plugged = 0; - main_bat.status = POWER_SUPPLY_STATUS_DISCHARGING; - psy_cfg.drv_data = &main_bat; - - main_bat.psy = power_supply_register(&pdev->dev, &main_bat_desc, &psy_cfg); - if (IS_ERR(main_bat.psy)) { - ret = PTR_ERR(main_bat.psy); - goto err_reg_main; - } - if (pdata->backup_volt_mult) { - const struct power_supply_config backup_psy_cfg - = { .drv_data = &backup_bat, }; - - backup_bat.client = client; - backup_bat.pdata = pdev->dev.platform_data; - backup_bat.charge_finished = gpiod; - backup_bat.volt_value = -1; - backup_bat.psy = power_supply_register(&pdev->dev, - &backup_bat_desc, - &backup_psy_cfg); - if (IS_ERR(backup_bat.psy)) { - ret = PTR_ERR(backup_bat.psy); - goto err_reg_backup; - } - } - - INIT_DELAYED_WORK(&bat_work, s3c_adc_bat_work); - - if (gpiod) { - ret = request_irq(gpiod_to_irq(gpiod), - s3c_adc_bat_charged, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "battery charged", NULL); - if (ret) - goto err_irq; - } - - if (pdata->init) { - ret = pdata->init(); - if (ret) - goto err_platform; - } - - dev_info(&pdev->dev, "successfully loaded\n"); - device_init_wakeup(&pdev->dev, 1); - - /* Schedule timer to check current status */ - schedule_delayed_work(&bat_work, - msecs_to_jiffies(JITTER_DELAY)); - - return 0; - -err_platform: - if (gpiod) - free_irq(gpiod_to_irq(gpiod), NULL); -err_irq: - if (pdata->backup_volt_mult) - power_supply_unregister(backup_bat.psy); -err_reg_backup: - power_supply_unregister(main_bat.psy); -err_reg_main: - return ret; -} - -static int s3c_adc_bat_remove(struct platform_device *pdev) -{ - struct s3c_adc_client *client = platform_get_drvdata(pdev); - struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data; - - power_supply_unregister(main_bat.psy); - if (pdata->backup_volt_mult) - power_supply_unregister(backup_bat.psy); - - s3c_adc_release(client); - - if (main_bat.charge_finished) - free_irq(gpiod_to_irq(main_bat.charge_finished), NULL); - - cancel_delayed_work_sync(&bat_work); - - if (pdata->exit) - pdata->exit(); - - return 0; -} - -#ifdef CONFIG_PM -static int s3c_adc_bat_suspend(struct platform_device *pdev, - pm_message_t state) -{ - if (main_bat.charge_finished) { - if (device_may_wakeup(&pdev->dev)) - enable_irq_wake( - gpiod_to_irq(main_bat.charge_finished)); - else { - disable_irq(gpiod_to_irq(main_bat.charge_finished)); - main_bat.pdata->disable_charger(); - } - } - - return 0; -} - -static int s3c_adc_bat_resume(struct platform_device *pdev) -{ - if (main_bat.charge_finished) { - if (device_may_wakeup(&pdev->dev)) - disable_irq_wake( - gpiod_to_irq(main_bat.charge_finished)); - else - enable_irq(gpiod_to_irq(main_bat.charge_finished)); - } - - /* Schedule timer to check current status */ - schedule_delayed_work(&bat_work, - msecs_to_jiffies(JITTER_DELAY)); - - return 0; -} -#else -#define s3c_adc_bat_suspend NULL -#define s3c_adc_bat_resume NULL -#endif - -static struct platform_driver s3c_adc_bat_driver = { - .driver = { - .name = "s3c-adc-battery", - }, - .probe = s3c_adc_bat_probe, - .remove = s3c_adc_bat_remove, - .suspend = s3c_adc_bat_suspend, - .resume = s3c_adc_bat_resume, -}; - -module_platform_driver(s3c_adc_bat_driver); - -MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>"); -MODULE_DESCRIPTION("iPAQ H1930/H1940/RX1950 battery controller driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/power/supply/tosa_battery.c b/drivers/power/supply/tosa_battery.c deleted file mode 100644 index 73d4aca4c386..000000000000 --- a/drivers/power/supply/tosa_battery.c +++ /dev/null @@ -1,512 +0,0 @@ -// 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 - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/power_supply.h> -#include <linux/wm97xx.h> -#include <linux/delay.h> -#include <linux/spinlock.h> -#include <linux/interrupt.h> -#include <linux/gpio/consumer.h> - -#include <asm/mach-types.h> - -static DEFINE_MUTEX(bat_lock); /* protects gpio pins */ -static struct work_struct bat_work; - -struct tosa_bat { - int status; - struct power_supply *psy; - int full_chrg; - - struct mutex work_lock; /* protects data */ - - bool (*is_present)(struct tosa_bat *bat); - struct gpio_desc *gpiod_full; - struct gpio_desc *gpiod_charge_off; - - int technology; - - struct gpio_desc *gpiod_bat; - int adc_bat; - int adc_bat_divider; - int bat_max; - int bat_min; - - struct gpio_desc *gpiod_temp; - int adc_temp; - int adc_temp_divider; -}; - -static struct gpio_desc *jacket_detect; -static struct tosa_bat tosa_bat_main; -static struct tosa_bat tosa_bat_jacket; - -static unsigned long tosa_read_bat(struct tosa_bat *bat) -{ - unsigned long value = 0; - - if (!bat->gpiod_bat || bat->adc_bat < 0) - return 0; - - mutex_lock(&bat_lock); - gpiod_set_value(bat->gpiod_bat, 1); - msleep(5); - value = wm97xx_read_aux_adc(dev_get_drvdata(bat->psy->dev.parent), - bat->adc_bat); - gpiod_set_value(bat->gpiod_bat, 0); - mutex_unlock(&bat_lock); - - value = value * 1000000 / bat->adc_bat_divider; - - return value; -} - -static unsigned long tosa_read_temp(struct tosa_bat *bat) -{ - unsigned long value = 0; - - if (!bat->gpiod_temp || bat->adc_temp < 0) - return 0; - - mutex_lock(&bat_lock); - gpiod_set_value(bat->gpiod_temp, 1); - msleep(5); - value = wm97xx_read_aux_adc(dev_get_drvdata(bat->psy->dev.parent), - bat->adc_temp); - gpiod_set_value(bat->gpiod_temp, 0); - mutex_unlock(&bat_lock); - - value = value * 10000 / bat->adc_temp_divider; - - return value; -} - -static int tosa_bat_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ - int ret = 0; - struct tosa_bat *bat = power_supply_get_drvdata(psy); - - if (bat->is_present && !bat->is_present(bat) - && psp != POWER_SUPPLY_PROP_PRESENT) { - return -ENODEV; - } - - switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - val->intval = bat->status; - break; - case POWER_SUPPLY_PROP_TECHNOLOGY: - val->intval = bat->technology; - break; - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - val->intval = tosa_read_bat(bat); - break; - case POWER_SUPPLY_PROP_VOLTAGE_MAX: - if (bat->full_chrg == -1) - val->intval = bat->bat_max; - else - val->intval = bat->full_chrg; - break; - case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: - val->intval = bat->bat_max; - break; - case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: - val->intval = bat->bat_min; - break; - case POWER_SUPPLY_PROP_TEMP: - val->intval = tosa_read_temp(bat); - break; - case POWER_SUPPLY_PROP_PRESENT: - val->intval = bat->is_present ? bat->is_present(bat) : 1; - break; - default: - ret = -EINVAL; - break; - } - return ret; -} - -static bool tosa_jacket_bat_is_present(struct tosa_bat *bat) -{ - return gpiod_get_value(jacket_detect) == 0; -} - -static void tosa_bat_external_power_changed(struct power_supply *psy) -{ - schedule_work(&bat_work); -} - -static irqreturn_t tosa_bat_gpio_isr(int irq, void *data) -{ - pr_info("tosa_bat_gpio irq\n"); - schedule_work(&bat_work); - return IRQ_HANDLED; -} - -static void tosa_bat_update(struct tosa_bat *bat) -{ - int old; - struct power_supply *psy = bat->psy; - - mutex_lock(&bat->work_lock); - - old = bat->status; - - if (bat->is_present && !bat->is_present(bat)) { - printk(KERN_NOTICE "%s not present\n", psy->desc->name); - bat->status = POWER_SUPPLY_STATUS_UNKNOWN; - bat->full_chrg = -1; - } else if (power_supply_am_i_supplied(psy)) { - if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) { - gpiod_set_value(bat->gpiod_charge_off, 0); - mdelay(15); - } - - if (gpiod_get_value(bat->gpiod_full)) { - if (old == POWER_SUPPLY_STATUS_CHARGING || - bat->full_chrg == -1) - bat->full_chrg = tosa_read_bat(bat); - - gpiod_set_value(bat->gpiod_charge_off, 1); - bat->status = POWER_SUPPLY_STATUS_FULL; - } else { - gpiod_set_value(bat->gpiod_charge_off, 0); - bat->status = POWER_SUPPLY_STATUS_CHARGING; - } - } else { - gpiod_set_value(bat->gpiod_charge_off, 1); - bat->status = POWER_SUPPLY_STATUS_DISCHARGING; - } - - if (old != bat->status) - power_supply_changed(psy); - - mutex_unlock(&bat->work_lock); -} - -static void tosa_bat_work(struct work_struct *work) -{ - tosa_bat_update(&tosa_bat_main); - tosa_bat_update(&tosa_bat_jacket); -} - - -static enum power_supply_property tosa_bat_main_props[] = { - POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_TECHNOLOGY, - POWER_SUPPLY_PROP_VOLTAGE_NOW, - POWER_SUPPLY_PROP_VOLTAGE_MAX, - POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, - POWER_SUPPLY_PROP_TEMP, - POWER_SUPPLY_PROP_PRESENT, -}; - -static enum power_supply_property tosa_bat_bu_props[] = { - POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_TECHNOLOGY, - POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, - POWER_SUPPLY_PROP_VOLTAGE_NOW, - POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, - POWER_SUPPLY_PROP_PRESENT, -}; - -static const struct power_supply_desc tosa_bat_main_desc = { - .name = "main-battery", - .type = POWER_SUPPLY_TYPE_BATTERY, - .properties = tosa_bat_main_props, - .num_properties = ARRAY_SIZE(tosa_bat_main_props), - .get_property = tosa_bat_get_property, - .external_power_changed = tosa_bat_external_power_changed, - .use_for_apm = 1, -}; - -static const struct power_supply_desc tosa_bat_jacket_desc = { - .name = "jacket-battery", - .type = POWER_SUPPLY_TYPE_BATTERY, - .properties = tosa_bat_main_props, - .num_properties = ARRAY_SIZE(tosa_bat_main_props), - .get_property = tosa_bat_get_property, - .external_power_changed = tosa_bat_external_power_changed, -}; - -static const struct power_supply_desc tosa_bat_bu_desc = { - .name = "backup-battery", - .type = POWER_SUPPLY_TYPE_BATTERY, - .properties = tosa_bat_bu_props, - .num_properties = ARRAY_SIZE(tosa_bat_bu_props), - .get_property = tosa_bat_get_property, - .external_power_changed = tosa_bat_external_power_changed, -}; - -static struct tosa_bat tosa_bat_main = { - .status = POWER_SUPPLY_STATUS_DISCHARGING, - .full_chrg = -1, - .psy = NULL, - - .gpiod_full = NULL, - .gpiod_charge_off = NULL, - - .technology = POWER_SUPPLY_TECHNOLOGY_LIPO, - - .gpiod_bat = NULL, - .adc_bat = WM97XX_AUX_ID3, - .adc_bat_divider = 414, - .bat_max = 4310000, - .bat_min = 1551 * 1000000 / 414, - - .gpiod_temp = NULL, - .adc_temp = WM97XX_AUX_ID2, - .adc_temp_divider = 10000, -}; - -static struct tosa_bat tosa_bat_jacket = { - .status = POWER_SUPPLY_STATUS_DISCHARGING, - .full_chrg = -1, - .psy = NULL, - - .is_present = tosa_jacket_bat_is_present, - .gpiod_full = NULL, - .gpiod_charge_off = NULL, - - .technology = POWER_SUPPLY_TECHNOLOGY_LIPO, - - .gpiod_bat = NULL, - .adc_bat = WM97XX_AUX_ID3, - .adc_bat_divider = 414, - .bat_max = 4310000, - .bat_min = 1551 * 1000000 / 414, - - .gpiod_temp = NULL, - .adc_temp = WM97XX_AUX_ID2, - .adc_temp_divider = 10000, -}; - -static struct tosa_bat tosa_bat_bu = { - .status = POWER_SUPPLY_STATUS_UNKNOWN, - .full_chrg = -1, - .psy = NULL, - - .gpiod_full = NULL, - .gpiod_charge_off = NULL, - - .technology = POWER_SUPPLY_TECHNOLOGY_LiMn, - - .gpiod_bat = NULL, - .adc_bat = WM97XX_AUX_ID4, - .adc_bat_divider = 1266, - - .gpiod_temp = NULL, - .adc_temp = -1, - .adc_temp_divider = -1, -}; - -#ifdef CONFIG_PM -static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state) -{ - /* flush all pending status updates */ - flush_work(&bat_work); - return 0; -} - -static int tosa_bat_resume(struct platform_device *dev) -{ - /* things may have changed while we were away */ - schedule_work(&bat_work); - return 0; -} -#else -#define tosa_bat_suspend NULL -#define tosa_bat_resume NULL -#endif - -static int tosa_bat_probe(struct platform_device *pdev) -{ - int ret; - struct power_supply_config main_psy_cfg = {}, - jacket_psy_cfg = {}, - bu_psy_cfg = {}; - struct device *dev = &pdev->dev; - struct gpio_desc *dummy; - - if (!machine_is_tosa()) - return -ENODEV; - - /* Main charging control GPIOs */ - tosa_bat_main.gpiod_charge_off = devm_gpiod_get(dev, "main charge off", GPIOD_OUT_HIGH); - if (IS_ERR(tosa_bat_main.gpiod_charge_off)) - return dev_err_probe(dev, PTR_ERR(tosa_bat_main.gpiod_charge_off), - "no main charger GPIO\n"); - tosa_bat_jacket.gpiod_charge_off = devm_gpiod_get(dev, "jacket charge off", GPIOD_OUT_HIGH); - if (IS_ERR(tosa_bat_jacket.gpiod_charge_off)) - return dev_err_probe(dev, PTR_ERR(tosa_bat_jacket.gpiod_charge_off), - "no jacket charger GPIO\n"); - - /* Per-battery output check (routes battery voltage to ADC) */ - tosa_bat_main.gpiod_bat = devm_gpiod_get(dev, "main battery", GPIOD_OUT_LOW); - if (IS_ERR(tosa_bat_main.gpiod_bat)) - return dev_err_probe(dev, PTR_ERR(tosa_bat_main.gpiod_bat), - "no main battery GPIO\n"); - tosa_bat_jacket.gpiod_bat = devm_gpiod_get(dev, "jacket battery", GPIOD_OUT_LOW); - if (IS_ERR(tosa_bat_jacket.gpiod_bat)) - return dev_err_probe(dev, PTR_ERR(tosa_bat_jacket.gpiod_bat), - "no jacket battery GPIO\n"); - tosa_bat_bu.gpiod_bat = devm_gpiod_get(dev, "backup battery", GPIOD_OUT_LOW); - if (IS_ERR(tosa_bat_bu.gpiod_bat)) - return dev_err_probe(dev, PTR_ERR(tosa_bat_bu.gpiod_bat), - "no backup battery GPIO\n"); - - /* Battery full detect GPIOs (using PXA SoC GPIOs) */ - tosa_bat_main.gpiod_full = devm_gpiod_get(dev, "main battery full", GPIOD_IN); - if (IS_ERR(tosa_bat_main.gpiod_full)) - return dev_err_probe(dev, PTR_ERR(tosa_bat_main.gpiod_full), - "no main battery full GPIO\n"); - tosa_bat_jacket.gpiod_full = devm_gpiod_get(dev, "jacket battery full", GPIOD_IN); - if (IS_ERR(tosa_bat_jacket.gpiod_full)) - return dev_err_probe(dev, PTR_ERR(tosa_bat_jacket.gpiod_full), - "no jacket battery full GPIO\n"); - - /* Battery temperature GPIOs (routes thermistor voltage to ADC) */ - tosa_bat_main.gpiod_temp = devm_gpiod_get(dev, "main battery temp", GPIOD_OUT_LOW); - if (IS_ERR(tosa_bat_main.gpiod_temp)) - return dev_err_probe(dev, PTR_ERR(tosa_bat_main.gpiod_temp), - "no main battery temp GPIO\n"); - tosa_bat_jacket.gpiod_temp = devm_gpiod_get(dev, "jacket battery temp", GPIOD_OUT_LOW); - if (IS_ERR(tosa_bat_jacket.gpiod_temp)) - return dev_err_probe(dev, PTR_ERR(tosa_bat_jacket.gpiod_temp), - "no jacket battery temp GPIO\n"); - - /* Jacket detect GPIO */ - jacket_detect = devm_gpiod_get(dev, "jacket detect", GPIOD_IN); - if (IS_ERR(jacket_detect)) - return dev_err_probe(dev, PTR_ERR(jacket_detect), - "no jacket detect GPIO\n"); - - /* Battery low indication GPIOs (not used, we just request them) */ - dummy = devm_gpiod_get(dev, "main battery low", GPIOD_IN); - if (IS_ERR(dummy)) - return dev_err_probe(dev, PTR_ERR(dummy), - "no main battery low GPIO\n"); - dummy = devm_gpiod_get(dev, "jacket battery low", GPIOD_IN); - if (IS_ERR(dummy)) - return dev_err_probe(dev, PTR_ERR(dummy), - "no jacket battery low GPIO\n"); - - /* Battery switch GPIO (not used just requested) */ - dummy = devm_gpiod_get(dev, "battery switch", GPIOD_OUT_LOW); - if (IS_ERR(dummy)) - return dev_err_probe(dev, PTR_ERR(dummy), - "no battery switch GPIO\n"); - - mutex_init(&tosa_bat_main.work_lock); - mutex_init(&tosa_bat_jacket.work_lock); - - INIT_WORK(&bat_work, tosa_bat_work); - - main_psy_cfg.drv_data = &tosa_bat_main; - tosa_bat_main.psy = power_supply_register(dev, - &tosa_bat_main_desc, - &main_psy_cfg); - if (IS_ERR(tosa_bat_main.psy)) { - ret = PTR_ERR(tosa_bat_main.psy); - goto err_psy_reg_main; - } - - jacket_psy_cfg.drv_data = &tosa_bat_jacket; - tosa_bat_jacket.psy = power_supply_register(dev, - &tosa_bat_jacket_desc, - &jacket_psy_cfg); - if (IS_ERR(tosa_bat_jacket.psy)) { - ret = PTR_ERR(tosa_bat_jacket.psy); - goto err_psy_reg_jacket; - } - - bu_psy_cfg.drv_data = &tosa_bat_bu; - tosa_bat_bu.psy = power_supply_register(dev, &tosa_bat_bu_desc, - &bu_psy_cfg); - if (IS_ERR(tosa_bat_bu.psy)) { - ret = PTR_ERR(tosa_bat_bu.psy); - goto err_psy_reg_bu; - } - - ret = request_irq(gpiod_to_irq(tosa_bat_main.gpiod_full), - tosa_bat_gpio_isr, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "main full", &tosa_bat_main); - if (ret) - goto err_req_main; - - ret = request_irq(gpiod_to_irq(tosa_bat_jacket.gpiod_full), - tosa_bat_gpio_isr, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "jacket full", &tosa_bat_jacket); - if (ret) - goto err_req_jacket; - - ret = request_irq(gpiod_to_irq(jacket_detect), - tosa_bat_gpio_isr, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "jacket detect", &tosa_bat_jacket); - if (!ret) { - schedule_work(&bat_work); - return 0; - } - - free_irq(gpiod_to_irq(tosa_bat_jacket.gpiod_full), &tosa_bat_jacket); -err_req_jacket: - free_irq(gpiod_to_irq(tosa_bat_main.gpiod_full), &tosa_bat_main); -err_req_main: - power_supply_unregister(tosa_bat_bu.psy); -err_psy_reg_bu: - power_supply_unregister(tosa_bat_jacket.psy); -err_psy_reg_jacket: - power_supply_unregister(tosa_bat_main.psy); -err_psy_reg_main: - - /* see comment in tosa_bat_remove */ - cancel_work_sync(&bat_work); - - return ret; -} - -static int tosa_bat_remove(struct platform_device *dev) -{ - free_irq(gpiod_to_irq(jacket_detect), &tosa_bat_jacket); - free_irq(gpiod_to_irq(tosa_bat_jacket.gpiod_full), &tosa_bat_jacket); - free_irq(gpiod_to_irq(tosa_bat_main.gpiod_full), &tosa_bat_main); - - power_supply_unregister(tosa_bat_bu.psy); - power_supply_unregister(tosa_bat_jacket.psy); - power_supply_unregister(tosa_bat_main.psy); - - /* - * Now cancel the bat_work. We won't get any more schedules, - * since all sources (isr and external_power_changed) are - * unregistered now. - */ - cancel_work_sync(&bat_work); - return 0; -} - -static struct platform_driver tosa_bat_driver = { - .driver.name = "wm97xx-battery", - .driver.owner = THIS_MODULE, - .probe = tosa_bat_probe, - .remove = tosa_bat_remove, - .suspend = tosa_bat_suspend, - .resume = tosa_bat_resume, -}; - -module_platform_driver(tosa_bat_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Dmitry Baryshkov"); -MODULE_DESCRIPTION("Tosa battery driver"); -MODULE_ALIAS("platform:wm97xx-battery"); diff --git a/drivers/power/supply/z2_battery.c b/drivers/power/supply/z2_battery.c deleted file mode 100644 index 0ba4a590a0a5..000000000000 --- a/drivers/power/supply/z2_battery.c +++ /dev/null @@ -1,318 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Battery measurement code for Zipit Z2 - * - * Copyright (C) 2009 Peter Edwards <sweetlilmre@gmail.com> - */ - -#include <linux/module.h> -#include <linux/gpio/consumer.h> -#include <linux/i2c.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/power_supply.h> -#include <linux/slab.h> -#include <linux/z2_battery.h> - -#define Z2_DEFAULT_NAME "Z2" - -struct z2_charger { - struct z2_battery_info *info; - struct gpio_desc *charge_gpiod; - int bat_status; - struct i2c_client *client; - struct power_supply *batt_ps; - struct power_supply_desc batt_ps_desc; - struct mutex work_lock; - struct work_struct bat_work; -}; - -static unsigned long z2_read_bat(struct z2_charger *charger) -{ - int data; - data = i2c_smbus_read_byte_data(charger->client, - charger->info->batt_I2C_reg); - if (data < 0) - return 0; - - return data * charger->info->batt_mult / charger->info->batt_div; -} - -static int z2_batt_get_property(struct power_supply *batt_ps, - enum power_supply_property psp, - union power_supply_propval *val) -{ - struct z2_charger *charger = power_supply_get_drvdata(batt_ps); - struct z2_battery_info *info = charger->info; - - switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - val->intval = charger->bat_status; - break; - case POWER_SUPPLY_PROP_TECHNOLOGY: - val->intval = info->batt_tech; - break; - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - if (info->batt_I2C_reg >= 0) - val->intval = z2_read_bat(charger); - else - return -EINVAL; - break; - case POWER_SUPPLY_PROP_VOLTAGE_MAX: - if (info->max_voltage >= 0) - val->intval = info->max_voltage; - else - return -EINVAL; - break; - case POWER_SUPPLY_PROP_VOLTAGE_MIN: - if (info->min_voltage >= 0) - val->intval = info->min_voltage; - else - return -EINVAL; - break; - case POWER_SUPPLY_PROP_PRESENT: - val->intval = 1; - break; - default: - return -EINVAL; - } - - return 0; -} - -static void z2_batt_ext_power_changed(struct power_supply *batt_ps) -{ - struct z2_charger *charger = power_supply_get_drvdata(batt_ps); - - schedule_work(&charger->bat_work); -} - -static void z2_batt_update(struct z2_charger *charger) -{ - int old_status = charger->bat_status; - - mutex_lock(&charger->work_lock); - - charger->bat_status = charger->charge_gpiod ? - (gpiod_get_value(charger->charge_gpiod) ? - POWER_SUPPLY_STATUS_CHARGING : - POWER_SUPPLY_STATUS_DISCHARGING) : - POWER_SUPPLY_STATUS_UNKNOWN; - - if (old_status != charger->bat_status) { - pr_debug("%s: %i -> %i\n", charger->batt_ps->desc->name, - old_status, - charger->bat_status); - power_supply_changed(charger->batt_ps); - } - - mutex_unlock(&charger->work_lock); -} - -static void z2_batt_work(struct work_struct *work) -{ - struct z2_charger *charger; - charger = container_of(work, struct z2_charger, bat_work); - z2_batt_update(charger); -} - -static irqreturn_t z2_charge_switch_irq(int irq, void *devid) -{ - struct z2_charger *charger = devid; - schedule_work(&charger->bat_work); - return IRQ_HANDLED; -} - -static int z2_batt_ps_init(struct z2_charger *charger, int props) -{ - int i = 0; - enum power_supply_property *prop; - struct z2_battery_info *info = charger->info; - - if (charger->charge_gpiod) - props++; /* POWER_SUPPLY_PROP_STATUS */ - if (info->batt_tech >= 0) - props++; /* POWER_SUPPLY_PROP_TECHNOLOGY */ - if (info->batt_I2C_reg >= 0) - props++; /* POWER_SUPPLY_PROP_VOLTAGE_NOW */ - if (info->max_voltage >= 0) - props++; /* POWER_SUPPLY_PROP_VOLTAGE_MAX */ - if (info->min_voltage >= 0) - props++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */ - - prop = kcalloc(props, sizeof(*prop), GFP_KERNEL); - if (!prop) - return -ENOMEM; - - prop[i++] = POWER_SUPPLY_PROP_PRESENT; - if (charger->charge_gpiod) - prop[i++] = POWER_SUPPLY_PROP_STATUS; - if (info->batt_tech >= 0) - prop[i++] = POWER_SUPPLY_PROP_TECHNOLOGY; - if (info->batt_I2C_reg >= 0) - prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_NOW; - if (info->max_voltage >= 0) - prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_MAX; - if (info->min_voltage >= 0) - prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_MIN; - - if (!info->batt_name) { - dev_info(&charger->client->dev, - "Please consider setting proper battery " - "name in platform definition file, falling " - "back to name \" Z2_DEFAULT_NAME \"\n"); - charger->batt_ps_desc.name = Z2_DEFAULT_NAME; - } else - charger->batt_ps_desc.name = info->batt_name; - - charger->batt_ps_desc.properties = prop; - charger->batt_ps_desc.num_properties = props; - charger->batt_ps_desc.type = POWER_SUPPLY_TYPE_BATTERY; - charger->batt_ps_desc.get_property = z2_batt_get_property; - charger->batt_ps_desc.external_power_changed = - z2_batt_ext_power_changed; - charger->batt_ps_desc.use_for_apm = 1; - - return 0; -} - -static int z2_batt_probe(struct i2c_client *client) -{ - int ret = 0; - int props = 1; /* POWER_SUPPLY_PROP_PRESENT */ - struct z2_charger *charger; - struct z2_battery_info *info = client->dev.platform_data; - struct power_supply_config psy_cfg = {}; - - if (info == NULL) { - dev_err(&client->dev, - "Please set platform device platform_data" - " to a valid z2_battery_info pointer!\n"); - return -EINVAL; - } - - charger = kzalloc(sizeof(*charger), GFP_KERNEL); - if (charger == NULL) - return -ENOMEM; - - charger->bat_status = POWER_SUPPLY_STATUS_UNKNOWN; - charger->info = info; - charger->client = client; - i2c_set_clientdata(client, charger); - psy_cfg.drv_data = charger; - - mutex_init(&charger->work_lock); - - charger->charge_gpiod = devm_gpiod_get_optional(&client->dev, - NULL, GPIOD_IN); - if (IS_ERR(charger->charge_gpiod)) { - ret = dev_err_probe(&client->dev, - PTR_ERR(charger->charge_gpiod), - "failed to get charge GPIO\n"); - goto err; - } - - if (charger->charge_gpiod) { - gpiod_set_consumer_name(charger->charge_gpiod, "BATT CHRG"); - - irq_set_irq_type(gpiod_to_irq(charger->charge_gpiod), - IRQ_TYPE_EDGE_BOTH); - ret = request_irq(gpiod_to_irq(charger->charge_gpiod), - z2_charge_switch_irq, 0, - "AC Detect", charger); - if (ret) - goto err; - } - - ret = z2_batt_ps_init(charger, props); - if (ret) - goto err3; - - INIT_WORK(&charger->bat_work, z2_batt_work); - - charger->batt_ps = power_supply_register(&client->dev, - &charger->batt_ps_desc, - &psy_cfg); - if (IS_ERR(charger->batt_ps)) { - ret = PTR_ERR(charger->batt_ps); - goto err4; - } - - schedule_work(&charger->bat_work); - - return 0; - -err4: - kfree(charger->batt_ps_desc.properties); -err3: - if (charger->charge_gpiod) - free_irq(gpiod_to_irq(charger->charge_gpiod), charger); -err: - kfree(charger); - return ret; -} - -static void z2_batt_remove(struct i2c_client *client) -{ - struct z2_charger *charger = i2c_get_clientdata(client); - - cancel_work_sync(&charger->bat_work); - power_supply_unregister(charger->batt_ps); - - kfree(charger->batt_ps_desc.properties); - if (charger->charge_gpiod) - free_irq(gpiod_to_irq(charger->charge_gpiod), charger); - - kfree(charger); -} - -#ifdef CONFIG_PM -static int z2_batt_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct z2_charger *charger = i2c_get_clientdata(client); - - flush_work(&charger->bat_work); - return 0; -} - -static int z2_batt_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct z2_charger *charger = i2c_get_clientdata(client); - - schedule_work(&charger->bat_work); - return 0; -} - -static const struct dev_pm_ops z2_battery_pm_ops = { - .suspend = z2_batt_suspend, - .resume = z2_batt_resume, -}; - -#define Z2_BATTERY_PM_OPS (&z2_battery_pm_ops) - -#else -#define Z2_BATTERY_PM_OPS (NULL) -#endif - -static const struct i2c_device_id z2_batt_id[] = { - { "aer915", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, z2_batt_id); - -static struct i2c_driver z2_batt_driver = { - .driver = { - .name = "z2-battery", - .pm = Z2_BATTERY_PM_OPS - }, - .probe_new = z2_batt_probe, - .remove = z2_batt_remove, - .id_table = z2_batt_id, -}; -module_i2c_driver(z2_batt_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Peter Edwards <sweetlilmre@gmail.com>"); -MODULE_DESCRIPTION("Zipit Z2 battery driver"); diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index e01b32d1fa17..00828f5baa97 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -498,6 +498,12 @@ static int da9211_i2c_probe(struct i2c_client *i2c) chip->chip_irq = i2c->irq; + ret = da9211_regulator_init(chip); + if (ret < 0) { + dev_err(chip->dev, "Failed to initialize regulator: %d\n", ret); + return ret; + } + if (chip->chip_irq != 0) { ret = devm_request_threaded_irq(chip->dev, chip->chip_irq, NULL, da9211_irq_handler, @@ -512,11 +518,6 @@ static int da9211_i2c_probe(struct i2c_client *i2c) dev_warn(chip->dev, "No IRQ configured\n"); } - ret = da9211_regulator_init(chip); - - if (ret < 0) - dev_err(chip->dev, "Failed to initialize regulator: %d\n", ret); - return ret; } diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 43b5b9377714..ae6021390143 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -1016,7 +1016,7 @@ static const struct rpmh_vreg_init_data pm8550_vreg_data[] = { RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo_lv, "vdd-l8-l9"), RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l8-l9"), RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l1-l4-l10"), - RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l11"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo, "vdd-l11"), RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo, "vdd-l12"), RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l2-l13-l14"), RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, "vdd-l2-l13-l14"), diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index de176c2fbad9..2a52c990d4fe 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -257,7 +257,7 @@ config RESET_SUNXI config RESET_TI_SCI tristate "TI System Control Interface (TI-SCI) reset driver" - depends on TI_SCI_PROTOCOL || COMPILE_TEST + depends on TI_SCI_PROTOCOL || (COMPILE_TEST && TI_SCI_PROTOCOL=n) help This enables the reset driver support over TI System Control Interface available on some new TI's SoCs. If you wish to use reset resources diff --git a/drivers/reset/reset-uniphier-glue.c b/drivers/reset/reset-uniphier-glue.c index 146fd5d45e99..15abac9fc72c 100644 --- a/drivers/reset/reset-uniphier-glue.c +++ b/drivers/reset/reset-uniphier-glue.c @@ -47,7 +47,6 @@ static int uniphier_glue_reset_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct uniphier_glue_reset_priv *priv; struct resource *res; - resource_size_t size; int i, ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -60,7 +59,6 @@ static int uniphier_glue_reset_probe(struct platform_device *pdev) return -EINVAL; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - size = resource_size(res); priv->rdata.membase = devm_ioremap_resource(dev, res); if (IS_ERR(priv->rdata.membase)) return PTR_ERR(priv->rdata.membase); @@ -96,7 +94,7 @@ static int uniphier_glue_reset_probe(struct platform_device *pdev) spin_lock_init(&priv->rdata.lock); priv->rdata.rcdev.owner = THIS_MODULE; - priv->rdata.rcdev.nr_resets = size * BITS_PER_BYTE; + priv->rdata.rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE; priv->rdata.rcdev.ops = &reset_simple_ops; priv->rdata.rcdev.of_node = dev->of_node; priv->rdata.active_low = true; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 677d2601d305..2ba72de0fa47 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1212,15 +1212,6 @@ config RTC_DRV_RP5C01 This driver can also be built as a module. If so, the module will be called rtc-rp5c01. -config RTC_DRV_V3020 - tristate "EM Microelectronic V3020" - help - If you say yes here you will get support for the - EM Microelectronic v3020 RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-v3020. - config RTC_DRV_GAMECUBE tristate "Nintendo GameCube, Wii and Wii U RTC" depends on GAMECUBE || WII || COMPILE_TEST @@ -1415,18 +1406,14 @@ config RTC_DRV_OMAP config RTC_DRV_S3C tristate "Samsung S3C series SoC RTC" - depends on ARCH_EXYNOS || ARCH_S3C64XX || ARCH_S3C24XX || ARCH_S5PV210 || \ + depends on ARCH_EXYNOS || ARCH_S3C64XX || ARCH_S5PV210 || \ COMPILE_TEST help RTC (Realtime Clock) driver for the clock inbuilt into the - Samsung S3C24XX series of SoCs. This can provide periodic + Samsung S3C64XX series of SoCs. This can provide periodic interrupt rates from 1Hz to 64Hz for user programs, and wakeup from Alarm. - The driver currently supports the common features on all the - S3C24XX range, such as the S3C2410, S3C2412, S3C2413, S3C2440 - and S3C2442. - This driver can also be build as a module. If so, the module will be called rtc-s3c. diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index d3c042dcbc73..59eb30289335 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -176,7 +176,6 @@ obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o -obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o obj-$(CONFIG_RTC_DRV_WILCO_EC) += rtc-wilco-ec.o obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index e991cccdb6e9..1e8bc6cc1e12 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -188,9 +188,10 @@ static int efi_set_time(struct device *dev, struct rtc_time *tm) static int efi_procfs(struct device *dev, struct seq_file *seq) { - efi_time_t eft, alm; - efi_time_cap_t cap; - efi_bool_t enabled, pending; + efi_time_t eft, alm; + efi_time_cap_t cap; + efi_bool_t enabled, pending; + struct rtc_device *rtc = dev_get_drvdata(dev); memset(&eft, 0, sizeof(eft)); memset(&alm, 0, sizeof(alm)); @@ -213,23 +214,25 @@ static int efi_procfs(struct device *dev, struct seq_file *seq) /* XXX fixme: convert to string? */ seq_printf(seq, "Timezone\t: %u\n", eft.timezone); - seq_printf(seq, - "Alarm Time\t: %u:%u:%u.%09u\n" - "Alarm Date\t: %u-%u-%u\n" - "Alarm Daylight\t: %u\n" - "Enabled\t\t: %s\n" - "Pending\t\t: %s\n", - alm.hour, alm.minute, alm.second, alm.nanosecond, - alm.year, alm.month, alm.day, - alm.daylight, - enabled == 1 ? "yes" : "no", - pending == 1 ? "yes" : "no"); - - if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE) - seq_puts(seq, "Timezone\t: unspecified\n"); - else - /* XXX fixme: convert to string? */ - seq_printf(seq, "Timezone\t: %u\n", alm.timezone); + if (test_bit(RTC_FEATURE_ALARM, rtc->features)) { + seq_printf(seq, + "Alarm Time\t: %u:%u:%u.%09u\n" + "Alarm Date\t: %u-%u-%u\n" + "Alarm Daylight\t: %u\n" + "Enabled\t\t: %s\n" + "Pending\t\t: %s\n", + alm.hour, alm.minute, alm.second, alm.nanosecond, + alm.year, alm.month, alm.day, + alm.daylight, + enabled == 1 ? "yes" : "no", + pending == 1 ? "yes" : "no"); + + if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE) + seq_puts(seq, "Timezone\t: unspecified\n"); + else + /* XXX fixme: convert to string? */ + seq_printf(seq, "Timezone\t: %u\n", alm.timezone); + } /* * now prints the capabilities @@ -269,7 +272,10 @@ static int __init efi_rtc_probe(struct platform_device *dev) rtc->ops = &efi_rtc_ops; clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); - set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->features); + if (efi_rt_services_supported(EFI_RT_SUPPORTED_WAKEUP_SERVICES)) + set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->features); + else + clear_bit(RTC_FEATURE_ALARM, rtc->features); device_init_wakeup(&dev->dev, true); diff --git a/drivers/rtc/rtc-sunplus.c b/drivers/rtc/rtc-sunplus.c index e8e2ab1103fc..4b578e4d44f6 100644 --- a/drivers/rtc/rtc-sunplus.c +++ b/drivers/rtc/rtc-sunplus.c @@ -240,8 +240,8 @@ static int sp_rtc_probe(struct platform_device *plat_dev) if (IS_ERR(sp_rtc->reg_base)) return dev_err_probe(&plat_dev->dev, PTR_ERR(sp_rtc->reg_base), "%s devm_ioremap_resource fail\n", RTC_REG_NAME); - dev_dbg(&plat_dev->dev, "res = 0x%x, reg_base = 0x%lx\n", - sp_rtc->res->start, (unsigned long)sp_rtc->reg_base); + dev_dbg(&plat_dev->dev, "res = %pR, reg_base = %p\n", + sp_rtc->res, sp_rtc->reg_base); sp_rtc->irq = platform_get_irq(plat_dev, 0); if (sp_rtc->irq < 0) diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c deleted file mode 100644 index 4e8341c49f51..000000000000 --- a/drivers/rtc/rtc-v3020.c +++ /dev/null @@ -1,369 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* drivers/rtc/rtc-v3020.c - * - * Copyright (C) 2006 8D Technologies inc. - * Copyright (C) 2004 Compulab Ltd. - * - * Driver for the V3020 RTC - * - * Changelog: - * - * 10-May-2006: Raphael Assenat <raph@8d.com> - * - Converted to platform driver - * - Use the generic rtc class - * - * ??-???-2004: Someone at Compulab - * - Initial driver creation. - */ -#include <linux/platform_device.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/rtc.h> -#include <linux/types.h> -#include <linux/bcd.h> -#include <linux/platform_data/rtc-v3020.h> -#include <linux/delay.h> -#include <linux/gpio.h> -#include <linux/slab.h> - -#include <linux/io.h> - -#undef DEBUG - -struct v3020; - -struct v3020_chip_ops { - int (*map_io)(struct v3020 *chip, struct platform_device *pdev, - struct v3020_platform_data *pdata); - void (*unmap_io)(struct v3020 *chip); - unsigned char (*read_bit)(struct v3020 *chip); - void (*write_bit)(struct v3020 *chip, unsigned char bit); -}; - -#define V3020_CS 0 -#define V3020_WR 1 -#define V3020_RD 2 -#define V3020_IO 3 - -struct v3020 { - /* MMIO access */ - void __iomem *ioaddress; - int leftshift; - - /* GPIO access */ - struct gpio *gpio; - - const struct v3020_chip_ops *ops; - - struct rtc_device *rtc; -}; - - -static int v3020_mmio_map(struct v3020 *chip, struct platform_device *pdev, - struct v3020_platform_data *pdata) -{ - if (pdev->num_resources != 1) - return -EBUSY; - - if (pdev->resource[0].flags != IORESOURCE_MEM) - return -EBUSY; - - chip->leftshift = pdata->leftshift; - chip->ioaddress = ioremap(pdev->resource[0].start, 1); - if (chip->ioaddress == NULL) - return -EBUSY; - - return 0; -} - -static void v3020_mmio_unmap(struct v3020 *chip) -{ - iounmap(chip->ioaddress); -} - -static void v3020_mmio_write_bit(struct v3020 *chip, unsigned char bit) -{ - writel(bit << chip->leftshift, chip->ioaddress); -} - -static unsigned char v3020_mmio_read_bit(struct v3020 *chip) -{ - return !!(readl(chip->ioaddress) & (1 << chip->leftshift)); -} - -static const struct v3020_chip_ops v3020_mmio_ops = { - .map_io = v3020_mmio_map, - .unmap_io = v3020_mmio_unmap, - .read_bit = v3020_mmio_read_bit, - .write_bit = v3020_mmio_write_bit, -}; - -static struct gpio v3020_gpio[] = { - { 0, GPIOF_OUT_INIT_HIGH, "RTC CS"}, - { 0, GPIOF_OUT_INIT_HIGH, "RTC WR"}, - { 0, GPIOF_OUT_INIT_HIGH, "RTC RD"}, - { 0, GPIOF_OUT_INIT_HIGH, "RTC IO"}, -}; - -static int v3020_gpio_map(struct v3020 *chip, struct platform_device *pdev, - struct v3020_platform_data *pdata) -{ - int err; - - v3020_gpio[V3020_CS].gpio = pdata->gpio_cs; - v3020_gpio[V3020_WR].gpio = pdata->gpio_wr; - v3020_gpio[V3020_RD].gpio = pdata->gpio_rd; - v3020_gpio[V3020_IO].gpio = pdata->gpio_io; - - err = gpio_request_array(v3020_gpio, ARRAY_SIZE(v3020_gpio)); - - if (!err) - chip->gpio = v3020_gpio; - - return err; -} - -static void v3020_gpio_unmap(struct v3020 *chip) -{ - gpio_free_array(v3020_gpio, ARRAY_SIZE(v3020_gpio)); -} - -static void v3020_gpio_write_bit(struct v3020 *chip, unsigned char bit) -{ - gpio_direction_output(chip->gpio[V3020_IO].gpio, bit); - gpio_set_value(chip->gpio[V3020_CS].gpio, 0); - gpio_set_value(chip->gpio[V3020_WR].gpio, 0); - udelay(1); - gpio_set_value(chip->gpio[V3020_WR].gpio, 1); - gpio_set_value(chip->gpio[V3020_CS].gpio, 1); -} - -static unsigned char v3020_gpio_read_bit(struct v3020 *chip) -{ - int bit; - - gpio_direction_input(chip->gpio[V3020_IO].gpio); - gpio_set_value(chip->gpio[V3020_CS].gpio, 0); - gpio_set_value(chip->gpio[V3020_RD].gpio, 0); - udelay(1); - bit = !!gpio_get_value(chip->gpio[V3020_IO].gpio); - udelay(1); - gpio_set_value(chip->gpio[V3020_RD].gpio, 1); - gpio_set_value(chip->gpio[V3020_CS].gpio, 1); - - return bit; -} - -static const struct v3020_chip_ops v3020_gpio_ops = { - .map_io = v3020_gpio_map, - .unmap_io = v3020_gpio_unmap, - .read_bit = v3020_gpio_read_bit, - .write_bit = v3020_gpio_write_bit, -}; - -static void v3020_set_reg(struct v3020 *chip, unsigned char address, - unsigned char data) -{ - int i; - unsigned char tmp; - - tmp = address; - for (i = 0; i < 4; i++) { - chip->ops->write_bit(chip, (tmp & 1)); - tmp >>= 1; - udelay(1); - } - - /* Commands dont have data */ - if (!V3020_IS_COMMAND(address)) { - for (i = 0; i < 8; i++) { - chip->ops->write_bit(chip, (data & 1)); - data >>= 1; - udelay(1); - } - } -} - -static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address) -{ - unsigned int data = 0; - int i; - - for (i = 0; i < 4; i++) { - chip->ops->write_bit(chip, (address & 1)); - address >>= 1; - udelay(1); - } - - for (i = 0; i < 8; i++) { - data >>= 1; - if (chip->ops->read_bit(chip)) - data |= 0x80; - udelay(1); - } - - return data; -} - -static int v3020_read_time(struct device *dev, struct rtc_time *dt) -{ - struct v3020 *chip = dev_get_drvdata(dev); - int tmp; - - /* Copy the current time to ram... */ - v3020_set_reg(chip, V3020_CMD_CLOCK2RAM, 0); - - /* ...and then read constant values. */ - tmp = v3020_get_reg(chip, V3020_SECONDS); - dt->tm_sec = bcd2bin(tmp); - tmp = v3020_get_reg(chip, V3020_MINUTES); - dt->tm_min = bcd2bin(tmp); - tmp = v3020_get_reg(chip, V3020_HOURS); - dt->tm_hour = bcd2bin(tmp); - tmp = v3020_get_reg(chip, V3020_MONTH_DAY); - dt->tm_mday = bcd2bin(tmp); - tmp = v3020_get_reg(chip, V3020_MONTH); - dt->tm_mon = bcd2bin(tmp) - 1; - tmp = v3020_get_reg(chip, V3020_WEEK_DAY); - dt->tm_wday = bcd2bin(tmp); - tmp = v3020_get_reg(chip, V3020_YEAR); - dt->tm_year = bcd2bin(tmp)+100; - - dev_dbg(dev, "\n%s : Read RTC values\n", __func__); - dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour); - dev_dbg(dev, "tm_min : %i\n", dt->tm_min); - dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec); - dev_dbg(dev, "tm_year: %i\n", dt->tm_year); - dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon); - dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday); - dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday); - - return 0; -} - - -static int v3020_set_time(struct device *dev, struct rtc_time *dt) -{ - struct v3020 *chip = dev_get_drvdata(dev); - - dev_dbg(dev, "\n%s : Setting RTC values\n", __func__); - dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec); - dev_dbg(dev, "tm_min : %i\n", dt->tm_min); - dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour); - dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday); - dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday); - dev_dbg(dev, "tm_year: %i\n", dt->tm_year); - - /* Write all the values to ram... */ - v3020_set_reg(chip, V3020_SECONDS, bin2bcd(dt->tm_sec)); - v3020_set_reg(chip, V3020_MINUTES, bin2bcd(dt->tm_min)); - v3020_set_reg(chip, V3020_HOURS, bin2bcd(dt->tm_hour)); - v3020_set_reg(chip, V3020_MONTH_DAY, bin2bcd(dt->tm_mday)); - v3020_set_reg(chip, V3020_MONTH, bin2bcd(dt->tm_mon + 1)); - v3020_set_reg(chip, V3020_WEEK_DAY, bin2bcd(dt->tm_wday)); - v3020_set_reg(chip, V3020_YEAR, bin2bcd(dt->tm_year % 100)); - - /* ...and set the clock. */ - v3020_set_reg(chip, V3020_CMD_RAM2CLOCK, 0); - - /* Compulab used this delay here. I dont know why, - * the datasheet does not specify a delay. */ - /*mdelay(5);*/ - - return 0; -} - -static const struct rtc_class_ops v3020_rtc_ops = { - .read_time = v3020_read_time, - .set_time = v3020_set_time, -}; - -static int rtc_probe(struct platform_device *pdev) -{ - struct v3020_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct v3020 *chip; - int retval; - int i; - - chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - if (pdata->use_gpio) - chip->ops = &v3020_gpio_ops; - else - chip->ops = &v3020_mmio_ops; - - retval = chip->ops->map_io(chip, pdev, pdata); - if (retval) - return retval; - - /* Make sure the v3020 expects a communication cycle - * by reading 8 times */ - for (i = 0; i < 8; i++) - chip->ops->read_bit(chip); - - /* Test chip by doing a write/read sequence - * to the chip ram */ - v3020_set_reg(chip, V3020_SECONDS, 0x33); - if (v3020_get_reg(chip, V3020_SECONDS) != 0x33) { - retval = -ENODEV; - goto err_io; - } - - /* Make sure frequency measurement mode, test modes, and lock - * are all disabled */ - v3020_set_reg(chip, V3020_STATUS_0, 0x0); - - if (pdata->use_gpio) - dev_info(&pdev->dev, "Chip available at GPIOs " - "%d, %d, %d, %d\n", - chip->gpio[V3020_CS].gpio, chip->gpio[V3020_WR].gpio, - chip->gpio[V3020_RD].gpio, chip->gpio[V3020_IO].gpio); - else - dev_info(&pdev->dev, "Chip available at " - "physical address 0x%llx," - "data connected to D%d\n", - (unsigned long long)pdev->resource[0].start, - chip->leftshift); - - platform_set_drvdata(pdev, chip); - - chip->rtc = devm_rtc_device_register(&pdev->dev, "v3020", - &v3020_rtc_ops, THIS_MODULE); - if (IS_ERR(chip->rtc)) { - retval = PTR_ERR(chip->rtc); - goto err_io; - } - - return 0; - -err_io: - chip->ops->unmap_io(chip); - - return retval; -} - -static int rtc_remove(struct platform_device *dev) -{ - struct v3020 *chip = platform_get_drvdata(dev); - - chip->ops->unmap_io(chip); - - return 0; -} - -static struct platform_driver rtc_device_driver = { - .probe = rtc_probe, - .remove = rtc_remove, - .driver = { - .name = "v3020", - }, -}; - -module_platform_driver(rtc_device_driver); - -MODULE_DESCRIPTION("V3020 RTC"); -MODULE_AUTHOR("Raphael Assenat"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:v3020"); diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 5a6d9c15395f..a9c2a8d76c45 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -3978,7 +3978,7 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, ccw = cqr->cpaddr; ccw->cmd_code = CCW_CMD_RDC; - ccw->cda = (__u32)(addr_t) cqr->data; + ccw->cda = (__u32)virt_to_phys(cqr->data); ccw->flags = 0; ccw->count = rdc_buffer_size; cqr->startdev = device; @@ -4022,8 +4022,7 @@ char *dasd_get_sense(struct irb *irb) if (scsw_is_tm(&irb->scsw) && (irb->scsw.tm.fcxs == 0x01)) { if (irb->scsw.tm.tcw) - tsb = tcw_get_tsb((struct tcw *)(unsigned long) - irb->scsw.tm.tcw); + tsb = tcw_get_tsb(phys_to_virt(irb->scsw.tm.tcw)); if (tsb && tsb->length == 64 && tsb->flags) switch (tsb->flags & 0x07) { case 1: /* tsa_iostat */ diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 81d283b3cd3b..9fd36c468706 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -220,7 +220,7 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier) memset(ccw, 0, sizeof(struct ccw1)); ccw->cmd_code = CCW_CMD_DCTL; ccw->count = 4; - ccw->cda = (__u32)(addr_t) DCTL_data; + ccw->cda = (__u32)virt_to_phys(DCTL_data); dctl_cqr->flags = erp->flags; dctl_cqr->function = dasd_3990_erp_DCTL; dctl_cqr->refers = erp; @@ -1714,7 +1714,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; ccw->flags = CCW_FLAG_CC; ccw->count = 16; - ccw->cda = (__u32)(addr_t) DE_data; + ccw->cda = (__u32)virt_to_phys(DE_data); /* create LO ccw */ ccw++; @@ -1722,7 +1722,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; ccw->flags = CCW_FLAG_CC; ccw->count = 16; - ccw->cda = (__u32)(addr_t) LO_data; + ccw->cda = (__u32)virt_to_phys(LO_data); /* TIC to the failed ccw */ ccw++; @@ -2419,7 +2419,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr) tcw = erp->cpaddr; tsb = (struct tsb *) &tcw[1]; *tcw = *((struct tcw *)cqr->cpaddr); - tcw->tsb = (long)tsb; + tcw->tsb = virt_to_phys(tsb); } else if (ccw->cmd_code == DASD_ECKD_CCW_PSF) { /* PSF cannot be chained from NOOP/TIC */ erp->cpaddr = cqr->cpaddr; @@ -2430,7 +2430,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr) ccw->flags = CCW_FLAG_CC; ccw++; ccw->cmd_code = CCW_CMD_TIC; - ccw->cda = (long)(cqr->cpaddr); + ccw->cda = (__u32)virt_to_phys(cqr->cpaddr); } erp->flags = cqr->flags; diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index b6b938aa6615..c9740ae88d1a 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -443,7 +443,7 @@ static int read_unit_address_configuration(struct dasd_device *device, ccw->cmd_code = DASD_ECKD_CCW_PSF; ccw->count = sizeof(struct dasd_psf_prssd_data); ccw->flags |= CCW_FLAG_CC; - ccw->cda = (__u32)(addr_t) prssdp; + ccw->cda = (__u32)virt_to_phys(prssdp); /* Read Subsystem Data - feature codes */ memset(lcu->uac, 0, sizeof(*(lcu->uac))); @@ -451,7 +451,7 @@ static int read_unit_address_configuration(struct dasd_device *device, ccw++; ccw->cmd_code = DASD_ECKD_CCW_RSSD; ccw->count = sizeof(*(lcu->uac)); - ccw->cda = (__u32)(addr_t) lcu->uac; + ccw->cda = (__u32)virt_to_phys(lcu->uac); cqr->buildclk = get_tod_clock(); cqr->status = DASD_CQR_FILLED; @@ -747,7 +747,7 @@ static int reset_summary_unit_check(struct alias_lcu *lcu, ccw->cmd_code = DASD_ECKD_CCW_RSCK; ccw->flags = CCW_FLAG_SLI; ccw->count = 16; - ccw->cda = (__u32)(addr_t) cqr->data; + ccw->cda = (__u32)virt_to_phys(cqr->data); ((char *)cqr->data)[0] = reason; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 5d0b9991e91a..1a69f97e88fb 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -288,7 +288,7 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk, ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; ccw->flags = 0; ccw->count = 16; - ccw->cda = (__u32)__pa(data); + ccw->cda = (__u32)virt_to_phys(data); } memset(data, 0, sizeof(struct DE_eckd_data)); @@ -398,7 +398,7 @@ static void locate_record_ext(struct ccw1 *ccw, struct LRE_eckd_data *data, ccw->count = 22; else ccw->count = 20; - ccw->cda = (__u32)__pa(data); + ccw->cda = (__u32)virt_to_phys(data); } memset(data, 0, sizeof(*data)); @@ -544,11 +544,11 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, ccw->flags = 0; if (cmd == DASD_ECKD_CCW_WRITE_FULL_TRACK) { ccw->count = sizeof(*pfxdata) + 2; - ccw->cda = (__u32) __pa(pfxdata); + ccw->cda = (__u32)virt_to_phys(pfxdata); memset(pfxdata, 0, sizeof(*pfxdata) + 2); } else { ccw->count = sizeof(*pfxdata); - ccw->cda = (__u32) __pa(pfxdata); + ccw->cda = (__u32)virt_to_phys(pfxdata); memset(pfxdata, 0, sizeof(*pfxdata)); } @@ -615,7 +615,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, unsigned int trk, ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; ccw->flags = 0; ccw->count = 16; - ccw->cda = (__u32) __pa(data); + ccw->cda = (__u32)virt_to_phys(data); memset(data, 0, sizeof(struct LO_eckd_data)); sector = 0; @@ -830,7 +830,7 @@ static void dasd_eckd_fill_rcd_cqr(struct dasd_device *device, ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_RCD; ccw->flags = 0; - ccw->cda = (__u32)(addr_t)rcd_buffer; + ccw->cda = (__u32)virt_to_phys(rcd_buffer); ccw->count = DASD_ECKD_RCD_DATA_SIZE; cqr->magic = DASD_ECKD_MAGIC; @@ -858,7 +858,7 @@ static void read_conf_cb(struct dasd_ccw_req *cqr, void *data) if (cqr->status != DASD_CQR_DONE) { ccw = cqr->cpaddr; - rcd_buffer = (__u8 *)((addr_t) ccw->cda); + rcd_buffer = phys_to_virt(ccw->cda); memset(rcd_buffer, 0, sizeof(*rcd_buffer)); rcd_buffer[0] = 0xE5; @@ -1547,7 +1547,7 @@ static int dasd_eckd_read_features(struct dasd_device *device) ccw->cmd_code = DASD_ECKD_CCW_PSF; ccw->count = sizeof(struct dasd_psf_prssd_data); ccw->flags |= CCW_FLAG_CC; - ccw->cda = (__u32)(addr_t) prssdp; + ccw->cda = (__u32)virt_to_phys(prssdp); /* Read Subsystem Data - feature codes */ features = (struct dasd_rssd_features *) (prssdp + 1); @@ -1556,7 +1556,7 @@ static int dasd_eckd_read_features(struct dasd_device *device) ccw++; ccw->cmd_code = DASD_ECKD_CCW_RSSD; ccw->count = sizeof(struct dasd_rssd_features); - ccw->cda = (__u32)(addr_t) features; + ccw->cda = (__u32)virt_to_phys(features); cqr->buildclk = get_tod_clock(); cqr->status = DASD_CQR_FILLED; @@ -1616,7 +1616,7 @@ static int dasd_eckd_read_vol_info(struct dasd_device *device) ccw->cmd_code = DASD_ECKD_CCW_PSF; ccw->count = sizeof(*prssdp); ccw->flags |= CCW_FLAG_CC; - ccw->cda = (__u32)(addr_t)prssdp; + ccw->cda = (__u32)virt_to_phys(prssdp); /* Read Subsystem Data - Volume Storage Query */ vsq = (struct dasd_rssd_vsq *)(prssdp + 1); @@ -1626,7 +1626,7 @@ static int dasd_eckd_read_vol_info(struct dasd_device *device) ccw->cmd_code = DASD_ECKD_CCW_RSSD; ccw->count = sizeof(*vsq); ccw->flags |= CCW_FLAG_SLI; - ccw->cda = (__u32)(addr_t)vsq; + ccw->cda = (__u32)virt_to_phys(vsq); cqr->buildclk = get_tod_clock(); cqr->status = DASD_CQR_FILLED; @@ -1801,7 +1801,7 @@ static int dasd_eckd_read_ext_pool_info(struct dasd_device *device) ccw->cmd_code = DASD_ECKD_CCW_PSF; ccw->count = sizeof(*prssdp); ccw->flags |= CCW_FLAG_CC; - ccw->cda = (__u32)(addr_t)prssdp; + ccw->cda = (__u32)virt_to_phys(prssdp); lcq = (struct dasd_rssd_lcq *)(prssdp + 1); memset(lcq, 0, sizeof(*lcq)); @@ -1810,7 +1810,7 @@ static int dasd_eckd_read_ext_pool_info(struct dasd_device *device) ccw->cmd_code = DASD_ECKD_CCW_RSSD; ccw->count = sizeof(*lcq); ccw->flags |= CCW_FLAG_SLI; - ccw->cda = (__u32)(addr_t)lcq; + ccw->cda = (__u32)virt_to_phys(lcq); cqr->buildclk = get_tod_clock(); cqr->status = DASD_CQR_FILLED; @@ -1907,7 +1907,7 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device, } ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_PSF; - ccw->cda = (__u32)(addr_t)psf_ssc_data; + ccw->cda = (__u32)virt_to_phys(psf_ssc_data); ccw->count = 66; cqr->startdev = device; @@ -2262,7 +2262,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device) ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; ccw->flags = 0; ccw->count = 8; - ccw->cda = (__u32)(addr_t) count_data; + ccw->cda = (__u32)virt_to_phys(count_data); ccw++; count_data++; } @@ -2276,7 +2276,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device) ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; ccw->flags = 0; ccw->count = 8; - ccw->cda = (__u32)(addr_t) count_data; + ccw->cda = (__u32)virt_to_phys(count_data); cqr->block = NULL; cqr->startdev = device; @@ -2647,7 +2647,7 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata, ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; ccw->flags = CCW_FLAG_SLI; ccw->count = 8; - ccw->cda = (__u32)(addr_t) fmt_buffer; + ccw->cda = (__u32)virt_to_phys(fmt_buffer); ccw++; fmt_buffer++; } @@ -2857,7 +2857,7 @@ dasd_eckd_build_format(struct dasd_device *base, struct dasd_device *startdev, ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO; ccw->flags = CCW_FLAG_SLI; ccw->count = 8; - ccw->cda = (__u32)(addr_t) ect; + ccw->cda = (__u32)virt_to_phys(ect); ccw++; } if ((intensity & ~0x08) & 0x04) { /* erase track */ @@ -2872,7 +2872,7 @@ dasd_eckd_build_format(struct dasd_device *base, struct dasd_device *startdev, ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD; ccw->flags = CCW_FLAG_SLI; ccw->count = 8; - ccw->cda = (__u32)(addr_t) ect; + ccw->cda = (__u32)virt_to_phys(ect); } else { /* write remaining records */ for (i = 0; i < rpt; i++) { ect = (struct eckd_count *) data; @@ -2907,7 +2907,7 @@ dasd_eckd_build_format(struct dasd_device *base, struct dasd_device *startdev, DASD_ECKD_CCW_WRITE_CKD_MT; ccw->flags = CCW_FLAG_SLI; ccw->count = 8; - ccw->cda = (__u32)(addr_t) ect; + ccw->cda = (__u32)virt_to_phys(ect); ccw++; } } @@ -3821,7 +3821,7 @@ dasd_eckd_dso_ras(struct dasd_device *device, struct dasd_block *block, } ccw = cqr->cpaddr; - ccw->cda = (__u32)(addr_t)cqr->data; + ccw->cda = (__u32)virt_to_phys(cqr->data); ccw->cmd_code = DASD_ECKD_CCW_DSO; ccw->count = size; @@ -4090,11 +4090,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( ccw->cmd_code = rcmd; ccw->count = count; if (idal_is_needed(dst, blksize)) { - ccw->cda = (__u32)(addr_t) idaws; + ccw->cda = (__u32)virt_to_phys(idaws); ccw->flags = CCW_FLAG_IDA; idaws = idal_create_words(idaws, dst, blksize); } else { - ccw->cda = (__u32)(addr_t) dst; + ccw->cda = (__u32)virt_to_phys(dst); ccw->flags = 0; } ccw++; @@ -4228,7 +4228,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( ccw[-1].flags |= CCW_FLAG_CC; ccw->cmd_code = cmd; ccw->count = len_to_track_end; - ccw->cda = (__u32)(addr_t)idaws; + ccw->cda = (__u32)virt_to_phys(idaws); ccw->flags = CCW_FLAG_IDA; ccw++; recid += count; @@ -4244,7 +4244,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( * idaw ends */ if (!idaw_dst) { - if (__pa(dst) & (IDA_BLOCK_SIZE-1)) { + if ((__u32)virt_to_phys(dst) & (IDA_BLOCK_SIZE - 1)) { dasd_sfree_request(cqr, startdev); return ERR_PTR(-ERANGE); } else @@ -4264,7 +4264,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( * idal_create_words will handle cases where idaw_len * is larger then IDA_BLOCK_SIZE */ - if (!(__pa(idaw_dst + idaw_len) & (IDA_BLOCK_SIZE-1))) + if (!((__u32)virt_to_phys(idaw_dst + idaw_len) & (IDA_BLOCK_SIZE - 1))) end_idaw = 1; /* We also need to end the idaw at track end */ if (!len_to_track_end) { @@ -4817,7 +4817,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev, ccw->count = 57326; /* 64k map to one track */ len_to_track_end = 65536 - start_padding_sectors * 512; - ccw->cda = (__u32)(addr_t)idaws; + ccw->cda = (__u32)virt_to_phys(idaws); ccw->flags |= CCW_FLAG_IDA; ccw->flags |= CCW_FLAG_SLI; ccw++; @@ -4836,7 +4836,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev, ccw->count = 57326; /* 64k map to one track */ len_to_track_end = 65536; - ccw->cda = (__u32)(addr_t)idaws; + ccw->cda = (__u32)virt_to_phys(idaws); ccw->flags |= CCW_FLAG_IDA; ccw->flags |= CCW_FLAG_SLI; ccw++; @@ -4893,9 +4893,9 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) ccw++; if (dst) { if (ccw->flags & CCW_FLAG_IDA) - cda = *((char **)((addr_t) ccw->cda)); + cda = *((char **)phys_to_virt(ccw->cda)); else - cda = (char *)((addr_t) ccw->cda); + cda = phys_to_virt(ccw->cda); if (dst != cda) { if (rq_data_dir(req) == READ) memcpy(dst, cda, bv.bv_len); @@ -5045,7 +5045,7 @@ dasd_eckd_release(struct dasd_device *device) ccw->cmd_code = DASD_ECKD_CCW_RELEASE; ccw->flags |= CCW_FLAG_SLI; ccw->count = 32; - ccw->cda = (__u32)(addr_t) cqr->data; + ccw->cda = (__u32)virt_to_phys(cqr->data); cqr->startdev = device; cqr->memdev = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); @@ -5100,7 +5100,7 @@ dasd_eckd_reserve(struct dasd_device *device) ccw->cmd_code = DASD_ECKD_CCW_RESERVE; ccw->flags |= CCW_FLAG_SLI; ccw->count = 32; - ccw->cda = (__u32)(addr_t) cqr->data; + ccw->cda = (__u32)virt_to_phys(cqr->data); cqr->startdev = device; cqr->memdev = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); @@ -5154,7 +5154,7 @@ dasd_eckd_steal_lock(struct dasd_device *device) ccw->cmd_code = DASD_ECKD_CCW_SLCK; ccw->flags |= CCW_FLAG_SLI; ccw->count = 32; - ccw->cda = (__u32)(addr_t) cqr->data; + ccw->cda = (__u32)virt_to_phys(cqr->data); cqr->startdev = device; cqr->memdev = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); @@ -5215,7 +5215,7 @@ static int dasd_eckd_snid(struct dasd_device *device, ccw->cmd_code = DASD_ECKD_CCW_SNID; ccw->flags |= CCW_FLAG_SLI; ccw->count = 12; - ccw->cda = (__u32)(addr_t) cqr->data; + ccw->cda = (__u32)virt_to_phys(cqr->data); cqr->startdev = device; cqr->memdev = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); @@ -5282,7 +5282,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp) ccw->cmd_code = DASD_ECKD_CCW_PSF; ccw->count = sizeof(struct dasd_psf_prssd_data); ccw->flags |= CCW_FLAG_CC; - ccw->cda = (__u32)(addr_t) prssdp; + ccw->cda = (__u32)virt_to_phys(prssdp); /* Read Subsystem Data - Performance Statistics */ stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1); @@ -5291,7 +5291,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp) ccw++; ccw->cmd_code = DASD_ECKD_CCW_RSSD; ccw->count = sizeof(struct dasd_rssd_perf_stats_t); - ccw->cda = (__u32)(addr_t) stats; + ccw->cda = (__u32)virt_to_phys(stats); cqr->buildclk = get_tod_clock(); cqr->status = DASD_CQR_FILLED; @@ -5435,7 +5435,7 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp) ccw->cmd_code = DASD_ECKD_CCW_PSF; ccw->count = usrparm.psf_data_len; ccw->flags |= CCW_FLAG_CC; - ccw->cda = (__u32)(addr_t) psf_data; + ccw->cda = (__u32)virt_to_phys(psf_data); ccw++; @@ -5443,7 +5443,7 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp) ccw->cmd_code = DASD_ECKD_CCW_RSSD; ccw->count = usrparm.rssd_result_len; ccw->flags = CCW_FLAG_SLI ; - ccw->cda = (__u32)(addr_t) rssd_result; + ccw->cda = (__u32)virt_to_phys(rssd_result); rc = dasd_sleep_on(cqr); if (rc) @@ -5512,9 +5512,9 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page) /* get pointer to data (consider IDALs) */ if (from->flags & CCW_FLAG_IDA) - datap = (char *) *((addr_t *) (addr_t) from->cda); + datap = (char *)*((addr_t *)phys_to_virt(from->cda)); else - datap = (char *) ((addr_t) from->cda); + datap = phys_to_virt(from->cda); /* dump data (max 128 bytes) */ for (count = 0; count < from->count && count < 128; count++) { @@ -5585,7 +5585,7 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device, len += sprintf(page + len, PRINTK_HEADER " device %s: Failing CCW: %p\n", dev_name(&device->cdev->dev), - (void *) (addr_t) irb->scsw.cmd.cpa); + phys_to_virt(irb->scsw.cmd.cpa)); if (irb->esw.esw0.erw.cons) { for (sl = 0; sl < 4; sl++) { len += sprintf(page + len, PRINTK_HEADER @@ -5632,8 +5632,7 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device, /* print failing CCW area (maximum 4) */ /* scsw->cda is either valid or zero */ from = ++to; - fail = (struct ccw1 *)(addr_t) - irb->scsw.cmd.cpa; /* failing CCW */ + fail = phys_to_virt(irb->scsw.cmd.cpa); /* failing CCW */ if (from < fail - 2) { from = fail - 2; /* there is a gap - print header */ printk(KERN_ERR PRINTK_HEADER "......\n"); @@ -5687,13 +5686,12 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, len += sprintf(page + len, PRINTK_HEADER " device %s: Failing TCW: %p\n", dev_name(&device->cdev->dev), - (void *) (addr_t) irb->scsw.tm.tcw); + phys_to_virt(irb->scsw.tm.tcw)); tsb = NULL; sense = NULL; if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs & 0x01)) - tsb = tcw_get_tsb( - (struct tcw *)(unsigned long)irb->scsw.tm.tcw); + tsb = tcw_get_tsb(phys_to_virt(irb->scsw.tm.tcw)); if (tsb) { len += sprintf(page + len, PRINTK_HEADER @@ -5917,7 +5915,7 @@ retry: ccw->count = sizeof(struct dasd_psf_prssd_data); ccw->flags |= CCW_FLAG_CC; ccw->flags |= CCW_FLAG_SLI; - ccw->cda = (__u32)(addr_t) prssdp; + ccw->cda = (__u32)virt_to_phys(prssdp); /* Read Subsystem Data - message buffer */ message_buf = (struct dasd_rssd_messages *) (prssdp + 1); @@ -5927,7 +5925,7 @@ retry: ccw->cmd_code = DASD_ECKD_CCW_RSSD; ccw->count = sizeof(struct dasd_rssd_messages); ccw->flags |= CCW_FLAG_SLI; - ccw->cda = (__u32)(addr_t) message_buf; + ccw->cda = (__u32)virt_to_phys(message_buf); cqr->buildclk = get_tod_clock(); cqr->status = DASD_CQR_FILLED; @@ -6008,14 +6006,14 @@ static int dasd_eckd_query_host_access(struct dasd_device *device, ccw->count = sizeof(struct dasd_psf_prssd_data); ccw->flags |= CCW_FLAG_CC; ccw->flags |= CCW_FLAG_SLI; - ccw->cda = (__u32)(addr_t) prssdp; + ccw->cda = (__u32)virt_to_phys(prssdp); /* Read Subsystem Data - query host access */ ccw++; ccw->cmd_code = DASD_ECKD_CCW_RSSD; ccw->count = sizeof(struct dasd_psf_query_host_access); ccw->flags |= CCW_FLAG_SLI; - ccw->cda = (__u32)(addr_t) host_access; + ccw->cda = (__u32)virt_to_phys(host_access); cqr->buildclk = get_tod_clock(); cqr->status = DASD_CQR_FILLED; @@ -6351,7 +6349,7 @@ dasd_eckd_psf_cuir_response(struct dasd_device *device, int response, psf_cuir->ssid = device->path[pos].ssid; ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_PSF; - ccw->cda = (__u32)(addr_t)psf_cuir; + ccw->cda = (__u32)virt_to_phys(psf_cuir); ccw->flags = CCW_FLAG_SLI; ccw->count = sizeof(struct dasd_psf_cuir_response); @@ -6956,8 +6954,10 @@ dasd_eckd_init(void) return -ENOMEM; dasd_vol_info_req = kmalloc(sizeof(*dasd_vol_info_req), GFP_KERNEL | GFP_DMA); - if (!dasd_vol_info_req) + if (!dasd_vol_info_req) { + kfree(dasd_reserve_req); return -ENOMEM; + } pe_handler_worker = kmalloc(sizeof(*pe_handler_worker), GFP_KERNEL | GFP_DMA); if (!pe_handler_worker) { diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index d4d31cd11d26..a4cc772208a6 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -491,7 +491,7 @@ int dasd_eer_enable(struct dasd_device *device) ccw->cmd_code = DASD_ECKD_CCW_SNSS; ccw->count = SNSS_DATA_SIZE; ccw->flags = 0; - ccw->cda = (__u32)(addr_t) cqr->data; + ccw->cda = (__u32)virt_to_phys(cqr->data); cqr->buildclk = get_tod_clock(); cqr->status = DASD_CQR_FILLED; diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index cddfb01a3dca..bcb67fa747a7 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -83,7 +83,7 @@ define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw, ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT; ccw->flags = 0; ccw->count = 16; - ccw->cda = (__u32) __pa(data); + ccw->cda = (__u32)virt_to_phys(data); memset(data, 0, sizeof (struct DE_fba_data)); if (rw == WRITE) (data->mask).perm = 0x0; @@ -103,7 +103,7 @@ locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw, ccw->cmd_code = DASD_FBA_CCW_LOCATE; ccw->flags = 0; ccw->count = 8; - ccw->cda = (__u32) __pa(data); + ccw->cda = (__u32)virt_to_phys(data); memset(data, 0, sizeof (struct LO_fba_data)); if (rw == WRITE) data->operation.cmd = 0x5; @@ -262,7 +262,7 @@ static void ccw_write_zero(struct ccw1 *ccw, int count) ccw->cmd_code = DASD_FBA_CCW_WRITE; ccw->flags |= CCW_FLAG_SLI; ccw->count = count; - ccw->cda = (__u32) (addr_t) dasd_fba_zero_page; + ccw->cda = (__u32)virt_to_phys(dasd_fba_zero_page); } /* @@ -528,11 +528,11 @@ static struct dasd_ccw_req *dasd_fba_build_cp_regular( ccw->cmd_code = cmd; ccw->count = block->bp_block; if (idal_is_needed(dst, blksize)) { - ccw->cda = (__u32)(addr_t) idaws; + ccw->cda = (__u32)virt_to_phys(idaws); ccw->flags = CCW_FLAG_IDA; idaws = idal_create_words(idaws, dst, blksize); } else { - ccw->cda = (__u32)(addr_t) dst; + ccw->cda = (__u32)virt_to_phys(dst); ccw->flags = 0; } ccw++; @@ -590,9 +590,9 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) ccw++; if (dst) { if (ccw->flags & CCW_FLAG_IDA) - cda = *((char **)((addr_t) ccw->cda)); + cda = *((char **)phys_to_virt(ccw->cda)); else - cda = (char *)((addr_t) ccw->cda); + cda = phys_to_virt(ccw->cda); if (dst != cda) { if (rq_data_dir(req) == READ) memcpy(dst, cda, bv.bv_len); diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index b392b9f5482e..c09f2e053bf8 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -864,8 +864,6 @@ dcssblk_submit_bio(struct bio *bio) unsigned long source_addr; unsigned long bytes_done; - bio = bio_split_to_limits(bio); - bytes_done = 0; dev_info = bio->bi_bdev->bd_disk->private_data; if (dev_info == NULL) diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 406be169173c..d1adc4b83193 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -410,13 +410,13 @@ static ssize_t qeth_dev_isolation_show(struct device *dev, switch (card->options.isolation) { case ISOLATION_MODE_NONE: - return snprintf(buf, 6, "%s\n", ATTR_QETH_ISOLATION_NONE); + return sysfs_emit(buf, "%s\n", ATTR_QETH_ISOLATION_NONE); case ISOLATION_MODE_FWD: - return snprintf(buf, 9, "%s\n", ATTR_QETH_ISOLATION_FWD); + return sysfs_emit(buf, "%s\n", ATTR_QETH_ISOLATION_FWD); case ISOLATION_MODE_DROP: - return snprintf(buf, 6, "%s\n", ATTR_QETH_ISOLATION_DROP); + return sysfs_emit(buf, "%s\n", ATTR_QETH_ISOLATION_DROP); default: - return snprintf(buf, 5, "%s\n", "N/A"); + return sysfs_emit(buf, "%s\n", "N/A"); } } @@ -500,9 +500,9 @@ static ssize_t qeth_hw_trap_show(struct device *dev, struct qeth_card *card = dev_get_drvdata(dev); if (card->info.hwtrap) - return snprintf(buf, 5, "arm\n"); + return sysfs_emit(buf, "arm\n"); else - return snprintf(buf, 8, "disarm\n"); + return sysfs_emit(buf, "disarm\n"); } static ssize_t qeth_hw_trap_store(struct device *dev, diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 49cc18a87473..29a2865b8e2e 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -981,6 +981,9 @@ queue_rtpg: * * Returns true if and only if alua_rtpg_work() will be called asynchronously. * That function is responsible for calling @qdata->fn(). + * + * Context: may be called from atomic context (alua_check()) only if the caller + * holds an sdev reference. */ static bool alua_rtpg_queue(struct alua_port_group *pg, struct scsi_device *sdev, @@ -989,8 +992,6 @@ static bool alua_rtpg_queue(struct alua_port_group *pg, int start_queue = 0; unsigned long flags; - might_sleep(); - if (WARN_ON_ONCE(!pg) || scsi_device_get(sdev)) return false; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 41ba22f6c7f0..8c038ccf1c09 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -162,7 +162,7 @@ static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx) static void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx) { if (hisi_hba->hw->slot_index_alloc || - slot_idx >= HISI_SAS_UNRESERVED_IPTT) { + slot_idx < HISI_SAS_RESERVED_IPTT) { spin_lock(&hisi_hba->lock); hisi_sas_slot_index_clear(hisi_hba, slot_idx); spin_unlock(&hisi_hba->lock); @@ -704,7 +704,7 @@ static int hisi_sas_init_device(struct domain_device *device) int_to_scsilun(0, &lun); while (retry-- > 0) { - rc = sas_clear_task_set(device, lun.scsi_lun); + rc = sas_abort_task_set(device, lun.scsi_lun); if (rc == TMF_RESP_FUNC_COMPLETE) { hisi_sas_release_task(hisi_hba, device); break; @@ -1316,7 +1316,7 @@ static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba) device->linkrate = phy->sas_phy.linkrate; hisi_hba->hw->setup_itct(hisi_hba, sas_dev); - } else + } else if (!port->port_attached) port->id = 0xff; } } diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4dbf51e2623a..f6da34850af9 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5850,7 +5850,7 @@ static int hpsa_scsi_host_alloc(struct ctlr_info *h) { struct Scsi_Host *sh; - sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h)); + sh = scsi_host_alloc(&hpsa_driver_template, sizeof(struct ctlr_info)); if (sh == NULL) { dev_err(&h->pdev->dev, "scsi_host_alloc failed\n"); return -ENOMEM; diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 1d1cf641937c..0454d94e8cf0 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -849,7 +849,7 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf) { struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(shost); - struct iscsi_session *session = tcp_sw_host->session; + struct iscsi_session *session; struct iscsi_conn *conn; struct iscsi_tcp_conn *tcp_conn; struct iscsi_sw_tcp_conn *tcp_sw_conn; @@ -859,6 +859,7 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost, switch (param) { case ISCSI_HOST_PARAM_IPADDRESS: + session = tcp_sw_host->session; if (!session) return -ENOTCONN; @@ -959,11 +960,13 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, if (!cls_session) goto remove_host; session = cls_session->dd_data; - tcp_sw_host = iscsi_host_priv(shost); - tcp_sw_host->session = session; if (iscsi_tcp_r2tpool_alloc(session)) goto remove_session; + + /* We are now fully setup so expose the session to sysfs. */ + tcp_sw_host = iscsi_host_priv(shost); + tcp_sw_host->session = session; return cls_session; remove_session: @@ -983,10 +986,17 @@ static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session) if (WARN_ON_ONCE(session->leadconn)) return; + iscsi_session_remove(cls_session); + /* + * Our get_host_param needs to access the session, so remove the + * host from sysfs before freeing the session to make sure userspace + * is no longer accessing the callout. + */ + iscsi_host_remove(shost, false); + iscsi_tcp_r2tpool_free(cls_session->dd_data); - iscsi_session_teardown(cls_session); - iscsi_host_remove(shost, false); + iscsi_session_free(cls_session); iscsi_host_free(shost); } diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index ef2fc860257e..127f3d7f19dc 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -3104,17 +3104,32 @@ dec_session_count: } EXPORT_SYMBOL_GPL(iscsi_session_setup); -/** - * iscsi_session_teardown - destroy session, host, and cls_session - * @cls_session: iscsi session +/* + * issi_session_remove - Remove session from iSCSI class. */ -void iscsi_session_teardown(struct iscsi_cls_session *cls_session) +void iscsi_session_remove(struct iscsi_cls_session *cls_session) { struct iscsi_session *session = cls_session->dd_data; - struct module *owner = cls_session->transport->owner; struct Scsi_Host *shost = session->host; iscsi_remove_session(cls_session); + /* + * host removal only has to wait for its children to be removed from + * sysfs, and iscsi_tcp needs to do iscsi_host_remove before freeing + * the session, so drop the session count here. + */ + iscsi_host_dec_session_cnt(shost); +} +EXPORT_SYMBOL_GPL(iscsi_session_remove); + +/** + * iscsi_session_free - Free iscsi session and it's resources + * @cls_session: iscsi session + */ +void iscsi_session_free(struct iscsi_cls_session *cls_session) +{ + struct iscsi_session *session = cls_session->dd_data; + struct module *owner = cls_session->transport->owner; iscsi_pool_free(&session->cmdpool); kfree(session->password); @@ -3132,10 +3147,19 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) kfree(session->discovery_parent_type); iscsi_free_session(cls_session); - - iscsi_host_dec_session_cnt(shost); module_put(owner); } +EXPORT_SYMBOL_GPL(iscsi_session_free); + +/** + * iscsi_session_teardown - destroy session and cls_session + * @cls_session: iscsi session + */ +void iscsi_session_teardown(struct iscsi_cls_session *cls_session) +{ + iscsi_session_remove(cls_session); + iscsi_session_free(cls_session); +} EXPORT_SYMBOL_GPL(iscsi_session_teardown); /** diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 1ccce706167a..5e80225b5308 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -889,7 +889,9 @@ void sas_ata_device_link_abort(struct domain_device *device, bool force_reset) { struct ata_port *ap = device->sata_dev.ap; struct ata_link *link = &ap->link; + unsigned long flags; + spin_lock_irqsave(ap->lock, flags); device->sata_dev.fis[2] = ATA_ERR | ATA_DRDY; /* tf status */ device->sata_dev.fis[3] = ATA_ABORTED; /* tf error */ @@ -897,6 +899,7 @@ void sas_ata_device_link_abort(struct domain_device *device, bool force_reset) if (force_reset) link->eh_info.action |= ATA_EH_RESET; ata_link_abort(link); + spin_unlock_irqrestore(ap->lock, flags); } EXPORT_SYMBOL_GPL(sas_ata_device_link_abort); diff --git a/drivers/scsi/mpi3mr/Makefile b/drivers/scsi/mpi3mr/Makefile index ef86ca46646b..3bf8cf34e1c3 100644 --- a/drivers/scsi/mpi3mr/Makefile +++ b/drivers/scsi/mpi3mr/Makefile @@ -1,5 +1,5 @@ # mpi3mr makefile -obj-m += mpi3mr.o +obj-$(CONFIG_SCSI_MPI3MR) += mpi3mr.o mpi3mr-y += mpi3mr_os.o \ mpi3mr_fw.o \ mpi3mr_app.o \ diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 0c4aabaefdcc..286a44506578 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -3633,8 +3633,7 @@ int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc) int i, retval = 0, capb = 0; u16 message_control; u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask : - (((dma_get_required_mask(&pdev->dev) > DMA_BIT_MASK(32)) && - (sizeof(dma_addr_t) > 4)) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32)); + ((sizeof(dma_addr_t) > 4) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32)); if (pci_enable_device_mem(pdev)) { ioc_err(mrioc, "pci_enable_device_mem: failed\n"); diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 4e981ccaac41..69061545d9d2 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -2992,8 +2992,7 @@ _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev) struct sysinfo s; u64 coherent_dma_mask, dma_mask; - if (ioc->is_mcpu_endpoint || sizeof(dma_addr_t) == 4 || - dma_get_required_mask(&pdev->dev) <= DMA_BIT_MASK(32)) { + if (ioc->is_mcpu_endpoint || sizeof(dma_addr_t) == 4) { ioc->dma_mask = 32; coherent_dma_mask = dma_mask = DMA_BIT_MASK(32); /* Set 63 bit DMA mask for all SAS3 and SAS35 controllers */ diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 1426b9b03612..9feb0323bc44 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -588,8 +588,6 @@ void scsi_device_put(struct scsi_device *sdev) { struct module *mod = sdev->host->hostt->module; - might_sleep(); - put_device(&sdev->sdev_gendev); module_put(mod); } diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index cc6953809a24..8553277effb3 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1511,8 +1511,6 @@ static int inquiry_vpd_b0(unsigned char *arr) put_unaligned_be64(sdebug_write_same_length, &arr[32]); return 0x3c; /* Mandatory page length for Logical Block Provisioning */ - - return sizeof(vpdb0_data); } /* Block device characteristics VPD page (SBC-3) */ diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index a7960ad2d386..2aa2c2aee6e7 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -231,6 +231,11 @@ scsi_abort_command(struct scsi_cmnd *scmd) struct Scsi_Host *shost = sdev->host; unsigned long flags; + if (!shost->hostt->eh_abort_handler) { + /* No abort handler, fail command directly */ + return FAILED; + } + if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) { /* * Retry after abort failed, escalate to next level. diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 7a6904a3928e..f9b18fdc7b3c 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1232,8 +1232,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, * that no LUN is present, so don't add sdev in these cases. * Two specific examples are: * 1) NetApp targets: return PQ=1, PDT=0x1f - * 2) IBM/2145 targets: return PQ=1, PDT=0 - * 3) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved" + * 2) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved" * in the UFI 1.0 spec (we cannot rely on reserved bits). * * References: @@ -1247,8 +1246,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, * PDT=00h Direct-access device (floppy) * PDT=1Fh none (no FDD connected to the requested logical unit) */ - if (((result[0] >> 5) == 1 || - (starget->pdt_1f_for_no_lun && (result[0] & 0x1f) == 0x1f)) && + if (((result[0] >> 5) == 1 || starget->pdt_1f_for_no_lun) && + (result[0] & 0x1f) == 0x1f && !scsi_is_wlun(lun)) { SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, "scsi scan: peripheral device type" diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 981d1bab2120..8ef9a5494340 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -451,6 +451,8 @@ static void scsi_device_dev_release(struct device *dev) struct scsi_vpd *vpd_pgb0 = NULL, *vpd_pgb1 = NULL, *vpd_pgb2 = NULL; unsigned long flags; + might_sleep(); + scsi_dh_release_device(sdev); parent = sdev->sdev_gendev.parent; diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 13cfd3e317cc..b9b97300e3b3 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -1677,6 +1677,13 @@ static const char *iscsi_session_state_name(int state) return name; } +static char *iscsi_session_target_state_name[] = { + [ISCSI_SESSION_TARGET_UNBOUND] = "UNBOUND", + [ISCSI_SESSION_TARGET_ALLOCATED] = "ALLOCATED", + [ISCSI_SESSION_TARGET_SCANNED] = "SCANNED", + [ISCSI_SESSION_TARGET_UNBINDING] = "UNBINDING", +}; + int iscsi_session_chkready(struct iscsi_cls_session *session) { int err; @@ -1786,9 +1793,13 @@ static int iscsi_user_scan_session(struct device *dev, void *data) if ((scan_data->channel == SCAN_WILD_CARD || scan_data->channel == 0) && (scan_data->id == SCAN_WILD_CARD || - scan_data->id == id)) + scan_data->id == id)) { scsi_scan_target(&session->dev, 0, id, scan_data->lun, scan_data->rescan); + spin_lock_irqsave(&session->lock, flags); + session->target_state = ISCSI_SESSION_TARGET_SCANNED; + spin_unlock_irqrestore(&session->lock, flags); + } } user_scan_exit: @@ -1961,31 +1972,41 @@ static void __iscsi_unbind_session(struct work_struct *work) struct iscsi_cls_host *ihost = shost->shost_data; unsigned long flags; unsigned int target_id; + bool remove_target = true; ISCSI_DBG_TRANS_SESSION(session, "Unbinding session\n"); /* Prevent new scans and make sure scanning is not in progress */ mutex_lock(&ihost->mutex); spin_lock_irqsave(&session->lock, flags); - if (session->target_id == ISCSI_MAX_TARGET) { + if (session->target_state == ISCSI_SESSION_TARGET_ALLOCATED) { + remove_target = false; + } else if (session->target_state != ISCSI_SESSION_TARGET_SCANNED) { spin_unlock_irqrestore(&session->lock, flags); mutex_unlock(&ihost->mutex); - goto unbind_session_exit; + ISCSI_DBG_TRANS_SESSION(session, + "Skipping target unbinding: Session is unbound/unbinding.\n"); + return; } + session->target_state = ISCSI_SESSION_TARGET_UNBINDING; target_id = session->target_id; session->target_id = ISCSI_MAX_TARGET; spin_unlock_irqrestore(&session->lock, flags); mutex_unlock(&ihost->mutex); - scsi_remove_target(&session->dev); + if (remove_target) + scsi_remove_target(&session->dev); if (session->ida_used) ida_free(&iscsi_sess_ida, target_id); -unbind_session_exit: iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION); ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n"); + + spin_lock_irqsave(&session->lock, flags); + session->target_state = ISCSI_SESSION_TARGET_UNBOUND; + spin_unlock_irqrestore(&session->lock, flags); } static void __iscsi_destroy_session(struct work_struct *work) @@ -2062,6 +2083,9 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) session->ida_used = true; } else session->target_id = target_id; + spin_lock_irqsave(&session->lock, flags); + session->target_state = ISCSI_SESSION_TARGET_ALLOCATED; + spin_unlock_irqrestore(&session->lock, flags); dev_set_name(&session->dev, "session%u", session->sid); err = device_add(&session->dev); @@ -4370,6 +4394,19 @@ iscsi_session_attr(discovery_parent_idx, ISCSI_PARAM_DISCOVERY_PARENT_IDX, 0); iscsi_session_attr(discovery_parent_type, ISCSI_PARAM_DISCOVERY_PARENT_TYPE, 0); static ssize_t +show_priv_session_target_state(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent); + + return sysfs_emit(buf, "%s\n", + iscsi_session_target_state_name[session->target_state]); +} + +static ISCSI_CLASS_ATTR(priv_sess, target_state, S_IRUGO, + show_priv_session_target_state, NULL); + +static ssize_t show_priv_session_state(struct device *dev, struct device_attribute *attr, char *buf) { @@ -4471,6 +4508,7 @@ static struct attribute *iscsi_session_attrs[] = { &dev_attr_sess_boot_target.attr, &dev_attr_priv_sess_recovery_tmo.attr, &dev_attr_priv_sess_state.attr, + &dev_attr_priv_sess_target_state.attr, &dev_attr_priv_sess_creator.attr, &dev_attr_sess_chap_out_idx.attr, &dev_attr_sess_chap_in_idx.attr, @@ -4584,6 +4622,8 @@ static umode_t iscsi_session_attr_is_visible(struct kobject *kobj, return S_IRUGO | S_IWUSR; else if (attr == &dev_attr_priv_sess_state.attr) return S_IRUGO; + else if (attr == &dev_attr_priv_sess_target_state.attr) + return S_IRUGO; else if (attr == &dev_attr_priv_sess_creator.attr) return S_IRUGO; else if (attr == &dev_attr_priv_sess_target_id.attr) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 47dafe6b8a66..277960decc10 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -831,6 +831,19 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) blk_queue_max_discard_sectors(q, max_blocks * (logical_block_size >> 9)); } +static void *sd_set_special_bvec(struct request *rq, unsigned int data_len) +{ + struct page *page; + + page = mempool_alloc(sd_page_pool, GFP_ATOMIC); + if (!page) + return NULL; + clear_highpage(page); + bvec_set_page(&rq->special_vec, page, data_len, 0); + rq->rq_flags |= RQF_SPECIAL_PAYLOAD; + return bvec_virt(&rq->special_vec); +} + static blk_status_t sd_setup_unmap_cmnd(struct scsi_cmnd *cmd) { struct scsi_device *sdp = cmd->device; @@ -841,19 +854,14 @@ static blk_status_t sd_setup_unmap_cmnd(struct scsi_cmnd *cmd) unsigned int data_len = 24; char *buf; - rq->special_vec.bv_page = mempool_alloc(sd_page_pool, GFP_ATOMIC); - if (!rq->special_vec.bv_page) + buf = sd_set_special_bvec(rq, data_len); + if (!buf) return BLK_STS_RESOURCE; - clear_highpage(rq->special_vec.bv_page); - rq->special_vec.bv_offset = 0; - rq->special_vec.bv_len = data_len; - rq->rq_flags |= RQF_SPECIAL_PAYLOAD; cmd->cmd_len = 10; cmd->cmnd[0] = UNMAP; cmd->cmnd[8] = 24; - buf = bvec_virt(&rq->special_vec); put_unaligned_be16(6 + 16, &buf[0]); put_unaligned_be16(16, &buf[2]); put_unaligned_be64(lba, &buf[8]); @@ -876,13 +884,8 @@ static blk_status_t sd_setup_write_same16_cmnd(struct scsi_cmnd *cmd, u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq)); u32 data_len = sdp->sector_size; - rq->special_vec.bv_page = mempool_alloc(sd_page_pool, GFP_ATOMIC); - if (!rq->special_vec.bv_page) + if (!sd_set_special_bvec(rq, data_len)) return BLK_STS_RESOURCE; - clear_highpage(rq->special_vec.bv_page); - rq->special_vec.bv_offset = 0; - rq->special_vec.bv_len = data_len; - rq->rq_flags |= RQF_SPECIAL_PAYLOAD; cmd->cmd_len = 16; cmd->cmnd[0] = WRITE_SAME_16; @@ -908,13 +911,8 @@ static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd, u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq)); u32 data_len = sdp->sector_size; - rq->special_vec.bv_page = mempool_alloc(sd_page_pool, GFP_ATOMIC); - if (!rq->special_vec.bv_page) + if (!sd_set_special_bvec(rq, data_len)) return BLK_STS_RESOURCE; - clear_highpage(rq->special_vec.bv_page); - rq->special_vec.bv_offset = 0; - rq->special_vec.bv_len = data_len; - rq->rq_flags |= RQF_SPECIAL_PAYLOAD; cmd->cmd_len = 10; cmd->cmnd[0] = WRITE_SAME; diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index d7a84c0bfaeb..22705eb781b0 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1823,6 +1823,9 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) ret = storvsc_do_io(dev, cmd_request, get_cpu()); put_cpu(); + if (ret) + scsi_dma_unmap(scmnd); + if (ret == -EAGAIN) { /* no more space */ ret = SCSI_MLQUEUE_DEVICE_BUSY; diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c index 66b316d173b0..71a3bb83984c 100644 --- a/drivers/scsi/xen-scsifront.c +++ b/drivers/scsi/xen-scsifront.c @@ -995,7 +995,7 @@ static int scsifront_suspend(struct xenbus_device *dev) return err; } -static int scsifront_remove(struct xenbus_device *dev) +static void scsifront_remove(struct xenbus_device *dev) { struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev); @@ -1011,8 +1011,6 @@ static int scsifront_remove(struct xenbus_device *dev) scsifront_free_ring(info); scsi_host_put(info->host); - - return 0; } static void scsifront_disconnect(struct vscsifrnt_info *info) diff --git a/drivers/soc/atmel/soc.c b/drivers/soc/atmel/soc.c index dae8a2e0f745..cc9a3e107479 100644 --- a/drivers/soc/atmel/soc.c +++ b/drivers/soc/atmel/soc.c @@ -235,6 +235,15 @@ static const struct at91_soc socs[] __initconst = { AT91_SOC(SAMA7G5_CIDR_MATCH, AT91_CIDR_MATCH_MASK, AT91_CIDR_VERSION_MASK_SAMA7G5, SAMA7G54_EXID_MATCH, "sama7g54", "sama7g5"), + AT91_SOC(SAMA7G5_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK_SAMA7G5, SAMA7G54_D1G_EXID_MATCH, + "SAMA7G54 1Gb DDR3L SiP", "sama7g5"), + AT91_SOC(SAMA7G5_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK_SAMA7G5, SAMA7G54_D2G_EXID_MATCH, + "SAMA7G54 2Gb DDR3L SiP", "sama7g5"), + AT91_SOC(SAMA7G5_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK_SAMA7G5, SAMA7G54_D4G_EXID_MATCH, + "SAMA7G54 4Gb DDR3L SiP", "sama7g5"), #endif { /* sentinel */ }, }; diff --git a/drivers/soc/atmel/soc.h b/drivers/soc/atmel/soc.h index 2ecaa75b00f0..7a9f47ce85fb 100644 --- a/drivers/soc/atmel/soc.h +++ b/drivers/soc/atmel/soc.h @@ -70,6 +70,9 @@ at91_soc_init(const struct at91_soc *socs); #define SAMA7G52_EXID_MATCH 0x2 #define SAMA7G53_EXID_MATCH 0x1 #define SAMA7G54_EXID_MATCH 0x0 +#define SAMA7G54_D1G_EXID_MATCH 0x00000018 +#define SAMA7G54_D2G_EXID_MATCH 0x00000020 +#define SAMA7G54_D4G_EXID_MATCH 0x00000028 #define AT91SAM9XE128_CIDR_MATCH 0x329973a0 #define AT91SAM9XE256_CIDR_MATCH 0x329a93a0 diff --git a/drivers/soc/imx/imx8mp-blk-ctrl.c b/drivers/soc/imx/imx8mp-blk-ctrl.c index 0e3b6ba22f94..0f13853901df 100644 --- a/drivers/soc/imx/imx8mp-blk-ctrl.c +++ b/drivers/soc/imx/imx8mp-blk-ctrl.c @@ -212,7 +212,7 @@ static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc, break; case IMX8MP_HDMIBLK_PD_LCDIF: regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, - BIT(7) | BIT(16) | BIT(17) | BIT(18) | + BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20)); regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11)); regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, @@ -241,6 +241,7 @@ static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc, regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1)); break; case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY: + regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(7)); regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24)); regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12)); regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3)); @@ -270,7 +271,7 @@ static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc, BIT(4) | BIT(5) | BIT(6)); regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11)); regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, - BIT(7) | BIT(16) | BIT(17) | BIT(18) | + BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20)); break; case IMX8MP_HDMIBLK_PD_PAI: @@ -298,6 +299,7 @@ static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc, case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY: regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3)); regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12)); + regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(7)); regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24)); break; case IMX8MP_HDMIBLK_PD_HDCP: @@ -590,7 +592,6 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev) ret = PTR_ERR(domain->power_dev); goto cleanup_pds; } - dev_set_name(domain->power_dev, "%s", data->name); domain->genpd.name = data->name; domain->genpd.power_on = imx8mp_blk_ctrl_power_on; diff --git a/drivers/soc/imx/soc-imx8m.c b/drivers/soc/imx/soc-imx8m.c index 28144c699b0c..32ed9dc88e45 100644 --- a/drivers/soc/imx/soc-imx8m.c +++ b/drivers/soc/imx/soc-imx8m.c @@ -66,8 +66,8 @@ static u32 __init imx8mq_soc_revision(void) ocotp_base = of_iomap(np, 0); WARN_ON(!ocotp_base); clk = of_clk_get_by_name(np, NULL); - if (!clk) { - WARN_ON(!clk); + if (IS_ERR(clk)) { + WARN_ON(IS_ERR(clk)); return 0; } diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c index cd44f17dad3d..d51abb462ae5 100644 --- a/drivers/soc/qcom/apr.c +++ b/drivers/soc/qcom/apr.c @@ -461,9 +461,10 @@ static int apr_add_device(struct device *dev, struct device_node *np, goto out; } + /* Protection domain is optional, it does not exist on older platforms */ ret = of_property_read_string_index(np, "qcom,protection-domain", 1, &adev->service_path); - if (ret < 0) { + if (ret < 0 && ret != -EINVAL) { dev_err(dev, "Failed to read second value of qcom,protection-domain\n"); goto out; } diff --git a/drivers/soc/qcom/cpr.c b/drivers/soc/qcom/cpr.c index e9b854ed1bdf..144ea68e0920 100644 --- a/drivers/soc/qcom/cpr.c +++ b/drivers/soc/qcom/cpr.c @@ -1708,12 +1708,16 @@ static int cpr_probe(struct platform_device *pdev) ret = of_genpd_add_provider_simple(dev->of_node, &drv->pd); if (ret) - return ret; + goto err_remove_genpd; platform_set_drvdata(pdev, drv); cpr_debugfs_init(drv); return 0; + +err_remove_genpd: + pm_genpd_remove(&drv->pd); + return ret; } static int cpr_remove(struct platform_device *pdev) diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig index 02e319508cc6..7a8f291e7704 100644 --- a/drivers/soc/samsung/Kconfig +++ b/drivers/soc/samsung/Kconfig @@ -52,29 +52,9 @@ config EXYNOS_PM_DOMAINS bool "Exynos PM domains" if COMPILE_TEST depends on (ARCH_EXYNOS && PM_GENERIC_DOMAINS) || COMPILE_TEST -config SAMSUNG_PM_DEBUG - bool "Samsung PM Suspend debug" - depends on PM && DEBUG_KERNEL - depends on PLAT_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210 - depends on DEBUG_S3C24XX_UART || DEBUG_S3C2410_UART - depends on DEBUG_LL && MMU - help - Say Y here if you want verbose debugging from the PM Suspend and - Resume code. See <file:Documentation/arm/samsung-s3c24xx/suspend.rst> - for more information. - -config S3C_PM_DEBUG_LED_SMDK - bool "SMDK LED suspend/resume debugging" - depends on PM && (MACH_SMDK6410) - help - Say Y here to enable the use of the SMDK LEDs on the baseboard - for debugging of the state of the suspend and resume process. - - Note, this currently only works for S3C64XX based SMDK boards. - config SAMSUNG_PM_CHECK bool "S3C2410 PM Suspend Memory CRC" - depends on PM && (PLAT_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210) + depends on PM && (ARCH_S3C64XX || ARCH_S5PV210) select CRC32 help Enable the PM code's memory area checksum over sleep. This option @@ -85,8 +65,6 @@ config SAMSUNG_PM_CHECK Note, this can take several seconds depending on memory size and CPU speed. - See <file:Documentation/arm/samsung-s3c24xx/suspend.rst> - config SAMSUNG_PM_CHECK_CHUNKSIZE int "S3C2410 PM Suspend CRC Chunksize (KiB)" depends on PM && SAMSUNG_PM_CHECK @@ -97,8 +75,6 @@ config SAMSUNG_PM_CHECK_CHUNKSIZE the CRC data block will take more memory, but will identify any faults with better precision. - See <file:Documentation/arm/samsung-s3c24xx/suspend.rst> - config EXYNOS_REGULATOR_COUPLER bool "Exynos SoC Regulator Coupler" if COMPILE_TEST depends on ARCH_EXYNOS || COMPILE_TEST diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile index 9f59d1905ab0..d35270fc6b2b 100644 --- a/drivers/soc/samsung/Makefile +++ b/drivers/soc/samsung/Makefile @@ -14,4 +14,3 @@ obj-$(CONFIG_EXYNOS_PM_DOMAINS) += pm_domains.o obj-$(CONFIG_EXYNOS_REGULATOR_COUPLER) += exynos-regulator-coupler.o obj-$(CONFIG_SAMSUNG_PM_CHECK) += s3c-pm-check.o -obj-$(CONFIG_SAMSUNG_PM_DEBUG) += s3c-pm-debug.o diff --git a/drivers/soc/samsung/s3c-pm-debug.c b/drivers/soc/samsung/s3c-pm-debug.c deleted file mode 100644 index b5ce0e9a41e5..000000000000 --- a/drivers/soc/samsung/s3c-pm-debug.c +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Copyright (C) 2013 Samsung Electronics Co., Ltd. -// Tomasz Figa <t.figa@samsung.com> -// Copyright (C) 2008 Openmoko, Inc. -// Copyright (C) 2004-2008 Simtec Electronics -// Ben Dooks <ben@simtec.co.uk> -// http://armlinux.simtec.co.uk/ -// -// Samsung common power management (suspend to RAM) debug support - -#include <linux/serial_core.h> -#include <linux/serial_s3c.h> -#include <linux/io.h> - -#include <asm/mach/map.h> - -#include <linux/soc/samsung/s3c-pm.h> - -static struct pm_uart_save uart_save; - -extern void printascii(const char *); - -void s3c_pm_dbg(const char *fmt, ...) -{ - va_list va; - char buff[256]; - - va_start(va, fmt); - vsnprintf(buff, sizeof(buff), fmt, va); - va_end(va); - - printascii(buff); -} - -static inline void __iomem *s3c_pm_uart_base(void) -{ - unsigned long paddr; - unsigned long vaddr; - - debug_ll_addr(&paddr, &vaddr); - - return (void __iomem *)vaddr; -} - -void s3c_pm_save_uarts(bool is_s3c2410) -{ - void __iomem *regs = s3c_pm_uart_base(); - struct pm_uart_save *save = &uart_save; - - save->ulcon = __raw_readl(regs + S3C2410_ULCON); - save->ucon = __raw_readl(regs + S3C2410_UCON); - save->ufcon = __raw_readl(regs + S3C2410_UFCON); - save->umcon = __raw_readl(regs + S3C2410_UMCON); - save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV); - - if (!is_s3c2410) - save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT); - - S3C_PMDBG("UART[%p]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n", - regs, save->ulcon, save->ucon, save->ufcon, save->ubrdiv); -} - -void s3c_pm_restore_uarts(bool is_s3c2410) -{ - void __iomem *regs = s3c_pm_uart_base(); - struct pm_uart_save *save = &uart_save; - - s3c_pm_arch_update_uart(regs, save); - - __raw_writel(save->ulcon, regs + S3C2410_ULCON); - __raw_writel(save->ucon, regs + S3C2410_UCON); - __raw_writel(save->ufcon, regs + S3C2410_UFCON); - __raw_writel(save->umcon, regs + S3C2410_UMCON); - __raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV); - - if (!is_s3c2410) - __raw_writel(save->udivslot, regs + S3C2443_DIVSLOT); -} diff --git a/drivers/soc/ti/smartreflex.c b/drivers/soc/ti/smartreflex.c index 6a389a6444f3..9d9496e0a94c 100644 --- a/drivers/soc/ti/smartreflex.c +++ b/drivers/soc/ti/smartreflex.c @@ -198,7 +198,6 @@ static void sr_stop_vddautocomp(struct omap_sr *sr) */ static int sr_late_init(struct omap_sr *sr_info) { - struct omap_sr_data *pdata = sr_info->pdev->dev.platform_data; int ret = 0; if (sr_class->notify && sr_class->notify_flags && sr_info->irq) { @@ -209,9 +208,6 @@ static int sr_late_init(struct omap_sr *sr_info) disable_irq(sr_info->irq); } - if (pdata && pdata->enable_on_init) - sr_start_vddautocomp(sr_info); - return ret; error: diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 3b1c0878bb85..2aba88a57a77 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -708,12 +708,6 @@ config SPI_TI_QSPI This device supports single, dual and quad read support, while it only supports single write mode. -config SPI_OMAP_100K - tristate "OMAP SPI 100K" - depends on ARCH_OMAP850 || ARCH_OMAP730 || COMPILE_TEST - help - OMAP SPI 100K master controller for omap7xx boards. - config SPI_ORION tristate "Orion SPI master" depends on PLAT_ORION || ARCH_MVEBU || COMPILE_TEST @@ -844,24 +838,6 @@ config SPI_QCOM_GENI This driver can also be built as a module. If so, the module will be called spi-geni-qcom. -config SPI_S3C24XX - tristate "Samsung S3C24XX series SPI" - depends on ARCH_S3C24XX - select SPI_BITBANG - help - SPI driver for Samsung S3C24XX series ARM SoCs - -config SPI_S3C24XX_FIQ - bool "S3C24XX driver with FIQ pseudo-DMA" - depends on SPI_S3C24XX - select FIQ - help - Enable FIQ support for the S3C24XX SPI driver to provide pseudo - DMA by using the fast-interrupt request framework, This allows - the driver to get DMA-like performance when there are either - no free DMA channels, or when doing transfers that required both - TX and RX data paths. - config SPI_S3C64XX tristate "Samsung S3C64XX/Exynos SoC series type SPI" depends on (PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST) diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index be9ba40ef8d0..12648f75a919 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -91,7 +91,6 @@ obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o spi-octeon-objs := spi-cavium.o spi-cavium-octeon.o obj-$(CONFIG_SPI_OCTEON) += spi-octeon.o obj-$(CONFIG_SPI_OMAP_UWIRE) += spi-omap-uwire.o -obj-$(CONFIG_SPI_OMAP_100K) += spi-omap-100k.o obj-$(CONFIG_SPI_OMAP24XX) += spi-omap2-mcspi.o obj-$(CONFIG_SPI_TI_QSPI) += spi-ti-qspi.o obj-$(CONFIG_SPI_ORION) += spi-orion.o @@ -112,8 +111,6 @@ obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o obj-$(CONFIG_SPI_RSPI) += spi-rspi.o -obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o -spi-s3c24xx-hw-y := spi-s3c24xx.o obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o obj-$(CONFIG_SPI_SC18IS602) += spi-sc18is602.o obj-$(CONFIG_SPI_SH) += spi-sh.o diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index 520b4cc69cdc..91db3c973167 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -177,7 +177,10 @@ #define CDNS_XSPI_CMD_FLD_DSEQ_CMD_3(op) ( \ FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R3_DCNT_H, \ ((op)->data.nbytes >> 16) & 0xffff) | \ - FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R3_NUM_OF_DUMMY, (op)->dummy.nbytes * 8)) + FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R3_NUM_OF_DUMMY, \ + (op)->dummy.buswidth != 0 ? \ + (((op)->dummy.nbytes * 8) / (op)->dummy.buswidth) : \ + 0)) #define CDNS_XSPI_CMD_FLD_DSEQ_CMD_4(op, chipsel) ( \ FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R4_BANK, chipsel) | \ diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index 99edddf9958b..c3bfb6c84cab 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -366,7 +366,7 @@ static void dw_spi_irq_setup(struct dw_spi *dws) * will be adjusted at the final stage of the IRQ-based SPI transfer * execution so not to lose the leftover of the incoming data. */ - level = min_t(u16, dws->fifo_len / 2, dws->tx_len); + level = min_t(unsigned int, dws->fifo_len / 2, dws->tx_len); dw_writel(dws, DW_SPI_TXFTLR, level); dw_writel(dws, DW_SPI_RXFTLR, level - 1); diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 6de8360e5c2a..9eab6c20dbc5 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -1253,6 +1253,11 @@ static int mtk_spi_probe(struct platform_device *pdev) dev_notice(dev, "SPI dma_set_mask(%d) failed, ret:%d\n", addr_bits, ret); + ret = devm_request_irq(dev, irq, mtk_spi_interrupt, + IRQF_TRIGGER_NONE, dev_name(dev), master); + if (ret) + return dev_err_probe(dev, ret, "failed to register irq\n"); + pm_runtime_enable(dev); ret = devm_spi_register_master(dev, master); @@ -1261,13 +1266,6 @@ static int mtk_spi_probe(struct platform_device *pdev) return dev_err_probe(dev, ret, "failed to register master\n"); } - ret = devm_request_irq(dev, irq, mtk_spi_interrupt, - IRQF_TRIGGER_NONE, dev_name(dev), master); - if (ret) { - pm_runtime_disable(dev); - return dev_err_probe(dev, ret, "failed to register irq\n"); - } - return 0; } diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c deleted file mode 100644 index 061f7394e5b9..000000000000 --- a/drivers/spi/spi-omap-100k.c +++ /dev/null @@ -1,490 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * OMAP7xx SPI 100k controller driver - * Author: Fabrice Crohas <fcrohas@gmail.com> - * from original omap1_mcspi driver - * - * Copyright (C) 2005, 2006 Nokia Corporation - * Author: Samuel Ortiz <samuel.ortiz@nokia.com> and - * Juha Yrjola <juha.yrjola@nokia.com> - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/delay.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/slab.h> - -#include <linux/spi/spi.h> - -#define OMAP1_SPI100K_MAX_FREQ 48000000 - -#define ICR_SPITAS (OMAP7XX_ICR_BASE + 0x12) - -#define SPI_SETUP1 0x00 -#define SPI_SETUP2 0x02 -#define SPI_CTRL 0x04 -#define SPI_STATUS 0x06 -#define SPI_TX_LSB 0x08 -#define SPI_TX_MSB 0x0a -#define SPI_RX_LSB 0x0c -#define SPI_RX_MSB 0x0e - -#define SPI_SETUP1_INT_READ_ENABLE (1UL << 5) -#define SPI_SETUP1_INT_WRITE_ENABLE (1UL << 4) -#define SPI_SETUP1_CLOCK_DIVISOR(x) ((x) << 1) -#define SPI_SETUP1_CLOCK_ENABLE (1UL << 0) - -#define SPI_SETUP2_ACTIVE_EDGE_FALLING (0UL << 0) -#define SPI_SETUP2_ACTIVE_EDGE_RISING (1UL << 0) -#define SPI_SETUP2_NEGATIVE_LEVEL (0UL << 5) -#define SPI_SETUP2_POSITIVE_LEVEL (1UL << 5) -#define SPI_SETUP2_LEVEL_TRIGGER (0UL << 10) -#define SPI_SETUP2_EDGE_TRIGGER (1UL << 10) - -#define SPI_CTRL_SEN(x) ((x) << 7) -#define SPI_CTRL_WORD_SIZE(x) (((x) - 1) << 2) -#define SPI_CTRL_WR (1UL << 1) -#define SPI_CTRL_RD (1UL << 0) - -#define SPI_STATUS_WE (1UL << 1) -#define SPI_STATUS_RD (1UL << 0) - -/* use PIO for small transfers, avoiding DMA setup/teardown overhead and - * cache operations; better heuristics consider wordsize and bitrate. - */ -#define DMA_MIN_BYTES 8 - -#define SPI_RUNNING 0 -#define SPI_SHUTDOWN 1 - -struct omap1_spi100k { - struct clk *ick; - struct clk *fck; - - /* Virtual base address of the controller */ - void __iomem *base; -}; - -struct omap1_spi100k_cs { - void __iomem *base; - int word_len; -}; - -static void spi100k_enable_clock(struct spi_master *master) -{ - unsigned int val; - struct omap1_spi100k *spi100k = spi_master_get_devdata(master); - - /* enable SPI */ - val = readw(spi100k->base + SPI_SETUP1); - val |= SPI_SETUP1_CLOCK_ENABLE; - writew(val, spi100k->base + SPI_SETUP1); -} - -static void spi100k_disable_clock(struct spi_master *master) -{ - unsigned int val; - struct omap1_spi100k *spi100k = spi_master_get_devdata(master); - - /* disable SPI */ - val = readw(spi100k->base + SPI_SETUP1); - val &= ~SPI_SETUP1_CLOCK_ENABLE; - writew(val, spi100k->base + SPI_SETUP1); -} - -static void spi100k_write_data(struct spi_master *master, int len, int data) -{ - struct omap1_spi100k *spi100k = spi_master_get_devdata(master); - - /* write 16-bit word, shifting 8-bit data if necessary */ - if (len <= 8) { - data <<= 8; - len = 16; - } - - spi100k_enable_clock(master); - writew(data, spi100k->base + SPI_TX_MSB); - - writew(SPI_CTRL_SEN(0) | - SPI_CTRL_WORD_SIZE(len) | - SPI_CTRL_WR, - spi100k->base + SPI_CTRL); - - /* Wait for bit ack send change */ - while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE) - ; - udelay(1000); - - spi100k_disable_clock(master); -} - -static int spi100k_read_data(struct spi_master *master, int len) -{ - int dataL; - struct omap1_spi100k *spi100k = spi_master_get_devdata(master); - - /* Always do at least 16 bits */ - if (len <= 8) - len = 16; - - spi100k_enable_clock(master); - writew(SPI_CTRL_SEN(0) | - SPI_CTRL_WORD_SIZE(len) | - SPI_CTRL_RD, - spi100k->base + SPI_CTRL); - - while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD) - ; - udelay(1000); - - dataL = readw(spi100k->base + SPI_RX_LSB); - readw(spi100k->base + SPI_RX_MSB); - spi100k_disable_clock(master); - - return dataL; -} - -static void spi100k_open(struct spi_master *master) -{ - /* get control of SPI */ - struct omap1_spi100k *spi100k = spi_master_get_devdata(master); - - writew(SPI_SETUP1_INT_READ_ENABLE | - SPI_SETUP1_INT_WRITE_ENABLE | - SPI_SETUP1_CLOCK_DIVISOR(0), spi100k->base + SPI_SETUP1); - - /* configure clock and interrupts */ - writew(SPI_SETUP2_ACTIVE_EDGE_FALLING | - SPI_SETUP2_NEGATIVE_LEVEL | - SPI_SETUP2_LEVEL_TRIGGER, spi100k->base + SPI_SETUP2); -} - -static void omap1_spi100k_force_cs(struct omap1_spi100k *spi100k, int enable) -{ - if (enable) - writew(0x05fc, spi100k->base + SPI_CTRL); - else - writew(0x05fd, spi100k->base + SPI_CTRL); -} - -static unsigned -omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) -{ - struct omap1_spi100k_cs *cs = spi->controller_state; - unsigned int count, c; - int word_len; - - count = xfer->len; - c = count; - word_len = cs->word_len; - - if (word_len <= 8) { - u8 *rx; - const u8 *tx; - - rx = xfer->rx_buf; - tx = xfer->tx_buf; - do { - c -= 1; - if (xfer->tx_buf != NULL) - spi100k_write_data(spi->master, word_len, *tx++); - if (xfer->rx_buf != NULL) - *rx++ = spi100k_read_data(spi->master, word_len); - } while (c); - } else if (word_len <= 16) { - u16 *rx; - const u16 *tx; - - rx = xfer->rx_buf; - tx = xfer->tx_buf; - do { - c -= 2; - if (xfer->tx_buf != NULL) - spi100k_write_data(spi->master, word_len, *tx++); - if (xfer->rx_buf != NULL) - *rx++ = spi100k_read_data(spi->master, word_len); - } while (c); - } else if (word_len <= 32) { - u32 *rx; - const u32 *tx; - - rx = xfer->rx_buf; - tx = xfer->tx_buf; - do { - c -= 4; - if (xfer->tx_buf != NULL) - spi100k_write_data(spi->master, word_len, *tx); - if (xfer->rx_buf != NULL) - *rx = spi100k_read_data(spi->master, word_len); - } while (c); - } - return count - c; -} - -/* called only when no transfer is active to this device */ -static int omap1_spi100k_setup_transfer(struct spi_device *spi, - struct spi_transfer *t) -{ - struct omap1_spi100k *spi100k = spi_master_get_devdata(spi->master); - struct omap1_spi100k_cs *cs = spi->controller_state; - u8 word_len; - - if (t != NULL) - word_len = t->bits_per_word; - else - word_len = spi->bits_per_word; - - if (word_len > 32) - return -EINVAL; - cs->word_len = word_len; - - /* SPI init before transfer */ - writew(0x3e, spi100k->base + SPI_SETUP1); - writew(0x00, spi100k->base + SPI_STATUS); - writew(0x3e, spi100k->base + SPI_CTRL); - - return 0; -} - -/* the spi->mode bits understood by this driver: */ -#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH) - -static int omap1_spi100k_setup(struct spi_device *spi) -{ - int ret; - struct omap1_spi100k *spi100k; - struct omap1_spi100k_cs *cs = spi->controller_state; - - spi100k = spi_master_get_devdata(spi->master); - - if (!cs) { - cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL); - if (!cs) - return -ENOMEM; - cs->base = spi100k->base + spi->chip_select * 0x14; - spi->controller_state = cs; - } - - spi100k_open(spi->master); - - clk_prepare_enable(spi100k->ick); - clk_prepare_enable(spi100k->fck); - - ret = omap1_spi100k_setup_transfer(spi, NULL); - - clk_disable_unprepare(spi100k->ick); - clk_disable_unprepare(spi100k->fck); - - return ret; -} - -static int omap1_spi100k_transfer_one_message(struct spi_master *master, - struct spi_message *m) -{ - struct omap1_spi100k *spi100k = spi_master_get_devdata(master); - struct spi_device *spi = m->spi; - struct spi_transfer *t = NULL; - int cs_active = 0; - int status = 0; - - list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { - break; - } - status = omap1_spi100k_setup_transfer(spi, t); - if (status < 0) - break; - - if (!cs_active) { - omap1_spi100k_force_cs(spi100k, 1); - cs_active = 1; - } - - if (t->len) { - unsigned count; - - count = omap1_spi100k_txrx_pio(spi, t); - m->actual_length += count; - - if (count != t->len) { - break; - } - } - - spi_transfer_delay_exec(t); - - /* ignore the "leave it on after last xfer" hint */ - - if (t->cs_change) { - omap1_spi100k_force_cs(spi100k, 0); - cs_active = 0; - } - } - - status = omap1_spi100k_setup_transfer(spi, NULL); - - if (cs_active) - omap1_spi100k_force_cs(spi100k, 0); - - m->status = status; - - spi_finalize_current_message(master); - - return status; -} - -static int omap1_spi100k_probe(struct platform_device *pdev) -{ - struct spi_master *master; - struct omap1_spi100k *spi100k; - int status = 0; - - if (!pdev->id) - return -EINVAL; - - master = spi_alloc_master(&pdev->dev, sizeof(*spi100k)); - if (master == NULL) { - dev_dbg(&pdev->dev, "master allocation failed\n"); - return -ENOMEM; - } - - if (pdev->id != -1) - master->bus_num = pdev->id; - - master->setup = omap1_spi100k_setup; - master->transfer_one_message = omap1_spi100k_transfer_one_message; - master->num_chipselect = 2; - master->mode_bits = MODEBITS; - master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); - master->min_speed_hz = OMAP1_SPI100K_MAX_FREQ/(1<<16); - master->max_speed_hz = OMAP1_SPI100K_MAX_FREQ; - master->auto_runtime_pm = true; - - spi100k = spi_master_get_devdata(master); - - /* - * The memory region base address is taken as the platform_data. - * You should allocate this with ioremap() before initializing - * the SPI. - */ - spi100k->base = (void __iomem *)dev_get_platdata(&pdev->dev); - - spi100k->ick = devm_clk_get(&pdev->dev, "ick"); - if (IS_ERR(spi100k->ick)) { - dev_dbg(&pdev->dev, "can't get spi100k_ick\n"); - status = PTR_ERR(spi100k->ick); - goto err; - } - - spi100k->fck = devm_clk_get(&pdev->dev, "fck"); - if (IS_ERR(spi100k->fck)) { - dev_dbg(&pdev->dev, "can't get spi100k_fck\n"); - status = PTR_ERR(spi100k->fck); - goto err; - } - - status = clk_prepare_enable(spi100k->ick); - if (status != 0) { - dev_err(&pdev->dev, "failed to enable ick: %d\n", status); - goto err; - } - - status = clk_prepare_enable(spi100k->fck); - if (status != 0) { - dev_err(&pdev->dev, "failed to enable fck: %d\n", status); - goto err_ick; - } - - pm_runtime_enable(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - - status = devm_spi_register_master(&pdev->dev, master); - if (status < 0) - goto err_fck; - - return status; - -err_fck: - pm_runtime_disable(&pdev->dev); - clk_disable_unprepare(spi100k->fck); -err_ick: - clk_disable_unprepare(spi100k->ick); -err: - spi_master_put(master); - return status; -} - -static int omap1_spi100k_remove(struct platform_device *pdev) -{ - struct spi_master *master = platform_get_drvdata(pdev); - struct omap1_spi100k *spi100k = spi_master_get_devdata(master); - - pm_runtime_disable(&pdev->dev); - - clk_disable_unprepare(spi100k->fck); - clk_disable_unprepare(spi100k->ick); - - return 0; -} - -#ifdef CONFIG_PM -static int omap1_spi100k_runtime_suspend(struct device *dev) -{ - struct spi_master *master = dev_get_drvdata(dev); - struct omap1_spi100k *spi100k = spi_master_get_devdata(master); - - clk_disable_unprepare(spi100k->ick); - clk_disable_unprepare(spi100k->fck); - - return 0; -} - -static int omap1_spi100k_runtime_resume(struct device *dev) -{ - struct spi_master *master = dev_get_drvdata(dev); - struct omap1_spi100k *spi100k = spi_master_get_devdata(master); - int ret; - - ret = clk_prepare_enable(spi100k->ick); - if (ret != 0) { - dev_err(dev, "Failed to enable ick: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(spi100k->fck); - if (ret != 0) { - dev_err(dev, "Failed to enable fck: %d\n", ret); - clk_disable_unprepare(spi100k->ick); - return ret; - } - - return 0; -} -#endif - -static const struct dev_pm_ops omap1_spi100k_pm = { - SET_RUNTIME_PM_OPS(omap1_spi100k_runtime_suspend, - omap1_spi100k_runtime_resume, NULL) -}; - -static struct platform_driver omap1_spi100k_driver = { - .driver = { - .name = "omap1_spi100k", - .pm = &omap1_spi100k_pm, - }, - .probe = omap1_spi100k_probe, - .remove = omap1_spi100k_remove, -}; - -module_platform_driver(omap1_spi100k_driver); - -MODULE_DESCRIPTION("OMAP7xx SPI 100k controller driver"); -MODULE_AUTHOR("Fabrice Crohas <fcrohas@gmail.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 29198e6815b2..20c87163d612 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -99,7 +99,7 @@ struct uwire_state { * Or, put it in a structure which is used throughout the driver; * that avoids having to issue two loads for each bit of static data. */ -static unsigned int uwire_idx_shift; +static unsigned int uwire_idx_shift = 2; static void __iomem *uwire_base; static inline void uwire_write_reg(int idx, u16 val) @@ -481,11 +481,6 @@ static int uwire_probe(struct platform_device *pdev) } clk_prepare_enable(uwire->ck); - if (cpu_is_omap7xx()) - uwire_idx_shift = 1; - else - uwire_idx_shift = 2; - uwire_write_reg(UWIRE_SR3, 1); /* the spi->mode bits understood by this driver: */ @@ -536,15 +531,6 @@ static struct platform_driver uwire_driver = { static int __init omap_uwire_init(void) { - /* FIXME move these into the relevant board init code. also, include - * H3 support; it uses tsc2101 like H2 (on a different chipselect). - */ - - if (machine_is_omap_h2()) { - /* defaults: W21 SDO, U18 SDI, V19 SCL */ - omap_cfg_reg(N14_1610_UWIRE_CS0); - omap_cfg_reg(N15_1610_UWIRE_CS1); - } return platform_driver_register(&uwire_driver); } diff --git a/drivers/spi/spi-s3c24xx-regs.h b/drivers/spi/spi-s3c24xx-regs.h deleted file mode 100644 index f51464ab5677..000000000000 --- a/drivers/spi/spi-s3c24xx-regs.h +++ /dev/null @@ -1,41 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2004 Fetron GmbH - * - * S3C2410 SPI register definition - */ - -#ifndef __SPI_S3C2410_H -#define __SPI_S3C2410_H - -#define S3C2410_SPCON (0x00) - -#define S3C2410_SPCON_SMOD_DMA (2 << 5) /* DMA mode */ -#define S3C2410_SPCON_SMOD_INT (1 << 5) /* interrupt mode */ -#define S3C2410_SPCON_SMOD_POLL (0 << 5) /* polling mode */ -#define S3C2410_SPCON_ENSCK (1 << 4) /* Enable SCK */ -#define S3C2410_SPCON_MSTR (1 << 3) /* Master:1, Slave:0 select */ -#define S3C2410_SPCON_CPOL_HIGH (1 << 2) /* Clock polarity select */ -#define S3C2410_SPCON_CPOL_LOW (0 << 2) /* Clock polarity select */ - -#define S3C2410_SPCON_CPHA_FMTB (1 << 1) /* Clock Phase Select */ -#define S3C2410_SPCON_CPHA_FMTA (0 << 1) /* Clock Phase Select */ - -#define S3C2410_SPSTA (0x04) - -#define S3C2410_SPSTA_DCOL (1 << 2) /* Data Collision Error */ -#define S3C2410_SPSTA_MULD (1 << 1) /* Multi Master Error */ -#define S3C2410_SPSTA_READY (1 << 0) /* Data Tx/Rx ready */ -#define S3C2412_SPSTA_READY_ORG (1 << 3) - -#define S3C2410_SPPIN (0x08) - -#define S3C2410_SPPIN_ENMUL (1 << 2) /* Multi Master Error detect */ -#define S3C2410_SPPIN_RESERVED (1 << 1) -#define S3C2410_SPPIN_KEEP (1 << 0) /* Master Out keep */ - -#define S3C2410_SPPRE (0x0C) -#define S3C2410_SPTDAT (0x10) -#define S3C2410_SPRDAT (0x14) - -#endif /* __SPI_S3C2410_H */ diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c deleted file mode 100644 index ef25b5e93900..000000000000 --- a/drivers/spi/spi-s3c24xx.c +++ /dev/null @@ -1,596 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2006 Ben Dooks - * Copyright 2006-2009 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> -*/ - -#include <linux/spinlock.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/slab.h> - -#include <linux/spi/spi.h> -#include <linux/spi/spi_bitbang.h> -#include <linux/spi/s3c24xx.h> -#include <linux/spi/s3c24xx-fiq.h> -#include <linux/module.h> - -#include <asm/fiq.h> - -#include "spi-s3c24xx-regs.h" - -/** - * struct s3c24xx_spi_devstate - per device data - * @hz: Last frequency calculated for @sppre field. - * @mode: Last mode setting for the @spcon field. - * @spcon: Value to write to the SPCON register. - * @sppre: Value to write to the SPPRE register. - */ -struct s3c24xx_spi_devstate { - unsigned int hz; - unsigned int mode; - u8 spcon; - u8 sppre; -}; - -enum spi_fiq_mode { - FIQ_MODE_NONE = 0, - FIQ_MODE_TX = 1, - FIQ_MODE_RX = 2, - FIQ_MODE_TXRX = 3, -}; - -struct s3c24xx_spi { - /* bitbang has to be first */ - struct spi_bitbang bitbang; - struct completion done; - - void __iomem *regs; - int irq; - int len; - int count; - - struct fiq_handler fiq_handler; - enum spi_fiq_mode fiq_mode; - unsigned char fiq_inuse; - unsigned char fiq_claimed; - - /* data buffers */ - const unsigned char *tx; - unsigned char *rx; - - struct clk *clk; - struct spi_master *master; - struct spi_device *curdev; - struct device *dev; - struct s3c2410_spi_info *pdata; -}; - -#define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT) -#define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP) - -static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev) -{ - return spi_master_get_devdata(sdev->master); -} - -static void s3c24xx_spi_chipsel(struct spi_device *spi, int value) -{ - struct s3c24xx_spi_devstate *cs = spi->controller_state; - struct s3c24xx_spi *hw = to_hw(spi); - - /* change the chipselect state and the state of the spi engine clock */ - - switch (value) { - case BITBANG_CS_INACTIVE: - writeb(cs->spcon, hw->regs + S3C2410_SPCON); - break; - - case BITBANG_CS_ACTIVE: - writeb(cs->spcon | S3C2410_SPCON_ENSCK, - hw->regs + S3C2410_SPCON); - break; - } -} - -static int s3c24xx_spi_update_state(struct spi_device *spi, - struct spi_transfer *t) -{ - struct s3c24xx_spi *hw = to_hw(spi); - struct s3c24xx_spi_devstate *cs = spi->controller_state; - unsigned int hz; - unsigned int div; - unsigned long clk; - - hz = t ? t->speed_hz : spi->max_speed_hz; - - if (!hz) - hz = spi->max_speed_hz; - - if (spi->mode != cs->mode) { - u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK; - - if (spi->mode & SPI_CPHA) - spcon |= S3C2410_SPCON_CPHA_FMTB; - - if (spi->mode & SPI_CPOL) - spcon |= S3C2410_SPCON_CPOL_HIGH; - - cs->mode = spi->mode; - cs->spcon = spcon; - } - - if (cs->hz != hz) { - clk = clk_get_rate(hw->clk); - div = DIV_ROUND_UP(clk, hz * 2) - 1; - - if (div > 255) - div = 255; - - dev_dbg(&spi->dev, "pre-scaler=%d (wanted %d, got %ld)\n", - div, hz, clk / (2 * (div + 1))); - - cs->hz = hz; - cs->sppre = div; - } - - return 0; -} - -static int s3c24xx_spi_setupxfer(struct spi_device *spi, - struct spi_transfer *t) -{ - struct s3c24xx_spi_devstate *cs = spi->controller_state; - struct s3c24xx_spi *hw = to_hw(spi); - int ret; - - ret = s3c24xx_spi_update_state(spi, t); - if (!ret) - writeb(cs->sppre, hw->regs + S3C2410_SPPRE); - - return ret; -} - -static int s3c24xx_spi_setup(struct spi_device *spi) -{ - struct s3c24xx_spi_devstate *cs = spi->controller_state; - struct s3c24xx_spi *hw = to_hw(spi); - int ret; - - /* allocate settings on the first call */ - if (!cs) { - cs = devm_kzalloc(&spi->dev, - sizeof(struct s3c24xx_spi_devstate), - GFP_KERNEL); - if (!cs) - return -ENOMEM; - - cs->spcon = SPCON_DEFAULT; - cs->hz = -1; - spi->controller_state = cs; - } - - /* initialise the state from the device */ - ret = s3c24xx_spi_update_state(spi, NULL); - if (ret) - return ret; - - mutex_lock(&hw->bitbang.lock); - if (!hw->bitbang.busy) { - hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); - /* need to ndelay for 0.5 clocktick ? */ - } - mutex_unlock(&hw->bitbang.lock); - - return 0; -} - -static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count) -{ - return hw->tx ? hw->tx[count] : 0; -} - -#ifdef CONFIG_SPI_S3C24XX_FIQ -/* Support for FIQ based pseudo-DMA to improve the transfer speed. - * - * This code uses the assembly helper in spi_s3c24xx_spi.S which is - * used by the FIQ core to move data between main memory and the peripheral - * block. Since this is code running on the processor, there is no problem - * with cache coherency of the buffers, so we can use any buffer we like. - */ - -/** - * struct spi_fiq_code - FIQ code and header - * @length: The length of the code fragment, excluding this header. - * @ack_offset: The offset from @data to the word to place the IRQ ACK bit at. - * @data: The code itself to install as a FIQ handler. - */ -struct spi_fiq_code { - u32 length; - u32 ack_offset; - u8 data[]; -}; - -/** - * s3c24xx_spi_tryfiq - attempt to claim and setup FIQ for transfer - * @hw: The hardware state. - * - * Claim the FIQ handler (only one can be active at any one time) and - * then setup the correct transfer code for this transfer. - * - * This call updates all the necessary state information if successful, - * so the caller does not need to do anything more than start the transfer - * as normal, since the IRQ will have been re-routed to the FIQ handler. -*/ -static void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw) -{ - struct pt_regs regs; - enum spi_fiq_mode mode; - struct spi_fiq_code *code; - u32 *ack_ptr = NULL; - int ret; - - if (!hw->fiq_claimed) { - /* try and claim fiq if we haven't got it, and if not - * then return and simply use another transfer method */ - - ret = claim_fiq(&hw->fiq_handler); - if (ret) - return; - } - - if (hw->tx && !hw->rx) - mode = FIQ_MODE_TX; - else if (hw->rx && !hw->tx) - mode = FIQ_MODE_RX; - else - mode = FIQ_MODE_TXRX; - - regs.uregs[fiq_rspi] = (long)hw->regs; - regs.uregs[fiq_rrx] = (long)hw->rx; - regs.uregs[fiq_rtx] = (long)hw->tx + 1; - regs.uregs[fiq_rcount] = hw->len - 1; - - set_fiq_regs(®s); - - if (hw->fiq_mode != mode) { - hw->fiq_mode = mode; - - switch (mode) { - case FIQ_MODE_TX: - code = &s3c24xx_spi_fiq_tx; - break; - case FIQ_MODE_RX: - code = &s3c24xx_spi_fiq_rx; - break; - case FIQ_MODE_TXRX: - code = &s3c24xx_spi_fiq_txrx; - break; - default: - code = NULL; - } - - BUG_ON(!code); - - ack_ptr = (u32 *)&code->data[code->ack_offset]; - set_fiq_handler(&code->data, code->length); - } - - s3c24xx_set_fiq(hw->irq, ack_ptr, true); - - hw->fiq_mode = mode; - hw->fiq_inuse = 1; -} - -/** - * s3c24xx_spi_fiqop - FIQ core code callback - * @pw: Data registered with the handler - * @release: Whether this is a release or a return. - * - * Called by the FIQ code when another module wants to use the FIQ, so - * return whether we are currently using this or not and then update our - * internal state. - */ -static int s3c24xx_spi_fiqop(void *pw, int release) -{ - struct s3c24xx_spi *hw = pw; - int ret = 0; - - if (release) { - if (hw->fiq_inuse) - ret = -EBUSY; - - /* note, we do not need to unroute the FIQ, as the FIQ - * vector code de-routes it to signal the end of transfer */ - - hw->fiq_mode = FIQ_MODE_NONE; - hw->fiq_claimed = 0; - } else { - hw->fiq_claimed = 1; - } - - return ret; -} - -/** - * s3c24xx_spi_initfiq - setup the information for the FIQ core - * @hw: The hardware state. - * - * Setup the fiq_handler block to pass to the FIQ core. - */ -static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *hw) -{ - hw->fiq_handler.dev_id = hw; - hw->fiq_handler.name = dev_name(hw->dev); - hw->fiq_handler.fiq_op = s3c24xx_spi_fiqop; -} - -/** - * s3c24xx_spi_usefiq - return if we should be using FIQ. - * @hw: The hardware state. - * - * Return true if the platform data specifies whether this channel is - * allowed to use the FIQ. - */ -static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *hw) -{ - return hw->pdata->use_fiq; -} - -/** - * s3c24xx_spi_usingfiq - return if channel is using FIQ - * @spi: The hardware state. - * - * Return whether the channel is currently using the FIQ (separate from - * whether the FIQ is claimed). - */ -static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *spi) -{ - return spi->fiq_inuse; -} -#else - -static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *s) { } -static inline void s3c24xx_spi_tryfiq(struct s3c24xx_spi *s) { } -static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *s) { return false; } -static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *s) { return false; } - -#endif /* CONFIG_SPI_S3C24XX_FIQ */ - -static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t) -{ - struct s3c24xx_spi *hw = to_hw(spi); - - hw->tx = t->tx_buf; - hw->rx = t->rx_buf; - hw->len = t->len; - hw->count = 0; - - init_completion(&hw->done); - - hw->fiq_inuse = 0; - if (s3c24xx_spi_usefiq(hw) && t->len >= 3) - s3c24xx_spi_tryfiq(hw); - - /* send the first byte */ - writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT); - - wait_for_completion(&hw->done); - return hw->count; -} - -static irqreturn_t s3c24xx_spi_irq(int irq, void *dev) -{ - struct s3c24xx_spi *hw = dev; - unsigned int spsta = readb(hw->regs + S3C2410_SPSTA); - unsigned int count = hw->count; - - if (spsta & S3C2410_SPSTA_DCOL) { - dev_dbg(hw->dev, "data-collision\n"); - complete(&hw->done); - goto irq_done; - } - - if (!(spsta & S3C2410_SPSTA_READY)) { - dev_dbg(hw->dev, "spi not ready for tx?\n"); - complete(&hw->done); - goto irq_done; - } - - if (!s3c24xx_spi_usingfiq(hw)) { - hw->count++; - - if (hw->rx) - hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT); - - count++; - - if (count < hw->len) - writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT); - else - complete(&hw->done); - } else { - hw->count = hw->len; - hw->fiq_inuse = 0; - - if (hw->rx) - hw->rx[hw->len-1] = readb(hw->regs + S3C2410_SPRDAT); - - complete(&hw->done); - } - - irq_done: - return IRQ_HANDLED; -} - -static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw) -{ - /* for the moment, permanently enable the clock */ - - clk_enable(hw->clk); - - /* program defaults into the registers */ - - writeb(0xff, hw->regs + S3C2410_SPPRE); - writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN); - writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON); -} - -static int s3c24xx_spi_probe(struct platform_device *pdev) -{ - struct s3c2410_spi_info *pdata; - struct s3c24xx_spi *hw; - struct spi_master *master; - int err = 0; - - master = devm_spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi)); - if (master == NULL) { - dev_err(&pdev->dev, "No memory for spi_master\n"); - return -ENOMEM; - } - - hw = spi_master_get_devdata(master); - - hw->master = master; - hw->pdata = pdata = dev_get_platdata(&pdev->dev); - hw->dev = &pdev->dev; - - if (pdata == NULL) { - dev_err(&pdev->dev, "No platform data supplied\n"); - return -ENOENT; - } - - platform_set_drvdata(pdev, hw); - init_completion(&hw->done); - - /* initialise fiq handler */ - - s3c24xx_spi_initfiq(hw); - - /* setup the master state. */ - - /* the spi->mode bits understood by this driver: */ - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; - - master->num_chipselect = hw->pdata->num_cs; - master->bus_num = pdata->bus_num; - master->bits_per_word_mask = SPI_BPW_MASK(8); - /* we need to call the local chipselect callback */ - master->flags = SPI_MASTER_GPIO_SS; - master->use_gpio_descriptors = true; - - /* setup the state for the bitbang driver */ - - hw->bitbang.master = hw->master; - hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer; - hw->bitbang.chipselect = s3c24xx_spi_chipsel; - hw->bitbang.txrx_bufs = s3c24xx_spi_txrx; - - hw->master->setup = s3c24xx_spi_setup; - - dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang); - - /* find and map our resources */ - hw->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(hw->regs)) - return PTR_ERR(hw->regs); - - hw->irq = platform_get_irq(pdev, 0); - if (hw->irq < 0) - return -ENOENT; - - err = devm_request_irq(&pdev->dev, hw->irq, s3c24xx_spi_irq, 0, - pdev->name, hw); - if (err) { - dev_err(&pdev->dev, "Cannot claim IRQ\n"); - return err; - } - - hw->clk = devm_clk_get(&pdev->dev, "spi"); - if (IS_ERR(hw->clk)) { - dev_err(&pdev->dev, "No clock for device\n"); - return PTR_ERR(hw->clk); - } - - s3c24xx_spi_initialsetup(hw); - - /* register our spi controller */ - - err = spi_bitbang_start(&hw->bitbang); - if (err) { - dev_err(&pdev->dev, "Failed to register SPI master\n"); - goto err_register; - } - - return 0; - - err_register: - clk_disable(hw->clk); - - return err; -} - -static int s3c24xx_spi_remove(struct platform_device *dev) -{ - struct s3c24xx_spi *hw = platform_get_drvdata(dev); - - spi_bitbang_stop(&hw->bitbang); - clk_disable(hw->clk); - spi_master_put(hw->master); - return 0; -} - - -#ifdef CONFIG_PM - -static int s3c24xx_spi_suspend(struct device *dev) -{ - struct s3c24xx_spi *hw = dev_get_drvdata(dev); - int ret; - - ret = spi_master_suspend(hw->master); - if (ret) - return ret; - - clk_disable(hw->clk); - return 0; -} - -static int s3c24xx_spi_resume(struct device *dev) -{ - struct s3c24xx_spi *hw = dev_get_drvdata(dev); - - s3c24xx_spi_initialsetup(hw); - return spi_master_resume(hw->master); -} - -static const struct dev_pm_ops s3c24xx_spi_pmops = { - .suspend = s3c24xx_spi_suspend, - .resume = s3c24xx_spi_resume, -}; - -#define S3C24XX_SPI_PMOPS &s3c24xx_spi_pmops -#else -#define S3C24XX_SPI_PMOPS NULL -#endif /* CONFIG_PM */ - -MODULE_ALIAS("platform:s3c2410-spi"); -static struct platform_driver s3c24xx_spi_driver = { - .probe = s3c24xx_spi_probe, - .remove = s3c24xx_spi_remove, - .driver = { - .name = "s3c2410-spi", - .pm = S3C24XX_SPI_PMOPS, - }, -}; -module_platform_driver(s3c24xx_spi_driver); - -MODULE_DESCRIPTION("S3C24XX SPI Driver"); -MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 3cc7bb4d03de..3f33934f5429 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2220,11 +2220,26 @@ void spi_flush_queue(struct spi_controller *ctlr) /*-------------------------------------------------------------------------*/ #if defined(CONFIG_OF) +static void of_spi_parse_dt_cs_delay(struct device_node *nc, + struct spi_delay *delay, const char *prop) +{ + u32 value; + + if (!of_property_read_u32(nc, prop, &value)) { + if (value > U16_MAX) { + delay->value = DIV_ROUND_UP(value, 1000); + delay->unit = SPI_DELAY_UNIT_USECS; + } else { + delay->value = value; + delay->unit = SPI_DELAY_UNIT_NSECS; + } + } +} + static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, struct device_node *nc) { u32 value; - u16 cs_setup; int rc; /* Mode (clock phase/polarity/etc.) */ @@ -2310,10 +2325,8 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, if (!of_property_read_u32(nc, "spi-max-frequency", &value)) spi->max_speed_hz = value; - if (!of_property_read_u16(nc, "spi-cs-setup-ns", &cs_setup)) { - spi->cs_setup.value = cs_setup; - spi->cs_setup.unit = SPI_DELAY_UNIT_NSECS; - } + /* Device CS delays */ + of_spi_parse_dt_cs_delay(nc, &spi->cs_setup, "spi-cs-setup-delay-ns"); return 0; } diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 6313e7d0cdf8..a1ea093795cf 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -68,7 +68,7 @@ static_assert(N_SPI_MINORS > 0 && N_SPI_MINORS <= 256); struct spidev_data { dev_t devt; - spinlock_t spi_lock; + struct mutex spi_lock; struct spi_device *spi; struct list_head device_entry; @@ -90,22 +90,32 @@ MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message"); /*-------------------------------------------------------------------------*/ static ssize_t +spidev_sync_unlocked(struct spi_device *spi, struct spi_message *message) +{ + ssize_t status; + + status = spi_sync(spi, message); + if (status == 0) + status = message->actual_length; + + return status; +} + +static ssize_t spidev_sync(struct spidev_data *spidev, struct spi_message *message) { - int status; + ssize_t status; struct spi_device *spi; - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); spi = spidev->spi; - spin_unlock_irq(&spidev->spi_lock); if (spi == NULL) status = -ESHUTDOWN; else - status = spi_sync(spi, message); + status = spidev_sync_unlocked(spi, message); - if (status == 0) - status = message->actual_length; + mutex_unlock(&spidev->spi_lock); return status; } @@ -294,7 +304,7 @@ static int spidev_message(struct spidev_data *spidev, spi_message_add_tail(k_tmp, &msg); } - status = spidev_sync(spidev, &msg); + status = spidev_sync_unlocked(spidev->spi, &msg); if (status < 0) goto done; @@ -359,12 +369,12 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) * we issue this ioctl. */ spidev = filp->private_data; - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); spi = spi_dev_get(spidev->spi); - spin_unlock_irq(&spidev->spi_lock); - - if (spi == NULL) + if (spi == NULL) { + mutex_unlock(&spidev->spi_lock); return -ESHUTDOWN; + } /* use the buffer lock here for triple duty: * - prevent I/O (from us) so calling spi_setup() is safe; @@ -508,6 +518,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) mutex_unlock(&spidev->buf_lock); spi_dev_put(spi); + mutex_unlock(&spidev->spi_lock); return retval; } @@ -529,12 +540,12 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd, * we issue this ioctl. */ spidev = filp->private_data; - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); spi = spi_dev_get(spidev->spi); - spin_unlock_irq(&spidev->spi_lock); - - if (spi == NULL) + if (spi == NULL) { + mutex_unlock(&spidev->spi_lock); return -ESHUTDOWN; + } /* SPI_IOC_MESSAGE needs the buffer locked "normally" */ mutex_lock(&spidev->buf_lock); @@ -561,6 +572,7 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd, done: mutex_unlock(&spidev->buf_lock); spi_dev_put(spi); + mutex_unlock(&spidev->spi_lock); return retval; } @@ -601,7 +613,6 @@ static int spidev_open(struct inode *inode, struct file *filp) if (!spidev->tx_buffer) { spidev->tx_buffer = kmalloc(bufsiz, GFP_KERNEL); if (!spidev->tx_buffer) { - dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); status = -ENOMEM; goto err_find_dev; } @@ -610,7 +621,6 @@ static int spidev_open(struct inode *inode, struct file *filp) if (!spidev->rx_buffer) { spidev->rx_buffer = kmalloc(bufsiz, GFP_KERNEL); if (!spidev->rx_buffer) { - dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); status = -ENOMEM; goto err_alloc_rx_buf; } @@ -640,10 +650,10 @@ static int spidev_release(struct inode *inode, struct file *filp) spidev = filp->private_data; filp->private_data = NULL; - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); /* ... after we unbound from the underlying device? */ dofree = (spidev->spi == NULL); - spin_unlock_irq(&spidev->spi_lock); + mutex_unlock(&spidev->spi_lock); /* last close? */ spidev->users--; @@ -776,7 +786,7 @@ static int spidev_probe(struct spi_device *spi) /* Initialize the driver data */ spidev->spi = spi; - spin_lock_init(&spidev->spi_lock); + mutex_init(&spidev->spi_lock); mutex_init(&spidev->buf_lock); INIT_LIST_HEAD(&spidev->device_entry); @@ -821,9 +831,9 @@ static void spidev_remove(struct spi_device *spi) /* prevent new opens */ mutex_lock(&device_list_lock); /* make sure ops on existing fds can abort cleanly */ - spin_lock_irq(&spidev->spi_lock); + mutex_lock(&spidev->spi_lock); spidev->spi = NULL; - spin_unlock_irq(&spidev->spi_lock); + mutex_unlock(&spidev->spi_lock); list_del(&spidev->device_entry); device_destroy(spidev_class, spidev->devt); diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index b79f93684c4f..617012e09a37 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -58,7 +58,6 @@ source "drivers/staging/media/deprecated/meye/Kconfig" source "drivers/staging/media/deprecated/saa7146/Kconfig" source "drivers/staging/media/deprecated/stkwebcam/Kconfig" source "drivers/staging/media/deprecated/tm6000/Kconfig" -source "drivers/staging/media/deprecated/vpfe_capture/Kconfig" source "drivers/staging/media/deprecated/zr364xx/Kconfig" endif diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 54bbdd4b0d08..1e14edc2d44c 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -15,5 +15,4 @@ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ obj-$(CONFIG_VIDEO_TM6000) += deprecated/tm6000/ obj-$(CONFIG_VIDEO_VIU) += deprecated/fsl-viu/ obj-$(CONFIG_USB_ZR364XX) += deprecated/zr364xx/ -obj-y += deprecated/vpfe_capture/ obj-y += deprecated/saa7146/ diff --git a/drivers/staging/media/deprecated/vpfe_capture/Kconfig b/drivers/staging/media/deprecated/vpfe_capture/Kconfig deleted file mode 100644 index 10250e7e566b..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/Kconfig +++ /dev/null @@ -1,58 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config VIDEO_DM6446_CCDC - tristate "TI DM6446 CCDC video capture driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV - depends on ARCH_DAVINCI || COMPILE_TEST - depends on I2C - select VIDEOBUF_DMA_CONTIG - help - Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces - with decoder modules such as TVP5146 over BT656 or - sensor module such as MT9T001 over a raw interface. This - module configures the interface and CCDC/ISIF to do - video frame capture from slave decoders. - - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - - To compile this driver as a module, choose M here. There will - be two modules called vpfe_capture.ko and dm644x_ccdc.ko - -config VIDEO_DM355_CCDC - tristate "TI DM355 CCDC video capture driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV - depends on ARCH_DAVINCI || COMPILE_TEST - depends on I2C - select VIDEOBUF_DMA_CONTIG - help - Enables DM355 CCD hw module. DM355 CCDC hw interfaces - with decoder modules such as TVP5146 over BT656 or - sensor module such as MT9T001 over a raw interface. This - module configures the interface and CCDC/ISIF to do - video frame capture from a slave decoders - - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - - To compile this driver as a module, choose M here. There will - be two modules called vpfe_capture.ko and dm355_ccdc.ko - -config VIDEO_DM365_ISIF - tristate "TI DM365 ISIF video capture driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV - depends on ARCH_DAVINCI || COMPILE_TEST - depends on I2C - select VIDEOBUF_DMA_CONTIG - help - Enables ISIF hw module. This is the hardware module for - configuring ISIF in VPFE to capture Raw Bayer RGB data from - a image sensor or YUV data from a YUV source. - - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - - To compile this driver as a module, choose M here. There will - be two modules called vpfe_capture.ko and isif.ko diff --git a/drivers/staging/media/deprecated/vpfe_capture/Makefile b/drivers/staging/media/deprecated/vpfe_capture/Makefile deleted file mode 100644 index 609e8dc09ce7..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_VIDEO_DM6446_CCDC) += vpfe_capture.o dm644x_ccdc.o -obj-$(CONFIG_VIDEO_DM355_CCDC) += vpfe_capture.o dm355_ccdc.o -obj-$(CONFIG_VIDEO_DM365_ISIF) += vpfe_capture.o isif.o diff --git a/drivers/staging/media/deprecated/vpfe_capture/TODO b/drivers/staging/media/deprecated/vpfe_capture/TODO deleted file mode 100644 index ce654d7337af..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/TODO +++ /dev/null @@ -1,7 +0,0 @@ -These are one of the few drivers still not using the vb2 -framework, so these drivers are now deprecated with the intent of -removing them altogether by the beginning of 2023. - -In order to keep these drivers they have to be converted to vb2. -If someone is interested in doing this work, then contact the -linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/staging/media/deprecated/vpfe_capture/ccdc_hw_device.h b/drivers/staging/media/deprecated/vpfe_capture/ccdc_hw_device.h deleted file mode 100644 index a545052a95a9..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/ccdc_hw_device.h +++ /dev/null @@ -1,80 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * ccdc device API - */ -#ifndef _CCDC_HW_DEVICE_H -#define _CCDC_HW_DEVICE_H - -#ifdef __KERNEL__ -#include <linux/videodev2.h> -#include <linux/device.h> -#include <media/davinci/vpfe_types.h> -#include <media/davinci/ccdc_types.h> - -/* - * ccdc hw operations - */ -struct ccdc_hw_ops { - /* Pointer to initialize function to initialize ccdc device */ - int (*open) (struct device *dev); - /* Pointer to deinitialize function */ - int (*close) (struct device *dev); - /* set ccdc base address */ - void (*set_ccdc_base)(void *base, int size); - /* Pointer to function to enable or disable ccdc */ - void (*enable) (int en); - /* reset sbl. only for 6446 */ - void (*reset) (void); - /* enable output to sdram */ - void (*enable_out_to_sdram) (int en); - /* Pointer to function to set hw parameters */ - int (*set_hw_if_params) (struct vpfe_hw_if_param *param); - /* get interface parameters */ - int (*get_hw_if_params) (struct vpfe_hw_if_param *param); - /* Pointer to function to configure ccdc */ - int (*configure) (void); - - /* Pointer to function to set buffer type */ - int (*set_buftype) (enum ccdc_buftype buf_type); - /* Pointer to function to get buffer type */ - enum ccdc_buftype (*get_buftype) (void); - /* Pointer to function to set frame format */ - int (*set_frame_format) (enum ccdc_frmfmt frm_fmt); - /* Pointer to function to get frame format */ - enum ccdc_frmfmt (*get_frame_format) (void); - /* enumerate hw pix formats */ - int (*enum_pix)(u32 *hw_pix, int i); - /* Pointer to function to set buffer type */ - u32 (*get_pixel_format) (void); - /* Pointer to function to get pixel format. */ - int (*set_pixel_format) (u32 pixfmt); - /* Pointer to function to set image window */ - int (*set_image_window) (struct v4l2_rect *win); - /* Pointer to function to set image window */ - void (*get_image_window) (struct v4l2_rect *win); - /* Pointer to function to get line length */ - unsigned int (*get_line_length) (void); - - /* Pointer to function to set frame buffer address */ - void (*setfbaddr) (unsigned long addr); - /* Pointer to function to get field id */ - int (*getfid) (void); -}; - -struct ccdc_hw_device { - /* ccdc device name */ - char name[32]; - /* module owner */ - struct module *owner; - /* hw ops */ - struct ccdc_hw_ops hw_ops; -}; - -/* Used by CCDC module to register & unregister with vpfe capture driver */ -int vpfe_register_ccdc_device(const struct ccdc_hw_device *dev); -void vpfe_unregister_ccdc_device(const struct ccdc_hw_device *dev); - -#endif -#endif diff --git a/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.c b/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.c deleted file mode 100644 index da8db53e9498..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.c +++ /dev/null @@ -1,934 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2005-2009 Texas Instruments Inc - * - * CCDC hardware module for DM355 - * ------------------------------ - * - * This module is for configuring DM355 CCD controller of VPFE to capture - * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules - * such as Defect Pixel Correction, Color Space Conversion etc to - * pre-process the Bayer RGB data, before writing it to SDRAM. - * - * TODO: 1) Raw bayer parameter settings and bayer capture - * 2) Split module parameter structure to module specific ioctl structs - * 3) add support for lense shading correction - * 4) investigate if enum used for user space type definition - * to be replaced by #defines or integer - */ -#include <linux/platform_device.h> -#include <linux/uaccess.h> -#include <linux/videodev2.h> -#include <linux/err.h> -#include <linux/module.h> - -#include "dm355_ccdc.h" -#include <media/davinci/vpss.h> - -#include "dm355_ccdc_regs.h" -#include "ccdc_hw_device.h" - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("CCDC Driver for DM355"); -MODULE_AUTHOR("Texas Instruments"); - -static struct ccdc_oper_config { - struct device *dev; - /* CCDC interface type */ - enum vpfe_hw_if_type if_type; - /* Raw Bayer configuration */ - struct ccdc_params_raw bayer; - /* YCbCr configuration */ - struct ccdc_params_ycbcr ycbcr; - /* ccdc base address */ - void __iomem *base_addr; -} ccdc_cfg = { - /* Raw configurations */ - .bayer = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = CCDC_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .gain = { - .r_ye = 256, - .gb_g = 256, - .gr_cy = 256, - .b_mg = 256 - }, - .config_params = { - .datasft = 2, - .mfilt1 = CCDC_NO_MEDIAN_FILTER1, - .mfilt2 = CCDC_NO_MEDIAN_FILTER2, - .alaw = { - .gamma_wd = 2, - }, - .blk_clamp = { - .sample_pixel = 1, - .dc_sub = 25 - }, - .col_pat_field0 = { - .olop = CCDC_GREEN_BLUE, - .olep = CCDC_BLUE, - .elop = CCDC_RED, - .elep = CCDC_GREEN_RED - }, - .col_pat_field1 = { - .olop = CCDC_GREEN_BLUE, - .olep = CCDC_BLUE, - .elop = CCDC_RED, - .elep = CCDC_GREEN_RED - }, - }, - }, - /* YCbCr configuration */ - .ycbcr = { - .win = CCDC_WIN_PAL, - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .bt656_enable = 1, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED - }, -}; - - -/* Raw Bayer formats */ -static u32 ccdc_raw_bayer_pix_formats[] = - {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; - -/* Raw YUV formats */ -static u32 ccdc_raw_yuv_pix_formats[] = - {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; - -/* register access routines */ -static inline u32 regr(u32 offset) -{ - return __raw_readl(ccdc_cfg.base_addr + offset); -} - -static inline void regw(u32 val, u32 offset) -{ - __raw_writel(val, ccdc_cfg.base_addr + offset); -} - -static void ccdc_enable(int en) -{ - unsigned int temp; - temp = regr(SYNCEN); - temp &= (~CCDC_SYNCEN_VDHDEN_MASK); - temp |= (en & CCDC_SYNCEN_VDHDEN_MASK); - regw(temp, SYNCEN); -} - -static void ccdc_enable_output_to_sdram(int en) -{ - unsigned int temp; - temp = regr(SYNCEN); - temp &= (~(CCDC_SYNCEN_WEN_MASK)); - temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK); - regw(temp, SYNCEN); -} - -static void ccdc_config_gain_offset(void) -{ - /* configure gain */ - regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN); - regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN); - regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN); - regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN); - /* configure offset */ - regw(ccdc_cfg.bayer.ccdc_offset, OFFSET); -} - -/* - * ccdc_restore_defaults() - * This function restore power on defaults in the ccdc registers - */ -static int ccdc_restore_defaults(void) -{ - int i; - - dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults..."); - /* set all registers to zero */ - for (i = 0; i <= CCDC_REG_LAST; i += 4) - regw(0, i); - - /* now override the values with power on defaults in registers */ - regw(MODESET_DEFAULT, MODESET); - /* no culling support */ - regw(CULH_DEFAULT, CULH); - regw(CULV_DEFAULT, CULV); - /* Set default Gain and Offset */ - ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT; - ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT; - ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT; - ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT; - ccdc_config_gain_offset(); - regw(OUTCLIP_DEFAULT, OUTCLIP); - regw(LSCCFG2_DEFAULT, LSCCFG2); - /* select ccdc input */ - if (vpss_select_ccdc_source(VPSS_CCDCIN)) { - dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source"); - return -EFAULT; - } - /* select ccdc clock */ - if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) { - dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock"); - return -EFAULT; - } - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults..."); - return 0; -} - -static int ccdc_open(struct device *device) -{ - return ccdc_restore_defaults(); -} - -static int ccdc_close(struct device *device) -{ - /* disable clock */ - vpss_enable_clock(VPSS_CCDC_CLOCK, 0); - /* do nothing for now */ - return 0; -} -/* - * ccdc_setwin() - * This function will configure the window size to - * be capture in CCDC reg. - */ -static void ccdc_setwin(struct v4l2_rect *image_win, - enum ccdc_frmfmt frm_fmt, int ppc) -{ - int horz_start, horz_nr_pixels; - int vert_start, vert_nr_lines; - int mid_img = 0; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); - - /* - * ppc - per pixel count. indicates how many pixels per cell - * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. - * raw capture this is 1 - */ - horz_start = image_win->left << (ppc - 1); - horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; - - /* Writing the horizontal info into the registers */ - regw(horz_start, SPH); - regw(horz_nr_pixels, NPH); - vert_start = image_win->top; - - if (frm_fmt == CCDC_FRMFMT_INTERLACED) { - vert_nr_lines = (image_win->height >> 1) - 1; - vert_start >>= 1; - /* Since first line doesn't have any data */ - vert_start += 1; - /* configure VDINT0 and VDINT1 */ - regw(vert_start, VDINT0); - } else { - /* Since first line doesn't have any data */ - vert_start += 1; - vert_nr_lines = image_win->height - 1; - /* configure VDINT0 and VDINT1 */ - mid_img = vert_start + (image_win->height / 2); - regw(vert_start, VDINT0); - regw(mid_img, VDINT1); - } - regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0); - regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1); - regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV); - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); -} - -/* This function will configure CCDC for YCbCr video capture */ -static void ccdc_config_ycbcr(void) -{ - struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; - u32 temp; - - /* first set the CCDC power on defaults values in all registers */ - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); - ccdc_restore_defaults(); - - /* configure pixel format & video frame format */ - temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) << - CCDC_INPUT_MODE_SHIFT) | - ((params->frm_fmt & CCDC_FRM_FMT_MASK) << - CCDC_FRM_FMT_SHIFT)); - - /* setup BT.656 sync mode */ - if (params->bt656_enable) { - regw(CCDC_REC656IF_BT656_EN, REC656IF); - /* - * configure the FID, VD, HD pin polarity fld,hd pol positive, - * vd negative, 8-bit pack mode - */ - temp |= CCDC_VD_POL_NEGATIVE; - } else { /* y/c external sync mode */ - temp |= (((params->fid_pol & CCDC_FID_POL_MASK) << - CCDC_FID_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << - CCDC_HD_POL_SHIFT) | - ((params->vd_pol & CCDC_VD_POL_MASK) << - CCDC_VD_POL_SHIFT)); - } - - /* pack the data to 8-bit */ - temp |= CCDC_DATA_PACK_ENABLE; - - regw(temp, MODESET); - - /* configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, 2); - - /* configure the order of y cb cr in SD-RAM */ - temp = (params->pix_order << CCDC_Y8POS_SHIFT); - temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC; - regw(temp, CCDCFG); - - /* - * configure the horizontal line offset. This is done by rounding up - * width to a multiple of 16 pixels and multiply by two to account for - * y:cb:cr 4:2:2 data - */ - regw(((params->win.width * 2 + 31) >> 5), HSIZE); - - /* configure the memory line offset */ - if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { - /* two fields are interleaved in memory */ - regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST); - } - - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); -} - -/* - * ccdc_config_black_clamp() - * configure parameters for Optical Black Clamp - */ -static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) -{ - u32 val; - - if (!bclamp->b_clamp_enable) { - /* configure DCSub */ - regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB); - regw(0x0000, CLAMP); - return; - } - /* Enable the Black clamping, set sample lines and pixels */ - val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) | - ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << - CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE; - regw(val, CLAMP); - - /* If Black clamping is enable then make dcsub 0 */ - val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK) - << CCDC_NUM_LINE_CALC_SHIFT; - regw(val, DCSUB); -} - -/* - * ccdc_config_black_compense() - * configure parameters for Black Compensation - */ -static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) -{ - u32 val; - - val = (bcomp->b & CCDC_BLK_COMP_MASK) | - ((bcomp->gb & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GB_COMP_SHIFT); - regw(val, BLKCMP1); - - val = ((bcomp->gr & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GR_COMP_SHIFT) | - ((bcomp->r & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_R_COMP_SHIFT); - regw(val, BLKCMP0); -} - -/* - * ccdc_write_dfc_entry() - * write an entry in the dfc table. - */ -static int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) -{ -/* TODO This is to be re-visited and adjusted */ -#define DFC_WRITE_WAIT_COUNT 1000 - u32 val, count = DFC_WRITE_WAIT_COUNT; - - regw(dfc->dft_corr_vert[index], DFCMEM0); - regw(dfc->dft_corr_horz[index], DFCMEM1); - regw(dfc->dft_corr_sub1[index], DFCMEM2); - regw(dfc->dft_corr_sub2[index], DFCMEM3); - regw(dfc->dft_corr_sub3[index], DFCMEM4); - /* set WR bit to write */ - val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK; - regw(val, DFCMEMCTL); - - /* - * Assume, it is very short. If we get an error, we need to - * adjust this value - */ - while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK) - count--; - /* - * TODO We expect the count to be non-zero to be successful. Adjust - * the count if write requires more time - */ - - if (count) { - dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n"); - return -1; - } - return 0; -} - -/* - * ccdc_config_vdfc() - * configure parameters for Vertical Defect Correction - */ -static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc) -{ - u32 val; - int i; - - /* Configure General Defect Correction. The table used is from IPIPE */ - val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK; - - /* Configure Vertical Defect Correction if needed */ - if (!dfc->ver_dft_en) { - /* Enable only General Defect Correction */ - regw(val, DFCCTL); - return 0; - } - - if (dfc->table_size > CCDC_DFT_TABLE_SIZE) - return -EINVAL; - - val |= CCDC_DFCCTL_VDFC_DISABLE; - val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) << - CCDC_DFCCTL_VDFCSL_SHIFT; - val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) << - CCDC_DFCCTL_VDFCUDA_SHIFT; - val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) << - CCDC_DFCCTL_VDFLSFT_SHIFT; - regw(val , DFCCTL); - - /* clear address ptr to offset 0 */ - val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT; - - /* write defect table entries */ - for (i = 0; i < dfc->table_size; i++) { - /* increment address for non zero index */ - if (i != 0) - val = CCDC_DFCMEMCTL_INC_ADDR; - regw(val, DFCMEMCTL); - if (ccdc_write_dfc_entry(i, dfc) < 0) - return -EFAULT; - } - - /* update saturation level and enable dfc */ - regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT); - val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK << - CCDC_DFCCTL_VDFCEN_SHIFT); - regw(val, DFCCTL); - return 0; -} - -/* - * ccdc_config_csc() - * configure parameters for color space conversion - * Each register CSCM0-7 has two values in S8Q5 format. - */ -static void ccdc_config_csc(struct ccdc_csc *csc) -{ - u32 val1 = 0, val2; - int i; - - if (!csc->enable) - return; - - /* Enable the CSC sub-module */ - regw(CCDC_CSC_ENABLE, CSCCTL); - - /* Converting the co-eff as per the format of the register */ - for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) { - if ((i % 2) == 0) { - /* CSCM - LSB */ - val1 = (csc->coeff[i].integer & - CCDC_CSC_COEF_INTEG_MASK) - << CCDC_CSC_COEF_INTEG_SHIFT; - /* - * convert decimal part to binary. Use 2 decimal - * precision, user values range from .00 - 0.99 - */ - val1 |= (((csc->coeff[i].decimal & - CCDC_CSC_COEF_DECIMAL_MASK) * - CCDC_CSC_DEC_MAX) / 100); - } else { - - /* CSCM - MSB */ - val2 = (csc->coeff[i].integer & - CCDC_CSC_COEF_INTEG_MASK) - << CCDC_CSC_COEF_INTEG_SHIFT; - val2 |= (((csc->coeff[i].decimal & - CCDC_CSC_COEF_DECIMAL_MASK) * - CCDC_CSC_DEC_MAX) / 100); - val2 <<= CCDC_CSCM_MSB_SHIFT; - val2 |= val1; - regw(val2, (CSCM0 + ((i - 1) << 1))); - } - } -} - -/* - * ccdc_config_color_patterns() - * configure parameters for color patterns - */ -static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0, - struct ccdc_col_pat *pat1) -{ - u32 val; - - val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) | - (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) | - (pat1->elop << 12) | (pat1->elep << 14)); - regw(val, COLPTN); -} - -/* This function will configure CCDC for Raw mode image capture */ -static int ccdc_config_raw(void) -{ - struct ccdc_params_raw *params = &ccdc_cfg.bayer; - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int val; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); - - /* restore power on defaults to register */ - ccdc_restore_defaults(); - - /* CCDCFG register: - * set CCD Not to swap input since input is RAW data - * set FID detection function to Latch at V-Sync - * set WENLOG - ccdc valid area to AND - * set TRGSEL to WENBIT - * set EXTRG to DISABLE - * disable latching function on VSYNC - shadowed registers - */ - regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC | - CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN | - CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG); - - /* - * Set VDHD direction to input, input type to raw input - * normal data polarity, do not use external WEN - */ - val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL | - CCDC_EXWEN_DISABLE); - - /* - * Configure the vertical sync polarity (MODESET.VDPOL), horizontal - * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL), - * frame format(progressive or interlace), & pixel format (Input mode) - */ - val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | - ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | - ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | - ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT)); - - /* set pack for alaw compression */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) - val |= CCDC_DATA_PACK_ENABLE; - - /* Configure for LPF */ - if (config_params->lpf_enable) - val |= (config_params->lpf_enable & CCDC_LPF_MASK) << - CCDC_LPF_SHIFT; - - /* Configure the data shift */ - val |= (config_params->datasft & CCDC_DATASFT_MASK) << - CCDC_DATASFT_SHIFT; - regw(val , MODESET); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val); - - /* Configure the Median Filter threshold */ - regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT); - - /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */ - val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT | - CCDC_CFA_MOSAIC; - - /* Enable and configure aLaw register if needed */ - if (config_params->alaw.enable) { - val |= (CCDC_ALAW_ENABLE | - ((config_params->alaw.gamma_wd & - CCDC_ALAW_GAMMA_WD_MASK) << - CCDC_GAMMAWD_INPUT_SHIFT)); - } - - /* Configure Median filter1 & filter2 */ - val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) | - (config_params->mfilt2 << CCDC_MFILT2_SHIFT)); - - regw(val, GAMMAWD); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val); - - /* configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, 1); - - /* Optical Clamp Averaging */ - ccdc_config_black_clamp(&config_params->blk_clamp); - - /* Black level compensation */ - ccdc_config_black_compense(&config_params->blk_comp); - - /* Vertical Defect Correction if needed */ - if (ccdc_config_vdfc(&config_params->vertical_dft) < 0) - return -EFAULT; - - /* color space conversion */ - ccdc_config_csc(&config_params->csc); - - /* color pattern */ - ccdc_config_color_patterns(&config_params->col_pat_field0, - &config_params->col_pat_field1); - - /* Configure the Gain & offset control */ - ccdc_config_gain_offset(); - - dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val); - - /* Configure DATAOFST register */ - val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) << - CCDC_DATAOFST_H_SHIFT; - val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) << - CCDC_DATAOFST_V_SHIFT; - regw(val, DATAOFST); - - /* configuring HSIZE register */ - val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) << - CCDC_HSIZE_FLIP_SHIFT; - - /* If pack 8 is enable then 1 pixel will take 1 byte */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) { - val |= (((params->win.width) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK; - - /* adjust to multiple of 32 */ - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", - (((params->win.width) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK); - } else { - /* else one pixel will take 2 byte */ - val |= (((params->win.width * 2) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK; - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", - (((params->win.width * 2) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK); - } - regw(val, HSIZE); - - /* Configure SDOFST register */ - if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { - if (params->image_invert_enable) { - /* For interlace inverse mode */ - regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_INTERLACE_INVERSE); - } else { - /* For interlace non inverse mode */ - regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_INTERLACE_NORMAL); - } - } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { - if (params->image_invert_enable) { - /* For progessive inverse mode */ - regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_PROGRESSIVE_INVERSE); - } else { - /* For progessive non inverse mode */ - regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_PROGRESSIVE_NORMAL); - } - } - dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); - return 0; -} - -static int ccdc_configure(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_config_raw(); - else - ccdc_config_ycbcr(); - return 0; -} - -static int ccdc_set_buftype(enum ccdc_buftype buf_type) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.buf_type = buf_type; - else - ccdc_cfg.ycbcr.buf_type = buf_type; - return 0; -} -static enum ccdc_buftype ccdc_get_buftype(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.buf_type; - return ccdc_cfg.ycbcr.buf_type; -} - -static int ccdc_enum_pix(u32 *pix, int i) -{ - int ret = -EINVAL; - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { - *pix = ccdc_raw_bayer_pix_formats[i]; - ret = 0; - } - } else { - if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { - *pix = ccdc_raw_yuv_pix_formats[i]; - ret = 0; - } - } - return ret; -} - -static int ccdc_set_pixel_format(u32 pixfmt) -{ - struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - if (pixfmt == V4L2_PIX_FMT_SBGGR8) - alaw->enable = 1; - else if (pixfmt != V4L2_PIX_FMT_SBGGR16) - return -EINVAL; - } else { - if (pixfmt == V4L2_PIX_FMT_YUYV) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; - else if (pixfmt == V4L2_PIX_FMT_UYVY) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - else - return -EINVAL; - } - return 0; -} -static u32 ccdc_get_pixel_format(void) -{ - struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; - u32 pixfmt; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - if (alaw->enable) - pixfmt = V4L2_PIX_FMT_SBGGR8; - else - pixfmt = V4L2_PIX_FMT_SBGGR16; - else { - if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) - pixfmt = V4L2_PIX_FMT_YUYV; - else - pixfmt = V4L2_PIX_FMT_UYVY; - } - return pixfmt; -} -static int ccdc_set_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.win = *win; - else - ccdc_cfg.ycbcr.win = *win; - return 0; -} - -static void ccdc_get_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - *win = ccdc_cfg.bayer.win; - else - *win = ccdc_cfg.ycbcr.win; -} - -static unsigned int ccdc_get_line_length(void) -{ - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int len; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if ((config_params->alaw.enable) || - (config_params->data_sz == CCDC_DATA_8BITS)) - len = ccdc_cfg.bayer.win.width; - else - len = ccdc_cfg.bayer.win.width * 2; - } else - len = ccdc_cfg.ycbcr.win.width * 2; - return ALIGN(len, 32); -} - -static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.frm_fmt = frm_fmt; - else - ccdc_cfg.ycbcr.frm_fmt = frm_fmt; - return 0; -} - -static enum ccdc_frmfmt ccdc_get_frame_format(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.frm_fmt; - else - return ccdc_cfg.ycbcr.frm_fmt; -} - -static int ccdc_getfid(void) -{ - return (regr(MODESET) >> 15) & 1; -} - -/* misc operations */ -static inline void ccdc_setfbaddr(unsigned long addr) -{ - regw((addr >> 21) & 0x007f, STADRH); - regw((addr >> 5) & 0x0ffff, STADRL); -} - -static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) -{ - ccdc_cfg.if_type = params->if_type; - - switch (params->if_type) { - case VPFE_BT656: - case VPFE_YCBCR_SYNC_16: - case VPFE_YCBCR_SYNC_8: - ccdc_cfg.ycbcr.vd_pol = params->vdpol; - ccdc_cfg.ycbcr.hd_pol = params->hdpol; - break; - default: - /* TODO add support for raw bayer here */ - return -EINVAL; - } - return 0; -} - -static const struct ccdc_hw_device ccdc_hw_dev = { - .name = "DM355 CCDC", - .owner = THIS_MODULE, - .hw_ops = { - .open = ccdc_open, - .close = ccdc_close, - .enable = ccdc_enable, - .enable_out_to_sdram = ccdc_enable_output_to_sdram, - .set_hw_if_params = ccdc_set_hw_if_params, - .configure = ccdc_configure, - .set_buftype = ccdc_set_buftype, - .get_buftype = ccdc_get_buftype, - .enum_pix = ccdc_enum_pix, - .set_pixel_format = ccdc_set_pixel_format, - .get_pixel_format = ccdc_get_pixel_format, - .set_frame_format = ccdc_set_frame_format, - .get_frame_format = ccdc_get_frame_format, - .set_image_window = ccdc_set_image_window, - .get_image_window = ccdc_get_image_window, - .get_line_length = ccdc_get_line_length, - .setfbaddr = ccdc_setfbaddr, - .getfid = ccdc_getfid, - }, -}; - -static int dm355_ccdc_probe(struct platform_device *pdev) -{ - void (*setup_pinmux)(void); - struct resource *res; - int status = 0; - - /* - * first try to register with vpfe. If not correct platform, then we - * don't have to iomap - */ - status = vpfe_register_ccdc_device(&ccdc_hw_dev); - if (status < 0) - return status; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - status = -ENODEV; - goto fail_nores; - } - - res = request_mem_region(res->start, resource_size(res), res->name); - if (!res) { - status = -EBUSY; - goto fail_nores; - } - - ccdc_cfg.base_addr = ioremap(res->start, resource_size(res)); - if (!ccdc_cfg.base_addr) { - status = -ENOMEM; - goto fail_nomem; - } - - /* Platform data holds setup_pinmux function ptr */ - if (NULL == pdev->dev.platform_data) { - status = -ENODEV; - goto fail_nomap; - } - setup_pinmux = pdev->dev.platform_data; - /* - * setup Mux configuration for ccdc which may be different for - * different SoCs using this CCDC - */ - setup_pinmux(); - ccdc_cfg.dev = &pdev->dev; - printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); - return 0; -fail_nomap: - iounmap(ccdc_cfg.base_addr); -fail_nomem: - release_mem_region(res->start, resource_size(res)); -fail_nores: - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return status; -} - -static int dm355_ccdc_remove(struct platform_device *pdev) -{ - struct resource *res; - - iounmap(ccdc_cfg.base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return 0; -} - -static struct platform_driver dm355_ccdc_driver = { - .driver = { - .name = "dm355_ccdc", - }, - .remove = dm355_ccdc_remove, - .probe = dm355_ccdc_probe, -}; - -module_platform_driver(dm355_ccdc_driver); diff --git a/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.h b/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.h deleted file mode 100644 index 1f3d00aa46d1..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.h +++ /dev/null @@ -1,308 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2005-2009 Texas Instruments Inc - */ -#ifndef _DM355_CCDC_H -#define _DM355_CCDC_H -#include <media/davinci/ccdc_types.h> -#include <media/davinci/vpfe_types.h> - -/* enum for No of pixel per line to be avg. in Black Clamping */ -enum ccdc_sample_length { - CCDC_SAMPLE_1PIXELS, - CCDC_SAMPLE_2PIXELS, - CCDC_SAMPLE_4PIXELS, - CCDC_SAMPLE_8PIXELS, - CCDC_SAMPLE_16PIXELS -}; - -/* enum for No of lines in Black Clamping */ -enum ccdc_sample_line { - CCDC_SAMPLE_1LINES, - CCDC_SAMPLE_2LINES, - CCDC_SAMPLE_4LINES, - CCDC_SAMPLE_8LINES, - CCDC_SAMPLE_16LINES -}; - -/* enum for Alaw gamma width */ -enum ccdc_gamma_width { - CCDC_GAMMA_BITS_13_4, - CCDC_GAMMA_BITS_12_3, - CCDC_GAMMA_BITS_11_2, - CCDC_GAMMA_BITS_10_1, - CCDC_GAMMA_BITS_09_0 -}; - -enum ccdc_colpats { - CCDC_RED, - CCDC_GREEN_RED, - CCDC_GREEN_BLUE, - CCDC_BLUE -}; - -struct ccdc_col_pat { - enum ccdc_colpats olop; - enum ccdc_colpats olep; - enum ccdc_colpats elop; - enum ccdc_colpats elep; -}; - -enum ccdc_datasft { - CCDC_DATA_NO_SHIFT, - CCDC_DATA_SHIFT_1BIT, - CCDC_DATA_SHIFT_2BIT, - CCDC_DATA_SHIFT_3BIT, - CCDC_DATA_SHIFT_4BIT, - CCDC_DATA_SHIFT_5BIT, - CCDC_DATA_SHIFT_6BIT -}; - -enum ccdc_data_size { - CCDC_DATA_16BITS, - CCDC_DATA_15BITS, - CCDC_DATA_14BITS, - CCDC_DATA_13BITS, - CCDC_DATA_12BITS, - CCDC_DATA_11BITS, - CCDC_DATA_10BITS, - CCDC_DATA_8BITS -}; -enum ccdc_mfilt1 { - CCDC_NO_MEDIAN_FILTER1, - CCDC_AVERAGE_FILTER1, - CCDC_MEDIAN_FILTER1 -}; - -enum ccdc_mfilt2 { - CCDC_NO_MEDIAN_FILTER2, - CCDC_AVERAGE_FILTER2, - CCDC_MEDIAN_FILTER2 -}; - -/* structure for ALaw */ -struct ccdc_a_law { - /* Enable/disable A-Law */ - unsigned char enable; - /* Gamma Width Input */ - enum ccdc_gamma_width gamma_wd; -}; - -/* structure for Black Clamping */ -struct ccdc_black_clamp { - /* only if bClampEnable is TRUE */ - unsigned char b_clamp_enable; - /* only if bClampEnable is TRUE */ - enum ccdc_sample_length sample_pixel; - /* only if bClampEnable is TRUE */ - enum ccdc_sample_line sample_ln; - /* only if bClampEnable is TRUE */ - unsigned short start_pixel; - /* only if bClampEnable is FALSE */ - unsigned short sgain; - unsigned short dc_sub; -}; - -/* structure for Black Level Compensation */ -struct ccdc_black_compensation { - /* Constant value to subtract from Red component */ - unsigned char r; - /* Constant value to subtract from Gr component */ - unsigned char gr; - /* Constant value to subtract from Blue component */ - unsigned char b; - /* Constant value to subtract from Gb component */ - unsigned char gb; -}; - -struct ccdc_float { - int integer; - unsigned int decimal; -}; - -#define CCDC_CSC_COEFF_TABLE_SIZE 16 -/* structure for color space converter */ -struct ccdc_csc { - unsigned char enable; - /* - * S8Q5. Use 2 decimal precision, user values range from -3.00 to 3.99. - * example - to use 1.03, set integer part as 1, and decimal part as 3 - * to use -1.03, set integer part as -1 and decimal part as 3 - */ - struct ccdc_float coeff[CCDC_CSC_COEFF_TABLE_SIZE]; -}; - -/* Structures for Vertical Defect Correction*/ -enum ccdc_vdf_csl { - CCDC_VDF_NORMAL, - CCDC_VDF_HORZ_INTERPOL_SAT, - CCDC_VDF_HORZ_INTERPOL -}; - -enum ccdc_vdf_cuda { - CCDC_VDF_WHOLE_LINE_CORRECT, - CCDC_VDF_UPPER_DISABLE -}; - -enum ccdc_dfc_mwr { - CCDC_DFC_MWR_WRITE_COMPLETE, - CCDC_DFC_WRITE_REG -}; - -enum ccdc_dfc_mrd { - CCDC_DFC_READ_COMPLETE, - CCDC_DFC_READ_REG -}; - -enum ccdc_dfc_ma_rst { - CCDC_DFC_INCR_ADDR, - CCDC_DFC_CLR_ADDR -}; - -enum ccdc_dfc_mclr { - CCDC_DFC_CLEAR_COMPLETE, - CCDC_DFC_CLEAR -}; - -struct ccdc_dft_corr_ctl { - enum ccdc_vdf_csl vdfcsl; - enum ccdc_vdf_cuda vdfcuda; - unsigned int vdflsft; -}; - -struct ccdc_dft_corr_mem_ctl { - enum ccdc_dfc_mwr dfcmwr; - enum ccdc_dfc_mrd dfcmrd; - enum ccdc_dfc_ma_rst dfcmarst; - enum ccdc_dfc_mclr dfcmclr; -}; - -#define CCDC_DFT_TABLE_SIZE 16 -/* - * Main Structure for vertical defect correction. Vertical defect - * correction can correct up to 16 defects if defects less than 16 - * then pad the rest with 0 - */ -struct ccdc_vertical_dft { - unsigned char ver_dft_en; - unsigned char gen_dft_en; - unsigned int saturation_ctl; - struct ccdc_dft_corr_ctl dft_corr_ctl; - struct ccdc_dft_corr_mem_ctl dft_corr_mem_ctl; - int table_size; - unsigned int dft_corr_horz[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_vert[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_sub1[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_sub2[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_sub3[CCDC_DFT_TABLE_SIZE]; -}; - -struct ccdc_data_offset { - unsigned char horz_offset; - unsigned char vert_offset; -}; - -/* - * Structure for CCDC configuration parameters for raw capture mode passed - * by application - */ -struct ccdc_config_params_raw { - /* data shift to be applied before storing */ - enum ccdc_datasft datasft; - /* data size value from 8 to 16 bits */ - enum ccdc_data_size data_sz; - /* median filter for sdram */ - enum ccdc_mfilt1 mfilt1; - enum ccdc_mfilt2 mfilt2; - /* low pass filter enable/disable */ - unsigned char lpf_enable; - /* Threshold of median filter */ - int med_filt_thres; - /* - * horz and vertical data offset. Applicable for defect correction - * and lsc - */ - struct ccdc_data_offset data_offset; - /* Structure for Optional A-Law */ - struct ccdc_a_law alaw; - /* Structure for Optical Black Clamp */ - struct ccdc_black_clamp blk_clamp; - /* Structure for Black Compensation */ - struct ccdc_black_compensation blk_comp; - /* structure for vertical Defect Correction Module Configuration */ - struct ccdc_vertical_dft vertical_dft; - /* structure for color space converter Module Configuration */ - struct ccdc_csc csc; - /* color patters for bayer capture */ - struct ccdc_col_pat col_pat_field0; - struct ccdc_col_pat col_pat_field1; -}; - -#ifdef __KERNEL__ -#include <linux/io.h> - -#define CCDC_WIN_PAL {0, 0, 720, 576} -#define CCDC_WIN_VGA {0, 0, 640, 480} - -struct ccdc_params_ycbcr { - /* pixel format */ - enum ccdc_pixfmt pix_fmt; - /* progressive or interlaced frame */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol hd_pol; - /* enable BT.656 embedded sync mode */ - int bt656_enable; - /* cb:y:cr:y or y:cb:y:cr in memory */ - enum ccdc_pixorder pix_order; - /* interleaved or separated fields */ - enum ccdc_buftype buf_type; -}; - -/* Gain applied to Raw Bayer data */ -struct ccdc_gain { - unsigned short r_ye; - unsigned short gr_cy; - unsigned short gb_g; - unsigned short b_mg; -}; - -/* Structure for CCDC configuration parameters for raw capture mode */ -struct ccdc_params_raw { - /* pixel format */ - enum ccdc_pixfmt pix_fmt; - /* progressive or interlaced frame */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol hd_pol; - /* interleaved or separated fields */ - enum ccdc_buftype buf_type; - /* Gain values */ - struct ccdc_gain gain; - /* offset */ - unsigned int ccdc_offset; - /* horizontal flip enable */ - unsigned char horz_flip_enable; - /* - * enable to store the image in inverse order in memory - * (bottom to top) - */ - unsigned char image_invert_enable; - /* Configurable part of raw data */ - struct ccdc_config_params_raw config_params; -}; - -#endif -#endif /* DM355_CCDC_H */ diff --git a/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc_regs.h b/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc_regs.h deleted file mode 100644 index eb381f075245..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc_regs.h +++ /dev/null @@ -1,297 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2005-2009 Texas Instruments Inc - */ -#ifndef _DM355_CCDC_REGS_H -#define _DM355_CCDC_REGS_H - -/**************************************************************************\ -* Register OFFSET Definitions -\**************************************************************************/ -#define SYNCEN 0x00 -#define MODESET 0x04 -#define HDWIDTH 0x08 -#define VDWIDTH 0x0c -#define PPLN 0x10 -#define LPFR 0x14 -#define SPH 0x18 -#define NPH 0x1c -#define SLV0 0x20 -#define SLV1 0x24 -#define NLV 0x28 -#define CULH 0x2c -#define CULV 0x30 -#define HSIZE 0x34 -#define SDOFST 0x38 -#define STADRH 0x3c -#define STADRL 0x40 -#define CLAMP 0x44 -#define DCSUB 0x48 -#define COLPTN 0x4c -#define BLKCMP0 0x50 -#define BLKCMP1 0x54 -#define MEDFILT 0x58 -#define RYEGAIN 0x5c -#define GRCYGAIN 0x60 -#define GBGGAIN 0x64 -#define BMGGAIN 0x68 -#define OFFSET 0x6c -#define OUTCLIP 0x70 -#define VDINT0 0x74 -#define VDINT1 0x78 -#define RSV0 0x7c -#define GAMMAWD 0x80 -#define REC656IF 0x84 -#define CCDCFG 0x88 -#define FMTCFG 0x8c -#define FMTPLEN 0x90 -#define FMTSPH 0x94 -#define FMTLNH 0x98 -#define FMTSLV 0x9c -#define FMTLNV 0xa0 -#define FMTRLEN 0xa4 -#define FMTHCNT 0xa8 -#define FMT_ADDR_PTR_B 0xac -#define FMT_ADDR_PTR(i) (FMT_ADDR_PTR_B + (i * 4)) -#define FMTPGM_VF0 0xcc -#define FMTPGM_VF1 0xd0 -#define FMTPGM_AP0 0xd4 -#define FMTPGM_AP1 0xd8 -#define FMTPGM_AP2 0xdc -#define FMTPGM_AP3 0xe0 -#define FMTPGM_AP4 0xe4 -#define FMTPGM_AP5 0xe8 -#define FMTPGM_AP6 0xec -#define FMTPGM_AP7 0xf0 -#define LSCCFG1 0xf4 -#define LSCCFG2 0xf8 -#define LSCH0 0xfc -#define LSCV0 0x100 -#define LSCKH 0x104 -#define LSCKV 0x108 -#define LSCMEMCTL 0x10c -#define LSCMEMD 0x110 -#define LSCMEMQ 0x114 -#define DFCCTL 0x118 -#define DFCVSAT 0x11c -#define DFCMEMCTL 0x120 -#define DFCMEM0 0x124 -#define DFCMEM1 0x128 -#define DFCMEM2 0x12c -#define DFCMEM3 0x130 -#define DFCMEM4 0x134 -#define CSCCTL 0x138 -#define CSCM0 0x13c -#define CSCM1 0x140 -#define CSCM2 0x144 -#define CSCM3 0x148 -#define CSCM4 0x14c -#define CSCM5 0x150 -#define CSCM6 0x154 -#define CSCM7 0x158 -#define DATAOFST 0x15c -#define CCDC_REG_LAST DATAOFST -/************************************************************** -* Define for various register bit mask and shifts for CCDC -* -**************************************************************/ -#define CCDC_RAW_IP_MODE 0 -#define CCDC_VDHDOUT_INPUT 0 -#define CCDC_YCINSWP_RAW (0 << 4) -#define CCDC_EXWEN_DISABLE 0 -#define CCDC_DATAPOL_NORMAL 0 -#define CCDC_CCDCFG_FIDMD_LATCH_VSYNC 0 -#define CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC (1 << 6) -#define CCDC_CCDCFG_WENLOG_AND 0 -#define CCDC_CCDCFG_TRGSEL_WEN 0 -#define CCDC_CCDCFG_EXTRG_DISABLE 0 -#define CCDC_CFA_MOSAIC 0 -#define CCDC_Y8POS_SHIFT 11 - -#define CCDC_VDC_DFCVSAT_MASK 0x3fff -#define CCDC_DATAOFST_MASK 0x0ff -#define CCDC_DATAOFST_H_SHIFT 0 -#define CCDC_DATAOFST_V_SHIFT 8 -#define CCDC_GAMMAWD_CFA_MASK 1 -#define CCDC_GAMMAWD_CFA_SHIFT 5 -#define CCDC_GAMMAWD_INPUT_SHIFT 2 -#define CCDC_FID_POL_MASK 1 -#define CCDC_FID_POL_SHIFT 4 -#define CCDC_HD_POL_MASK 1 -#define CCDC_HD_POL_SHIFT 3 -#define CCDC_VD_POL_MASK 1 -#define CCDC_VD_POL_SHIFT 2 -#define CCDC_VD_POL_NEGATIVE (1 << 2) -#define CCDC_FRM_FMT_MASK 1 -#define CCDC_FRM_FMT_SHIFT 7 -#define CCDC_DATA_SZ_MASK 7 -#define CCDC_DATA_SZ_SHIFT 8 -#define CCDC_VDHDOUT_MASK 1 -#define CCDC_VDHDOUT_SHIFT 0 -#define CCDC_EXWEN_MASK 1 -#define CCDC_EXWEN_SHIFT 5 -#define CCDC_INPUT_MODE_MASK 3 -#define CCDC_INPUT_MODE_SHIFT 12 -#define CCDC_PIX_FMT_MASK 3 -#define CCDC_PIX_FMT_SHIFT 12 -#define CCDC_DATAPOL_MASK 1 -#define CCDC_DATAPOL_SHIFT 6 -#define CCDC_WEN_ENABLE (1 << 1) -#define CCDC_VDHDEN_ENABLE (1 << 16) -#define CCDC_LPF_ENABLE (1 << 14) -#define CCDC_ALAW_ENABLE 1 -#define CCDC_ALAW_GAMMA_WD_MASK 7 -#define CCDC_REC656IF_BT656_EN 3 - -#define CCDC_FMTCFG_FMTMODE_MASK 3 -#define CCDC_FMTCFG_FMTMODE_SHIFT 1 -#define CCDC_FMTCFG_LNUM_MASK 3 -#define CCDC_FMTCFG_LNUM_SHIFT 4 -#define CCDC_FMTCFG_ADDRINC_MASK 7 -#define CCDC_FMTCFG_ADDRINC_SHIFT 8 - -#define CCDC_CCDCFG_FIDMD_SHIFT 6 -#define CCDC_CCDCFG_WENLOG_SHIFT 8 -#define CCDC_CCDCFG_TRGSEL_SHIFT 9 -#define CCDC_CCDCFG_EXTRG_SHIFT 10 -#define CCDC_CCDCFG_MSBINVI_SHIFT 13 - -#define CCDC_HSIZE_FLIP_SHIFT 12 -#define CCDC_HSIZE_FLIP_MASK 1 -#define CCDC_HSIZE_VAL_MASK 0xFFF -#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 -#define CCDC_SDOFST_INTERLACE_INVERSE 0x4B6D -#define CCDC_SDOFST_INTERLACE_NORMAL 0x0B6D -#define CCDC_SDOFST_PROGRESSIVE_INVERSE 0x4000 -#define CCDC_SDOFST_PROGRESSIVE_NORMAL 0 -#define CCDC_START_PX_HOR_MASK 0x7FFF -#define CCDC_NUM_PX_HOR_MASK 0x7FFF -#define CCDC_START_VER_ONE_MASK 0x7FFF -#define CCDC_START_VER_TWO_MASK 0x7FFF -#define CCDC_NUM_LINES_VER 0x7FFF - -#define CCDC_BLK_CLAMP_ENABLE (1 << 15) -#define CCDC_BLK_SGAIN_MASK 0x1F -#define CCDC_BLK_ST_PXL_MASK 0x1FFF -#define CCDC_BLK_SAMPLE_LN_MASK 3 -#define CCDC_BLK_SAMPLE_LN_SHIFT 13 - -#define CCDC_NUM_LINE_CALC_MASK 3 -#define CCDC_NUM_LINE_CALC_SHIFT 14 - -#define CCDC_BLK_DC_SUB_MASK 0x3FFF -#define CCDC_BLK_COMP_MASK 0xFF -#define CCDC_BLK_COMP_GB_COMP_SHIFT 8 -#define CCDC_BLK_COMP_GR_COMP_SHIFT 0 -#define CCDC_BLK_COMP_R_COMP_SHIFT 8 -#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15) -#define CCDC_LATCH_ON_VSYNC_ENABLE (0 << 15) -#define CCDC_FPC_ENABLE (1 << 15) -#define CCDC_FPC_FPC_NUM_MASK 0x7FFF -#define CCDC_DATA_PACK_ENABLE (1 << 11) -#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF -#define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF -#define CCDC_FMT_HORZ_FMTSPH_SHIFT 16 -#define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF -#define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF -#define CCDC_FMT_VERT_FMTSLV_SHIFT 16 -#define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF -#define CCDC_VP_OUT_VERT_NUM_SHIFT 17 -#define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF -#define CCDC_VP_OUT_HORZ_NUM_SHIFT 4 -#define CCDC_VP_OUT_HORZ_ST_MASK 0xF - -#define CCDC_CSC_COEF_INTEG_MASK 7 -#define CCDC_CSC_COEF_DECIMAL_MASK 0x1f -#define CCDC_CSC_COEF_INTEG_SHIFT 5 -#define CCDC_CSCM_MSB_SHIFT 8 -#define CCDC_CSC_ENABLE 1 -#define CCDC_CSC_DEC_MAX 32 - -#define CCDC_MFILT1_SHIFT 10 -#define CCDC_MFILT2_SHIFT 8 -#define CCDC_MED_FILT_THRESH 0x3FFF -#define CCDC_LPF_MASK 1 -#define CCDC_LPF_SHIFT 14 -#define CCDC_OFFSET_MASK 0x3FF -#define CCDC_DATASFT_MASK 7 -#define CCDC_DATASFT_SHIFT 8 - -#define CCDC_DF_ENABLE 1 - -#define CCDC_FMTPLEN_P0_MASK 0xF -#define CCDC_FMTPLEN_P1_MASK 0xF -#define CCDC_FMTPLEN_P2_MASK 7 -#define CCDC_FMTPLEN_P3_MASK 7 -#define CCDC_FMTPLEN_P0_SHIFT 0 -#define CCDC_FMTPLEN_P1_SHIFT 4 -#define CCDC_FMTPLEN_P2_SHIFT 8 -#define CCDC_FMTPLEN_P3_SHIFT 12 - -#define CCDC_FMTSPH_MASK 0x1FFF -#define CCDC_FMTLNH_MASK 0x1FFF -#define CCDC_FMTSLV_MASK 0x1FFF -#define CCDC_FMTLNV_MASK 0x7FFF -#define CCDC_FMTRLEN_MASK 0x1FFF -#define CCDC_FMTHCNT_MASK 0x1FFF - -#define CCDC_ADP_INIT_MASK 0x1FFF -#define CCDC_ADP_LINE_SHIFT 13 -#define CCDC_ADP_LINE_MASK 3 -#define CCDC_FMTPGN_APTR_MASK 7 - -#define CCDC_DFCCTL_GDFCEN_MASK 1 -#define CCDC_DFCCTL_VDFCEN_MASK 1 -#define CCDC_DFCCTL_VDFC_DISABLE (0 << 4) -#define CCDC_DFCCTL_VDFCEN_SHIFT 4 -#define CCDC_DFCCTL_VDFCSL_MASK 3 -#define CCDC_DFCCTL_VDFCSL_SHIFT 5 -#define CCDC_DFCCTL_VDFCUDA_MASK 1 -#define CCDC_DFCCTL_VDFCUDA_SHIFT 7 -#define CCDC_DFCCTL_VDFLSFT_MASK 3 -#define CCDC_DFCCTL_VDFLSFT_SHIFT 8 -#define CCDC_DFCMEMCTL_DFCMARST_MASK 1 -#define CCDC_DFCMEMCTL_DFCMARST_SHIFT 2 -#define CCDC_DFCMEMCTL_DFCMWR_MASK 1 -#define CCDC_DFCMEMCTL_DFCMWR_SHIFT 0 -#define CCDC_DFCMEMCTL_INC_ADDR (0 << 2) - -#define CCDC_LSCCFG_GFTSF_MASK 7 -#define CCDC_LSCCFG_GFTSF_SHIFT 1 -#define CCDC_LSCCFG_GFTINV_MASK 0xf -#define CCDC_LSCCFG_GFTINV_SHIFT 4 -#define CCDC_LSC_GFTABLE_SEL_MASK 3 -#define CCDC_LSC_GFTABLE_EPEL_SHIFT 8 -#define CCDC_LSC_GFTABLE_OPEL_SHIFT 10 -#define CCDC_LSC_GFTABLE_EPOL_SHIFT 12 -#define CCDC_LSC_GFTABLE_OPOL_SHIFT 14 -#define CCDC_LSC_GFMODE_MASK 3 -#define CCDC_LSC_GFMODE_SHIFT 4 -#define CCDC_LSC_DISABLE 0 -#define CCDC_LSC_ENABLE 1 -#define CCDC_LSC_TABLE1_SLC 0 -#define CCDC_LSC_TABLE2_SLC 1 -#define CCDC_LSC_TABLE3_SLC 2 -#define CCDC_LSC_MEMADDR_RESET (1 << 2) -#define CCDC_LSC_MEMADDR_INCR (0 << 2) -#define CCDC_LSC_FRAC_MASK_T1 0xFF -#define CCDC_LSC_INT_MASK 3 -#define CCDC_LSC_FRAC_MASK 0x3FFF -#define CCDC_LSC_CENTRE_MASK 0x3FFF -#define CCDC_LSC_COEF_MASK 0xff -#define CCDC_LSC_COEFL_SHIFT 0 -#define CCDC_LSC_COEFU_SHIFT 8 -#define CCDC_GAIN_MASK 0x7FF -#define CCDC_SYNCEN_VDHDEN_MASK (1 << 0) -#define CCDC_SYNCEN_WEN_MASK (1 << 1) -#define CCDC_SYNCEN_WEN_SHIFT 1 - -/* Power on Defaults in hardware */ -#define MODESET_DEFAULT 0x200 -#define CULH_DEFAULT 0xFFFF -#define CULV_DEFAULT 0xFF -#define GAIN_DEFAULT 256 -#define OUTCLIP_DEFAULT 0x3FFF -#define LSCCFG2_DEFAULT 0xE - -#endif diff --git a/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.c b/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.c deleted file mode 100644 index 4a93e5ad6415..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.c +++ /dev/null @@ -1,879 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2006-2009 Texas Instruments Inc - * - * CCDC hardware module for DM6446 - * ------------------------------ - * - * This module is for configuring CCD controller of DM6446 VPFE to capture - * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules - * such as Defect Pixel Correction, Color Space Conversion etc to - * pre-process the Raw Bayer RGB data, before writing it to SDRAM. - * This file is named DM644x so that other variants such DM6443 - * may be supported using the same module. - * - * TODO: Test Raw bayer parameter settings and bayer capture - * Split module parameter structure to module specific ioctl structs - * investigate if enum used for user space type definition - * to be replaced by #defines or integer - */ -#include <linux/platform_device.h> -#include <linux/uaccess.h> -#include <linux/videodev2.h> -#include <linux/gfp.h> -#include <linux/err.h> -#include <linux/module.h> - -#include "dm644x_ccdc.h" -#include <media/davinci/vpss.h> - -#include "dm644x_ccdc_regs.h" -#include "ccdc_hw_device.h" - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("CCDC Driver for DM6446"); -MODULE_AUTHOR("Texas Instruments"); - -static struct ccdc_oper_config { - struct device *dev; - /* CCDC interface type */ - enum vpfe_hw_if_type if_type; - /* Raw Bayer configuration */ - struct ccdc_params_raw bayer; - /* YCbCr configuration */ - struct ccdc_params_ycbcr ycbcr; - /* ccdc base address */ - void __iomem *base_addr; -} ccdc_cfg = { - /* Raw configurations */ - .bayer = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = CCDC_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .config_params = { - .data_sz = CCDC_DATA_10BITS, - }, - }, - .ycbcr = { - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .win = CCDC_WIN_PAL, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .bt656_enable = 1, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED - }, -}; - -#define CCDC_MAX_RAW_YUV_FORMATS 2 - -/* Raw Bayer formats */ -static u32 ccdc_raw_bayer_pix_formats[] = - {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; - -/* Raw YUV formats */ -static u32 ccdc_raw_yuv_pix_formats[] = - {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; - -/* CCDC Save/Restore context */ -static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)]; - -/* register access routines */ -static inline u32 regr(u32 offset) -{ - return __raw_readl(ccdc_cfg.base_addr + offset); -} - -static inline void regw(u32 val, u32 offset) -{ - __raw_writel(val, ccdc_cfg.base_addr + offset); -} - -static void ccdc_enable(int flag) -{ - regw(flag, CCDC_PCR); -} - -static void ccdc_enable_vport(int flag) -{ - if (flag) - /* enable video port */ - regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG); - else - regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG); -} - -/* - * ccdc_setwin() - * This function will configure the window size - * to be capture in CCDC reg - */ -static void ccdc_setwin(struct v4l2_rect *image_win, - enum ccdc_frmfmt frm_fmt, - int ppc) -{ - int horz_start, horz_nr_pixels; - int vert_start, vert_nr_lines; - int val = 0, mid_img = 0; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); - /* - * ppc - per pixel count. indicates how many pixels per cell - * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. - * raw capture this is 1 - */ - horz_start = image_win->left << (ppc - 1); - horz_nr_pixels = (image_win->width << (ppc - 1)) - 1; - regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels, - CCDC_HORZ_INFO); - - vert_start = image_win->top; - - if (frm_fmt == CCDC_FRMFMT_INTERLACED) { - vert_nr_lines = (image_win->height >> 1) - 1; - vert_start >>= 1; - /* Since first line doesn't have any data */ - vert_start += 1; - /* configure VDINT0 */ - val = (vert_start << CCDC_VDINT_VDINT0_SHIFT); - regw(val, CCDC_VDINT); - - } else { - /* Since first line doesn't have any data */ - vert_start += 1; - vert_nr_lines = image_win->height - 1; - /* - * configure VDINT0 and VDINT1. VDINT1 will be at half - * of image height - */ - mid_img = vert_start + (image_win->height / 2); - val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) | - (mid_img & CCDC_VDINT_VDINT1_MASK); - regw(val, CCDC_VDINT); - - } - regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start, - CCDC_VERT_START); - regw(vert_nr_lines, CCDC_VERT_LINES); - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); -} - -static void ccdc_readregs(void) -{ - unsigned int val = 0; - - val = regr(CCDC_ALAW); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val); - val = regr(CCDC_CLAMP); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val); - val = regr(CCDC_DCSUB); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val); - val = regr(CCDC_BLKCMP); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val); - val = regr(CCDC_FPC_ADDR); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val); - val = regr(CCDC_FPC); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val); - val = regr(CCDC_FMTCFG); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val); - val = regr(CCDC_COLPTN); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val); - val = regr(CCDC_FMT_HORZ); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val); - val = regr(CCDC_FMT_VERT); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val); - val = regr(CCDC_HSIZE_OFF); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val); - val = regr(CCDC_SDOFST); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val); - val = regr(CCDC_VP_OUT); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val); - val = regr(CCDC_SYN_MODE); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val); - val = regr(CCDC_HORZ_INFO); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val); - val = regr(CCDC_VERT_START); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val); - val = regr(CCDC_VERT_LINES); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val); -} - -static int ccdc_close(struct device *dev) -{ - return 0; -} - -/* - * ccdc_restore_defaults() - * This function will write defaults to all CCDC registers - */ -static void ccdc_restore_defaults(void) -{ - int i; - - /* disable CCDC */ - ccdc_enable(0); - /* set all registers to default value */ - for (i = 4; i <= 0x94; i += 4) - regw(0, i); - regw(CCDC_NO_CULLING, CCDC_CULLING); - regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW); -} - -static int ccdc_open(struct device *device) -{ - ccdc_restore_defaults(); - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_enable_vport(1); - return 0; -} - -static void ccdc_sbl_reset(void) -{ - vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O); -} - -/* - * ccdc_config_ycbcr() - * This function will configure CCDC for YCbCr video capture - */ -static void ccdc_config_ycbcr(void) -{ - struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; - u32 syn_mode; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); - /* - * first restore the CCDC registers to default values - * This is important since we assume default values to be set in - * a lot of registers that we didn't touch - */ - ccdc_restore_defaults(); - - /* - * configure pixel format, frame format, configure video frame - * format, enable output to SDRAM, enable internal timing generator - * and 8bit pack mode - */ - syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) << - CCDC_SYN_MODE_INPMOD_SHIFT) | - ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) << - CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE | - CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE); - - /* setup BT.656 sync mode */ - if (params->bt656_enable) { - regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF); - - /* - * configure the FID, VD, HD pin polarity, - * fld,hd pol positive, vd negative, 8-bit data - */ - syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE; - if (ccdc_cfg.if_type == VPFE_BT656_10BIT) - syn_mode |= CCDC_SYN_MODE_10BITS; - else - syn_mode |= CCDC_SYN_MODE_8BITS; - } else { - /* y/c external sync mode */ - syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) << - CCDC_FID_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << - CCDC_HD_POL_SHIFT) | - ((params->vd_pol & CCDC_VD_POL_MASK) << - CCDC_VD_POL_SHIFT)); - } - regw(syn_mode, CCDC_SYN_MODE); - - /* configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, 2); - - /* - * configure the order of y cb cr in SDRAM, and disable latch - * internal register on vsync - */ - if (ccdc_cfg.if_type == VPFE_BT656_10BIT) - regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | - CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT, - CCDC_CCDCFG); - else - regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | - CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); - - /* - * configure the horizontal line offset. This should be a - * on 32 byte boundary. So clear LSB 5 bits - */ - regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF); - - /* configure the memory line offset */ - if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) - /* two fields are interleaved in memory */ - regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST); - - ccdc_sbl_reset(); - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); -} - -static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) -{ - u32 val; - - if (!bclamp->enable) { - /* configure DCSub */ - val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK; - regw(val, CCDC_DCSUB); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val); - regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n"); - return; - } - /* - * Configure gain, Start pixel, No of line to be avg, - * No of pixel/line to be avg, & Enable the Black clamping - */ - val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) | - ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) << - CCDC_BLK_ST_PXL_SHIFT) | - ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) << - CCDC_BLK_SAMPLE_LINE_SHIFT) | - ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << - CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE); - regw(val, CCDC_CLAMP); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val); - /* If Black clamping is enable then make dcsub 0 */ - regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n"); -} - -static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) -{ - u32 val; - - val = ((bcomp->b & CCDC_BLK_COMP_MASK) | - ((bcomp->gb & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GB_COMP_SHIFT) | - ((bcomp->gr & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GR_COMP_SHIFT) | - ((bcomp->r & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_R_COMP_SHIFT)); - regw(val, CCDC_BLKCMP); -} - -/* - * ccdc_config_raw() - * This function will configure CCDC for Raw capture mode - */ -static void ccdc_config_raw(void) -{ - struct ccdc_params_raw *params = &ccdc_cfg.bayer; - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int syn_mode = 0; - unsigned int val; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); - - /* Reset CCDC */ - ccdc_restore_defaults(); - - /* Disable latching function registers on VSYNC */ - regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); - - /* - * Configure the vertical sync polarity(SYN_MODE.VDPOL), - * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity - * (SYN_MODE.FLDPOL), frame format(progressive or interlace), - * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output - * SDRAM, enable internal timing generator - */ - syn_mode = - (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | - ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | - ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | - ((config_params->data_sz & CCDC_DATA_SZ_MASK) << - CCDC_DATA_SZ_SHIFT) | - ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) | - CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE); - - /* Enable and configure aLaw register if needed */ - if (config_params->alaw.enable) { - val = ((config_params->alaw.gamma_wd & - CCDC_ALAW_GAMMA_WD_MASK) | CCDC_ALAW_ENABLE); - regw(val, CCDC_ALAW); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val); - } - - /* Configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, CCDC_PPC_RAW); - - /* Configure Black Clamp */ - ccdc_config_black_clamp(&config_params->blk_clamp); - - /* Configure Black level compensation */ - ccdc_config_black_compense(&config_params->blk_comp); - - /* If data size is 8 bit then pack the data */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) - syn_mode |= CCDC_DATA_PACK_ENABLE; - - /* disable video port */ - val = CCDC_DISABLE_VIDEO_PORT; - - if (config_params->data_sz == CCDC_DATA_8BITS) - val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK) - << CCDC_FMTCFG_VPIN_SHIFT; - else - val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK) - << CCDC_FMTCFG_VPIN_SHIFT; - /* Write value in FMTCFG */ - regw(val, CCDC_FMTCFG); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val); - /* Configure the color pattern according to mt9t001 sensor */ - regw(CCDC_COLPTN_VAL, CCDC_COLPTN); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n"); - /* - * Configure Data formatter(Video port) pixel selection - * (FMT_HORZ, FMT_VERT) - */ - val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) << - CCDC_FMT_HORZ_FMTSPH_SHIFT) | - (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK); - regw(val, CCDC_FMT_HORZ); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val); - val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK) - << CCDC_FMT_VERT_FMTSLV_SHIFT; - if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) - val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK; - else - val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK; - - dev_dbg(ccdc_cfg.dev, "\nparams->win.height 0x%x ...\n", - params->win.height); - regw(val, CCDC_FMT_VERT); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val); - - dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)..."); - - /* - * Configure Horizontal offset register. If pack 8 is enabled then - * 1 pixel will take 1 byte - */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) - regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) & - CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF); - else - /* else one pixel will take 2 byte */ - regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) + - CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK, - CCDC_HSIZE_OFF); - - /* Set value for SDOFST */ - if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { - if (params->image_invert_enable) { - /* For intelace inverse mode */ - regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n"); - } - - else { - /* For intelace non inverse mode */ - regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n"); - } - } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { - regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n"); - } - - /* - * Configure video port pixel selection (VPOUT) - * Here -1 is to make the height value less than FMT_VERT.FMTLNV - */ - if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) - val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK)) - << CCDC_VP_OUT_VERT_NUM_SHIFT; - else - val = - ((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) - - 1) & CCDC_VP_OUT_VERT_NUM_MASK)) << - CCDC_VP_OUT_VERT_NUM_SHIFT; - - val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK) - << CCDC_VP_OUT_HORZ_NUM_SHIFT; - val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK; - regw(val, CCDC_VP_OUT); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val); - regw(syn_mode, CCDC_SYN_MODE); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode); - - ccdc_sbl_reset(); - dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); - ccdc_readregs(); -} - -static int ccdc_configure(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_config_raw(); - else - ccdc_config_ycbcr(); - return 0; -} - -static int ccdc_set_buftype(enum ccdc_buftype buf_type) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.buf_type = buf_type; - else - ccdc_cfg.ycbcr.buf_type = buf_type; - return 0; -} - -static enum ccdc_buftype ccdc_get_buftype(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.buf_type; - return ccdc_cfg.ycbcr.buf_type; -} - -static int ccdc_enum_pix(u32 *pix, int i) -{ - int ret = -EINVAL; - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { - *pix = ccdc_raw_bayer_pix_formats[i]; - ret = 0; - } - } else { - if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { - *pix = ccdc_raw_yuv_pix_formats[i]; - ret = 0; - } - } - return ret; -} - -static int ccdc_set_pixel_format(u32 pixfmt) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - if (pixfmt == V4L2_PIX_FMT_SBGGR8) - ccdc_cfg.bayer.config_params.alaw.enable = 1; - else if (pixfmt != V4L2_PIX_FMT_SBGGR16) - return -EINVAL; - } else { - if (pixfmt == V4L2_PIX_FMT_YUYV) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; - else if (pixfmt == V4L2_PIX_FMT_UYVY) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - else - return -EINVAL; - } - return 0; -} - -static u32 ccdc_get_pixel_format(void) -{ - struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; - u32 pixfmt; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - if (alaw->enable) - pixfmt = V4L2_PIX_FMT_SBGGR8; - else - pixfmt = V4L2_PIX_FMT_SBGGR16; - else { - if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) - pixfmt = V4L2_PIX_FMT_YUYV; - else - pixfmt = V4L2_PIX_FMT_UYVY; - } - return pixfmt; -} - -static int ccdc_set_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.win = *win; - else - ccdc_cfg.ycbcr.win = *win; - return 0; -} - -static void ccdc_get_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - *win = ccdc_cfg.bayer.win; - else - *win = ccdc_cfg.ycbcr.win; -} - -static unsigned int ccdc_get_line_length(void) -{ - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int len; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if ((config_params->alaw.enable) || - (config_params->data_sz == CCDC_DATA_8BITS)) - len = ccdc_cfg.bayer.win.width; - else - len = ccdc_cfg.bayer.win.width * 2; - } else - len = ccdc_cfg.ycbcr.win.width * 2; - return ALIGN(len, 32); -} - -static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.frm_fmt = frm_fmt; - else - ccdc_cfg.ycbcr.frm_fmt = frm_fmt; - return 0; -} - -static enum ccdc_frmfmt ccdc_get_frame_format(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.frm_fmt; - else - return ccdc_cfg.ycbcr.frm_fmt; -} - -static int ccdc_getfid(void) -{ - return (regr(CCDC_SYN_MODE) >> 15) & 1; -} - -/* misc operations */ -static inline void ccdc_setfbaddr(unsigned long addr) -{ - regw(addr & 0xffffffe0, CCDC_SDR_ADDR); -} - -static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) -{ - ccdc_cfg.if_type = params->if_type; - - switch (params->if_type) { - case VPFE_BT656: - case VPFE_YCBCR_SYNC_16: - case VPFE_YCBCR_SYNC_8: - case VPFE_BT656_10BIT: - ccdc_cfg.ycbcr.vd_pol = params->vdpol; - ccdc_cfg.ycbcr.hd_pol = params->hdpol; - break; - default: - /* TODO add support for raw bayer here */ - return -EINVAL; - } - return 0; -} - -static void ccdc_save_context(void) -{ - ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR); - ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE); - ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID); - ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES); - ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO); - ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START); - ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES); - ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING); - ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF); - ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST); - ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR); - ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP); - ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB); - ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN); - ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP); - ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC); - ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR); - ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT); - ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW); - ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF); - ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG); - ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG); - ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ); - ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT); - ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0); - ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1); - ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2); - ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3); - ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4); - ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5); - ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6); - ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7); - ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0); - ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1); - ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0); - ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1); - ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT); -} - -static void ccdc_restore_context(void) -{ - regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE); - regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID); - regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES); - regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO); - regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START); - regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES); - regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING); - regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF); - regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST); - regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR); - regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP); - regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB); - regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN); - regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP); - regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC); - regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR); - regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT); - regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW); - regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF); - regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG); - regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG); - regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ); - regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT); - regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0); - regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1); - regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2); - regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3); - regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4); - regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5); - regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6); - regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7); - regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0); - regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1); - regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0); - regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1); - regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT); - regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR); -} -static const struct ccdc_hw_device ccdc_hw_dev = { - .name = "DM6446 CCDC", - .owner = THIS_MODULE, - .hw_ops = { - .open = ccdc_open, - .close = ccdc_close, - .reset = ccdc_sbl_reset, - .enable = ccdc_enable, - .set_hw_if_params = ccdc_set_hw_if_params, - .configure = ccdc_configure, - .set_buftype = ccdc_set_buftype, - .get_buftype = ccdc_get_buftype, - .enum_pix = ccdc_enum_pix, - .set_pixel_format = ccdc_set_pixel_format, - .get_pixel_format = ccdc_get_pixel_format, - .set_frame_format = ccdc_set_frame_format, - .get_frame_format = ccdc_get_frame_format, - .set_image_window = ccdc_set_image_window, - .get_image_window = ccdc_get_image_window, - .get_line_length = ccdc_get_line_length, - .setfbaddr = ccdc_setfbaddr, - .getfid = ccdc_getfid, - }, -}; - -static int dm644x_ccdc_probe(struct platform_device *pdev) -{ - struct resource *res; - int status = 0; - - /* - * first try to register with vpfe. If not correct platform, then we - * don't have to iomap - */ - status = vpfe_register_ccdc_device(&ccdc_hw_dev); - if (status < 0) - return status; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - status = -ENODEV; - goto fail_nores; - } - - res = request_mem_region(res->start, resource_size(res), res->name); - if (!res) { - status = -EBUSY; - goto fail_nores; - } - - ccdc_cfg.base_addr = ioremap(res->start, resource_size(res)); - if (!ccdc_cfg.base_addr) { - status = -ENOMEM; - goto fail_nomem; - } - - ccdc_cfg.dev = &pdev->dev; - printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); - return 0; -fail_nomem: - release_mem_region(res->start, resource_size(res)); -fail_nores: - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return status; -} - -static int dm644x_ccdc_remove(struct platform_device *pdev) -{ - struct resource *res; - - iounmap(ccdc_cfg.base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return 0; -} - -static int dm644x_ccdc_suspend(struct device *dev) -{ - /* Save CCDC context */ - ccdc_save_context(); - /* Disable CCDC */ - ccdc_enable(0); - - return 0; -} - -static int dm644x_ccdc_resume(struct device *dev) -{ - /* Restore CCDC context */ - ccdc_restore_context(); - - return 0; -} - -static const struct dev_pm_ops dm644x_ccdc_pm_ops = { - .suspend = dm644x_ccdc_suspend, - .resume = dm644x_ccdc_resume, -}; - -static struct platform_driver dm644x_ccdc_driver = { - .driver = { - .name = "dm644x_ccdc", - .pm = &dm644x_ccdc_pm_ops, - }, - .remove = dm644x_ccdc_remove, - .probe = dm644x_ccdc_probe, -}; - -module_platform_driver(dm644x_ccdc_driver); diff --git a/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.h b/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.h deleted file mode 100644 index c20dba3d76d6..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.h +++ /dev/null @@ -1,171 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2006-2009 Texas Instruments Inc - */ -#ifndef _DM644X_CCDC_H -#define _DM644X_CCDC_H -#include <media/davinci/ccdc_types.h> -#include <media/davinci/vpfe_types.h> - -/* enum for No of pixel per line to be avg. in Black Clamping*/ -enum ccdc_sample_length { - CCDC_SAMPLE_1PIXELS, - CCDC_SAMPLE_2PIXELS, - CCDC_SAMPLE_4PIXELS, - CCDC_SAMPLE_8PIXELS, - CCDC_SAMPLE_16PIXELS -}; - -/* enum for No of lines in Black Clamping */ -enum ccdc_sample_line { - CCDC_SAMPLE_1LINES, - CCDC_SAMPLE_2LINES, - CCDC_SAMPLE_4LINES, - CCDC_SAMPLE_8LINES, - CCDC_SAMPLE_16LINES -}; - -/* enum for Alaw gamma width */ -enum ccdc_gamma_width { - CCDC_GAMMA_BITS_15_6, /* use bits 15-6 for gamma */ - CCDC_GAMMA_BITS_14_5, - CCDC_GAMMA_BITS_13_4, - CCDC_GAMMA_BITS_12_3, - CCDC_GAMMA_BITS_11_2, - CCDC_GAMMA_BITS_10_1, - CCDC_GAMMA_BITS_09_0 /* use bits 9-0 for gamma */ -}; - -/* returns the highest bit used for the gamma */ -static inline u8 ccdc_gamma_width_max_bit(enum ccdc_gamma_width width) -{ - return 15 - width; -} - -enum ccdc_data_size { - CCDC_DATA_16BITS, - CCDC_DATA_15BITS, - CCDC_DATA_14BITS, - CCDC_DATA_13BITS, - CCDC_DATA_12BITS, - CCDC_DATA_11BITS, - CCDC_DATA_10BITS, - CCDC_DATA_8BITS -}; - -/* returns the highest bit used for this data size */ -static inline u8 ccdc_data_size_max_bit(enum ccdc_data_size sz) -{ - return sz == CCDC_DATA_8BITS ? 7 : 15 - sz; -} - -/* structure for ALaw */ -struct ccdc_a_law { - /* Enable/disable A-Law */ - unsigned char enable; - /* Gamma Width Input */ - enum ccdc_gamma_width gamma_wd; -}; - -/* structure for Black Clamping */ -struct ccdc_black_clamp { - unsigned char enable; - /* only if bClampEnable is TRUE */ - enum ccdc_sample_length sample_pixel; - /* only if bClampEnable is TRUE */ - enum ccdc_sample_line sample_ln; - /* only if bClampEnable is TRUE */ - unsigned short start_pixel; - /* only if bClampEnable is TRUE */ - unsigned short sgain; - /* only if bClampEnable is FALSE */ - unsigned short dc_sub; -}; - -/* structure for Black Level Compensation */ -struct ccdc_black_compensation { - /* Constant value to subtract from Red component */ - char r; - /* Constant value to subtract from Gr component */ - char gr; - /* Constant value to subtract from Blue component */ - char b; - /* Constant value to subtract from Gb component */ - char gb; -}; - -/* Structure for CCDC configuration parameters for raw capture mode passed - * by application - */ -struct ccdc_config_params_raw { - /* data size value from 8 to 16 bits */ - enum ccdc_data_size data_sz; - /* Structure for Optional A-Law */ - struct ccdc_a_law alaw; - /* Structure for Optical Black Clamp */ - struct ccdc_black_clamp blk_clamp; - /* Structure for Black Compensation */ - struct ccdc_black_compensation blk_comp; -}; - - -#ifdef __KERNEL__ -#include <linux/io.h> -/* Define to enable/disable video port */ -#define FP_NUM_BYTES 4 -/* Define for extra pixel/line and extra lines/frame */ -#define NUM_EXTRAPIXELS 8 -#define NUM_EXTRALINES 8 - -/* settings for commonly used video formats */ -#define CCDC_WIN_PAL {0, 0, 720, 576} -/* ntsc square pixel */ -#define CCDC_WIN_VGA {0, 0, (640 + NUM_EXTRAPIXELS), (480 + NUM_EXTRALINES)} - -/* Structure for CCDC configuration parameters for raw capture mode */ -struct ccdc_params_raw { - /* pixel format */ - enum ccdc_pixfmt pix_fmt; - /* progressive or interlaced frame */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol hd_pol; - /* interleaved or separated fields */ - enum ccdc_buftype buf_type; - /* - * enable to store the image in inverse - * order in memory(bottom to top) - */ - unsigned char image_invert_enable; - /* configurable parameters */ - struct ccdc_config_params_raw config_params; -}; - -struct ccdc_params_ycbcr { - /* pixel format */ - enum ccdc_pixfmt pix_fmt; - /* progressive or interlaced frame */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol hd_pol; - /* enable BT.656 embedded sync mode */ - int bt656_enable; - /* cb:y:cr:y or y:cb:y:cr in memory */ - enum ccdc_pixorder pix_order; - /* interleaved or separated fields */ - enum ccdc_buftype buf_type; -}; -#endif -#endif /* _DM644X_CCDC_H */ diff --git a/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc_regs.h b/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc_regs.h deleted file mode 100644 index c4894f6a254e..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc_regs.h +++ /dev/null @@ -1,140 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2006-2009 Texas Instruments Inc - */ -#ifndef _DM644X_CCDC_REGS_H -#define _DM644X_CCDC_REGS_H - -/**************************************************************************\ -* Register OFFSET Definitions -\**************************************************************************/ -#define CCDC_PID 0x0 -#define CCDC_PCR 0x4 -#define CCDC_SYN_MODE 0x8 -#define CCDC_HD_VD_WID 0xc -#define CCDC_PIX_LINES 0x10 -#define CCDC_HORZ_INFO 0x14 -#define CCDC_VERT_START 0x18 -#define CCDC_VERT_LINES 0x1c -#define CCDC_CULLING 0x20 -#define CCDC_HSIZE_OFF 0x24 -#define CCDC_SDOFST 0x28 -#define CCDC_SDR_ADDR 0x2c -#define CCDC_CLAMP 0x30 -#define CCDC_DCSUB 0x34 -#define CCDC_COLPTN 0x38 -#define CCDC_BLKCMP 0x3c -#define CCDC_FPC 0x40 -#define CCDC_FPC_ADDR 0x44 -#define CCDC_VDINT 0x48 -#define CCDC_ALAW 0x4c -#define CCDC_REC656IF 0x50 -#define CCDC_CCDCFG 0x54 -#define CCDC_FMTCFG 0x58 -#define CCDC_FMT_HORZ 0x5c -#define CCDC_FMT_VERT 0x60 -#define CCDC_FMT_ADDR0 0x64 -#define CCDC_FMT_ADDR1 0x68 -#define CCDC_FMT_ADDR2 0x6c -#define CCDC_FMT_ADDR3 0x70 -#define CCDC_FMT_ADDR4 0x74 -#define CCDC_FMT_ADDR5 0x78 -#define CCDC_FMT_ADDR6 0x7c -#define CCDC_FMT_ADDR7 0x80 -#define CCDC_PRGEVEN_0 0x84 -#define CCDC_PRGEVEN_1 0x88 -#define CCDC_PRGODD_0 0x8c -#define CCDC_PRGODD_1 0x90 -#define CCDC_VP_OUT 0x94 -#define CCDC_REG_END 0x98 - -/*************************************************************** -* Define for various register bit mask and shifts for CCDC -****************************************************************/ -#define CCDC_FID_POL_MASK 1 -#define CCDC_FID_POL_SHIFT 4 -#define CCDC_HD_POL_MASK 1 -#define CCDC_HD_POL_SHIFT 3 -#define CCDC_VD_POL_MASK 1 -#define CCDC_VD_POL_SHIFT 2 -#define CCDC_HSIZE_OFF_MASK 0xffffffe0 -#define CCDC_32BYTE_ALIGN_VAL 31 -#define CCDC_FRM_FMT_MASK 0x1 -#define CCDC_FRM_FMT_SHIFT 7 -#define CCDC_DATA_SZ_MASK 7 -#define CCDC_DATA_SZ_SHIFT 8 -#define CCDC_PIX_FMT_MASK 3 -#define CCDC_PIX_FMT_SHIFT 12 -#define CCDC_VP2SDR_DISABLE 0xFFFBFFFF -#define CCDC_WEN_ENABLE BIT(17) -#define CCDC_SDR2RSZ_DISABLE 0xFFF7FFFF -#define CCDC_VDHDEN_ENABLE BIT(16) -#define CCDC_LPF_ENABLE BIT(14) -#define CCDC_ALAW_ENABLE BIT(3) -#define CCDC_ALAW_GAMMA_WD_MASK 7 -#define CCDC_BLK_CLAMP_ENABLE BIT(31) -#define CCDC_BLK_SGAIN_MASK 0x1F -#define CCDC_BLK_ST_PXL_MASK 0x7FFF -#define CCDC_BLK_ST_PXL_SHIFT 10 -#define CCDC_BLK_SAMPLE_LN_MASK 7 -#define CCDC_BLK_SAMPLE_LN_SHIFT 28 -#define CCDC_BLK_SAMPLE_LINE_MASK 7 -#define CCDC_BLK_SAMPLE_LINE_SHIFT 25 -#define CCDC_BLK_DC_SUB_MASK 0x03FFF -#define CCDC_BLK_COMP_MASK 0xFF -#define CCDC_BLK_COMP_GB_COMP_SHIFT 8 -#define CCDC_BLK_COMP_GR_COMP_SHIFT 16 -#define CCDC_BLK_COMP_R_COMP_SHIFT 24 -#define CCDC_LATCH_ON_VSYNC_DISABLE BIT(15) -#define CCDC_FPC_ENABLE BIT(15) -#define CCDC_FPC_DISABLE 0 -#define CCDC_FPC_FPC_NUM_MASK 0x7FFF -#define CCDC_DATA_PACK_ENABLE BIT(11) -#define CCDC_FMTCFG_VPIN_MASK 7 -#define CCDC_FMTCFG_VPIN_SHIFT 12 -#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF -#define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF -#define CCDC_FMT_HORZ_FMTSPH_SHIFT 16 -#define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF -#define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF -#define CCDC_FMT_VERT_FMTSLV_SHIFT 16 -#define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF -#define CCDC_VP_OUT_VERT_NUM_SHIFT 17 -#define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF -#define CCDC_VP_OUT_HORZ_NUM_SHIFT 4 -#define CCDC_VP_OUT_HORZ_ST_MASK 0xF -#define CCDC_HORZ_INFO_SPH_SHIFT 16 -#define CCDC_VERT_START_SLV0_SHIFT 16 -#define CCDC_VDINT_VDINT0_SHIFT 16 -#define CCDC_VDINT_VDINT1_MASK 0xFFFF -#define CCDC_PPC_RAW 1 -#define CCDC_DCSUB_DEFAULT_VAL 0 -#define CCDC_CLAMP_DEFAULT_VAL 0 -#define CCDC_ENABLE_VIDEO_PORT 0x8000 -#define CCDC_DISABLE_VIDEO_PORT 0 -#define CCDC_COLPTN_VAL 0xBB11BB11 -#define CCDC_TWO_BYTES_PER_PIXEL 2 -#define CCDC_INTERLACED_IMAGE_INVERT 0x4B6D -#define CCDC_INTERLACED_NO_IMAGE_INVERT 0x0249 -#define CCDC_PROGRESSIVE_IMAGE_INVERT 0x4000 -#define CCDC_PROGRESSIVE_NO_IMAGE_INVERT 0 -#define CCDC_INTERLACED_HEIGHT_SHIFT 1 -#define CCDC_SYN_MODE_INPMOD_SHIFT 12 -#define CCDC_SYN_MODE_INPMOD_MASK 3 -#define CCDC_SYN_MODE_8BITS (7 << 8) -#define CCDC_SYN_MODE_10BITS (6 << 8) -#define CCDC_SYN_MODE_11BITS (5 << 8) -#define CCDC_SYN_MODE_12BITS (4 << 8) -#define CCDC_SYN_MODE_13BITS (3 << 8) -#define CCDC_SYN_MODE_14BITS (2 << 8) -#define CCDC_SYN_MODE_15BITS (1 << 8) -#define CCDC_SYN_MODE_16BITS (0 << 8) -#define CCDC_SYN_FLDMODE_MASK 1 -#define CCDC_SYN_FLDMODE_SHIFT 7 -#define CCDC_REC656IF_BT656_EN 3 -#define CCDC_SYN_MODE_VD_POL_NEGATIVE BIT(2) -#define CCDC_CCDCFG_Y8POS_SHIFT 11 -#define CCDC_CCDCFG_BW656_10BIT BIT(5) -#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 -#define CCDC_NO_CULLING 0xffff00ff -#endif diff --git a/drivers/staging/media/deprecated/vpfe_capture/isif.c b/drivers/staging/media/deprecated/vpfe_capture/isif.c deleted file mode 100644 index 4059891c2824..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/isif.c +++ /dev/null @@ -1,1127 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * Image Sensor Interface (ISIF) driver - * - * This driver is for configuring the ISIF IP available on DM365 or any other - * TI SoCs. This is used for capturing yuv or bayer video or image data - * from a decoder or sensor. This IP is similar to the CCDC IP on DM355 - * and DM6446, but with enhanced or additional ip blocks. The driver - * configures the ISIF upon commands from the vpfe bridge driver through - * ccdc_hw_device interface. - * - * TODO: 1) Raw bayer parameter settings and bayer capture - * 2) Add support for control ioctl - */ -#include <linux/delay.h> -#include <linux/platform_device.h> -#include <linux/uaccess.h> -#include <linux/io.h> -#include <linux/videodev2.h> -#include <linux/err.h> -#include <linux/module.h> - -#include "isif.h" -#include <media/davinci/vpss.h> - -#include "isif_regs.h" -#include "ccdc_hw_device.h" - -/* Defaults for module configuration parameters */ -static const struct isif_config_params_raw isif_config_defaults = { - .linearize = { - .en = 0, - .corr_shft = ISIF_NO_SHIFT, - .scale_fact = {1, 0}, - }, - .df_csc = { - .df_or_csc = 0, - .csc = { - .en = 0, - }, - }, - .dfc = { - .en = 0, - }, - .bclamp = { - .en = 0, - }, - .gain_offset = { - .gain = { - .r_ye = {1, 0}, - .gr_cy = {1, 0}, - .gb_g = {1, 0}, - .b_mg = {1, 0}, - }, - }, - .culling = { - .hcpat_odd = 0xff, - .hcpat_even = 0xff, - .vcpat = 0xff, - }, - .compress = { - .alg = ISIF_ALAW, - }, -}; - -/* ISIF operation configuration */ -static struct isif_oper_config { - struct device *dev; - enum vpfe_hw_if_type if_type; - struct isif_ycbcr_config ycbcr; - struct isif_params_raw bayer; - enum isif_data_pack data_pack; - /* ISIF base address */ - void __iomem *base_addr; - /* ISIF Linear Table 0 */ - void __iomem *linear_tbl0_addr; - /* ISIF Linear Table 1 */ - void __iomem *linear_tbl1_addr; -} isif_cfg = { - .ycbcr = { - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .win = ISIF_WIN_NTSC, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED, - }, - .bayer = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = ISIF_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .gain = { - .r_ye = {1, 0}, - .gr_cy = {1, 0}, - .gb_g = {1, 0}, - .b_mg = {1, 0}, - }, - .cfa_pat = ISIF_CFA_PAT_MOSAIC, - .data_msb = ISIF_BIT_MSB_11, - .config_params = { - .data_shift = ISIF_NO_SHIFT, - .col_pat_field0 = { - .olop = ISIF_GREEN_BLUE, - .olep = ISIF_BLUE, - .elop = ISIF_RED, - .elep = ISIF_GREEN_RED, - }, - .col_pat_field1 = { - .olop = ISIF_GREEN_BLUE, - .olep = ISIF_BLUE, - .elop = ISIF_RED, - .elep = ISIF_GREEN_RED, - }, - .test_pat_gen = 0, - }, - }, - .data_pack = ISIF_DATA_PACK8, -}; - -/* Raw Bayer formats */ -static const u32 isif_raw_bayer_pix_formats[] = { - V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; - -/* Raw YUV formats */ -static const u32 isif_raw_yuv_pix_formats[] = { - V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; - -/* register access routines */ -static inline u32 regr(u32 offset) -{ - return __raw_readl(isif_cfg.base_addr + offset); -} - -static inline void regw(u32 val, u32 offset) -{ - __raw_writel(val, isif_cfg.base_addr + offset); -} - -/* reg_modify() - read, modify and write register */ -static inline u32 reg_modify(u32 mask, u32 val, u32 offset) -{ - u32 new_val = (regr(offset) & ~mask) | (val & mask); - - regw(new_val, offset); - return new_val; -} - -static inline void regw_lin_tbl(u32 val, u32 offset, int i) -{ - if (!i) - __raw_writel(val, isif_cfg.linear_tbl0_addr + offset); - else - __raw_writel(val, isif_cfg.linear_tbl1_addr + offset); -} - -static void isif_disable_all_modules(void) -{ - /* disable BC */ - regw(0, CLAMPCFG); - /* disable vdfc */ - regw(0, DFCCTL); - /* disable CSC */ - regw(0, CSCCTL); - /* disable linearization */ - regw(0, LINCFG0); - /* disable other modules here as they are supported */ -} - -static void isif_enable(int en) -{ - if (!en) { - /* Before disable isif, disable all ISIF modules */ - isif_disable_all_modules(); - /* - * wait for next VD. Assume lowest scan rate is 12 Hz. So - * 100 msec delay is good enough - */ - msleep(100); - } - reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN); -} - -static void isif_enable_output_to_sdram(int en) -{ - reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN); -} - -static void isif_config_culling(struct isif_cul *cul) -{ - u32 val; - - /* Horizontal pattern */ - val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd; - regw(val, CULH); - - /* vertical pattern */ - regw(cul->vcpat, CULV); - - /* LPF */ - reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT, - cul->en_lpf << ISIF_LPF_SHIFT, MODESET); -} - -static void isif_config_gain_offset(void) -{ - struct isif_gain_offsets_adj *gain_off_p = - &isif_cfg.bayer.config_params.gain_offset; - u32 val; - - val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) | - (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) | - (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) | - (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) | - (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) | - (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT); - - reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD); - - val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.r_ye.decimal; - regw(val, CRGAIN); - - val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.gr_cy.decimal; - regw(val, CGRGAIN); - - val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.gb_g.decimal; - regw(val, CGBGAIN); - - val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.b_mg.decimal; - regw(val, CBGAIN); - - regw(gain_off_p->offset, COFSTA); -} - -static void isif_restore_defaults(void) -{ - enum vpss_ccdc_source_sel source = VPSS_CCDCIN; - - dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults..."); - isif_cfg.bayer.config_params = isif_config_defaults; - /* Enable clock to ISIF, IPIPEIF and BL */ - vpss_enable_clock(VPSS_CCDC_CLOCK, 1); - vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); - vpss_enable_clock(VPSS_BL_CLOCK, 1); - /* Set default offset and gain */ - isif_config_gain_offset(); - vpss_select_ccdc_source(source); - dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults..."); -} - -static int isif_open(struct device *device) -{ - isif_restore_defaults(); - return 0; -} - -/* This function will configure the window size to be capture in ISIF reg */ -static void isif_setwin(struct v4l2_rect *image_win, - enum ccdc_frmfmt frm_fmt, int ppc) -{ - int horz_start, horz_nr_pixels; - int vert_start, vert_nr_lines; - int mid_img = 0; - - dev_dbg(isif_cfg.dev, "\nStarting isif_setwin..."); - /* - * ppc - per pixel count. indicates how many pixels per cell - * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. - * raw capture this is 1 - */ - horz_start = image_win->left << (ppc - 1); - horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; - - /* Writing the horizontal info into the registers */ - regw(horz_start & START_PX_HOR_MASK, SPH); - regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH); - vert_start = image_win->top; - - if (frm_fmt == CCDC_FRMFMT_INTERLACED) { - vert_nr_lines = (image_win->height >> 1) - 1; - vert_start >>= 1; - /* To account for VD since line 0 doesn't have any data */ - vert_start += 1; - } else { - /* To account for VD since line 0 doesn't have any data */ - vert_start += 1; - vert_nr_lines = image_win->height - 1; - /* configure VDINT0 and VDINT1 */ - mid_img = vert_start + (image_win->height / 2); - regw(mid_img, VDINT1); - } - - regw(0, VDINT0); - regw(vert_start & START_VER_ONE_MASK, SLV0); - regw(vert_start & START_VER_TWO_MASK, SLV1); - regw(vert_nr_lines & NUM_LINES_VER, LNV); -} - -static void isif_config_bclamp(struct isif_black_clamp *bc) -{ - u32 val; - - /* - * DC Offset is always added to image data irrespective of bc enable - * status - */ - regw(bc->dc_offset, CLDCOFST); - - if (bc->en) { - val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT; - - /* Enable BC and horizontal clamp calculation parameters */ - val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT); - - regw(val, CLAMPCFG); - - if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) { - /* - * Window count for calculation - * Base window selection - * pixel limit - * Horizontal size of window - * vertical size of the window - * Horizontal start position of the window - * Vertical start position of the window - */ - val = bc->horz.win_count_calc | - ((!!bc->horz.base_win_sel_calc) << - ISIF_HORZ_BC_WIN_SEL_SHIFT) | - ((!!bc->horz.clamp_pix_limit) << - ISIF_HORZ_BC_PIX_LIMIT_SHIFT) | - (bc->horz.win_h_sz_calc << - ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) | - (bc->horz.win_v_sz_calc << - ISIF_HORZ_BC_WIN_V_SIZE_SHIFT); - regw(val, CLHWIN0); - - regw(bc->horz.win_start_h_calc, CLHWIN1); - regw(bc->horz.win_start_v_calc, CLHWIN2); - } - - /* vertical clamp calculation parameters */ - - /* Reset clamp value sel for previous line */ - val |= - (bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) | - (bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT); - regw(val, CLVWIN0); - - /* Optical Black horizontal start position */ - regw(bc->vert.ob_start_h, CLVWIN1); - /* Optical Black vertical start position */ - regw(bc->vert.ob_start_v, CLVWIN2); - /* Optical Black vertical size for calculation */ - regw(bc->vert.ob_v_sz_calc, CLVWIN3); - /* Vertical start position for BC subtraction */ - regw(bc->vert_start_sub, CLSV); - } -} - -static void isif_config_linearization(struct isif_linearize *linearize) -{ - u32 val, i; - - if (!linearize->en) { - regw(0, LINCFG0); - return; - } - - /* shift value for correction & enable linearization (set lsb) */ - val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1; - regw(val, LINCFG0); - - /* Scale factor */ - val = ((!!linearize->scale_fact.integer) << - ISIF_LIN_SCALE_FACT_INTEG_SHIFT) | - linearize->scale_fact.decimal; - regw(val, LINCFG1); - - for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) { - if (i % 2) - regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1); - else - regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0); - } -} - -static int isif_config_dfc(struct isif_dfc *vdfc) -{ - /* initialize retries to loop for max ~ 250 usec */ - u32 val, count, retries = loops_per_jiffy / (4000/HZ); - int i; - - if (!vdfc->en) - return 0; - - /* Correction mode */ - val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT); - - /* Correct whole line or partial */ - if (vdfc->corr_whole_line) - val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT; - - /* level shift value */ - val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT; - - regw(val, DFCCTL); - - /* Defect saturation level */ - regw(vdfc->def_sat_level, VDFSATLV); - - regw(vdfc->table[0].pos_vert, DFCMEM0); - regw(vdfc->table[0].pos_horz, DFCMEM1); - if (vdfc->corr_mode == ISIF_VDFC_NORMAL || - vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { - regw(vdfc->table[0].level_at_pos, DFCMEM2); - regw(vdfc->table[0].level_up_pixels, DFCMEM3); - regw(vdfc->table[0].level_low_pixels, DFCMEM4); - } - - /* set DFCMARST and set DFCMWR */ - val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1; - regw(val, DFCMEMCTL); - - count = retries; - while (count && (regr(DFCMEMCTL) & 0x1)) - count--; - - if (!count) { - dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n"); - return -1; - } - - for (i = 1; i < vdfc->num_vdefects; i++) { - regw(vdfc->table[i].pos_vert, DFCMEM0); - regw(vdfc->table[i].pos_horz, DFCMEM1); - if (vdfc->corr_mode == ISIF_VDFC_NORMAL || - vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { - regw(vdfc->table[i].level_at_pos, DFCMEM2); - regw(vdfc->table[i].level_up_pixels, DFCMEM3); - regw(vdfc->table[i].level_low_pixels, DFCMEM4); - } - val = regr(DFCMEMCTL); - /* clear DFCMARST and set DFCMWR */ - val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); - val |= 1; - regw(val, DFCMEMCTL); - - count = retries; - while (count && (regr(DFCMEMCTL) & 0x1)) - count--; - - if (!count) { - dev_err(isif_cfg.dev, - "defect table write timeout !!!\n"); - return -1; - } - } - if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) { - /* Extra cycle needed */ - regw(0, DFCMEM0); - regw(0x1FFF, DFCMEM1); - regw(1, DFCMEMCTL); - } - - /* enable VDFC */ - reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT), - DFCCTL); - return 0; -} - -static void isif_config_csc(struct isif_df_csc *df_csc) -{ - u32 val1 = 0, val2 = 0, i; - - if (!df_csc->csc.en) { - regw(0, CSCCTL); - return; - } - for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) { - if ((i % 2) == 0) { - /* CSCM - LSB */ - val1 = (df_csc->csc.coeff[i].integer << - ISIF_CSC_COEF_INTEG_SHIFT) | - df_csc->csc.coeff[i].decimal; - } else { - - /* CSCM - MSB */ - val2 = (df_csc->csc.coeff[i].integer << - ISIF_CSC_COEF_INTEG_SHIFT) | - df_csc->csc.coeff[i].decimal; - val2 <<= ISIF_CSCM_MSB_SHIFT; - val2 |= val1; - regw(val2, (CSCM0 + ((i - 1) << 1))); - } - } - - /* program the active area */ - regw(df_csc->start_pix, FMTSPH); - /* - * one extra pixel as required for CSC. Actually number of - * pixel - 1 should be configured in this register. So we - * need to subtract 1 before writing to FMTSPH, but we will - * not do this since csc requires one extra pixel - */ - regw(df_csc->num_pixels, FMTLNH); - regw(df_csc->start_line, FMTSLV); - /* - * one extra line as required for CSC. See reason documented for - * num_pixels - */ - regw(df_csc->num_lines, FMTLNV); - - /* Enable CSC */ - regw(1, CSCCTL); -} - -static int isif_config_raw(void) -{ - struct isif_params_raw *params = &isif_cfg.bayer; - struct isif_config_params_raw *module_params = - &isif_cfg.bayer.config_params; - struct vpss_pg_frame_size frame_size; - struct vpss_sync_pol sync; - u32 val; - - dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n"); - - /* - * Configure CCDCFG register:- - * Set CCD Not to swap input since input is RAW data - * Set FID detection function to Latch at V-Sync - * Set WENLOG - isif valid area - * Set TRGSEL - * Set EXTRG - * Packed to 8 or 16 bits - */ - - val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC | - ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN | - ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack; - - dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val); - regw(val, CCDCFG); - - /* - * Configure the vertical sync polarity(MODESET.VDPOL) - * Configure the horizontal sync polarity (MODESET.HDPOL) - * Configure frame id polarity (MODESET.FLDPOL) - * Configure data polarity - * Configure External WEN Selection - * Configure frame format(progressive or interlace) - * Configure pixel format (Input mode) - * Configure the data shift - */ - - val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) | - (params->hd_pol << ISIF_HD_POL_SHIFT) | - (params->fid_pol << ISIF_FID_POL_SHIFT) | - (ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) | - (ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) | - (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | - (params->pix_fmt << ISIF_INPUT_SHIFT) | - (params->config_params.data_shift << ISIF_DATASFT_SHIFT); - - regw(val, MODESET); - dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val); - - /* - * Configure GAMMAWD register - * CFA pattern setting - */ - val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT; - - /* Gamma msb */ - if (module_params->compress.alg == ISIF_ALAW) - val |= ISIF_ALAW_ENABLE; - - val |= (params->data_msb << ISIF_ALAW_GAMMA_WD_SHIFT); - regw(val, CGAMMAWD); - - /* Configure DPCM compression settings */ - if (module_params->compress.alg == ISIF_DPCM) { - val = BIT(ISIF_DPCM_EN_SHIFT) | - (module_params->compress.pred << - ISIF_DPCM_PREDICTOR_SHIFT); - } - - regw(val, MISC); - - /* Configure Gain & Offset */ - isif_config_gain_offset(); - - /* Configure Color pattern */ - val = (params->config_params.col_pat_field0.olop) | - (params->config_params.col_pat_field0.olep << 2) | - (params->config_params.col_pat_field0.elop << 4) | - (params->config_params.col_pat_field0.elep << 6) | - (params->config_params.col_pat_field1.olop << 8) | - (params->config_params.col_pat_field1.olep << 10) | - (params->config_params.col_pat_field1.elop << 12) | - (params->config_params.col_pat_field1.elep << 14); - regw(val, CCOLP); - dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val); - - /* Configure HSIZE register */ - val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT; - - /* calculate line offset in 32 bytes based on pack value */ - if (isif_cfg.data_pack == ISIF_PACK_8BIT) - val |= ((params->win.width + 31) >> 5); - else if (isif_cfg.data_pack == ISIF_PACK_12BIT) - val |= (((params->win.width + - (params->win.width >> 2)) + 31) >> 5); - else - val |= (((params->win.width * 2) + 31) >> 5); - regw(val, HSIZE); - - /* Configure SDOFST register */ - if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { - if (params->image_invert_en) { - /* For interlace inverse mode */ - regw(0x4B6D, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n"); - } else { - /* For interlace non inverse mode */ - regw(0x0B6D, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n"); - } - } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { - if (params->image_invert_en) { - /* For progressive inverse mode */ - regw(0x4000, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n"); - } else { - /* For progressive non inverse mode */ - regw(0x0000, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n"); - } - } - - /* Configure video window */ - isif_setwin(¶ms->win, params->frm_fmt, 1); - - /* Configure Black Clamp */ - isif_config_bclamp(&module_params->bclamp); - - /* Configure Vertical Defection Pixel Correction */ - if (isif_config_dfc(&module_params->dfc) < 0) - return -EFAULT; - - if (!module_params->df_csc.df_or_csc) - /* Configure Color Space Conversion */ - isif_config_csc(&module_params->df_csc); - - isif_config_linearization(&module_params->linearize); - - /* Configure Culling */ - isif_config_culling(&module_params->culling); - - /* Configure horizontal and vertical offsets(DFC,LSC,Gain) */ - regw(module_params->horz_offset, DATAHOFST); - regw(module_params->vert_offset, DATAVOFST); - - /* Setup test pattern if enabled */ - if (params->config_params.test_pat_gen) { - /* Use the HD/VD pol settings from user */ - sync.ccdpg_hdpol = params->hd_pol; - sync.ccdpg_vdpol = params->vd_pol; - dm365_vpss_set_sync_pol(sync); - frame_size.hlpfr = isif_cfg.bayer.win.width; - frame_size.pplen = isif_cfg.bayer.win.height; - dm365_vpss_set_pg_frame_size(frame_size); - vpss_select_ccdc_source(VPSS_PGLPBK); - } - - dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n"); - return 0; -} - -static int isif_set_buftype(enum ccdc_buftype buf_type) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - isif_cfg.bayer.buf_type = buf_type; - else - isif_cfg.ycbcr.buf_type = buf_type; - - return 0; - -} -static enum ccdc_buftype isif_get_buftype(void) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - return isif_cfg.bayer.buf_type; - - return isif_cfg.ycbcr.buf_type; -} - -static int isif_enum_pix(u32 *pix, int i) -{ - int ret = -EINVAL; - - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) { - *pix = isif_raw_bayer_pix_formats[i]; - ret = 0; - } - } else { - if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) { - *pix = isif_raw_yuv_pix_formats[i]; - ret = 0; - } - } - - return ret; -} - -static int isif_set_pixel_format(unsigned int pixfmt) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - if (pixfmt == V4L2_PIX_FMT_SBGGR8) { - if ((isif_cfg.bayer.config_params.compress.alg != - ISIF_ALAW) && - (isif_cfg.bayer.config_params.compress.alg != - ISIF_DPCM)) { - dev_dbg(isif_cfg.dev, - "Either configure A-Law or DPCM\n"); - return -EINVAL; - } - isif_cfg.data_pack = ISIF_PACK_8BIT; - } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) { - isif_cfg.bayer.config_params.compress.alg = - ISIF_NO_COMPRESSION; - isif_cfg.data_pack = ISIF_PACK_16BIT; - } else - return -EINVAL; - isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - } else { - if (pixfmt == V4L2_PIX_FMT_YUYV) - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; - else if (pixfmt == V4L2_PIX_FMT_UYVY) - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - else - return -EINVAL; - isif_cfg.data_pack = ISIF_PACK_8BIT; - } - return 0; -} - -static u32 isif_get_pixel_format(void) -{ - u32 pixfmt; - - if (isif_cfg.if_type == VPFE_RAW_BAYER) - if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW || - isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM) - pixfmt = V4L2_PIX_FMT_SBGGR8; - else - pixfmt = V4L2_PIX_FMT_SBGGR16; - else { - if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) - pixfmt = V4L2_PIX_FMT_YUYV; - else - pixfmt = V4L2_PIX_FMT_UYVY; - } - return pixfmt; -} - -static int isif_set_image_window(struct v4l2_rect *win) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - isif_cfg.bayer.win.top = win->top; - isif_cfg.bayer.win.left = win->left; - isif_cfg.bayer.win.width = win->width; - isif_cfg.bayer.win.height = win->height; - } else { - isif_cfg.ycbcr.win.top = win->top; - isif_cfg.ycbcr.win.left = win->left; - isif_cfg.ycbcr.win.width = win->width; - isif_cfg.ycbcr.win.height = win->height; - } - return 0; -} - -static void isif_get_image_window(struct v4l2_rect *win) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - *win = isif_cfg.bayer.win; - else - *win = isif_cfg.ycbcr.win; -} - -static unsigned int isif_get_line_length(void) -{ - unsigned int len; - - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - if (isif_cfg.data_pack == ISIF_PACK_8BIT) - len = ((isif_cfg.bayer.win.width)); - else if (isif_cfg.data_pack == ISIF_PACK_12BIT) - len = (((isif_cfg.bayer.win.width * 2) + - (isif_cfg.bayer.win.width >> 2))); - else - len = (((isif_cfg.bayer.win.width * 2))); - } else - len = (((isif_cfg.ycbcr.win.width * 2))); - return ALIGN(len, 32); -} - -static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - isif_cfg.bayer.frm_fmt = frm_fmt; - else - isif_cfg.ycbcr.frm_fmt = frm_fmt; - return 0; -} -static enum ccdc_frmfmt isif_get_frame_format(void) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - return isif_cfg.bayer.frm_fmt; - return isif_cfg.ycbcr.frm_fmt; -} - -static int isif_getfid(void) -{ - return (regr(MODESET) >> 15) & 0x1; -} - -/* misc operations */ -static void isif_setfbaddr(unsigned long addr) -{ - regw((addr >> 21) & 0x07ff, CADU); - regw((addr >> 5) & 0x0ffff, CADL); -} - -static int isif_set_hw_if_params(struct vpfe_hw_if_param *params) -{ - isif_cfg.if_type = params->if_type; - - switch (params->if_type) { - case VPFE_BT656: - case VPFE_BT656_10BIT: - case VPFE_YCBCR_SYNC_8: - isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT; - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - break; - case VPFE_BT1120: - case VPFE_YCBCR_SYNC_16: - isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT; - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - break; - case VPFE_RAW_BAYER: - isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - break; - default: - dev_dbg(isif_cfg.dev, "Invalid interface type\n"); - return -EINVAL; - } - - return 0; -} - -/* This function will configure ISIF for YCbCr parameters. */ -static int isif_config_ycbcr(void) -{ - struct isif_ycbcr_config *params = &isif_cfg.ycbcr; - u32 modeset = 0, ccdcfg = 0; - - dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr..."); - - /* configure pixel format or input mode */ - modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) | - (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | - (params->fid_pol << ISIF_FID_POL_SHIFT) | - (params->hd_pol << ISIF_HD_POL_SHIFT) | - (params->vd_pol << ISIF_VD_POL_SHIFT); - - /* pack the data to 8-bit ISIFCFG */ - switch (isif_cfg.if_type) { - case VPFE_BT656: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT); - regw(3, REC656IF); - ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR; - break; - case VPFE_BT656_10BIT: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - /* setup BT.656, embedded sync */ - regw(3, REC656IF); - /* enable 10 bit mode in ccdcfg */ - ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR | - ISIF_BW656_ENABLE; - break; - case VPFE_BT1120: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - regw(3, REC656IF); - break; - - case VPFE_YCBCR_SYNC_8: - ccdcfg |= ISIF_DATA_PACK8; - ccdcfg |= ISIF_YCINSWP_YCBCR; - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - break; - case VPFE_YCBCR_SYNC_16: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - break; - default: - /* should never come here */ - dev_dbg(isif_cfg.dev, "Invalid interface type\n"); - return -EINVAL; - } - - regw(modeset, MODESET); - - /* Set up pix order */ - ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT; - - regw(ccdcfg, CCDCFG); - - /* configure video window */ - if ((isif_cfg.if_type == VPFE_BT1120) || - (isif_cfg.if_type == VPFE_YCBCR_SYNC_16)) - isif_setwin(¶ms->win, params->frm_fmt, 1); - else - isif_setwin(¶ms->win, params->frm_fmt, 2); - - /* - * configure the horizontal line offset - * this is done by rounding up width to a multiple of 16 pixels - * and multiply by two to account for y:cb:cr 4:2:2 data - */ - regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE); - - /* configure the memory line offset */ - if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) && - (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)) - /* two fields are interleaved in memory */ - regw(0x00000249, SDOFST); - - return 0; -} - -static int isif_configure(void) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - return isif_config_raw(); - return isif_config_ycbcr(); -} - -static int isif_close(struct device *device) -{ - /* copy defaults to module params */ - isif_cfg.bayer.config_params = isif_config_defaults; - return 0; -} - -static const struct ccdc_hw_device isif_hw_dev = { - .name = "ISIF", - .owner = THIS_MODULE, - .hw_ops = { - .open = isif_open, - .close = isif_close, - .enable = isif_enable, - .enable_out_to_sdram = isif_enable_output_to_sdram, - .set_hw_if_params = isif_set_hw_if_params, - .configure = isif_configure, - .set_buftype = isif_set_buftype, - .get_buftype = isif_get_buftype, - .enum_pix = isif_enum_pix, - .set_pixel_format = isif_set_pixel_format, - .get_pixel_format = isif_get_pixel_format, - .set_frame_format = isif_set_frame_format, - .get_frame_format = isif_get_frame_format, - .set_image_window = isif_set_image_window, - .get_image_window = isif_get_image_window, - .get_line_length = isif_get_line_length, - .setfbaddr = isif_setfbaddr, - .getfid = isif_getfid, - }, -}; - -static int isif_probe(struct platform_device *pdev) -{ - void (*setup_pinmux)(void); - struct resource *res; - void __iomem *addr; - int status = 0, i; - - /* Platform data holds setup_pinmux function ptr */ - if (!pdev->dev.platform_data) - return -ENODEV; - - /* - * first try to register with vpfe. If not correct platform, then we - * don't have to iomap - */ - status = vpfe_register_ccdc_device(&isif_hw_dev); - if (status < 0) - return status; - - setup_pinmux = pdev->dev.platform_data; - /* - * setup Mux configuration for ccdc which may be different for - * different SoCs using this CCDC - */ - setup_pinmux(); - - i = 0; - /* Get the ISIF base address, linearization table0 and table1 addr. */ - while (i < 3) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (!res) { - status = -ENODEV; - goto fail_nobase_res; - } - res = request_mem_region(res->start, resource_size(res), - res->name); - if (!res) { - status = -EBUSY; - goto fail_nobase_res; - } - addr = ioremap(res->start, resource_size(res)); - if (!addr) { - status = -ENOMEM; - goto fail_base_iomap; - } - switch (i) { - case 0: - /* ISIF base address */ - isif_cfg.base_addr = addr; - break; - case 1: - /* ISIF linear tbl0 address */ - isif_cfg.linear_tbl0_addr = addr; - break; - default: - /* ISIF linear tbl0 address */ - isif_cfg.linear_tbl1_addr = addr; - break; - } - i++; - } - isif_cfg.dev = &pdev->dev; - - printk(KERN_NOTICE "%s is registered with vpfe.\n", - isif_hw_dev.name); - return 0; -fail_base_iomap: - release_mem_region(res->start, resource_size(res)); - i--; -fail_nobase_res: - if (isif_cfg.base_addr) { - iounmap(isif_cfg.base_addr); - isif_cfg.base_addr = NULL; - } - if (isif_cfg.linear_tbl0_addr) { - iounmap(isif_cfg.linear_tbl0_addr); - isif_cfg.linear_tbl0_addr = NULL; - } - - while (i >= 0) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (res) - release_mem_region(res->start, resource_size(res)); - i--; - } - vpfe_unregister_ccdc_device(&isif_hw_dev); - return status; -} - -static int isif_remove(struct platform_device *pdev) -{ - struct resource *res; - int i = 0; - - iounmap(isif_cfg.base_addr); - isif_cfg.base_addr = NULL; - iounmap(isif_cfg.linear_tbl0_addr); - isif_cfg.linear_tbl0_addr = NULL; - iounmap(isif_cfg.linear_tbl1_addr); - isif_cfg.linear_tbl1_addr = NULL; - while (i < 3) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - release_mem_region(res->start, resource_size(res)); - i++; - } - vpfe_unregister_ccdc_device(&isif_hw_dev); - return 0; -} - -static struct platform_driver isif_driver = { - .driver = { - .name = "isif", - }, - .remove = isif_remove, - .probe = isif_probe, -}; - -module_platform_driver(isif_driver); - -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/deprecated/vpfe_capture/isif.h b/drivers/staging/media/deprecated/vpfe_capture/isif.h deleted file mode 100644 index 8369acd26e7e..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/isif.h +++ /dev/null @@ -1,518 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * isif header file - */ -#ifndef _ISIF_H -#define _ISIF_H - -#include <media/davinci/ccdc_types.h> -#include <media/davinci/vpfe_types.h> - -/* isif float type S8Q8/U8Q8 */ -struct isif_float_8 { - /* 8 bit integer part */ - __u8 integer; - /* 8 bit decimal part */ - __u8 decimal; -}; - -/* isif float type U16Q16/S16Q16 */ -struct isif_float_16 { - /* 16 bit integer part */ - __u16 integer; - /* 16 bit decimal part */ - __u16 decimal; -}; - -/************************************************************************ - * Vertical Defect Correction parameters - ***********************************************************************/ -/* Defect Correction (DFC) table entry */ -struct isif_vdfc_entry { - /* vertical position of defect */ - __u16 pos_vert; - /* horizontal position of defect */ - __u16 pos_horz; - /* - * Defect level of Vertical line defect position. This is subtracted - * from the data at the defect position - */ - __u8 level_at_pos; - /* - * Defect level of the pixels upper than the vertical line defect. - * This is subtracted from the data - */ - __u8 level_up_pixels; - /* - * Defect level of the pixels lower than the vertical line defect. - * This is subtracted from the data - */ - __u8 level_low_pixels; -}; - -#define ISIF_VDFC_TABLE_SIZE 8 -struct isif_dfc { - /* enable vertical defect correction */ - __u8 en; - /* Defect level subtraction. Just fed through if saturating */ -#define ISIF_VDFC_NORMAL 0 - /* - * Defect level subtraction. Horizontal interpolation ((i-2)+(i+2))/2 - * if data saturating - */ -#define ISIF_VDFC_HORZ_INTERPOL_IF_SAT 1 - /* Horizontal interpolation (((i-2)+(i+2))/2) */ -#define ISIF_VDFC_HORZ_INTERPOL 2 - /* one of the vertical defect correction modes above */ - __u8 corr_mode; - /* 0 - whole line corrected, 1 - not pixels upper than the defect */ - __u8 corr_whole_line; -#define ISIF_VDFC_NO_SHIFT 0 -#define ISIF_VDFC_SHIFT_1 1 -#define ISIF_VDFC_SHIFT_2 2 -#define ISIF_VDFC_SHIFT_3 3 -#define ISIF_VDFC_SHIFT_4 4 - /* - * defect level shift value. level_at_pos, level_upper_pos, - * and level_lower_pos can be shifted up by this value. Choose - * one of the values above - */ - __u8 def_level_shift; - /* defect saturation level */ - __u16 def_sat_level; - /* number of vertical defects. Max is ISIF_VDFC_TABLE_SIZE */ - __u16 num_vdefects; - /* VDFC table ptr */ - struct isif_vdfc_entry table[ISIF_VDFC_TABLE_SIZE]; -}; - -struct isif_horz_bclamp { - - /* Horizontal clamp disabled. Only vertical clamp value is subtracted */ -#define ISIF_HORZ_BC_DISABLE 0 - /* - * Horizontal clamp value is calculated and subtracted from image data - * along with vertical clamp value - */ -#define ISIF_HORZ_BC_CLAMP_CALC_ENABLED 1 - /* - * Horizontal clamp value calculated from previous image is subtracted - * from image data along with vertical clamp value. - */ -#define ISIF_HORZ_BC_CLAMP_NOT_UPDATED 2 - /* horizontal clamp mode. One of the values above */ - __u8 mode; - /* - * pixel value limit enable. - * 0 - limit disabled - * 1 - pixel value limited to 1023 - */ - __u8 clamp_pix_limit; - /* Select Most left window for bc calculation */ -#define ISIF_SEL_MOST_LEFT_WIN 0 - /* Select Most right window for bc calculation */ -#define ISIF_SEL_MOST_RIGHT_WIN 1 - /* Select most left or right window for clamp val calculation */ - __u8 base_win_sel_calc; - /* Window count per color for calculation. range 1-32 */ - __u8 win_count_calc; - /* Window start position - horizontal for calculation. 0 - 8191 */ - __u16 win_start_h_calc; - /* Window start position - vertical for calculation 0 - 8191 */ - __u16 win_start_v_calc; -#define ISIF_HORZ_BC_SZ_H_2PIXELS 0 -#define ISIF_HORZ_BC_SZ_H_4PIXELS 1 -#define ISIF_HORZ_BC_SZ_H_8PIXELS 2 -#define ISIF_HORZ_BC_SZ_H_16PIXELS 3 - /* Width of the sample window in pixels for calculation */ - __u8 win_h_sz_calc; -#define ISIF_HORZ_BC_SZ_V_32PIXELS 0 -#define ISIF_HORZ_BC_SZ_V_64PIXELS 1 -#define ISIF_HORZ_BC_SZ_V_128PIXELS 2 -#define ISIF_HORZ_BC_SZ_V_256PIXELS 3 - /* Height of the sample window in pixels for calculation */ - __u8 win_v_sz_calc; -}; - -/************************************************************************ - * Black Clamp parameters - ***********************************************************************/ -struct isif_vert_bclamp { - /* Reset value used is the clamp value calculated */ -#define ISIF_VERT_BC_USE_HORZ_CLAMP_VAL 0 - /* Reset value used is reset_clamp_val configured */ -#define ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL 1 - /* No update, previous image value is used */ -#define ISIF_VERT_BC_NO_UPDATE 2 - /* - * Reset value selector for vertical clamp calculation. Use one of - * the above values - */ - __u8 reset_val_sel; - /* U8Q8. Line average coefficient used in vertical clamp calculation */ - __u8 line_ave_coef; - /* Height of the optical black region for calculation */ - __u16 ob_v_sz_calc; - /* Optical black region start position - horizontal. 0 - 8191 */ - __u16 ob_start_h; - /* Optical black region start position - vertical 0 - 8191 */ - __u16 ob_start_v; -}; - -struct isif_black_clamp { - /* - * This offset value is added irrespective of the clamp enable status. - * S13 - */ - __u16 dc_offset; - /* - * Enable black/digital clamp value to be subtracted from the image data - */ - __u8 en; - /* - * black clamp mode. same/separate clamp for 4 colors - * 0 - disable - same clamp value for all colors - * 1 - clamp value calculated separately for all colors - */ - __u8 bc_mode_color; - /* Vertical start position for bc subtraction */ - __u16 vert_start_sub; - /* Black clamp for horizontal direction */ - struct isif_horz_bclamp horz; - /* Black clamp for vertical direction */ - struct isif_vert_bclamp vert; -}; - -/************************************************************************* -** Color Space Conversion (CSC) -*************************************************************************/ -#define ISIF_CSC_NUM_COEFF 16 -struct isif_color_space_conv { - /* Enable color space conversion */ - __u8 en; - /* - * csc coefficient table. S8Q5, M00 at index 0, M01 at index 1, and - * so forth - */ - struct isif_float_8 coeff[ISIF_CSC_NUM_COEFF]; -}; - - -/************************************************************************* -** Black Compensation parameters -*************************************************************************/ -struct isif_black_comp { - /* Comp for Red */ - __s8 r_comp; - /* Comp for Gr */ - __s8 gr_comp; - /* Comp for Blue */ - __s8 b_comp; - /* Comp for Gb */ - __s8 gb_comp; -}; - -/************************************************************************* -** Gain parameters -*************************************************************************/ -struct isif_gain { - /* Gain for Red or ye */ - struct isif_float_16 r_ye; - /* Gain for Gr or cy */ - struct isif_float_16 gr_cy; - /* Gain for Gb or g */ - struct isif_float_16 gb_g; - /* Gain for Blue or mg */ - struct isif_float_16 b_mg; -}; - -#define ISIF_LINEAR_TAB_SIZE 192 -/************************************************************************* -** Linearization parameters -*************************************************************************/ -struct isif_linearize { - /* Enable or Disable linearization of data */ - __u8 en; - /* Shift value applied */ - __u8 corr_shft; - /* scale factor applied U11Q10 */ - struct isif_float_16 scale_fact; - /* Size of the linear table */ - __u16 table[ISIF_LINEAR_TAB_SIZE]; -}; - -/* Color patterns */ -#define ISIF_RED 0 -#define ISIF_GREEN_RED 1 -#define ISIF_GREEN_BLUE 2 -#define ISIF_BLUE 3 -struct isif_col_pat { - __u8 olop; - __u8 olep; - __u8 elop; - __u8 elep; -}; - -/************************************************************************* -** Data formatter parameters -*************************************************************************/ -struct isif_fmtplen { - /* - * number of program entries for SET0, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen0; - /* - * number of program entries for SET1, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen1; - /** - * number of program entries for SET2, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen2; - /** - * number of program entries for SET3, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen3; -}; - -struct isif_fmt_cfg { -#define ISIF_SPLIT 0 -#define ISIF_COMBINE 1 - /* Split or combine or line alternate */ - __u8 fmtmode; - /* enable or disable line alternating mode */ - __u8 ln_alter_en; -#define ISIF_1LINE 0 -#define ISIF_2LINES 1 -#define ISIF_3LINES 2 -#define ISIF_4LINES 3 - /* Split/combine line number */ - __u8 lnum; - /* Address increment Range 1 - 16 */ - __u8 addrinc; -}; - -struct isif_fmt_addr_ptr { - /* Initial address */ - __u32 init_addr; - /* output line number */ -#define ISIF_1STLINE 0 -#define ISIF_2NDLINE 1 -#define ISIF_3RDLINE 2 -#define ISIF_4THLINE 3 - __u8 out_line; -}; - -struct isif_fmtpgm_ap { - /* program address pointer */ - __u8 pgm_aptr; - /* program address increment or decrement */ - __u8 pgmupdt; -}; - -struct isif_data_formatter { - /* Enable/Disable data formatter */ - __u8 en; - /* data formatter configuration */ - struct isif_fmt_cfg cfg; - /* Formatter program entries length */ - struct isif_fmtplen plen; - /* first pixel in a line fed to formatter */ - __u16 fmtrlen; - /* HD interval for output line. Only valid when split line */ - __u16 fmthcnt; - /* formatter address pointers */ - struct isif_fmt_addr_ptr fmtaddr_ptr[16]; - /* program enable/disable */ - __u8 pgm_en[32]; - /* program address pointers */ - struct isif_fmtpgm_ap fmtpgm_ap[32]; -}; - -struct isif_df_csc { - /* Color Space Conversion configuration, 0 - csc, 1 - df */ - __u8 df_or_csc; - /* csc configuration valid if df_or_csc is 0 */ - struct isif_color_space_conv csc; - /* data formatter configuration valid if df_or_csc is 1 */ - struct isif_data_formatter df; - /* start pixel in a line at the input */ - __u32 start_pix; - /* number of pixels in input line */ - __u32 num_pixels; - /* start line at the input */ - __u32 start_line; - /* number of lines at the input */ - __u32 num_lines; -}; - -struct isif_gain_offsets_adj { - /* Gain adjustment per color */ - struct isif_gain gain; - /* Offset adjustment */ - __u16 offset; - /* Enable or Disable Gain adjustment for SDRAM data */ - __u8 gain_sdram_en; - /* Enable or Disable Gain adjustment for IPIPE data */ - __u8 gain_ipipe_en; - /* Enable or Disable Gain adjustment for H3A data */ - __u8 gain_h3a_en; - /* Enable or Disable Gain adjustment for SDRAM data */ - __u8 offset_sdram_en; - /* Enable or Disable Gain adjustment for IPIPE data */ - __u8 offset_ipipe_en; - /* Enable or Disable Gain adjustment for H3A data */ - __u8 offset_h3a_en; -}; - -struct isif_cul { - /* Horizontal Cull pattern for odd lines */ - __u8 hcpat_odd; - /* Horizontal Cull pattern for even lines */ - __u8 hcpat_even; - /* Vertical Cull pattern */ - __u8 vcpat; - /* Enable or disable lpf. Apply when cull is enabled */ - __u8 en_lpf; -}; - -struct isif_compress { -#define ISIF_ALAW 0 -#define ISIF_DPCM 1 -#define ISIF_NO_COMPRESSION 2 - /* Compression Algorithm used */ - __u8 alg; - /* Choose Predictor1 for DPCM compression */ -#define ISIF_DPCM_PRED1 0 - /* Choose Predictor2 for DPCM compression */ -#define ISIF_DPCM_PRED2 1 - /* Predictor for DPCM compression */ - __u8 pred; -}; - -/* all the stuff in this struct will be provided by userland */ -struct isif_config_params_raw { - /* Linearization parameters for image sensor data input */ - struct isif_linearize linearize; - /* Data formatter or CSC */ - struct isif_df_csc df_csc; - /* Defect Pixel Correction (DFC) configuration */ - struct isif_dfc dfc; - /* Black/Digital Clamp configuration */ - struct isif_black_clamp bclamp; - /* Gain, offset adjustments */ - struct isif_gain_offsets_adj gain_offset; - /* Culling */ - struct isif_cul culling; - /* A-Law and DPCM compression options */ - struct isif_compress compress; - /* horizontal offset for Gain/LSC/DFC */ - __u16 horz_offset; - /* vertical offset for Gain/LSC/DFC */ - __u16 vert_offset; - /* color pattern for field 0 */ - struct isif_col_pat col_pat_field0; - /* color pattern for field 1 */ - struct isif_col_pat col_pat_field1; -#define ISIF_NO_SHIFT 0 -#define ISIF_1BIT_SHIFT 1 -#define ISIF_2BIT_SHIFT 2 -#define ISIF_3BIT_SHIFT 3 -#define ISIF_4BIT_SHIFT 4 -#define ISIF_5BIT_SHIFT 5 -#define ISIF_6BIT_SHIFT 6 - /* Data shift applied before storing to SDRAM */ - __u8 data_shift; - /* enable input test pattern generation */ - __u8 test_pat_gen; -}; - -#ifdef __KERNEL__ -struct isif_ycbcr_config { - /* isif pixel format */ - enum ccdc_pixfmt pix_fmt; - /* isif frame format */ - enum ccdc_frmfmt frm_fmt; - /* ISIF crop window */ - struct v4l2_rect win; - /* field polarity */ - enum vpfe_pin_pol fid_pol; - /* interface VD polarity */ - enum vpfe_pin_pol vd_pol; - /* interface HD polarity */ - enum vpfe_pin_pol hd_pol; - /* isif pix order. Only used for ycbcr capture */ - enum ccdc_pixorder pix_order; - /* isif buffer type. Only used for ycbcr capture */ - enum ccdc_buftype buf_type; -}; - -/* MSB of image data connected to sensor port */ -enum isif_data_msb { - ISIF_BIT_MSB_15, - ISIF_BIT_MSB_14, - ISIF_BIT_MSB_13, - ISIF_BIT_MSB_12, - ISIF_BIT_MSB_11, - ISIF_BIT_MSB_10, - ISIF_BIT_MSB_9, - ISIF_BIT_MSB_8, - ISIF_BIT_MSB_7 -}; - -enum isif_cfa_pattern { - ISIF_CFA_PAT_MOSAIC, - ISIF_CFA_PAT_STRIPE -}; - -struct isif_params_raw { - /* isif pixel format */ - enum ccdc_pixfmt pix_fmt; - /* isif frame format */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field polarity */ - enum vpfe_pin_pol fid_pol; - /* interface VD polarity */ - enum vpfe_pin_pol vd_pol; - /* interface HD polarity */ - enum vpfe_pin_pol hd_pol; - /* buffer type. Applicable for interlaced mode */ - enum ccdc_buftype buf_type; - /* Gain values */ - struct isif_gain gain; - /* cfa pattern */ - enum isif_cfa_pattern cfa_pat; - /* Data MSB position */ - enum isif_data_msb data_msb; - /* Enable horizontal flip */ - unsigned char horz_flip_en; - /* Enable image invert vertically */ - unsigned char image_invert_en; - - /* all the userland defined stuff*/ - struct isif_config_params_raw config_params; -}; - -enum isif_data_pack { - ISIF_PACK_16BIT, - ISIF_PACK_12BIT, - ISIF_PACK_8BIT -}; - -#define ISIF_WIN_NTSC {0, 0, 720, 480} -#define ISIF_WIN_VGA {0, 0, 640, 480} - -#endif -#endif diff --git a/drivers/staging/media/deprecated/vpfe_capture/isif_regs.h b/drivers/staging/media/deprecated/vpfe_capture/isif_regs.h deleted file mode 100644 index d68d38841ae7..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/isif_regs.h +++ /dev/null @@ -1,256 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - */ -#ifndef _ISIF_REGS_H -#define _ISIF_REGS_H - -/* ISIF registers relative offsets */ -#define SYNCEN 0x00 -#define MODESET 0x04 -#define HDW 0x08 -#define VDW 0x0c -#define PPLN 0x10 -#define LPFR 0x14 -#define SPH 0x18 -#define LNH 0x1c -#define SLV0 0x20 -#define SLV1 0x24 -#define LNV 0x28 -#define CULH 0x2c -#define CULV 0x30 -#define HSIZE 0x34 -#define SDOFST 0x38 -#define CADU 0x3c -#define CADL 0x40 -#define LINCFG0 0x44 -#define LINCFG1 0x48 -#define CCOLP 0x4c -#define CRGAIN 0x50 -#define CGRGAIN 0x54 -#define CGBGAIN 0x58 -#define CBGAIN 0x5c -#define COFSTA 0x60 -#define FLSHCFG0 0x64 -#define FLSHCFG1 0x68 -#define FLSHCFG2 0x6c -#define VDINT0 0x70 -#define VDINT1 0x74 -#define VDINT2 0x78 -#define MISC 0x7c -#define CGAMMAWD 0x80 -#define REC656IF 0x84 -#define CCDCFG 0x88 -/***************************************************** -* Defect Correction registers -*****************************************************/ -#define DFCCTL 0x8c -#define VDFSATLV 0x90 -#define DFCMEMCTL 0x94 -#define DFCMEM0 0x98 -#define DFCMEM1 0x9c -#define DFCMEM2 0xa0 -#define DFCMEM3 0xa4 -#define DFCMEM4 0xa8 -/**************************************************** -* Black Clamp registers -****************************************************/ -#define CLAMPCFG 0xac -#define CLDCOFST 0xb0 -#define CLSV 0xb4 -#define CLHWIN0 0xb8 -#define CLHWIN1 0xbc -#define CLHWIN2 0xc0 -#define CLVRV 0xc4 -#define CLVWIN0 0xc8 -#define CLVWIN1 0xcc -#define CLVWIN2 0xd0 -#define CLVWIN3 0xd4 -/**************************************************** -* Lense Shading Correction -****************************************************/ -#define DATAHOFST 0xd8 -#define DATAVOFST 0xdc -#define LSCHVAL 0xe0 -#define LSCVVAL 0xe4 -#define TWODLSCCFG 0xe8 -#define TWODLSCOFST 0xec -#define TWODLSCINI 0xf0 -#define TWODLSCGRBU 0xf4 -#define TWODLSCGRBL 0xf8 -#define TWODLSCGROF 0xfc -#define TWODLSCORBU 0x100 -#define TWODLSCORBL 0x104 -#define TWODLSCOROF 0x108 -#define TWODLSCIRQEN 0x10c -#define TWODLSCIRQST 0x110 -/**************************************************** -* Data formatter -****************************************************/ -#define FMTCFG 0x114 -#define FMTPLEN 0x118 -#define FMTSPH 0x11c -#define FMTLNH 0x120 -#define FMTSLV 0x124 -#define FMTLNV 0x128 -#define FMTRLEN 0x12c -#define FMTHCNT 0x130 -#define FMTAPTR_BASE 0x134 -/* Below macro for addresses FMTAPTR0 - FMTAPTR15 */ -#define FMTAPTR(i) (FMTAPTR_BASE + (i * 4)) -#define FMTPGMVF0 0x174 -#define FMTPGMVF1 0x178 -#define FMTPGMAPU0 0x17c -#define FMTPGMAPU1 0x180 -#define FMTPGMAPS0 0x184 -#define FMTPGMAPS1 0x188 -#define FMTPGMAPS2 0x18c -#define FMTPGMAPS3 0x190 -#define FMTPGMAPS4 0x194 -#define FMTPGMAPS5 0x198 -#define FMTPGMAPS6 0x19c -#define FMTPGMAPS7 0x1a0 -/************************************************ -* Color Space Converter -************************************************/ -#define CSCCTL 0x1a4 -#define CSCM0 0x1a8 -#define CSCM1 0x1ac -#define CSCM2 0x1b0 -#define CSCM3 0x1b4 -#define CSCM4 0x1b8 -#define CSCM5 0x1bc -#define CSCM6 0x1c0 -#define CSCM7 0x1c4 -#define OBWIN0 0x1c8 -#define OBWIN1 0x1cc -#define OBWIN2 0x1d0 -#define OBWIN3 0x1d4 -#define OBVAL0 0x1d8 -#define OBVAL1 0x1dc -#define OBVAL2 0x1e0 -#define OBVAL3 0x1e4 -#define OBVAL4 0x1e8 -#define OBVAL5 0x1ec -#define OBVAL6 0x1f0 -#define OBVAL7 0x1f4 -#define CLKCTL 0x1f8 - -/* Masks & Shifts below */ -#define START_PX_HOR_MASK 0x7FFF -#define NUM_PX_HOR_MASK 0x7FFF -#define START_VER_ONE_MASK 0x7FFF -#define START_VER_TWO_MASK 0x7FFF -#define NUM_LINES_VER 0x7FFF - -/* gain - offset masks */ -#define GAIN_INTEGER_SHIFT 9 -#define OFFSET_MASK 0xFFF -#define GAIN_SDRAM_EN_SHIFT 12 -#define GAIN_IPIPE_EN_SHIFT 13 -#define GAIN_H3A_EN_SHIFT 14 -#define OFST_SDRAM_EN_SHIFT 8 -#define OFST_IPIPE_EN_SHIFT 9 -#define OFST_H3A_EN_SHIFT 10 -#define GAIN_OFFSET_EN_MASK 0x7700 - -/* Culling */ -#define CULL_PAT_EVEN_LINE_SHIFT 8 - -/* CCDCFG register */ -#define ISIF_YCINSWP_RAW (0x00 << 4) -#define ISIF_YCINSWP_YCBCR (0x01 << 4) -#define ISIF_CCDCFG_FIDMD_LATCH_VSYNC (0x00 << 6) -#define ISIF_CCDCFG_WENLOG_AND (0x00 << 8) -#define ISIF_CCDCFG_TRGSEL_WEN (0x00 << 9) -#define ISIF_CCDCFG_EXTRG_DISABLE (0x00 << 10) -#define ISIF_LATCH_ON_VSYNC_DISABLE (0x01 << 15) -#define ISIF_LATCH_ON_VSYNC_ENABLE (0x00 << 15) -#define ISIF_DATA_PACK_MASK 3 -#define ISIF_DATA_PACK16 0 -#define ISIF_DATA_PACK12 1 -#define ISIF_DATA_PACK8 2 -#define ISIF_PIX_ORDER_SHIFT 11 -#define ISIF_BW656_ENABLE (0x01 << 5) - -/* MODESET registers */ -#define ISIF_VDHDOUT_INPUT (0x00 << 0) -#define ISIF_INPUT_SHIFT 12 -#define ISIF_RAW_INPUT_MODE 0 -#define ISIF_FID_POL_SHIFT 4 -#define ISIF_HD_POL_SHIFT 3 -#define ISIF_VD_POL_SHIFT 2 -#define ISIF_DATAPOL_NORMAL 0 -#define ISIF_DATAPOL_SHIFT 6 -#define ISIF_EXWEN_DISABLE 0 -#define ISIF_EXWEN_SHIFT 5 -#define ISIF_FRM_FMT_SHIFT 7 -#define ISIF_DATASFT_SHIFT 8 -#define ISIF_LPF_SHIFT 14 -#define ISIF_LPF_MASK 1 - -/* GAMMAWD registers */ -#define ISIF_ALAW_GAMMA_WD_MASK 0xF -#define ISIF_ALAW_GAMMA_WD_SHIFT 1 -#define ISIF_ALAW_ENABLE 1 -#define ISIF_GAMMAWD_CFA_SHIFT 5 - -/* HSIZE registers */ -#define ISIF_HSIZE_FLIP_MASK 1 -#define ISIF_HSIZE_FLIP_SHIFT 12 - -/* MISC registers */ -#define ISIF_DPCM_EN_SHIFT 12 -#define ISIF_DPCM_PREDICTOR_SHIFT 13 - -/* Black clamp related */ -#define ISIF_BC_MODE_COLOR_SHIFT 4 -#define ISIF_HORZ_BC_MODE_SHIFT 1 -#define ISIF_HORZ_BC_WIN_SEL_SHIFT 5 -#define ISIF_HORZ_BC_PIX_LIMIT_SHIFT 6 -#define ISIF_HORZ_BC_WIN_H_SIZE_SHIFT 8 -#define ISIF_HORZ_BC_WIN_V_SIZE_SHIFT 12 -#define ISIF_VERT_BC_RST_VAL_SEL_SHIFT 4 -#define ISIF_VERT_BC_LINE_AVE_COEF_SHIFT 8 - -/* VDFC registers */ -#define ISIF_VDFC_EN_SHIFT 4 -#define ISIF_VDFC_CORR_MOD_SHIFT 5 -#define ISIF_VDFC_CORR_WHOLE_LN_SHIFT 7 -#define ISIF_VDFC_LEVEL_SHFT_SHIFT 8 -#define ISIF_VDFC_POS_MASK 0x1FFF -#define ISIF_DFCMEMCTL_DFCMARST_SHIFT 2 - -/* CSC registers */ -#define ISIF_CSC_COEF_INTEG_MASK 7 -#define ISIF_CSC_COEF_DECIMAL_MASK 0x1f -#define ISIF_CSC_COEF_INTEG_SHIFT 5 -#define ISIF_CSCM_MSB_SHIFT 8 -#define ISIF_DF_CSC_SPH_MASK 0x1FFF -#define ISIF_DF_CSC_LNH_MASK 0x1FFF -#define ISIF_DF_CSC_SLV_MASK 0x1FFF -#define ISIF_DF_CSC_LNV_MASK 0x1FFF -#define ISIF_DF_NUMLINES 0x7FFF -#define ISIF_DF_NUMPIX 0x1FFF - -/* Offsets for LSC/DFC/Gain */ -#define ISIF_DATA_H_OFFSET_MASK 0x1FFF -#define ISIF_DATA_V_OFFSET_MASK 0x1FFF - -/* Linearization */ -#define ISIF_LIN_CORRSFT_SHIFT 4 -#define ISIF_LIN_SCALE_FACT_INTEG_SHIFT 10 - - -/* Pattern registers */ -#define ISIF_PG_EN (1 << 3) -#define ISIF_SEL_PG_SRC (3 << 4) -#define ISIF_PG_VD_POL_SHIFT 0 -#define ISIF_PG_HD_POL_SHIFT 1 - -/*random other junk*/ -#define ISIF_SYNCEN_VDHDEN_MASK (1 << 0) -#define ISIF_SYNCEN_WEN_MASK (1 << 1) -#define ISIF_SYNCEN_WEN_SHIFT 1 - -#endif diff --git a/drivers/staging/media/deprecated/vpfe_capture/vpfe_capture.c b/drivers/staging/media/deprecated/vpfe_capture/vpfe_capture.c deleted file mode 100644 index 0a2226b321d7..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/vpfe_capture.c +++ /dev/null @@ -1,1902 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * Driver name : VPFE Capture driver - * VPFE Capture driver allows applications to capture and stream video - * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as - * TVP5146 or Raw Bayer RGB image data from an image sensor - * such as Microns' MT9T001, MT9T031 etc. - * - * These SoCs have, in common, a Video Processing Subsystem (VPSS) that - * consists of a Video Processing Front End (VPFE) for capturing - * video/raw image data and Video Processing Back End (VPBE) for displaying - * YUV data through an in-built analog encoder or Digital LCD port. This - * driver is for capture through VPFE. A typical EVM using these SoCs have - * following high level configuration. - * - * decoder(TVP5146/ YUV/ - * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF) - * data input | | - * V | - * SDRAM | - * V - * Image Processor - * | - * V - * SDRAM - * The data flow happens from a decoder connected to the VPFE over a - * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface - * and to the input of VPFE through an optional MUX (if more inputs are - * to be interfaced on the EVM). The input data is first passed through - * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC - * does very little or no processing on YUV data and does pre-process Raw - * Bayer RGB data through modules such as Defect Pixel Correction (DFC) - * Color Space Conversion (CSC), data gain/offset etc. After this, data - * can be written to SDRAM or can be connected to the image processing - * block such as IPIPE (on DM355 only). - * - * Features supported - * - MMAP IO - * - Capture using TVP5146 over BT.656 - * - support for interfacing decoders using sub device model - * - Work with DM355 or DM6446 CCDC to do Raw Bayer RGB/YUV - * data capture to SDRAM. - * TODO list - * - Support multiple REQBUF after open - * - Support for de-allocating buffers through REQBUF - * - Support for Raw Bayer RGB capture - * - Support for chaining Image Processor - * - Support for static allocation of buffers - * - Support for USERPTR IO - * - Support for STREAMON before QBUF - * - Support for control ioctls - */ -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <media/v4l2-common.h> -#include <linux/io.h> -#include <media/davinci/vpfe_capture.h> -#include "ccdc_hw_device.h" - -static int debug; -static u32 numbuffers = 3; -static u32 bufsize = (720 * 576 * 2); - -module_param(numbuffers, uint, S_IRUGO); -module_param(bufsize, uint, S_IRUGO); -module_param(debug, int, 0644); - -MODULE_PARM_DESC(numbuffers, "buffer count (default:3)"); -MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)"); -MODULE_PARM_DESC(debug, "Debug level 0-1"); - -MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Texas Instruments"); - -/* standard information */ -struct vpfe_standard { - v4l2_std_id std_id; - unsigned int width; - unsigned int height; - struct v4l2_fract pixelaspect; - /* 0 - progressive, 1 - interlaced */ - int frame_format; -}; - -/* ccdc configuration */ -struct ccdc_config { - /* This make sure vpfe is probed and ready to go */ - int vpfe_probed; - /* name of ccdc device */ - char name[32]; -}; - -/* data structures */ -static struct vpfe_config_params config_params = { - .min_numbuffers = 3, - .numbuffers = 3, - .min_bufsize = 720 * 480 * 2, - .device_bufsize = 720 * 576 * 2, -}; - -/* ccdc device registered */ -static const struct ccdc_hw_device *ccdc_dev; -/* lock for accessing ccdc information */ -static DEFINE_MUTEX(ccdc_lock); -/* ccdc configuration */ -static struct ccdc_config *ccdc_cfg; - -static const struct vpfe_standard vpfe_standards[] = { - {V4L2_STD_525_60, 720, 480, {11, 10}, 1}, - {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, -}; - -/* Used when raw Bayer image from ccdc is directly captured to SDRAM */ -static const struct vpfe_pixel_format vpfe_pix_fmts[] = { - { - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .bpp = 1, - }, - { - .pixelformat = V4L2_PIX_FMT_SBGGR16, - .bpp = 2, - }, - { - .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, - .bpp = 1, - }, - { - .pixelformat = V4L2_PIX_FMT_UYVY, - .bpp = 2, - }, - { - .pixelformat = V4L2_PIX_FMT_YUYV, - .bpp = 2, - }, - { - .pixelformat = V4L2_PIX_FMT_NV12, - .bpp = 1, - }, -}; - -/* - * vpfe_lookup_pix_format() - * lookup an entry in the vpfe pix format table based on pix_format - */ -static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) { - if (pix_format == vpfe_pix_fmts[i].pixelformat) - return &vpfe_pix_fmts[i]; - } - return NULL; -} - -/* - * vpfe_register_ccdc_device. CCDC module calls this to - * register with vpfe capture - */ -int vpfe_register_ccdc_device(const struct ccdc_hw_device *dev) -{ - int ret = 0; - printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name); - - if (!dev->hw_ops.open || - !dev->hw_ops.enable || - !dev->hw_ops.set_hw_if_params || - !dev->hw_ops.configure || - !dev->hw_ops.set_buftype || - !dev->hw_ops.get_buftype || - !dev->hw_ops.enum_pix || - !dev->hw_ops.set_frame_format || - !dev->hw_ops.get_frame_format || - !dev->hw_ops.get_pixel_format || - !dev->hw_ops.set_pixel_format || - !dev->hw_ops.set_image_window || - !dev->hw_ops.get_image_window || - !dev->hw_ops.get_line_length || - !dev->hw_ops.getfid) - return -EINVAL; - - mutex_lock(&ccdc_lock); - if (!ccdc_cfg) { - /* - * TODO. Will this ever happen? if so, we need to fix it. - * Probably we need to add the request to a linked list and - * walk through it during vpfe probe - */ - printk(KERN_ERR "vpfe capture not initialized\n"); - ret = -EFAULT; - goto unlock; - } - - if (strcmp(dev->name, ccdc_cfg->name)) { - /* ignore this ccdc */ - ret = -EINVAL; - goto unlock; - } - - if (ccdc_dev) { - printk(KERN_ERR "ccdc already registered\n"); - ret = -EINVAL; - goto unlock; - } - - ccdc_dev = dev; -unlock: - mutex_unlock(&ccdc_lock); - return ret; -} -EXPORT_SYMBOL(vpfe_register_ccdc_device); - -/* - * vpfe_unregister_ccdc_device. CCDC module calls this to - * unregister with vpfe capture - */ -void vpfe_unregister_ccdc_device(const struct ccdc_hw_device *dev) -{ - if (!dev) { - printk(KERN_ERR "invalid ccdc device ptr\n"); - return; - } - - printk(KERN_NOTICE "vpfe_unregister_ccdc_device, dev->name = %s\n", - dev->name); - - if (strcmp(dev->name, ccdc_cfg->name)) { - /* ignore this ccdc */ - return; - } - - mutex_lock(&ccdc_lock); - ccdc_dev = NULL; - mutex_unlock(&ccdc_lock); -} -EXPORT_SYMBOL(vpfe_unregister_ccdc_device); - -/* - * vpfe_config_ccdc_image_format() - * For a pix format, configure ccdc to setup the capture - */ -static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev) -{ - enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; - int ret = 0; - - if (ccdc_dev->hw_ops.set_pixel_format( - vpfe_dev->fmt.fmt.pix.pixelformat) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "couldn't set pix format in ccdc\n"); - return -EINVAL; - } - /* configure the image window */ - ccdc_dev->hw_ops.set_image_window(&vpfe_dev->crop); - - switch (vpfe_dev->fmt.fmt.pix.field) { - case V4L2_FIELD_INTERLACED: - /* do nothing, since it is default */ - ret = ccdc_dev->hw_ops.set_buftype( - CCDC_BUFTYPE_FLD_INTERLEAVED); - break; - case V4L2_FIELD_NONE: - frm_fmt = CCDC_FRMFMT_PROGRESSIVE; - /* buffer type only applicable for interlaced scan */ - break; - case V4L2_FIELD_SEQ_TB: - ret = ccdc_dev->hw_ops.set_buftype( - CCDC_BUFTYPE_FLD_SEPARATED); - break; - default: - return -EINVAL; - } - - /* set the frame format */ - if (!ret) - ret = ccdc_dev->hw_ops.set_frame_format(frm_fmt); - return ret; -} -/* - * vpfe_config_image_format() - * For a given standard, this functions sets up the default - * pix format & crop values in the vpfe device and ccdc. It first - * starts with defaults based values from the standard table. - * It then checks if sub device supports get_fmt and then override the - * values based on that.Sets crop values to match with scan resolution - * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the - * values in ccdc - */ -static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, - v4l2_std_id std_id) -{ - struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev; - struct v4l2_subdev_format fmt = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_mbus_framefmt *mbus_fmt = &fmt.format; - struct v4l2_pix_format *pix = &vpfe_dev->fmt.fmt.pix; - int i, ret; - - for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { - if (vpfe_standards[i].std_id & std_id) { - vpfe_dev->std_info.active_pixels = - vpfe_standards[i].width; - vpfe_dev->std_info.active_lines = - vpfe_standards[i].height; - vpfe_dev->std_info.frame_format = - vpfe_standards[i].frame_format; - vpfe_dev->std_index = i; - break; - } - } - - if (i == ARRAY_SIZE(vpfe_standards)) { - v4l2_err(&vpfe_dev->v4l2_dev, "standard not supported\n"); - return -EINVAL; - } - - vpfe_dev->crop.top = 0; - vpfe_dev->crop.left = 0; - vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels; - vpfe_dev->crop.height = vpfe_dev->std_info.active_lines; - pix->width = vpfe_dev->crop.width; - pix->height = vpfe_dev->crop.height; - - /* first field and frame format based on standard frame format */ - if (vpfe_dev->std_info.frame_format) { - pix->field = V4L2_FIELD_INTERLACED; - /* assume V4L2_PIX_FMT_UYVY as default */ - pix->pixelformat = V4L2_PIX_FMT_UYVY; - v4l2_fill_mbus_format(mbus_fmt, pix, - MEDIA_BUS_FMT_YUYV10_2X10); - } else { - pix->field = V4L2_FIELD_NONE; - /* assume V4L2_PIX_FMT_SBGGR8 */ - pix->pixelformat = V4L2_PIX_FMT_SBGGR8; - v4l2_fill_mbus_format(mbus_fmt, pix, - MEDIA_BUS_FMT_SBGGR8_1X8); - } - - /* if sub device supports get_fmt, override the defaults */ - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - sdinfo->grp_id, pad, get_fmt, NULL, &fmt); - - if (ret && ret != -ENOIOCTLCMD) { - v4l2_err(&vpfe_dev->v4l2_dev, - "error in getting get_fmt from sub device\n"); - return ret; - } - v4l2_fill_pix_format(pix, mbus_fmt); - pix->bytesperline = pix->width * 2; - pix->sizeimage = pix->bytesperline * pix->height; - - /* Sets the values in CCDC */ - ret = vpfe_config_ccdc_image_format(vpfe_dev); - if (ret) - return ret; - - /* Update the values of sizeimage and bytesperline */ - pix->bytesperline = ccdc_dev->hw_ops.get_line_length(); - pix->sizeimage = pix->bytesperline * pix->height; - - return 0; -} - -static int vpfe_initialize_device(struct vpfe_device *vpfe_dev) -{ - int ret; - - /* set first input of current subdevice as the current input */ - vpfe_dev->current_input = 0; - - /* set default standard */ - vpfe_dev->std_index = 0; - - /* Configure the default format information */ - ret = vpfe_config_image_format(vpfe_dev, - vpfe_standards[vpfe_dev->std_index].std_id); - if (ret) - return ret; - - /* now open the ccdc device to initialize it */ - mutex_lock(&ccdc_lock); - if (!ccdc_dev) { - v4l2_err(&vpfe_dev->v4l2_dev, "ccdc device not registered\n"); - ret = -ENODEV; - goto unlock; - } - - if (!try_module_get(ccdc_dev->owner)) { - v4l2_err(&vpfe_dev->v4l2_dev, "Couldn't lock ccdc module\n"); - ret = -ENODEV; - goto unlock; - } - ret = ccdc_dev->hw_ops.open(vpfe_dev->pdev); - if (!ret) - vpfe_dev->initialized = 1; - - /* Clear all VPFE/CCDC interrupts */ - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(-1); - -unlock: - mutex_unlock(&ccdc_lock); - return ret; -} - -/* - * vpfe_open : It creates object of file handle structure and - * stores it in private_data member of filepointer - */ -static int vpfe_open(struct file *file) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - struct vpfe_fh *fh; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_open\n"); - - if (!vpfe_dev->cfg->num_subdevs) { - v4l2_err(&vpfe_dev->v4l2_dev, "No decoder registered\n"); - return -ENODEV; - } - - /* Allocate memory for the file handle object */ - fh = kmalloc(sizeof(*fh), GFP_KERNEL); - if (!fh) - return -ENOMEM; - - /* store pointer to fh in private_data member of file */ - file->private_data = fh; - fh->vpfe_dev = vpfe_dev; - v4l2_fh_init(&fh->fh, vdev); - mutex_lock(&vpfe_dev->lock); - /* If decoder is not initialized. initialize it */ - if (!vpfe_dev->initialized) { - if (vpfe_initialize_device(vpfe_dev)) { - mutex_unlock(&vpfe_dev->lock); - v4l2_fh_exit(&fh->fh); - kfree(fh); - return -ENODEV; - } - } - /* Increment device usrs counter */ - vpfe_dev->usrs++; - /* Set io_allowed member to false */ - fh->io_allowed = 0; - v4l2_fh_add(&fh->fh); - mutex_unlock(&vpfe_dev->lock); - return 0; -} - -static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev) -{ - unsigned long addr; - - vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, - struct videobuf_buffer, queue); - list_del(&vpfe_dev->next_frm->queue); - vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE; - addr = videobuf_to_dma_contig(vpfe_dev->next_frm); - - ccdc_dev->hw_ops.setfbaddr(addr); -} - -static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev) -{ - unsigned long addr; - - addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); - addr += vpfe_dev->field_off; - ccdc_dev->hw_ops.setfbaddr(addr); -} - -static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev) -{ - vpfe_dev->cur_frm->ts = ktime_get_ns(); - vpfe_dev->cur_frm->state = VIDEOBUF_DONE; - vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage; - wake_up_interruptible(&vpfe_dev->cur_frm->done); - vpfe_dev->cur_frm = vpfe_dev->next_frm; -} - -/* ISR for VINT0*/ -static irqreturn_t vpfe_isr(int irq, void *dev_id) -{ - struct vpfe_device *vpfe_dev = dev_id; - enum v4l2_field field; - int fid; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n"); - field = vpfe_dev->fmt.fmt.pix.field; - - /* if streaming not started, don't do anything */ - if (!vpfe_dev->started) - goto clear_intr; - - /* only for 6446 this will be applicable */ - if (ccdc_dev->hw_ops.reset) - ccdc_dev->hw_ops.reset(); - - if (field == V4L2_FIELD_NONE) { - /* handle progressive frame capture */ - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "frame format is progressive...\n"); - if (vpfe_dev->cur_frm != vpfe_dev->next_frm) - vpfe_process_buffer_complete(vpfe_dev); - goto clear_intr; - } - - /* interlaced or TB capture check which field we are in hardware */ - fid = ccdc_dev->hw_ops.getfid(); - - /* switch the software maintained field id */ - vpfe_dev->field_id ^= 1; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "field id = %x:%x.\n", - fid, vpfe_dev->field_id); - if (fid == vpfe_dev->field_id) { - /* we are in-sync here,continue */ - if (fid == 0) { - /* - * One frame is just being captured. If the next frame - * is available, release the current frame and move on - */ - if (vpfe_dev->cur_frm != vpfe_dev->next_frm) - vpfe_process_buffer_complete(vpfe_dev); - /* - * based on whether the two fields are stored - * interleavely or separately in memory, reconfigure - * the CCDC memory address - */ - if (field == V4L2_FIELD_SEQ_TB) - vpfe_schedule_bottom_field(vpfe_dev); - goto clear_intr; - } - /* - * if one field is just being captured configure - * the next frame get the next frame from the empty - * queue if no frame is available hold on to the - * current buffer - */ - spin_lock(&vpfe_dev->dma_queue_lock); - if (!list_empty(&vpfe_dev->dma_queue) && - vpfe_dev->cur_frm == vpfe_dev->next_frm) - vpfe_schedule_next_buffer(vpfe_dev); - spin_unlock(&vpfe_dev->dma_queue_lock); - } else if (fid == 0) { - /* - * out of sync. Recover from any hardware out-of-sync. - * May loose one frame - */ - vpfe_dev->field_id = fid; - } -clear_intr: - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(irq); - - return IRQ_HANDLED; -} - -/* vdint1_isr - isr handler for VINT1 interrupt */ -static irqreturn_t vdint1_isr(int irq, void *dev_id) -{ - struct vpfe_device *vpfe_dev = dev_id; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nInside vdint1_isr...\n"); - - /* if streaming not started, don't do anything */ - if (!vpfe_dev->started) { - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(irq); - return IRQ_HANDLED; - } - - spin_lock(&vpfe_dev->dma_queue_lock); - if ((vpfe_dev->fmt.fmt.pix.field == V4L2_FIELD_NONE) && - !list_empty(&vpfe_dev->dma_queue) && - vpfe_dev->cur_frm == vpfe_dev->next_frm) - vpfe_schedule_next_buffer(vpfe_dev); - spin_unlock(&vpfe_dev->dma_queue_lock); - - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(irq); - - return IRQ_HANDLED; -} - -static void vpfe_detach_irq(struct vpfe_device *vpfe_dev) -{ - enum ccdc_frmfmt frame_format; - - frame_format = ccdc_dev->hw_ops.get_frame_format(); - if (frame_format == CCDC_FRMFMT_PROGRESSIVE) - free_irq(vpfe_dev->ccdc_irq1, vpfe_dev); -} - -static int vpfe_attach_irq(struct vpfe_device *vpfe_dev) -{ - enum ccdc_frmfmt frame_format; - - frame_format = ccdc_dev->hw_ops.get_frame_format(); - if (frame_format == CCDC_FRMFMT_PROGRESSIVE) { - return request_irq(vpfe_dev->ccdc_irq1, vdint1_isr, - 0, "vpfe_capture1", - vpfe_dev); - } - return 0; -} - -/* vpfe_stop_ccdc_capture: stop streaming in ccdc/isif */ -static void vpfe_stop_ccdc_capture(struct vpfe_device *vpfe_dev) -{ - vpfe_dev->started = 0; - ccdc_dev->hw_ops.enable(0); - if (ccdc_dev->hw_ops.enable_out_to_sdram) - ccdc_dev->hw_ops.enable_out_to_sdram(0); -} - -/* - * vpfe_release : This function deletes buffer queue, frees the - * buffers and the vpfe file handle - */ -static int vpfe_release(struct file *file) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - struct vpfe_subdev_info *sdinfo; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n"); - - /* Get the device lock */ - mutex_lock(&vpfe_dev->lock); - /* if this instance is doing IO */ - if (fh->io_allowed) { - if (vpfe_dev->started) { - sdinfo = vpfe_dev->current_subdev; - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - sdinfo->grp_id, - video, s_stream, 0); - if (ret && (ret != -ENOIOCTLCMD)) - v4l2_err(&vpfe_dev->v4l2_dev, - "stream off failed in subdev\n"); - vpfe_stop_ccdc_capture(vpfe_dev); - vpfe_detach_irq(vpfe_dev); - videobuf_streamoff(&vpfe_dev->buffer_queue); - } - vpfe_dev->io_usrs = 0; - vpfe_dev->numbuffers = config_params.numbuffers; - videobuf_stop(&vpfe_dev->buffer_queue); - videobuf_mmap_free(&vpfe_dev->buffer_queue); - } - - /* Decrement device usrs counter */ - vpfe_dev->usrs--; - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - /* If this is the last file handle */ - if (!vpfe_dev->usrs) { - vpfe_dev->initialized = 0; - if (ccdc_dev->hw_ops.close) - ccdc_dev->hw_ops.close(vpfe_dev->pdev); - module_put(ccdc_dev->owner); - } - mutex_unlock(&vpfe_dev->lock); - file->private_data = NULL; - /* Free memory allocated to file handle object */ - kfree(fh); - return 0; -} - -/* - * vpfe_mmap : It is used to map kernel space buffers - * into user spaces - */ -static int vpfe_mmap(struct file *file, struct vm_area_struct *vma) -{ - /* Get the device object and file handle object */ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n"); - - return videobuf_mmap_mapper(&vpfe_dev->buffer_queue, vma); -} - -/* - * vpfe_poll: It is used for select/poll system call - */ -static __poll_t vpfe_poll(struct file *file, poll_table *wait) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n"); - - if (vpfe_dev->started) - return videobuf_poll_stream(file, - &vpfe_dev->buffer_queue, wait); - return 0; -} - -/* vpfe capture driver file operations */ -static const struct v4l2_file_operations vpfe_fops = { - .owner = THIS_MODULE, - .open = vpfe_open, - .release = vpfe_release, - .unlocked_ioctl = video_ioctl2, - .mmap = vpfe_mmap, - .poll = vpfe_poll -}; - -/* - * vpfe_check_format() - * This function adjust the input pixel format as per hardware - * capabilities and update the same in pixfmt. - * Following algorithm used :- - * - * If given pixformat is not in the vpfe list of pix formats or not - * supported by the hardware, current value of pixformat in the device - * is used - * If given field is not supported, then current field is used. If field - * is different from current, then it is matched with that from sub device. - * Minimum height is 2 lines for interlaced or tb field and 1 line for - * progressive. Maximum height is clamped to active active lines of scan - * Minimum width is 32 bytes in memory and width is clamped to active - * pixels of scan. - * bytesperline is a multiple of 32. - */ -static const struct vpfe_pixel_format * - vpfe_check_format(struct vpfe_device *vpfe_dev, - struct v4l2_pix_format *pixfmt) -{ - u32 min_height = 1, min_width = 32, max_width, max_height; - const struct vpfe_pixel_format *vpfe_pix_fmt; - u32 pix; - int temp, found; - - vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); - if (!vpfe_pix_fmt) { - /* - * use current pixel format in the vpfe device. We - * will find this pix format in the table - */ - pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; - vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); - } - - /* check if hw supports it */ - temp = 0; - found = 0; - while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) { - if (vpfe_pix_fmt->pixelformat == pix) { - found = 1; - break; - } - temp++; - } - - if (!found) { - /* use current pixel format */ - pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; - /* - * Since this is currently used in the vpfe device, we - * will find this pix format in the table - */ - vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); - } - - /* check what field format is supported */ - if (pixfmt->field == V4L2_FIELD_ANY) { - /* if field is any, use current value as default */ - pixfmt->field = vpfe_dev->fmt.fmt.pix.field; - } - - /* - * if field is not same as current field in the vpfe device - * try matching the field with the sub device field - */ - if (vpfe_dev->fmt.fmt.pix.field != pixfmt->field) { - /* - * If field value is not in the supported fields, use current - * field used in the device as default - */ - switch (pixfmt->field) { - case V4L2_FIELD_INTERLACED: - case V4L2_FIELD_SEQ_TB: - /* if sub device is supporting progressive, use that */ - if (!vpfe_dev->std_info.frame_format) - pixfmt->field = V4L2_FIELD_NONE; - break; - case V4L2_FIELD_NONE: - if (vpfe_dev->std_info.frame_format) - pixfmt->field = V4L2_FIELD_INTERLACED; - break; - - default: - /* use current field as default */ - pixfmt->field = vpfe_dev->fmt.fmt.pix.field; - break; - } - } - - /* Now adjust image resolutions supported */ - if (pixfmt->field == V4L2_FIELD_INTERLACED || - pixfmt->field == V4L2_FIELD_SEQ_TB) - min_height = 2; - - max_width = vpfe_dev->std_info.active_pixels; - max_height = vpfe_dev->std_info.active_lines; - min_width /= vpfe_pix_fmt->bpp; - - v4l2_info(&vpfe_dev->v4l2_dev, "width = %d, height = %d, bpp = %d\n", - pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp); - - pixfmt->width = clamp((pixfmt->width), min_width, max_width); - pixfmt->height = clamp((pixfmt->height), min_height, max_height); - - /* If interlaced, adjust height to be a multiple of 2 */ - if (pixfmt->field == V4L2_FIELD_INTERLACED) - pixfmt->height &= (~1); - /* - * recalculate bytesperline and sizeimage since width - * and height might have changed - */ - pixfmt->bytesperline = (((pixfmt->width * vpfe_pix_fmt->bpp) + 31) - & ~31); - if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) - pixfmt->sizeimage = - pixfmt->bytesperline * pixfmt->height + - ((pixfmt->bytesperline * pixfmt->height) >> 1); - else - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; - - v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height = %d, bpp = %d, bytesperline = %d, sizeimage = %d\n", - pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp, - pixfmt->bytesperline, pixfmt->sizeimage); - return vpfe_pix_fmt; -} - -static int vpfe_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n"); - - strscpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); - strscpy(cap->bus_info, "VPFE", sizeof(cap->bus_info)); - strscpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card)); - return 0; -} - -static int vpfe_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n"); - /* Fill in the information about format */ - *fmt = vpfe_dev->fmt; - return 0; -} - -static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - const struct vpfe_pixel_format *pix_fmt; - u32 pix; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n"); - - if (ccdc_dev->hw_ops.enum_pix(&pix, fmt->index) < 0) - return -EINVAL; - - /* Fill in the information about format */ - pix_fmt = vpfe_lookup_pix_format(pix); - if (pix_fmt) { - fmt->pixelformat = pix_fmt->pixelformat; - return 0; - } - return -EINVAL; -} - -static int vpfe_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - const struct vpfe_pixel_format *pix_fmts; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n"); - - /* If streaming is started, return error */ - if (vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n"); - return -EBUSY; - } - - /* Check for valid frame format */ - pix_fmts = vpfe_check_format(vpfe_dev, &fmt->fmt.pix); - if (!pix_fmts) - return -EINVAL; - - /* store the pixel format in the device object */ - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - /* First detach any IRQ if currently attached */ - vpfe_detach_irq(vpfe_dev); - vpfe_dev->fmt = *fmt; - /* set image capture parameters in the ccdc */ - ret = vpfe_config_ccdc_image_format(vpfe_dev); - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - const struct vpfe_pixel_format *pix_fmts; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt_vid_cap\n"); - - pix_fmts = vpfe_check_format(vpfe_dev, &f->fmt.pix); - if (!pix_fmts) - return -EINVAL; - return 0; -} - -/* - * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a - * given app input index - */ -static int vpfe_get_subdev_input_index(struct vpfe_device *vpfe_dev, - int *subdev_index, - int *subdev_input_index, - int app_input_index) -{ - struct vpfe_config *cfg = vpfe_dev->cfg; - struct vpfe_subdev_info *sdinfo; - int i, j = 0; - - for (i = 0; i < cfg->num_subdevs; i++) { - sdinfo = &cfg->sub_devs[i]; - if (app_input_index < (j + sdinfo->num_inputs)) { - *subdev_index = i; - *subdev_input_index = app_input_index - j; - return 0; - } - j += sdinfo->num_inputs; - } - return -EINVAL; -} - -/* - * vpfe_get_app_input - Get app input index for a given subdev input index - * driver stores the input index of the current sub device and translate it - * when application request the current input - */ -static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev, - int *app_input_index) -{ - struct vpfe_config *cfg = vpfe_dev->cfg; - struct vpfe_subdev_info *sdinfo; - int i, j = 0; - - for (i = 0; i < cfg->num_subdevs; i++) { - sdinfo = &cfg->sub_devs[i]; - if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) { - if (vpfe_dev->current_input >= sdinfo->num_inputs) - return -1; - *app_input_index = j + vpfe_dev->current_input; - return 0; - } - j += sdinfo->num_inputs; - } - return -EINVAL; -} - -static int vpfe_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - int subdev, index ; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n"); - - if (vpfe_get_subdev_input_index(vpfe_dev, - &subdev, - &index, - inp->index) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "input information not found for the subdev\n"); - return -EINVAL; - } - sdinfo = &vpfe_dev->cfg->sub_devs[subdev]; - *inp = sdinfo->inputs[index]; - return 0; -} - -static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n"); - - return vpfe_get_app_input_index(vpfe_dev, index); -} - - -static int vpfe_s_input(struct file *file, void *priv, unsigned int index) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct v4l2_subdev *sd; - struct vpfe_subdev_info *sdinfo; - int subdev_index, inp_index; - struct vpfe_route *route; - u32 input, output; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n"); - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - /* - * If streaming is started return device busy - * error - */ - if (vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n"); - ret = -EBUSY; - goto unlock_out; - } - ret = vpfe_get_subdev_input_index(vpfe_dev, - &subdev_index, - &inp_index, - index); - if (ret < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n"); - goto unlock_out; - } - - sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index]; - sd = vpfe_dev->sd[subdev_index]; - route = &sdinfo->routes[inp_index]; - if (route && sdinfo->can_route) { - input = route->input; - output = route->output; - } else { - input = 0; - output = 0; - } - - if (sd) - ret = v4l2_subdev_call(sd, video, s_routing, input, output, 0); - - if (ret) { - v4l2_err(&vpfe_dev->v4l2_dev, - "vpfe_doioctl:error in setting input in decoder\n"); - ret = -EINVAL; - goto unlock_out; - } - vpfe_dev->current_subdev = sdinfo; - if (sd) - vpfe_dev->v4l2_dev.ctrl_handler = sd->ctrl_handler; - vpfe_dev->current_input = index; - vpfe_dev->std_index = 0; - - /* set the bus/interface parameter for the sub device in ccdc */ - ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params); - if (ret) - goto unlock_out; - - /* set the default image parameters in the device */ - ret = vpfe_config_image_format(vpfe_dev, - vpfe_standards[vpfe_dev->std_index].std_id); -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n"); - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - sdinfo = vpfe_dev->current_subdev; - if (ret) - return ret; - /* Call querystd function of decoder device */ - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, querystd, std_id); - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n"); - - /* Call decoder driver function to set the standard */ - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - sdinfo = vpfe_dev->current_subdev; - /* If streaming is started, return device busy error */ - if (vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n"); - ret = -EBUSY; - goto unlock_out; - } - - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_std, std_id); - if (ret < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); - goto unlock_out; - } - ret = vpfe_config_image_format(vpfe_dev, std_id); - -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n"); - - *std_id = vpfe_standards[vpfe_dev->std_index].std_id; - return 0; -} -/* - * Videobuf operations - */ -static int vpfe_videobuf_setup(struct videobuf_queue *vq, - unsigned int *count, - unsigned int *size) -{ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n"); - *size = vpfe_dev->fmt.fmt.pix.sizeimage; - if (vpfe_dev->memory == V4L2_MEMORY_MMAP && - vpfe_dev->fmt.fmt.pix.sizeimage > config_params.device_bufsize) - *size = config_params.device_bufsize; - - if (*count < config_params.min_numbuffers) - *count = config_params.min_numbuffers; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "count=%d, size=%d\n", *count, *size); - return 0; -} - -static int vpfe_videobuf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - unsigned long addr; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n"); - - /* If buffer is not initialized, initialize it */ - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->width = vpfe_dev->fmt.fmt.pix.width; - vb->height = vpfe_dev->fmt.fmt.pix.height; - vb->size = vpfe_dev->fmt.fmt.pix.sizeimage; - vb->field = field; - - ret = videobuf_iolock(vq, vb, NULL); - if (ret < 0) - return ret; - - addr = videobuf_to_dma_contig(vb); - /* Make sure user addresses are aligned to 32 bytes */ - if (!ALIGN(addr, 32)) - return -EINVAL; - - vb->state = VIDEOBUF_PREPARED; - } - return 0; -} - -static void vpfe_videobuf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - /* Get the file handle object and device object */ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - unsigned long flags; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue\n"); - - /* add the buffer to the DMA queue */ - spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); - list_add_tail(&vb->queue, &vpfe_dev->dma_queue); - spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); - - /* Change state of the buffer */ - vb->state = VIDEOBUF_QUEUED; -} - -static void vpfe_videobuf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - unsigned long flags; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n"); - - /* - * We need to flush the buffer from the dma queue since - * they are de-allocated - */ - spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); - INIT_LIST_HEAD(&vpfe_dev->dma_queue); - spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); - videobuf_dma_contig_free(vq, vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static const struct videobuf_queue_ops vpfe_videobuf_qops = { - .buf_setup = vpfe_videobuf_setup, - .buf_prepare = vpfe_videobuf_prepare, - .buf_queue = vpfe_videobuf_queue, - .buf_release = vpfe_videobuf_release, -}; - -/* - * vpfe_reqbufs. currently support REQBUF only once opening - * the device. - */ -static int vpfe_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req_buf) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n"); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - if (vpfe_dev->io_usrs != 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n"); - ret = -EBUSY; - goto unlock_out; - } - - vpfe_dev->memory = req_buf->memory; - videobuf_queue_dma_contig_init(&vpfe_dev->buffer_queue, - &vpfe_videobuf_qops, - vpfe_dev->pdev, - &vpfe_dev->irqlock, - req_buf->type, - vpfe_dev->fmt.fmt.pix.field, - sizeof(struct videobuf_buffer), - fh, NULL); - - fh->io_allowed = 1; - vpfe_dev->io_usrs = 1; - INIT_LIST_HEAD(&vpfe_dev->dma_queue); - ret = videobuf_reqbufs(&vpfe_dev->buffer_queue, req_buf); -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - if (vpfe_dev->memory != V4L2_MEMORY_MMAP) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n"); - return -EINVAL; - } - /* Call videobuf_querybuf to get information */ - return videobuf_querybuf(&vpfe_dev->buffer_queue, buf); -} - -static int vpfe_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - /* - * If this file handle is not allowed to do IO, - * return error - */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - return videobuf_qbuf(&vpfe_dev->buffer_queue, p); -} - -static int vpfe_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - return videobuf_dqbuf(&vpfe_dev->buffer_queue, - buf, file->f_flags & O_NONBLOCK); -} - -/* - * vpfe_calculate_offsets : This function calculates buffers offset - * for top and bottom field - */ -static void vpfe_calculate_offsets(struct vpfe_device *vpfe_dev) -{ - struct v4l2_rect image_win; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_calculate_offsets\n"); - - ccdc_dev->hw_ops.get_image_window(&image_win); - vpfe_dev->field_off = image_win.height * image_win.width; -} - -/* vpfe_start_ccdc_capture: start streaming in ccdc/isif */ -static void vpfe_start_ccdc_capture(struct vpfe_device *vpfe_dev) -{ - ccdc_dev->hw_ops.enable(1); - if (ccdc_dev->hw_ops.enable_out_to_sdram) - ccdc_dev->hw_ops.enable_out_to_sdram(1); - vpfe_dev->started = 1; -} - -/* - * vpfe_streamon. Assume the DMA queue is not empty. - * application is expected to call QBUF before calling - * this ioctl. If not, driver returns error - */ -static int vpfe_streamon(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - struct vpfe_subdev_info *sdinfo; - unsigned long addr; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - /* If file handle is not allowed IO, return error */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - - sdinfo = vpfe_dev->current_subdev; - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_stream, 1); - - if (ret && (ret != -ENOIOCTLCMD)) { - v4l2_err(&vpfe_dev->v4l2_dev, "stream on failed in subdev\n"); - return -EINVAL; - } - - /* If buffer queue is empty, return error */ - if (list_empty(&vpfe_dev->buffer_queue.stream)) { - v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n"); - return -EIO; - } - - /* Call videobuf_streamon to start streaming * in videobuf */ - ret = videobuf_streamon(&vpfe_dev->buffer_queue); - if (ret) - return ret; - - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - goto streamoff; - /* Get the next frame from the buffer queue */ - vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, - struct videobuf_buffer, queue); - vpfe_dev->cur_frm = vpfe_dev->next_frm; - /* Remove buffer from the buffer queue */ - list_del(&vpfe_dev->cur_frm->queue); - /* Mark state of the current frame to active */ - vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE; - /* Initialize field_id and started member */ - vpfe_dev->field_id = 0; - addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); - - /* Calculate field offset */ - vpfe_calculate_offsets(vpfe_dev); - - if (vpfe_attach_irq(vpfe_dev) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error in attaching interrupt handle\n"); - ret = -EFAULT; - goto unlock_out; - } - if (ccdc_dev->hw_ops.configure() < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error in configuring ccdc\n"); - ret = -EINVAL; - goto unlock_out; - } - ccdc_dev->hw_ops.setfbaddr((unsigned long)(addr)); - vpfe_start_ccdc_capture(vpfe_dev); - mutex_unlock(&vpfe_dev->lock); - return ret; -unlock_out: - mutex_unlock(&vpfe_dev->lock); -streamoff: - videobuf_streamoff(&vpfe_dev->buffer_queue); - return ret; -} - -static int vpfe_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - struct vpfe_subdev_info *sdinfo; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - /* If io is allowed for this file handle, return error */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - - /* If streaming is not started, return error */ - if (!vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "device started\n"); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - vpfe_stop_ccdc_capture(vpfe_dev); - vpfe_detach_irq(vpfe_dev); - - sdinfo = vpfe_dev->current_subdev; - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_stream, 0); - - if (ret && (ret != -ENOIOCTLCMD)) - v4l2_err(&vpfe_dev->v4l2_dev, "stream off failed in subdev\n"); - ret = videobuf_streamoff(&vpfe_dev->buffer_queue); - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_g_pixelaspect(struct file *file, void *priv, - int type, struct v4l2_fract *f) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_pixelaspect\n"); - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - /* If std_index is invalid, then just return (== 1:1 aspect) */ - if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards)) - return 0; - - *f = vpfe_standards[vpfe_dev->std_index].pixelaspect; - return 0; -} - -static int vpfe_g_selection(struct file *file, void *priv, - struct v4l2_selection *sel) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_selection\n"); - - if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - sel->r = vpfe_dev->crop; - break; - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.width = vpfe_standards[vpfe_dev->std_index].width; - sel->r.height = vpfe_standards[vpfe_dev->std_index].height; - break; - default: - return -EINVAL; - } - return 0; -} - -static int vpfe_s_selection(struct file *file, void *priv, - struct v4l2_selection *sel) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct v4l2_rect rect = sel->r; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_selection\n"); - - if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - if (vpfe_dev->started) { - /* make sure streaming is not started */ - v4l2_err(&vpfe_dev->v4l2_dev, - "Cannot change crop when streaming is ON\n"); - return -EBUSY; - } - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - if (rect.top < 0 || rect.left < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "doesn't support negative values for top & left\n"); - ret = -EINVAL; - goto unlock_out; - } - - /* adjust the width to 16 pixel boundary */ - rect.width = ((rect.width + 15) & ~0xf); - - /* make sure parameters are valid */ - if ((rect.left + rect.width > - vpfe_dev->std_info.active_pixels) || - (rect.top + rect.height > - vpfe_dev->std_info.active_lines)) { - v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_SELECTION params\n"); - ret = -EINVAL; - goto unlock_out; - } - ccdc_dev->hw_ops.set_image_window(&rect); - vpfe_dev->fmt.fmt.pix.width = rect.width; - vpfe_dev->fmt.fmt.pix.height = rect.height; - vpfe_dev->fmt.fmt.pix.bytesperline = - ccdc_dev->hw_ops.get_line_length(); - vpfe_dev->fmt.fmt.pix.sizeimage = - vpfe_dev->fmt.fmt.pix.bytesperline * - vpfe_dev->fmt.fmt.pix.height; - vpfe_dev->crop = rect; - sel->r = rect; -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -/* vpfe capture ioctl operations */ -static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { - .vidioc_querycap = vpfe_querycap, - .vidioc_g_fmt_vid_cap = vpfe_g_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vpfe_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vpfe_try_fmt_vid_cap, - .vidioc_enum_input = vpfe_enum_input, - .vidioc_g_input = vpfe_g_input, - .vidioc_s_input = vpfe_s_input, - .vidioc_querystd = vpfe_querystd, - .vidioc_s_std = vpfe_s_std, - .vidioc_g_std = vpfe_g_std, - .vidioc_reqbufs = vpfe_reqbufs, - .vidioc_querybuf = vpfe_querybuf, - .vidioc_qbuf = vpfe_qbuf, - .vidioc_dqbuf = vpfe_dqbuf, - .vidioc_streamon = vpfe_streamon, - .vidioc_streamoff = vpfe_streamoff, - .vidioc_g_pixelaspect = vpfe_g_pixelaspect, - .vidioc_g_selection = vpfe_g_selection, - .vidioc_s_selection = vpfe_s_selection, -}; - -static struct vpfe_device *vpfe_initialize(void) -{ - struct vpfe_device *vpfe_dev; - - /* Default number of buffers should be 3 */ - if ((numbuffers > 0) && - (numbuffers < config_params.min_numbuffers)) - numbuffers = config_params.min_numbuffers; - - /* - * Set buffer size to min buffers size if invalid buffer size is - * given - */ - if (bufsize < config_params.min_bufsize) - bufsize = config_params.min_bufsize; - - config_params.numbuffers = numbuffers; - - if (numbuffers) - config_params.device_bufsize = bufsize; - - /* Allocate memory for device objects */ - vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL); - - return vpfe_dev; -} - -/* - * vpfe_probe : This function creates device entries by register - * itself to the V4L2 driver and initializes fields of each - * device objects - */ -static int vpfe_probe(struct platform_device *pdev) -{ - struct vpfe_subdev_info *sdinfo; - struct vpfe_config *vpfe_cfg; - struct resource *res1; - struct vpfe_device *vpfe_dev; - struct i2c_adapter *i2c_adap; - struct video_device *vfd; - int ret, i, j; - int num_subdevs = 0; - - /* Get the pointer to the device object */ - vpfe_dev = vpfe_initialize(); - - if (!vpfe_dev) { - v4l2_err(pdev->dev.driver, - "Failed to allocate memory for vpfe_dev\n"); - return -ENOMEM; - } - - vpfe_dev->pdev = &pdev->dev; - - if (!pdev->dev.platform_data) { - v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n"); - ret = -ENODEV; - goto probe_free_dev_mem; - } - - vpfe_cfg = pdev->dev.platform_data; - vpfe_dev->cfg = vpfe_cfg; - if (!vpfe_cfg->ccdc || !vpfe_cfg->card_name || !vpfe_cfg->sub_devs) { - v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n"); - ret = -ENOENT; - goto probe_free_dev_mem; - } - - /* Allocate memory for ccdc configuration */ - ccdc_cfg = kmalloc(sizeof(*ccdc_cfg), GFP_KERNEL); - if (!ccdc_cfg) { - ret = -ENOMEM; - goto probe_free_dev_mem; - } - - mutex_lock(&ccdc_lock); - - strscpy(ccdc_cfg->name, vpfe_cfg->ccdc, sizeof(ccdc_cfg->name)); - /* Get VINT0 irq resource */ - res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get interrupt for VINT0\n"); - ret = -ENODEV; - goto probe_free_ccdc_cfg_mem; - } - vpfe_dev->ccdc_irq0 = res1->start; - - /* Get VINT1 irq resource */ - res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get interrupt for VINT1\n"); - ret = -ENODEV; - goto probe_free_ccdc_cfg_mem; - } - vpfe_dev->ccdc_irq1 = res1->start; - - ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, 0, - "vpfe_capture0", vpfe_dev); - - if (0 != ret) { - v4l2_err(pdev->dev.driver, "Unable to request interrupt\n"); - goto probe_free_ccdc_cfg_mem; - } - - vfd = &vpfe_dev->video_dev; - /* Initialize field of video device */ - vfd->release = video_device_release_empty; - vfd->fops = &vpfe_fops; - vfd->ioctl_ops = &vpfe_ioctl_ops; - vfd->tvnorms = 0; - vfd->v4l2_dev = &vpfe_dev->v4l2_dev; - vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - snprintf(vfd->name, sizeof(vfd->name), - "%s_V%d.%d.%d", - CAPTURE_DRV_NAME, - (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff, - (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff, - (VPFE_CAPTURE_VERSION_CODE) & 0xff); - - ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev); - if (ret) { - v4l2_err(pdev->dev.driver, - "Unable to register v4l2 device.\n"); - goto probe_out_release_irq; - } - v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n"); - spin_lock_init(&vpfe_dev->irqlock); - spin_lock_init(&vpfe_dev->dma_queue_lock); - mutex_init(&vpfe_dev->lock); - - /* Initialize field of the device objects */ - vpfe_dev->numbuffers = config_params.numbuffers; - - /* register video device */ - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "trying to register vpfe device.\n"); - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "video_dev=%p\n", &vpfe_dev->video_dev); - vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ret = video_register_device(&vpfe_dev->video_dev, - VFL_TYPE_VIDEO, -1); - - if (ret) { - v4l2_err(pdev->dev.driver, - "Unable to register video device.\n"); - goto probe_out_v4l2_unregister; - } - - v4l2_info(&vpfe_dev->v4l2_dev, "video device registered\n"); - /* set the driver data in platform device */ - platform_set_drvdata(pdev, vpfe_dev); - /* set driver private data */ - video_set_drvdata(&vpfe_dev->video_dev, vpfe_dev); - i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id); - num_subdevs = vpfe_cfg->num_subdevs; - vpfe_dev->sd = kmalloc_array(num_subdevs, - sizeof(*vpfe_dev->sd), - GFP_KERNEL); - if (!vpfe_dev->sd) { - ret = -ENOMEM; - goto probe_out_video_unregister; - } - - for (i = 0; i < num_subdevs; i++) { - struct v4l2_input *inps; - - sdinfo = &vpfe_cfg->sub_devs[i]; - - /* Load up the subdevice */ - vpfe_dev->sd[i] = - v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev, - i2c_adap, - &sdinfo->board_info, - NULL); - if (vpfe_dev->sd[i]) { - v4l2_info(&vpfe_dev->v4l2_dev, - "v4l2 sub device %s registered\n", - sdinfo->name); - vpfe_dev->sd[i]->grp_id = sdinfo->grp_id; - /* update tvnorms from the sub devices */ - for (j = 0; j < sdinfo->num_inputs; j++) { - inps = &sdinfo->inputs[j]; - vfd->tvnorms |= inps->std; - } - } else { - v4l2_info(&vpfe_dev->v4l2_dev, - "v4l2 sub device %s register fails\n", - sdinfo->name); - ret = -ENXIO; - goto probe_sd_out; - } - } - - /* set first sub device as current one */ - vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0]; - vpfe_dev->v4l2_dev.ctrl_handler = vpfe_dev->sd[0]->ctrl_handler; - - /* We have at least one sub device to work with */ - mutex_unlock(&ccdc_lock); - return 0; - -probe_sd_out: - kfree(vpfe_dev->sd); -probe_out_video_unregister: - video_unregister_device(&vpfe_dev->video_dev); -probe_out_v4l2_unregister: - v4l2_device_unregister(&vpfe_dev->v4l2_dev); -probe_out_release_irq: - free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); -probe_free_ccdc_cfg_mem: - kfree(ccdc_cfg); - mutex_unlock(&ccdc_lock); -probe_free_dev_mem: - kfree(vpfe_dev); - return ret; -} - -/* - * vpfe_remove : It un-register device from V4L2 driver - */ -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"); - - free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); - kfree(vpfe_dev->sd); - v4l2_device_unregister(&vpfe_dev->v4l2_dev); - video_unregister_device(&vpfe_dev->video_dev); - kfree(vpfe_dev); - kfree(ccdc_cfg); - return 0; -} - -static int vpfe_suspend(struct device *dev) -{ - return 0; -} - -static int vpfe_resume(struct device *dev) -{ - return 0; -} - -static const struct dev_pm_ops vpfe_dev_pm_ops = { - .suspend = vpfe_suspend, - .resume = vpfe_resume, -}; - -static struct platform_driver vpfe_driver = { - .driver = { - .name = CAPTURE_DRV_NAME, - .pm = &vpfe_dev_pm_ops, - }, - .probe = vpfe_probe, - .remove = vpfe_remove, -}; - -module_platform_driver(vpfe_driver); diff --git a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h index db1441c0cc66..690ab7165b2c 100644 --- a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h +++ b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h @@ -86,7 +86,7 @@ struct vchiq_service_params_kernel { struct vchiq_instance; -extern enum vchiq_status vchiq_initialise(struct vchiq_instance **pinstance); +extern int vchiq_initialise(struct vchiq_instance **pinstance); extern enum vchiq_status vchiq_shutdown(struct vchiq_instance *instance); extern enum vchiq_status vchiq_connect(struct vchiq_instance *instance); extern enum vchiq_status vchiq_open_service(struct vchiq_instance *instance, diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h index 2851ef6b9cd0..cd20eb18f275 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h @@ -100,10 +100,10 @@ vchiq_dump_platform_use_state(struct vchiq_state *state); extern void vchiq_dump_service_use_state(struct vchiq_state *state); -extern enum vchiq_status +extern int vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service, enum USE_TYPE_E use_type); -extern enum vchiq_status +extern int vchiq_release_internal(struct vchiq_state *state, struct vchiq_service *service); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index fd584111da45..ce0e000b74fc 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -281,10 +281,8 @@ fd_execute_rw_aio(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; for_each_sg(sgl, sg, sgl_nents, i) { - aio_cmd->bvecs[i].bv_page = sg_page(sg); - aio_cmd->bvecs[i].bv_len = sg->length; - aio_cmd->bvecs[i].bv_offset = sg->offset; - + bvec_set_page(&aio_cmd->bvecs[i], sg_page(sg), sg->length, + sg->offset); len += sg->length; } @@ -329,10 +327,7 @@ static int fd_do_rw(struct se_cmd *cmd, struct file *fd, } for_each_sg(sgl, sg, sgl_nents, i) { - bvec[i].bv_page = sg_page(sg); - bvec[i].bv_len = sg->length; - bvec[i].bv_offset = sg->offset; - + bvec_set_page(&bvec[i], sg_page(sg), sg->length, sg->offset); len += sg->length; } @@ -465,10 +460,9 @@ fd_execute_write_same(struct se_cmd *cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; for (i = 0; i < nolb; i++) { - bvec[i].bv_page = sg_page(&cmd->t_data_sg[0]); - bvec[i].bv_len = cmd->t_data_sg[0].length; - bvec[i].bv_offset = cmd->t_data_sg[0].offset; - + bvec_set_page(&bvec[i], sg_page(&cmd->t_data_sg[0]), + cmd->t_data_sg[0].length, + cmd->t_data_sg[0].offset); len += se_dev->dev_attrib.block_size; } diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index bac111456fa1..2b95b4550a63 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -73,8 +73,8 @@ static bool __target_check_io_state(struct se_cmd *se_cmd, { struct se_session *sess = se_cmd->se_sess; - assert_spin_locked(&sess->sess_cmd_lock); - WARN_ON_ONCE(!irqs_disabled()); + lockdep_assert_held(&sess->sess_cmd_lock); + /* * If command already reached CMD_T_COMPLETE state within * target_complete_cmd() or CMD_T_FABRIC_STOP due to shutdown, diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c index 27295bda3e0b..b1c6231defad 100644 --- a/drivers/tee/tee_shm.c +++ b/drivers/tee/tee_shm.c @@ -11,6 +11,7 @@ #include <linux/tee_drv.h> #include <linux/uaccess.h> #include <linux/uio.h> +#include <linux/highmem.h> #include "tee_private.h" static void shm_put_kernel_pages(struct page **pages, size_t page_count) @@ -24,38 +25,20 @@ static void shm_put_kernel_pages(struct page **pages, size_t page_count) static int shm_get_kernel_pages(unsigned long start, size_t page_count, struct page **pages) { + struct page *page; size_t n; - int rc; - - if (is_vmalloc_addr((void *)start)) { - struct page *page; - - for (n = 0; n < page_count; n++) { - page = vmalloc_to_page((void *)(start + PAGE_SIZE * n)); - if (!page) - return -ENOMEM; - get_page(page); - pages[n] = page; - } - rc = page_count; - } else { - struct kvec *kiov; - - kiov = kcalloc(page_count, sizeof(*kiov), GFP_KERNEL); - if (!kiov) - return -ENOMEM; - - for (n = 0; n < page_count; n++) { - kiov[n].iov_base = (void *)(start + n * PAGE_SIZE); - kiov[n].iov_len = PAGE_SIZE; - } + if (WARN_ON_ONCE(is_vmalloc_addr((void *)start) || + is_kmap_addr((void *)start))) + return -EINVAL; - rc = get_kernel_pages(kiov, page_count, 0, pages); - kfree(kiov); + page = virt_to_page(start); + for (n = 0; n < page_count; n++) { + pages[n] = page + n; + get_page(pages[n]); } - return rc; + return page_count; } static void release_registered_pages(struct tee_shm *shm) diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c index 62c0aa5d0783..0a4eaa307156 100644 --- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c +++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c @@ -44,11 +44,13 @@ static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone, int trip, int *temp) { struct int34x_thermal_zone *d = zone->devdata; - int i; + int i, ret = 0; if (d->override_ops && d->override_ops->get_trip_temp) return d->override_ops->get_trip_temp(zone, trip, temp); + mutex_lock(&d->trip_mutex); + if (trip < d->aux_trip_nr) *temp = d->aux_trips[trip]; else if (trip == d->crt_trip_id) @@ -66,10 +68,12 @@ static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone, } } if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) - return -EINVAL; + ret = -EINVAL; } - return 0; + mutex_unlock(&d->trip_mutex); + + return ret; } static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, @@ -77,11 +81,13 @@ static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, enum thermal_trip_type *type) { struct int34x_thermal_zone *d = zone->devdata; - int i; + int i, ret = 0; if (d->override_ops && d->override_ops->get_trip_type) return d->override_ops->get_trip_type(zone, trip, type); + mutex_lock(&d->trip_mutex); + if (trip < d->aux_trip_nr) *type = THERMAL_TRIP_PASSIVE; else if (trip == d->crt_trip_id) @@ -99,10 +105,12 @@ static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, } } if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) - return -EINVAL; + ret = -EINVAL; } - return 0; + mutex_unlock(&d->trip_mutex); + + return ret; } static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone, @@ -180,6 +188,8 @@ int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone) int trip_cnt = int34x_zone->aux_trip_nr; int i; + mutex_lock(&int34x_zone->trip_mutex); + int34x_zone->crt_trip_id = -1; if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_CRT", &int34x_zone->crt_temp)) @@ -207,6 +217,8 @@ int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone) int34x_zone->act_trips[i].valid = true; } + mutex_unlock(&int34x_zone->trip_mutex); + return trip_cnt; } EXPORT_SYMBOL_GPL(int340x_thermal_read_trips); @@ -230,6 +242,8 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, if (!int34x_thermal_zone) return ERR_PTR(-ENOMEM); + mutex_init(&int34x_thermal_zone->trip_mutex); + int34x_thermal_zone->adev = adev; int34x_thermal_zone->override_ops = override_ops; @@ -281,6 +295,7 @@ err_thermal_zone: acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); kfree(int34x_thermal_zone->aux_trips); err_trip_alloc: + mutex_destroy(&int34x_thermal_zone->trip_mutex); kfree(int34x_thermal_zone); return ERR_PTR(ret); } @@ -292,6 +307,7 @@ void int340x_thermal_zone_remove(struct int34x_thermal_zone thermal_zone_device_unregister(int34x_thermal_zone->zone); acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); kfree(int34x_thermal_zone->aux_trips); + mutex_destroy(&int34x_thermal_zone->trip_mutex); kfree(int34x_thermal_zone); } EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove); diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h index 3b4971df1b33..8f9872afd0d3 100644 --- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h +++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h @@ -32,6 +32,7 @@ struct int34x_thermal_zone { struct thermal_zone_device_ops *override_ops; void *priv_data; struct acpi_lpat_conversion_table *lpat_table; + struct mutex trip_mutex; }; struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *, diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c index 8c42e7662033..92ed1213fe37 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c @@ -172,6 +172,7 @@ static const struct attribute_group fivr_attribute_group = { RFIM_SHOW(rfi_restriction_run_busy, 1) RFIM_SHOW(rfi_restriction_err_code, 1) RFIM_SHOW(rfi_restriction_data_rate, 1) +RFIM_SHOW(rfi_restriction_data_rate_base, 1) RFIM_SHOW(ddr_data_rate_point_0, 1) RFIM_SHOW(ddr_data_rate_point_1, 1) RFIM_SHOW(ddr_data_rate_point_2, 1) @@ -181,11 +182,13 @@ RFIM_SHOW(rfi_disable, 1) RFIM_STORE(rfi_restriction_run_busy, 1) RFIM_STORE(rfi_restriction_err_code, 1) RFIM_STORE(rfi_restriction_data_rate, 1) +RFIM_STORE(rfi_restriction_data_rate_base, 1) RFIM_STORE(rfi_disable, 1) static DEVICE_ATTR_RW(rfi_restriction_run_busy); static DEVICE_ATTR_RW(rfi_restriction_err_code); static DEVICE_ATTR_RW(rfi_restriction_data_rate); +static DEVICE_ATTR_RW(rfi_restriction_data_rate_base); static DEVICE_ATTR_RO(ddr_data_rate_point_0); static DEVICE_ATTR_RO(ddr_data_rate_point_1); static DEVICE_ATTR_RO(ddr_data_rate_point_2); @@ -248,6 +251,7 @@ static struct attribute *dvfs_attrs[] = { &dev_attr_rfi_restriction_run_busy.attr, &dev_attr_rfi_restriction_err_code.attr, &dev_attr_rfi_restriction_data_rate.attr, + &dev_attr_rfi_restriction_data_rate_base.attr, &dev_attr_ddr_data_rate_point_0.attr, &dev_attr_ddr_data_rate_point_1.attr, &dev_attr_ddr_data_rate_point_2.attr, diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index f17ab2316dbd..77bd47d976a2 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -909,15 +909,20 @@ __thermal_cooling_device_register(struct device_node *np, cdev->devdata = devdata; ret = cdev->ops->get_max_state(cdev, &cdev->max_state); - if (ret) - goto out_kfree_type; + if (ret) { + kfree(cdev->type); + goto out_ida_remove; + } thermal_cooling_device_setup_sysfs(cdev); + ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id); if (ret) { + kfree(cdev->type); thermal_cooling_device_destroy_sysfs(cdev); - goto out_kfree_type; + goto out_ida_remove; } + ret = device_register(&cdev->device); if (ret) goto out_kfree_type; @@ -943,6 +948,8 @@ out_kfree_type: thermal_cooling_device_destroy_sysfs(cdev); kfree(cdev->type); put_device(&cdev->device); + + /* thermal_release() takes care of the rest */ cdev = NULL; out_ida_remove: ida_free(&thermal_cdev_ida, id); diff --git a/drivers/thunderbolt/retimer.c b/drivers/thunderbolt/retimer.c index 81252e31014a..56008eb91e2e 100644 --- a/drivers/thunderbolt/retimer.c +++ b/drivers/thunderbolt/retimer.c @@ -427,13 +427,6 @@ int tb_retimer_scan(struct tb_port *port, bool add) { u32 status[TB_MAX_RETIMER_INDEX + 1] = {}; int ret, i, last_idx = 0; - struct usb4_port *usb4; - - usb4 = port->usb4; - if (!usb4) - return 0; - - pm_runtime_get_sync(&usb4->dev); /* * Send broadcast RT to make sure retimer indices facing this @@ -441,7 +434,7 @@ int tb_retimer_scan(struct tb_port *port, bool add) */ ret = usb4_port_enumerate_retimers(port); if (ret) - goto out; + return ret; /* * Enable sideband channel for each retimer. We can do this @@ -471,12 +464,11 @@ int tb_retimer_scan(struct tb_port *port, bool add) break; } - if (!last_idx) { - ret = 0; - goto out; - } + if (!last_idx) + return 0; /* Add on-board retimers if they do not exist already */ + ret = 0; for (i = 1; i <= last_idx; i++) { struct tb_retimer *rt; @@ -490,10 +482,6 @@ int tb_retimer_scan(struct tb_port *port, bool add) } } -out: - pm_runtime_mark_last_busy(&usb4->dev); - pm_runtime_put_autosuspend(&usb4->dev); - return ret; } diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 462845804427..3f1ab30c4fb1 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -628,11 +628,15 @@ static void tb_scan_port(struct tb_port *port) * Downstream switch is reachable through two ports. * Only scan on the primary port (link_nr == 0). */ + + if (port->usb4) + pm_runtime_get_sync(&port->usb4->dev); + if (tb_wait_for_port(port, false) <= 0) - return; + goto out_rpm_put; if (port->remote) { tb_port_dbg(port, "port already has a remote\n"); - return; + goto out_rpm_put; } tb_retimer_scan(port, true); @@ -647,12 +651,12 @@ static void tb_scan_port(struct tb_port *port) */ if (PTR_ERR(sw) == -EIO || PTR_ERR(sw) == -EADDRNOTAVAIL) tb_scan_xdomain(port); - return; + goto out_rpm_put; } if (tb_switch_configure(sw)) { tb_switch_put(sw); - return; + goto out_rpm_put; } /* @@ -681,7 +685,7 @@ static void tb_scan_port(struct tb_port *port) if (tb_switch_add(sw)) { tb_switch_put(sw); - return; + goto out_rpm_put; } /* Link the switches using both links if available */ @@ -733,6 +737,12 @@ static void tb_scan_port(struct tb_port *port) tb_add_dp_resources(sw); tb_scan_switch(sw); + +out_rpm_put: + if (port->usb4) { + pm_runtime_mark_last_busy(&port->usb4->dev); + pm_runtime_put_autosuspend(&port->usb4->dev); + } } static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel) diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c index 2c3cf7fc3357..1fc3c29b24f8 100644 --- a/drivers/thunderbolt/tunnel.c +++ b/drivers/thunderbolt/tunnel.c @@ -1275,7 +1275,7 @@ static void tb_usb3_reclaim_available_bandwidth(struct tb_tunnel *tunnel, return; } else if (!ret) { /* Use maximum link rate if the link valid is not set */ - ret = usb4_usb3_port_max_link_rate(tunnel->src_port); + ret = tb_usb3_max_link_rate(tunnel->dst_port, tunnel->src_port); if (ret < 0) { tb_tunnel_warn(tunnel, "failed to read maximum link rate\n"); return; diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index cfa83486c9da..3c51e47dd86b 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -1419,12 +1419,19 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd) * registered, we notify the userspace that it has changed. */ if (!update) { - struct tb_port *port; + /* + * Now disable lane 1 if bonding was not enabled. Do + * this only if bonding was possible at the beginning + * (that is we are the connection manager and there are + * two lanes). + */ + if (xd->bonding_possible) { + struct tb_port *port; - /* Now disable lane 1 if bonding was not enabled */ - port = tb_port_at(xd->route, tb_xdomain_parent(xd)); - if (!port->bonded) - tb_port_disable(port->dual_link_port); + port = tb_port_at(xd->route, tb_xdomain_parent(xd)); + if (!port->bonded) + tb_port_disable(port->dual_link_port); + } if (device_add(&xd->dev)) { dev_err(&xd->dev, "failed to add XDomain device\n"); diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 7c23112dc923..5bddb2f5e931 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -52,17 +52,22 @@ static DEFINE_SPINLOCK(xencons_lock); static struct xencons_info *vtermno_to_xencons(int vtermno) { - struct xencons_info *entry, *n, *ret = NULL; + struct xencons_info *entry, *ret = NULL; + unsigned long flags; - if (list_empty(&xenconsoles)) - return NULL; + spin_lock_irqsave(&xencons_lock, flags); + if (list_empty(&xenconsoles)) { + spin_unlock_irqrestore(&xencons_lock, flags); + return NULL; + } - list_for_each_entry_safe(entry, n, &xenconsoles, list) { + list_for_each_entry(entry, &xenconsoles, list) { if (entry->vtermno == vtermno) { ret = entry; break; } } + spin_unlock_irqrestore(&xencons_lock, flags); return ret; } @@ -223,7 +228,7 @@ static int xen_hvm_console_init(void) { int r; uint64_t v = 0; - unsigned long gfn; + unsigned long gfn, flags; struct xencons_info *info; if (!xen_hvm_domain()) @@ -258,9 +263,9 @@ static int xen_hvm_console_init(void) goto err; info->vtermno = HVC_COOKIE; - spin_lock(&xencons_lock); + spin_lock_irqsave(&xencons_lock, flags); list_add_tail(&info->list, &xenconsoles); - spin_unlock(&xencons_lock); + spin_unlock_irqrestore(&xencons_lock, flags); return 0; err: @@ -283,6 +288,7 @@ static int xencons_info_pv_init(struct xencons_info *info, int vtermno) static int xen_pv_console_init(void) { struct xencons_info *info; + unsigned long flags; if (!xen_pv_domain()) return -ENODEV; @@ -299,9 +305,9 @@ static int xen_pv_console_init(void) /* already configured */ return 0; } - spin_lock(&xencons_lock); + spin_lock_irqsave(&xencons_lock, flags); xencons_info_pv_init(info, HVC_COOKIE); - spin_unlock(&xencons_lock); + spin_unlock_irqrestore(&xencons_lock, flags); return 0; } @@ -309,6 +315,7 @@ static int xen_pv_console_init(void) static int xen_initial_domain_console_init(void) { struct xencons_info *info; + unsigned long flags; if (!xen_initial_domain()) return -ENODEV; @@ -323,9 +330,9 @@ static int xen_initial_domain_console_init(void) info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0, false); info->vtermno = HVC_COOKIE; - spin_lock(&xencons_lock); + spin_lock_irqsave(&xencons_lock, flags); list_add_tail(&info->list, &xenconsoles); - spin_unlock(&xencons_lock); + spin_unlock_irqrestore(&xencons_lock, flags); return 0; } @@ -380,10 +387,12 @@ static void xencons_free(struct xencons_info *info) static int xen_console_remove(struct xencons_info *info) { + unsigned long flags; + xencons_disconnect_backend(info); - spin_lock(&xencons_lock); + spin_lock_irqsave(&xencons_lock, flags); list_del(&info->list); - spin_unlock(&xencons_lock); + spin_unlock_irqrestore(&xencons_lock, flags); if (info->xbdev != NULL) xencons_free(info); else { @@ -394,9 +403,9 @@ static int xen_console_remove(struct xencons_info *info) return 0; } -static int xencons_remove(struct xenbus_device *dev) +static void xencons_remove(struct xenbus_device *dev) { - return xen_console_remove(dev_get_drvdata(&dev->dev)); + xen_console_remove(dev_get_drvdata(&dev->dev)); } static int xencons_connect_backend(struct xenbus_device *dev, @@ -464,6 +473,7 @@ static int xencons_probe(struct xenbus_device *dev, { int ret, devid; struct xencons_info *info; + unsigned long flags; devid = dev->nodename[strlen(dev->nodename) - 1] - '0'; if (devid == 0) @@ -482,9 +492,9 @@ static int xencons_probe(struct xenbus_device *dev, ret = xencons_connect_backend(dev, info); if (ret < 0) goto error; - spin_lock(&xencons_lock); + spin_lock_irqsave(&xencons_lock, flags); list_add_tail(&info->list, &xenconsoles); - spin_unlock(&xencons_lock); + spin_unlock_irqrestore(&xencons_lock, flags); return 0; @@ -584,10 +594,12 @@ static int __init xen_hvc_init(void) info->hvc = hvc_alloc(HVC_COOKIE, info->irq, ops, 256); if (IS_ERR(info->hvc)) { + unsigned long flags; + r = PTR_ERR(info->hvc); - spin_lock(&xencons_lock); + spin_lock_irqsave(&xencons_lock, flags); list_del(&info->list); - spin_unlock(&xencons_lock); + spin_unlock_irqrestore(&xencons_lock, flags); if (info->irq) unbind_from_irqhandler(info->irq, NULL); kfree(info); diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 37d6af2ec427..7fa66501792d 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -43,15 +43,23 @@ static void __dma_rx_complete(struct uart_8250_port *p) struct uart_8250_dma *dma = p->dma; struct tty_port *tty_port = &p->port.state->port; struct dma_tx_state state; + enum dma_status dma_status; int count; - dma->rx_running = 0; - dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); + /* + * New DMA Rx can be started during the completion handler before it + * could acquire port's lock and it might still be ongoing. Don't to + * anything in such case. + */ + dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); + if (dma_status == DMA_IN_PROGRESS) + return; count = dma->rx_size - state.residue; tty_insert_flip_string(tty_port, dma->rx_buf, count); p->port.icount.rx += count; + dma->rx_running = 0; tty_flip_buffer_push(tty_port); } @@ -62,9 +70,14 @@ static void dma_rx_complete(void *param) struct uart_8250_dma *dma = p->dma; unsigned long flags; - __dma_rx_complete(p); - spin_lock_irqsave(&p->port.lock, flags); + if (dma->rx_running) + __dma_rx_complete(p); + + /* + * Cannot be combined with the previous check because __dma_rx_complete() + * changes dma->rx_running. + */ if (!dma->rx_running && (serial_lsr_in(p) & UART_LSR_DR)) p->dma->rx_dma(p); spin_unlock_irqrestore(&p->port.lock, flags); diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 314a05e009df..64770c62bbec 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -43,6 +43,12 @@ #define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358 #define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358 +#define PCI_DEVICE_ID_SEALEVEL_710xC 0x1001 +#define PCI_DEVICE_ID_SEALEVEL_720xC 0x1002 +#define PCI_DEVICE_ID_SEALEVEL_740xC 0x1004 +#define PCI_DEVICE_ID_SEALEVEL_780xC 0x1008 +#define PCI_DEVICE_ID_SEALEVEL_716xC 0x1010 + #define UART_EXAR_INT0 0x80 #define UART_EXAR_8XMODE 0x88 /* 8X sampling rate select */ #define UART_EXAR_SLEEP 0x8b /* Sleep mode */ @@ -638,6 +644,8 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) nr_ports = BIT(((pcidev->device & 0x38) >> 3) - 1); else if (board->num_ports) nr_ports = board->num_ports; + else if (pcidev->vendor == PCI_VENDOR_ID_SEALEVEL) + nr_ports = pcidev->device & 0xff; else nr_ports = pcidev->device & 0x0f; @@ -864,6 +872,12 @@ static const struct pci_device_id exar_pci_tbl[] = { EXAR_DEVICE(COMMTECH, 4224PCI335, pbn_fastcom335_4), EXAR_DEVICE(COMMTECH, 2324PCI335, pbn_fastcom335_4), EXAR_DEVICE(COMMTECH, 2328PCI335, pbn_fastcom335_8), + + EXAR_DEVICE(SEALEVEL, 710xC, pbn_exar_XR17V35x), + EXAR_DEVICE(SEALEVEL, 720xC, pbn_exar_XR17V35x), + EXAR_DEVICE(SEALEVEL, 740xC, pbn_exar_XR17V35x), + EXAR_DEVICE(SEALEVEL, 780xC, pbn_exar_XR17V35x), + EXAR_DEVICE(SEALEVEL, 716xC, pbn_exar_XR17V35x), { 0, } }; MODULE_DEVICE_TABLE(pci, exar_pci_tbl); diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index c55b947f3cdb..ed0672d2d0ef 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -242,23 +242,23 @@ config SERIAL_SAMSUNG select SERIAL_CORE help Support for the on-chip UARTs on the Samsung - S3C24xx/S3C64xx/S5Pv210/Exynos and Apple M1 SoCs, providing + S3C64xx/S5Pv210/Exynos and Apple M1 SoCs, providing /dev/ttySAC0, 1 and 2 (note, some machines may not provide all of these ports, depending on how the serial port pins are configured. + Choose Y/M here only if you build for such SoC. config SERIAL_SAMSUNG_UARTS_4 bool depends on SERIAL_SAMSUNG - default y if !(CPU_S3C2410 || CPU_S3C2412 || CPU_S3C2440 || CPU_S3C2442) + default y help Internal node for the common case of 4 Samsung compatible UARTs config SERIAL_SAMSUNG_UARTS int depends on SERIAL_SAMSUNG - default 4 if SERIAL_SAMSUNG_UARTS_4 || CPU_S3C2416 - default 3 + default 4 help Select the number of available UART ports for the Samsung S3C serial driver diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index d75c39f4622b..d8c2f3455eeb 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1466,6 +1466,10 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) struct circ_buf *xmit = &uap->port.state->xmit; int count = uap->fifosize >> 1; + if ((uap->port.rs485.flags & SER_RS485_ENABLED) && + !uap->rs485_tx_started) + pl011_rs485_tx_start(uap); + if (uap->port.x_char) { if (!pl011_tx_char(uap, uap->port.x_char, from_irq)) return true; @@ -1477,10 +1481,6 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) return false; } - if ((uap->port.rs485.flags & SER_RS485_ENABLED) && - !uap->rs485_tx_started) - pl011_rs485_tx_start(uap); - /* If we are using DMA mode, try to send some characters. */ if (pl011_dma_tx_irq(uap)) return true; diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index f1c06e12efa0..9cd7479b03c0 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2657,13 +2657,7 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud, else if (mr == ATMEL_US_PAR_ODD) *parity = 'o'; - /* - * The serial core only rounds down when matching this to a - * supported baud rate. Make sure we don't end up slightly - * lower than one of those, as it would make us fall through - * to a much lower baud rate than we really want. - */ - *baud = port->uartclk / (16 * (quot - 1)); + *baud = port->uartclk / (16 * quot); } static int __init atmel_console_setup(struct console *co, char *options) diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index a3ed9b34e2ab..7ce7bb164005 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -171,6 +171,7 @@ static int configure_kgdboc(void) int err = -ENODEV; char *cptr = config; struct console *cons; + int cookie; if (!strlen(config) || isspace(config[0])) { err = 0; @@ -189,20 +190,9 @@ static int configure_kgdboc(void) if (kgdboc_register_kbd(&cptr)) goto do_register; - /* - * tty_find_polling_driver() can call uart_set_options() - * (via poll_init) to configure the uart. Take the console_list_lock - * in order to synchronize against register_console(), which can also - * configure the uart via uart_set_options(). This also allows safe - * traversal of the console list. - */ - console_list_lock(); - p = tty_find_polling_driver(cptr, &tty_line); - if (!p) { - console_list_unlock(); + if (!p) goto noconfig; - } /* * Take console_lock to serialize device() callback with @@ -211,7 +201,8 @@ static int configure_kgdboc(void) */ console_lock(); - for_each_console(cons) { + cookie = console_srcu_read_lock(); + for_each_console_srcu(cons) { int idx; if (cons->device && cons->device(cons, &idx) == p && idx == tty_line) { @@ -219,11 +210,10 @@ static int configure_kgdboc(void) break; } } + console_srcu_read_unlock(cookie); console_unlock(); - console_list_unlock(); - kgdb_tty_driver = p; kgdb_tty_line = tty_line; diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 3d54a43768cd..9576ba8bbc40 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -749,7 +749,7 @@ static void pch_dma_tx_complete(void *arg) uart_xmit_advance(port, sg_dma_len(sg)); async_tx_ack(priv->desc_tx); - dma_unmap_sg(port->dev, sg, priv->orig_nent, DMA_TO_DEVICE); + dma_unmap_sg(port->dev, priv->sg_tx_p, priv->orig_nent, DMA_TO_DEVICE); priv->tx_dma_use = 0; priv->nent = 0; priv->orig_nent = 0; diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index b487823f0e61..57f04f8bf504 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -864,9 +864,10 @@ out_unlock: return IRQ_HANDLED; } -static void get_tx_fifo_size(struct qcom_geni_serial_port *port) +static int setup_fifos(struct qcom_geni_serial_port *port) { struct uart_port *uport; + u32 old_rx_fifo_depth = port->rx_fifo_depth; uport = &port->uport; port->tx_fifo_depth = geni_se_get_tx_fifo_depth(&port->se); @@ -874,6 +875,16 @@ static void get_tx_fifo_size(struct qcom_geni_serial_port *port) port->rx_fifo_depth = geni_se_get_rx_fifo_depth(&port->se); uport->fifosize = (port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE; + + if (port->rx_fifo && (old_rx_fifo_depth != port->rx_fifo_depth) && port->rx_fifo_depth) { + port->rx_fifo = devm_krealloc(uport->dev, port->rx_fifo, + port->rx_fifo_depth * sizeof(u32), + GFP_KERNEL); + if (!port->rx_fifo) + return -ENOMEM; + } + + return 0; } @@ -888,6 +899,7 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) u32 rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT; u32 proto; u32 pin_swap; + int ret; proto = geni_se_read_proto(&port->se); if (proto != GENI_SE_UART) { @@ -897,7 +909,9 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) qcom_geni_serial_stop_rx(uport); - get_tx_fifo_size(port); + ret = setup_fifos(port); + if (ret) + return ret; writel(rxstale, uport->membase + SE_UART_RX_STALE_CNT); @@ -1516,7 +1530,7 @@ static int qcom_geni_serial_remove(struct platform_device *pdev) return 0; } -static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev) +static int qcom_geni_serial_sys_suspend(struct device *dev) { struct qcom_geni_serial_port *port = dev_get_drvdata(dev); struct uart_port *uport = &port->uport; @@ -1533,7 +1547,7 @@ static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev) return uart_suspend_port(private_data->drv, uport); } -static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev) +static int qcom_geni_serial_sys_resume(struct device *dev) { int ret; struct qcom_geni_serial_port *port = dev_get_drvdata(dev); @@ -1581,10 +1595,12 @@ static int qcom_geni_serial_sys_hib_resume(struct device *dev) } static const struct dev_pm_ops qcom_geni_serial_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend, - qcom_geni_serial_sys_resume) - .restore = qcom_geni_serial_sys_hib_resume, - .thaw = qcom_geni_serial_sys_hib_resume, + .suspend = pm_sleep_ptr(qcom_geni_serial_sys_suspend), + .resume = pm_sleep_ptr(qcom_geni_serial_sys_resume), + .freeze = pm_sleep_ptr(qcom_geni_serial_sys_suspend), + .poweroff = pm_sleep_ptr(qcom_geni_serial_sys_suspend), + .restore = pm_sleep_ptr(qcom_geni_serial_sys_hib_resume), + .thaw = pm_sleep_ptr(qcom_geni_serial_sys_hib_resume), }; static const struct of_device_id qcom_geni_serial_match_table[] = { diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 0fce856434da..2a7520ad3abd 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -152,10 +152,6 @@ struct s3c24xx_uart_port { const struct s3c2410_uartcfg *cfg; struct s3c24xx_uart_dma *dma; - -#ifdef CONFIG_ARM_S3C24XX_CPUFREQ - struct notifier_block freq_transition; -#endif }; static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport); @@ -1855,93 +1851,6 @@ static void s3c24xx_serial_resetport(struct uart_port *port, udelay(1); } -#ifdef CONFIG_ARM_S3C24XX_CPUFREQ - -static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct s3c24xx_uart_port *port; - struct uart_port *uport; - - port = container_of(nb, struct s3c24xx_uart_port, freq_transition); - uport = &port->port; - - /* check to see if port is enabled */ - - if (port->pm_level != 0) - return 0; - - /* try and work out if the baudrate is changing, we can detect - * a change in rate, but we do not have support for detecting - * a disturbance in the clock-rate over the change. - */ - - if (IS_ERR(port->baudclk)) - goto exit; - - if (port->baudclk_rate == clk_get_rate(port->baudclk)) - goto exit; - - if (val == CPUFREQ_PRECHANGE) { - /* we should really shut the port down whilst the - * frequency change is in progress. - */ - - } else if (val == CPUFREQ_POSTCHANGE) { - struct ktermios *termios; - struct tty_struct *tty; - - if (uport->state == NULL) - goto exit; - - tty = uport->state->port.tty; - - if (tty == NULL) - goto exit; - - termios = &tty->termios; - - if (termios == NULL) { - dev_warn(uport->dev, "%s: no termios?\n", __func__); - goto exit; - } - - s3c24xx_serial_set_termios(uport, termios, NULL); - } - -exit: - return 0; -} - -static inline int -s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) -{ - port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition; - - return cpufreq_register_notifier(&port->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -static inline void -s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) -{ - cpufreq_unregister_notifier(&port->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -#else -static inline int -s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) -{ - return 0; -} - -static inline void -s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) -{ -} -#endif - static int s3c24xx_serial_enable_baudclk(struct s3c24xx_uart_port *ourport) { struct device *dev = ourport->port.dev; @@ -2233,10 +2142,6 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) if (!IS_ERR(ourport->baudclk)) clk_disable_unprepare(ourport->baudclk); - ret = s3c24xx_serial_cpufreq_register(ourport); - if (ret < 0) - dev_err(&pdev->dev, "failed to add cpufreq notifier\n"); - probe_index++; return 0; @@ -2247,7 +2152,6 @@ static int s3c24xx_serial_remove(struct platform_device *dev) struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); if (port) { - s3c24xx_serial_cpufreq_deregister(to_ourport(port)); uart_remove_one_port(&s3c24xx_uart_drv, port); } @@ -2585,94 +2489,6 @@ static struct console s3c24xx_serial_console = { }; #endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */ -#ifdef CONFIG_CPU_S3C2410 -static const struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = { - .info = { - .name = "Samsung S3C2410 UART", - .type = TYPE_S3C24XX, - .port_type = PORT_S3C2410, - .fifosize = 16, - .rx_fifomask = S3C2410_UFSTAT_RXMASK, - .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT, - .rx_fifofull = S3C2410_UFSTAT_RXFULL, - .tx_fifofull = S3C2410_UFSTAT_TXFULL, - .tx_fifomask = S3C2410_UFSTAT_TXMASK, - .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT, - .def_clk_sel = S3C2410_UCON_CLKSEL0, - .num_clks = 2, - .clksel_mask = S3C2410_UCON_CLKMASK, - .clksel_shift = S3C2410_UCON_CLKSHIFT, - }, - .def_cfg = { - .ucon = S3C2410_UCON_DEFAULT, - .ufcon = S3C2410_UFCON_DEFAULT, - }, -}; -#define S3C2410_SERIAL_DRV_DATA (&s3c2410_serial_drv_data) -#else -#define S3C2410_SERIAL_DRV_DATA NULL -#endif - -#ifdef CONFIG_CPU_S3C2412 -static const struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = { - .info = { - .name = "Samsung S3C2412 UART", - .type = TYPE_S3C24XX, - .port_type = PORT_S3C2412, - .fifosize = 64, - .has_divslot = 1, - .rx_fifomask = S3C2440_UFSTAT_RXMASK, - .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, - .rx_fifofull = S3C2440_UFSTAT_RXFULL, - .tx_fifofull = S3C2440_UFSTAT_TXFULL, - .tx_fifomask = S3C2440_UFSTAT_TXMASK, - .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, - .def_clk_sel = S3C2410_UCON_CLKSEL2, - .num_clks = 4, - .clksel_mask = S3C2412_UCON_CLKMASK, - .clksel_shift = S3C2412_UCON_CLKSHIFT, - }, - .def_cfg = { - .ucon = S3C2410_UCON_DEFAULT, - .ufcon = S3C2410_UFCON_DEFAULT, - }, -}; -#define S3C2412_SERIAL_DRV_DATA (&s3c2412_serial_drv_data) -#else -#define S3C2412_SERIAL_DRV_DATA NULL -#endif - -#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2416) || \ - defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2442) -static const struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { - .info = { - .name = "Samsung S3C2440 UART", - .type = TYPE_S3C24XX, - .port_type = PORT_S3C2440, - .fifosize = 64, - .has_divslot = 1, - .rx_fifomask = S3C2440_UFSTAT_RXMASK, - .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, - .rx_fifofull = S3C2440_UFSTAT_RXFULL, - .tx_fifofull = S3C2440_UFSTAT_TXFULL, - .tx_fifomask = S3C2440_UFSTAT_TXMASK, - .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, - .def_clk_sel = S3C2410_UCON_CLKSEL2, - .num_clks = 4, - .clksel_mask = S3C2412_UCON_CLKMASK, - .clksel_shift = S3C2412_UCON_CLKSHIFT, - .ucon_mask = S3C2440_UCON0_DIVMASK, - }, - .def_cfg = { - .ucon = S3C2410_UCON_DEFAULT, - .ufcon = S3C2410_UFCON_DEFAULT, - }, -}; -#define S3C2440_SERIAL_DRV_DATA (&s3c2440_serial_drv_data) -#else -#define S3C2440_SERIAL_DRV_DATA NULL -#endif - #if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) static const struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { .info = { @@ -2841,15 +2657,6 @@ static const struct s3c24xx_serial_drv_data artpec8_serial_drv_data = { static const struct platform_device_id s3c24xx_serial_driver_ids[] = { { - .name = "s3c2410-uart", - .driver_data = (kernel_ulong_t)S3C2410_SERIAL_DRV_DATA, - }, { - .name = "s3c2412-uart", - .driver_data = (kernel_ulong_t)S3C2412_SERIAL_DRV_DATA, - }, { - .name = "s3c2440-uart", - .driver_data = (kernel_ulong_t)S3C2440_SERIAL_DRV_DATA, - }, { .name = "s3c6400-uart", .driver_data = (kernel_ulong_t)S3C6400_SERIAL_DRV_DATA, }, { @@ -2877,12 +2684,6 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_serial_driver_ids); #ifdef CONFIG_OF static const struct of_device_id s3c24xx_uart_dt_match[] = { - { .compatible = "samsung,s3c2410-uart", - .data = S3C2410_SERIAL_DRV_DATA }, - { .compatible = "samsung,s3c2412-uart", - .data = S3C2412_SERIAL_DRV_DATA }, - { .compatible = "samsung,s3c2440-uart", - .data = S3C2440_SERIAL_DRV_DATA }, { .compatible = "samsung,s3c6400-uart", .data = S3C6400_SERIAL_DRV_DATA }, { .compatible = "samsung,s5pv210-uart", diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index b9fbbee598b8..ec874f3a567c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2212,6 +2212,9 @@ EXPORT_SYMBOL_GPL(uart_parse_options); * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) * @bits: number of data bits * @flow: flow control character - 'r' (rts) + * + * Locking: Caller must hold console_list_lock in order to serialize + * early initialization of the serial-console lock. */ int uart_set_options(struct uart_port *port, struct console *co, @@ -2619,7 +2622,9 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) if (!ret && options) { uart_parse_options(options, &baud, &parity, &bits, &flow); + console_list_lock(); ret = uart_set_options(port, NULL, baud, parity, bits, flow); + console_list_unlock(); } out: mutex_unlock(&tport->mutex); diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index a1490033aa16..409e91d6829a 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -797,25 +797,11 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) spin_unlock(&port->lock); } - if (stm32_usart_rx_dma_enabled(port)) - return IRQ_WAKE_THREAD; - else - return IRQ_HANDLED; -} - -static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr) -{ - struct uart_port *port = ptr; - struct tty_port *tport = &port->state->port; - struct stm32_port *stm32_port = to_stm32_port(port); - unsigned int size; - unsigned long flags; - /* Receiver timeout irq for DMA RX */ - if (!stm32_port->throttled) { - spin_lock_irqsave(&port->lock, flags); + if (stm32_usart_rx_dma_enabled(port) && !stm32_port->throttled) { + spin_lock(&port->lock); size = stm32_usart_receive_chars(port, false); - uart_unlock_and_check_sysrq_irqrestore(port, flags); + uart_unlock_and_check_sysrq(port); if (size) tty_flip_buffer_push(tport); } @@ -1015,10 +1001,8 @@ static int stm32_usart_startup(struct uart_port *port) u32 val; int ret; - ret = request_threaded_irq(port->irq, stm32_usart_interrupt, - stm32_usart_threaded_interrupt, - IRQF_ONESHOT | IRQF_NO_SUSPEND, - name, port); + ret = request_irq(port->irq, stm32_usart_interrupt, + IRQF_NO_SUSPEND, name, port); if (ret) return ret; @@ -1601,13 +1585,6 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, struct dma_slave_config config; int ret; - /* - * Using DMA and threaded handler for the console could lead to - * deadlocks. - */ - if (uart_console(port)) - return -ENODEV; - stm32port->rx_buf = dma_alloc_coherent(dev, RX_BUF_L, &stm32port->rx_dma_buf, GFP_KERNEL); diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 1850bacdb5b0..f566eb1839dc 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -386,10 +386,6 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) uni_mode = use_unicode(inode); attr = use_attributes(inode); - ret = -ENXIO; - vc = vcs_vc(inode, &viewed); - if (!vc) - goto unlock_out; ret = -EINVAL; if (pos < 0) @@ -407,6 +403,11 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) unsigned int this_round, skip = 0; int size; + ret = -ENXIO; + vc = vcs_vc(inode, &viewed); + if (!vc) + goto unlock_out; + /* Check whether we are above size each round, * as copy_to_user at the end of this loop * could sleep. diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index e18c9f4463ec..3a1c4d31e010 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -1234,12 +1234,14 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba) * clock scaling is in progress */ ufshcd_scsi_block_requests(hba); + mutex_lock(&hba->wb_mutex); down_write(&hba->clk_scaling_lock); if (!hba->clk_scaling.is_allowed || ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) { ret = -EBUSY; up_write(&hba->clk_scaling_lock); + mutex_unlock(&hba->wb_mutex); ufshcd_scsi_unblock_requests(hba); goto out; } @@ -1251,12 +1253,16 @@ out: return ret; } -static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, bool writelock) +static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err, bool scale_up) { - if (writelock) - up_write(&hba->clk_scaling_lock); - else - up_read(&hba->clk_scaling_lock); + up_write(&hba->clk_scaling_lock); + + /* Enable Write Booster if we have scaled up else disable it */ + if (ufshcd_enable_wb_if_scaling_up(hba) && !err) + ufshcd_wb_toggle(hba, scale_up); + + mutex_unlock(&hba->wb_mutex); + ufshcd_scsi_unblock_requests(hba); ufshcd_release(hba); } @@ -1273,7 +1279,6 @@ static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, bool writelock) static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) { int ret = 0; - bool is_writelock = true; ret = ufshcd_clock_scaling_prepare(hba); if (ret) @@ -1302,15 +1307,8 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) } } - /* Enable Write Booster if we have scaled up else disable it */ - if (ufshcd_enable_wb_if_scaling_up(hba)) { - downgrade_write(&hba->clk_scaling_lock); - is_writelock = false; - ufshcd_wb_toggle(hba, scale_up); - } - out_unprepare: - ufshcd_clock_scaling_unprepare(hba, is_writelock); + ufshcd_clock_scaling_unprepare(hba, ret, scale_up); return ret; } @@ -6056,11 +6054,21 @@ void ufshcd_schedule_eh_work(struct ufs_hba *hba) } } +static void ufshcd_force_error_recovery(struct ufs_hba *hba) +{ + spin_lock_irq(hba->host->host_lock); + hba->force_reset = true; + ufshcd_schedule_eh_work(hba); + spin_unlock_irq(hba->host->host_lock); +} + static void ufshcd_clk_scaling_allow(struct ufs_hba *hba, bool allow) { + mutex_lock(&hba->wb_mutex); down_write(&hba->clk_scaling_lock); hba->clk_scaling.is_allowed = allow; up_write(&hba->clk_scaling_lock); + mutex_unlock(&hba->wb_mutex); } static void ufshcd_clk_scaling_suspend(struct ufs_hba *hba, bool suspend) @@ -9083,6 +9091,15 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (!hba->dev_info.b_rpm_dev_flush_capable) { ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode); + if (ret && pm_op != UFS_SHUTDOWN_PM) { + /* + * If return err in suspend flow, IO will hang. + * Trigger error handler and break suspend for + * error recovery. + */ + ufshcd_force_error_recovery(hba); + ret = -EBUSY; + } if (ret) goto enable_scaling; } @@ -9094,6 +9111,15 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) */ check_for_bkops = !ufshcd_is_ufs_dev_deepsleep(hba); ret = ufshcd_link_state_transition(hba, req_link_state, check_for_bkops); + if (ret && pm_op != UFS_SHUTDOWN_PM) { + /* + * If return err in suspend flow, IO will hang. + * Trigger error handler and break suspend for + * error recovery. + */ + ufshcd_force_error_recovery(hba); + ret = -EBUSY; + } if (ret) goto set_dev_active; @@ -9767,6 +9793,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) /* Initialize mutex for exception event control */ mutex_init(&hba->ee_ctrl_mutex); + mutex_init(&hba->wb_mutex); init_rwsem(&hba->clk_scaling_lock); ufshcd_init_clk_gating(hba); diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c index 5adcb349718c..ccfaebca6faa 100644 --- a/drivers/usb/cdns3/cdns3-gadget.c +++ b/drivers/usb/cdns3/cdns3-gadget.c @@ -2614,6 +2614,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep, u8 req_on_hw_ring = 0; unsigned long flags; int ret = 0; + int val; if (!ep || !request || !ep->desc) return -EINVAL; @@ -2649,6 +2650,13 @@ found: /* Update ring only if removed request is on pending_req_list list */ if (req_on_hw_ring && link_trb) { + /* Stop DMA */ + writel(EP_CMD_DFLUSH, &priv_dev->regs->ep_cmd); + + /* wait for DFLUSH cleared */ + readl_poll_timeout_atomic(&priv_dev->regs->ep_cmd, val, + !(val & EP_CMD_DFLUSH), 1, 1000); + link_trb->buffer = cpu_to_le32(TRB_BUFFER(priv_ep->trb_pool_dma + ((priv_req->end_trb + 1) * TRB_SIZE))); link_trb->control = cpu_to_le32((le32_to_cpu(link_trb->control) & TRB_CYCLE) | @@ -2660,6 +2668,10 @@ found: cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET); + req = cdns3_next_request(&priv_ep->pending_req_list); + if (req) + cdns3_rearm_transfer(priv_ep, 1); + not_found: spin_unlock_irqrestore(&priv_dev->lock, flags); return ret; diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 484b1cd23431..27c601296130 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -1294,12 +1294,12 @@ static void ci_extcon_wakeup_int(struct ci_hdrc *ci) cable_id = &ci->platdata->id_extcon; cable_vbus = &ci->platdata->vbus_extcon; - if ((!IS_ERR(cable_id->edev) || !IS_ERR(ci->role_switch)) + if ((!IS_ERR(cable_id->edev) || ci->role_switch) && ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) ci_irq(ci); - if ((!IS_ERR(cable_vbus->edev) || !IS_ERR(ci->role_switch)) + if ((!IS_ERR(cable_vbus->edev) || ci->role_switch) && ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) ci_irq(ci); diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index 60e8174686a1..d7c8461976ce 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -207,7 +207,7 @@ static int ulpi_read_id(struct ulpi *ulpi) /* Test the interface */ ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa); if (ret < 0) - return ret; + goto err; ret = ulpi_read(ulpi, ULPI_SCRATCH); if (ret < 0) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 77e73fc8d673..9eca403af2a8 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -44,6 +44,9 @@ #define USB_PRODUCT_USB5534B 0x5534 #define USB_VENDOR_CYPRESS 0x04b4 #define USB_PRODUCT_CY7C65632 0x6570 +#define USB_VENDOR_TEXAS_INSTRUMENTS 0x0451 +#define USB_PRODUCT_TUSB8041_USB3 0x8140 +#define USB_PRODUCT_TUSB8041_USB2 0x8142 #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01 #define HUB_QUIRK_DISABLE_AUTOSUSPEND 0x02 @@ -5854,6 +5857,16 @@ static const struct usb_device_id hub_id_table[] = { .idVendor = USB_VENDOR_GENESYS_LOGIC, .bInterfaceClass = USB_CLASS_HUB, .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND}, + { .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT, + .idVendor = USB_VENDOR_TEXAS_INSTRUMENTS, + .idProduct = USB_PRODUCT_TUSB8041_USB2, + .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND}, + { .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT, + .idVendor = USB_VENDOR_TEXAS_INSTRUMENTS, + .idProduct = USB_PRODUCT_TUSB8041_USB3, + .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND}, { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, .bDeviceClass = USB_CLASS_HUB}, { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 079e183cf3bf..934b3d997702 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -526,6 +526,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* DJI CineSSD */ { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM }, + /* Alcor Link AK9563 SC Reader used in 2022 Lenovo ThinkPads */ + { USB_DEVICE(0x2ce3, 0x9563), .driver_info = USB_QUIRK_NO_LPM }, + /* DELL USB GEN2 */ { USB_DEVICE(0x413c, 0xb062), .driver_info = USB_QUIRK_NO_LPM | USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 6d93428432f1..533baa85083c 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -37,6 +37,71 @@ bool usb_acpi_power_manageable(struct usb_device *hdev, int index) } EXPORT_SYMBOL_GPL(usb_acpi_power_manageable); +#define UUID_USB_CONTROLLER_DSM "ce2ee385-00e6-48cb-9f05-2edb927c4899" +#define USB_DSM_DISABLE_U1_U2_FOR_PORT 5 + +/** + * usb_acpi_port_lpm_incapable - check if lpm should be disabled for a port. + * @hdev: USB device belonging to the usb hub + * @index: zero based port index + * + * Some USB3 ports may not support USB3 link power management U1/U2 states + * due to different retimer setup. ACPI provides _DSM method which returns 0x01 + * if U1 and U2 states should be disabled. Evaluate _DSM with: + * Arg0: UUID = ce2ee385-00e6-48cb-9f05-2edb927c4899 + * Arg1: Revision ID = 0 + * Arg2: Function Index = 5 + * Arg3: (empty) + * + * Return 1 if USB3 port is LPM incapable, negative on error, otherwise 0 + */ + +int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index) +{ + union acpi_object *obj; + acpi_handle port_handle; + int port1 = index + 1; + guid_t guid; + int ret; + + ret = guid_parse(UUID_USB_CONTROLLER_DSM, &guid); + if (ret) + return ret; + + port_handle = usb_get_hub_port_acpi_handle(hdev, port1); + if (!port_handle) { + dev_dbg(&hdev->dev, "port-%d no acpi handle\n", port1); + return -ENODEV; + } + + if (!acpi_check_dsm(port_handle, &guid, 0, + BIT(USB_DSM_DISABLE_U1_U2_FOR_PORT))) { + dev_dbg(&hdev->dev, "port-%d no _DSM function %d\n", + port1, USB_DSM_DISABLE_U1_U2_FOR_PORT); + return -ENODEV; + } + + obj = acpi_evaluate_dsm(port_handle, &guid, 0, + USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL); + + if (!obj) + return -ENODEV; + + if (obj->type != ACPI_TYPE_INTEGER) { + dev_dbg(&hdev->dev, "evaluate port-%d _DSM failed\n", port1); + ACPI_FREE(obj); + return -EINVAL; + } + + if (obj->integer.value == 0x01) + ret = 1; + + ACPI_FREE(obj); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_acpi_port_lpm_incapable); + /** * usb_acpi_set_power_state - control usb port's power via acpi power * resource diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index b2f72b0e75c6..be954a9abbe0 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -3,6 +3,7 @@ config USB_DWC3 tristate "DesignWare USB3 DRD Core Support" depends on (USB || USB_GADGET) && HAS_DMA + depends on (EXTCON || EXTCON=n) select USB_XHCI_PLATFORM if USB_XHCI_HCD select USB_ROLE_SWITCH if USB_DWC3_DUAL_ROLE help @@ -44,7 +45,6 @@ config USB_DWC3_GADGET config USB_DWC3_DUAL_ROLE bool "Dual Role mode" depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3)) - depends on (EXTCON=y || EXTCON=USB_DWC3) help This is the default mode of working of DWC3 controller where both host and gadget features are enabled. diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index b0a0351d2d8b..959fc925ca7c 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -901,7 +901,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev) qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev); /* enable vbus override for device mode */ - if (qcom->mode == USB_DR_MODE_PERIPHERAL) + if (qcom->mode != USB_DR_MODE_HOST) dwc3_qcom_vbus_override_enable(qcom, true); /* register extcon to override sw_vbus on Vbus change later */ diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c index 8607d4c23283..0745e9f11b2e 100644 --- a/drivers/usb/dwc3/dwc3-xilinx.c +++ b/drivers/usb/dwc3/dwc3-xilinx.c @@ -13,6 +13,7 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/gpio/consumer.h> #include <linux/of_gpio.h> #include <linux/of_platform.h> #include <linux/pm_runtime.h> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 789976567f9f..89dcfac01235 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1727,6 +1727,7 @@ static int __dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool int else if (!ret) dep->flags |= DWC3_EP_END_TRANSFER_PENDING; + dep->flags &= ~DWC3_EP_DELAY_STOP; return ret; } @@ -3732,8 +3733,10 @@ void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, if (dep->number <= 1 && dwc->ep0state != EP0_DATA_PHASE) return; + if (interrupt && (dep->flags & DWC3_EP_DELAY_STOP)) + return; + if (!(dep->flags & DWC3_EP_TRANSFER_STARTED) || - (dep->flags & DWC3_EP_DELAY_STOP) || (dep->flags & DWC3_EP_END_TRANSFER_PENDING)) return; diff --git a/drivers/usb/fotg210/fotg210-core.c b/drivers/usb/fotg210/fotg210-core.c index 8a54edf921ac..ee740a6da463 100644 --- a/drivers/usb/fotg210/fotg210-core.c +++ b/drivers/usb/fotg210/fotg210-core.c @@ -144,10 +144,7 @@ static struct platform_driver fotg210_driver = { static int __init fotg210_init(void) { - if (usb_disabled()) - return -ENODEV; - - if (IS_ENABLED(CONFIG_USB_FOTG210_HCD)) + if (IS_ENABLED(CONFIG_USB_FOTG210_HCD) && !usb_disabled()) fotg210_hcd_init(); return platform_driver_register(&fotg210_driver); } diff --git a/drivers/usb/fotg210/fotg210-udc.c b/drivers/usb/fotg210/fotg210-udc.c index 66e1b7ee3346..eb076746f032 100644 --- a/drivers/usb/fotg210/fotg210-udc.c +++ b/drivers/usb/fotg210/fotg210-udc.c @@ -1014,7 +1014,6 @@ static int fotg210_udc_start(struct usb_gadget *g, int ret; /* hook up the driver */ - driver->driver.bus = NULL; fotg210->driver = driver; if (!IS_ERR_OR_NULL(fotg210->phy)) { @@ -1201,6 +1200,8 @@ int fotg210_udc_probe(struct platform_device *pdev) dev_info(dev, "found and initialized PHY\n"); } + ret = -ENOMEM; + for (i = 0; i < FOTG210_MAX_NUM_EP; i++) { fotg210->ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL); if (!fotg210->ep[i]) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 96121d1c8df4..0853536cbf2e 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -393,6 +393,7 @@ static void gadget_info_attr_release(struct config_item *item) WARN_ON(!list_empty(&gi->string_list)); WARN_ON(!list_empty(&gi->available_func)); kfree(gi->composite.gadget_driver.function); + kfree(gi->composite.gadget_driver.driver.name); kfree(gi); } @@ -1572,7 +1573,6 @@ static const struct usb_gadget_driver configfs_driver_template = { .max_speed = USB_SPEED_SUPER_PLUS, .driver = { .owner = THIS_MODULE, - .name = "configfs-gadget", }, .match_existing_only = 1, }; @@ -1623,13 +1623,21 @@ static struct config_group *gadgets_make( gi->composite.gadget_driver = configfs_driver_template; + gi->composite.gadget_driver.driver.name = kasprintf(GFP_KERNEL, + "configfs-gadget.%s", name); + if (!gi->composite.gadget_driver.driver.name) + goto err; + gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL); gi->composite.name = gi->composite.gadget_driver.function; if (!gi->composite.gadget_driver.function) - goto err; + goto out_free_driver_name; return &gi->group; + +out_free_driver_name: + kfree(gi->composite.gadget_driver.driver.name); err: kfree(gi); return ERR_PTR(-ENOMEM); diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 73dc10a77cde..8ad354741380 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -279,6 +279,11 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) struct usb_request *req = ffs->ep0req; int ret; + if (!req) { + spin_unlock_irq(&ffs->ev.waitq.lock); + return -EINVAL; + } + req->zero = len < le16_to_cpu(ffs->ev.setup.wLength); spin_unlock_irq(&ffs->ev.waitq.lock); @@ -1892,10 +1897,14 @@ static void functionfs_unbind(struct ffs_data *ffs) ENTER(); if (!WARN_ON(!ffs->gadget)) { + /* dequeue before freeing ep0req */ + usb_ep_dequeue(ffs->gadget->ep0, ffs->ep0req); + mutex_lock(&ffs->mutex); usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req); ffs->ep0req = NULL; ffs->gadget = NULL; clear_bit(FFS_FL_BOUND, &ffs->flags); + mutex_unlock(&ffs->mutex); ffs_data_put(ffs); } } diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index c36bcfa0e9b4..424bb3b666db 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -83,7 +83,9 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f) /* peak (theoretical) bulk transfer rate in bits-per-second */ static inline unsigned ncm_bitrate(struct usb_gadget *g) { - if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS) + if (!g) + return 0; + else if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS) return 4250000000U; else if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) return 3750000000U; diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 08726e4c68a5..0219cd79493a 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -1142,6 +1142,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) } std_as_out_if0_desc.bInterfaceNumber = ret; std_as_out_if1_desc.bInterfaceNumber = ret; + std_as_out_if1_desc.bNumEndpoints = 1; uac2->as_out_intf = ret; uac2->as_out_alt = 0; diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 8f12f3f8f6ee..e06022873df1 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -798,6 +798,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, net->max_mtu = GETHER_MAX_MTU_SIZE; dev->gadget = g; + SET_NETDEV_DEV(net, &g->dev); SET_NETDEV_DEVTYPE(net, &gadget_type); status = register_netdev(net); @@ -872,6 +873,8 @@ int gether_register_netdev(struct net_device *net) struct usb_gadget *g; int status; + if (!net->dev.parent) + return -EINVAL; dev = netdev_priv(net); g = dev->gadget; @@ -902,6 +905,7 @@ void gether_set_gadget(struct net_device *net, struct usb_gadget *g) dev = netdev_priv(net); dev->gadget = g; + SET_NETDEV_DEV(net, &g->dev); } EXPORT_SYMBOL_GPL(gether_set_gadget); diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index 01c3ead7d1b4..d605bc2e7e8f 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -229,6 +229,7 @@ static void put_ep (struct ep_data *data) */ static const char *CHIP; +static DEFINE_MUTEX(sb_mutex); /* Serialize superblock operations */ /*----------------------------------------------------------------------*/ @@ -2010,13 +2011,20 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc) { struct inode *inode; struct dev_data *dev; + int rc; - if (the_device) - return -ESRCH; + mutex_lock(&sb_mutex); + + if (the_device) { + rc = -ESRCH; + goto Done; + } CHIP = usb_get_gadget_udc_name(); - if (!CHIP) - return -ENODEV; + if (!CHIP) { + rc = -ENODEV; + goto Done; + } /* superblock */ sb->s_blocksize = PAGE_SIZE; @@ -2053,13 +2061,17 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc) * from binding to a controller. */ the_device = dev; - return 0; + rc = 0; + goto Done; -Enomem: + Enomem: kfree(CHIP); CHIP = NULL; + rc = -ENOMEM; - return -ENOMEM; + Done: + mutex_unlock(&sb_mutex); + return rc; } /* "mount -t gadgetfs path /dev/gadget" ends up here */ @@ -2081,6 +2093,7 @@ static int gadgetfs_init_fs_context(struct fs_context *fc) static void gadgetfs_kill_sb (struct super_block *sb) { + mutex_lock(&sb_mutex); kill_litter_super (sb); if (the_device) { put_dev (the_device); @@ -2088,6 +2101,7 @@ gadgetfs_kill_sb (struct super_block *sb) } kfree(CHIP); CHIP = NULL; + mutex_unlock(&sb_mutex); } /*----------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c index 53e38f87472b..c06dd1af7a0c 100644 --- a/drivers/usb/gadget/legacy/webcam.c +++ b/drivers/usb/gadget/legacy/webcam.c @@ -293,6 +293,7 @@ static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = { (const struct uvc_descriptor_header *) &uvc_format_yuv, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, + (const struct uvc_descriptor_header *) &uvc_color_matching, (const struct uvc_descriptor_header *) &uvc_format_mjpg, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, @@ -305,6 +306,7 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = { (const struct uvc_descriptor_header *) &uvc_format_yuv, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, + (const struct uvc_descriptor_header *) &uvc_color_matching, (const struct uvc_descriptor_header *) &uvc_format_mjpg, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, @@ -317,6 +319,7 @@ static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = { (const struct uvc_descriptor_header *) &uvc_format_yuv, (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, + (const struct uvc_descriptor_header *) &uvc_color_matching, (const struct uvc_descriptor_header *) &uvc_format_mjpg, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index b3006d8b04ab..511ab57cdc81 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -118,7 +118,6 @@ config USB_GR_UDC config USB_OMAP tristate "OMAP USB Device Controller" depends on ARCH_OMAP1 - depends on ISP1301_OMAP || !(MACH_OMAP_H2 || MACH_OMAP_H3) help Many Texas Instruments OMAP processors have flexible full speed USB device controllers, with support for up to 30 @@ -207,31 +206,6 @@ config USB_PXA27X dynamically linked module called "pxa27x_udc" and force all gadget drivers to also be dynamically linked. -config USB_S3C2410 - tristate "S3C2410 USB Device Controller" - depends on ARCH_S3C24XX - help - Samsung's S3C2410 is an ARM-4 processor with an integrated - full speed USB 1.1 device controller. It has 4 configurable - endpoints, as well as endpoint zero (for control transfers). - - This driver has been tested on the S3C2410, S3C2412, and - S3C2440 processors. - -config USB_S3C2410_DEBUG - bool "S3C2410 udc debug messages" - depends on USB_S3C2410 - -config USB_S3C_HSUDC - tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller" - depends on ARCH_S3C24XX - help - Samsung's S3C2416, S3C2443 and S3C2450 is an ARM9 based SoC - integrated with dual speed USB 2.0 device controller. It has - 8 endpoints, as well as endpoint zero. - - This driver has been tested on S3C2416 and S3C2450 processors. - config USB_MV_UDC tristate "Marvell USB2.0 Device Controller" depends on HAS_DMA diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile index 39daf36a2baa..239ea22bdfd9 100644 --- a/drivers/usb/gadget/udc/Makefile +++ b/drivers/usb/gadget/udc/Makefile @@ -17,7 +17,6 @@ obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o obj-$(CONFIG_USB_GOKU) += goku_udc.o obj-$(CONFIG_USB_OMAP) += omap_udc.o -obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o obj-$(CONFIG_USB_AT91) += at91_udc.o obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o obj-$(CONFIG_USB_BCM63XX_UDC) += bcm63xx_udc.o @@ -28,7 +27,6 @@ obj-$(CONFIG_USB_M66592) += m66592-udc.o obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o obj-$(CONFIG_USB_RENESAS_USB3) += renesas_usb3.o obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o -obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o obj-$(CONFIG_USB_EG20T) += pch_udc.o obj-$(CONFIG_USB_MV_UDC) += mv_udc.o diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c index 2cdb07905bde..d04d72f5816e 100644 --- a/drivers/usb/gadget/udc/bcm63xx_udc.c +++ b/drivers/usb/gadget/udc/bcm63xx_udc.c @@ -1830,7 +1830,6 @@ static int bcm63xx_udc_start(struct usb_gadget *gadget, bcm63xx_select_phy_mode(udc, true); udc->driver = driver; - driver->driver.bus = NULL; udc->gadget.dev.of_node = udc->dev->of_node; spin_unlock_irqrestore(&udc->lock, flags); diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index bf745358e28e..3b1cc8fa30c8 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -2285,7 +2285,6 @@ static int fsl_qe_start(struct usb_gadget *gadget, /* lock is needed but whether should use this lock or another */ spin_lock_irqsave(&udc->lock, flags); - driver->driver.bus = NULL; /* hook up the driver */ udc->driver = driver; udc->gadget.speed = driver->max_speed; diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index 50435e804118..a67873a074b7 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -1943,7 +1943,6 @@ static int fsl_udc_start(struct usb_gadget *g, /* lock is needed but whether should use this lock or another */ spin_lock_irqsave(&udc_controller->lock, flags); - driver->driver.bus = NULL; /* hook up the driver */ udc_controller->driver = driver; spin_unlock_irqrestore(&udc_controller->lock, flags); diff --git a/drivers/usb/gadget/udc/fusb300_udc.c b/drivers/usb/gadget/udc/fusb300_udc.c index 9af8b415f303..5954800d652c 100644 --- a/drivers/usb/gadget/udc/fusb300_udc.c +++ b/drivers/usb/gadget/udc/fusb300_udc.c @@ -1311,7 +1311,6 @@ static int fusb300_udc_start(struct usb_gadget *g, struct fusb300 *fusb300 = to_fusb300(g); /* hook up the driver */ - driver->driver.bus = NULL; fusb300->driver = driver; return 0; diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index bdc56b24b5c9..5ffb3d5c635b 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -1375,7 +1375,6 @@ static int goku_udc_start(struct usb_gadget *g, struct goku_udc *dev = to_goku_udc(g); /* hook up the driver */ - driver->driver.bus = NULL; dev->driver = driver; /* diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index 22096f8505de..85cdc0af3bf9 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -1906,7 +1906,6 @@ static int gr_udc_start(struct usb_gadget *gadget, spin_lock(&dev->lock); /* Hook up the driver */ - driver->driver.bus = NULL; dev->driver = driver; /* Get ready for host detection */ diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index c7e421b449f3..06e21cee431b 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -1454,7 +1454,6 @@ static int m66592_udc_start(struct usb_gadget *g, struct m66592 *m66592 = to_m66592(g); /* hook up the driver */ - driver->driver.bus = NULL; m66592->driver = driver; m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); diff --git a/drivers/usb/gadget/udc/max3420_udc.c b/drivers/usb/gadget/udc/max3420_udc.c index 3074da00c3df..ddf0ed3eb4f2 100644 --- a/drivers/usb/gadget/udc/max3420_udc.c +++ b/drivers/usb/gadget/udc/max3420_udc.c @@ -1108,7 +1108,6 @@ static int max3420_udc_start(struct usb_gadget *gadget, spin_lock_irqsave(&udc->lock, flags); /* hook up the driver */ - driver->driver.bus = NULL; udc->driver = driver; udc->gadget.speed = USB_SPEED_FULL; diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c index 598654a3cb41..411b6179782c 100644 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ b/drivers/usb/gadget/udc/mv_u3d_core.c @@ -1243,7 +1243,6 @@ static int mv_u3d_start(struct usb_gadget *g, } /* hook up the driver ... */ - driver->driver.bus = NULL; u3d->driver = driver; u3d->ep0_dir = USB_DIR_OUT; diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index fdb17d86cd65..b397f3a848cf 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -1359,7 +1359,6 @@ static int mv_udc_start(struct usb_gadget *gadget, spin_lock_irqsave(&udc->lock, flags); /* hook up the driver ... */ - driver->driver.bus = NULL; udc->driver = driver; udc->usb_state = USB_STATE_ATTACHED; diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 84605a4d0715..538c1b9a2883 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -1451,7 +1451,6 @@ static int net2272_start(struct usb_gadget *_gadget, dev->ep[i].irqs = 0; /* hook up the driver ... */ dev->softconnect = 1; - driver->driver.bus = NULL; dev->driver = driver; /* ... then enable host detection and ep0; and we're ready diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index d6a68631354a..1b929c519cd7 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -2423,7 +2423,6 @@ static int net2280_start(struct usb_gadget *_gadget, dev->ep[i].irqs = 0; /* hook up the driver ... */ - driver->driver.bus = NULL; dev->driver = driver; retval = device_create_file(&dev->pdev->dev, &dev_attr_function); diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index bea346e362b2..2d87c7cd5f7e 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -2036,12 +2036,7 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev) static inline int machine_without_vbus_sense(void) { - return machine_is_omap_innovator() - || machine_is_omap_osk() - || machine_is_omap_palmte() - || machine_is_sx1() - /* No known omap7xx boards with vbus sense */ - || cpu_is_omap7xx(); + return machine_is_omap_osk() || machine_is_sx1(); } static int omap_udc_start(struct usb_gadget *g, @@ -2066,7 +2061,6 @@ static int omap_udc_start(struct usb_gadget *g, udc->softconnect = 1; /* hook up the driver */ - driver->driver.bus = NULL; udc->driver = driver; spin_unlock_irqrestore(&udc->lock, flags); @@ -2759,9 +2753,6 @@ static int omap_udc_probe(struct platform_device *pdev) struct clk *dc_clk = NULL; struct clk *hhc_clk = NULL; - if (cpu_is_omap7xx()) - use_dma = 0; - /* NOTE: "knows" the order of the resources! */ if (!request_mem_region(pdev->resource[0].start, resource_size(&pdev->resource[0]), @@ -2780,16 +2771,6 @@ static int omap_udc_probe(struct platform_device *pdev) udelay(100); } - if (cpu_is_omap7xx()) { - dc_clk = clk_get(&pdev->dev, "usb_dc_ck"); - hhc_clk = clk_get(&pdev->dev, "l3_ocpi_ck"); - BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk)); - /* can't use omap_udc_enable_clock yet */ - clk_prepare_enable(dc_clk); - clk_prepare_enable(hhc_clk); - udelay(100); - } - INFO("OMAP UDC rev %d.%d%s\n", omap_readw(UDC_REV) >> 4, omap_readw(UDC_REV) & 0xf, config->otg ? ", Mini-AB" : ""); @@ -2914,7 +2895,7 @@ bad_on_1710: goto cleanup1; } #endif - if (cpu_is_omap16xx() || cpu_is_omap7xx()) { + if (cpu_is_omap16xx()) { udc->dc_clk = dc_clk; udc->hhc_clk = hhc_clk; clk_disable(hhc_clk); @@ -2933,7 +2914,7 @@ cleanup0: if (!IS_ERR_OR_NULL(xceiv)) usb_put_phy(xceiv); - if (cpu_is_omap16xx() || cpu_is_omap7xx()) { + if (cpu_is_omap16xx()) { clk_disable_unprepare(hhc_clk); clk_disable_unprepare(dc_clk); clk_put(hhc_clk); diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 9bb7a9d7a2fb..4f8617210d85 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -2908,7 +2908,6 @@ static int pch_udc_start(struct usb_gadget *g, { struct pch_udc_dev *dev = to_pch_udc(g); - driver->driver.bus = NULL; dev->driver = driver; /* get ready for ep0 traffic */ diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index c593fc383481..e19b84a46a1e 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -1561,40 +1561,6 @@ static int pxa25x_udc_stop(struct usb_gadget*g) /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_ARCH_LUBBOCK - -/* Lubbock has separate connect and disconnect irqs. More typical designs - * use one GPIO as the VBUS IRQ, and another to control the D+ pullup. - */ - -static irqreturn_t -lubbock_vbus_irq(int irq, void *_dev) -{ - struct pxa25x_udc *dev = _dev; - int vbus; - - dev->stats.irqs++; - if (irq == dev->usb_irq) { - vbus = 1; - disable_irq(dev->usb_irq); - enable_irq(dev->usb_disc_irq); - } else if (irq == dev->usb_disc_irq) { - vbus = 0; - disable_irq(dev->usb_disc_irq); - enable_irq(dev->usb_irq); - } else { - return IRQ_NONE; - } - - pxa25x_udc_vbus_session(&dev->gadget, vbus); - return IRQ_HANDLED; -} - -#endif - - -/*-------------------------------------------------------------------------*/ - static inline void clear_ep_state (struct pxa25x_udc *dev) { unsigned i; @@ -2413,34 +2379,6 @@ static int pxa25x_udc_probe(struct platform_device *pdev) } dev->got_irq = 1; -#ifdef CONFIG_ARCH_LUBBOCK - if (machine_is_lubbock()) { - dev->usb_irq = platform_get_irq(pdev, 1); - if (dev->usb_irq < 0) - return dev->usb_irq; - - dev->usb_disc_irq = platform_get_irq(pdev, 2); - if (dev->usb_disc_irq < 0) - return dev->usb_disc_irq; - - retval = devm_request_irq(&pdev->dev, dev->usb_disc_irq, - lubbock_vbus_irq, 0, driver_name, - dev); - if (retval != 0) { - pr_err("%s: can't get irq %i, err %d\n", - driver_name, dev->usb_disc_irq, retval); - goto err; - } - retval = devm_request_irq(&pdev->dev, dev->usb_irq, - lubbock_vbus_irq, 0, driver_name, - dev); - if (retval != 0) { - pr_err("%s: can't get irq %i, err %d\n", - driver_name, dev->usb_irq, retval); - goto err; - } - } else -#endif create_debug_files(dev); retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c deleted file mode 100644 index 4b7eb7701470..000000000000 --- a/drivers/usb/gadget/udc/s3c-hsudc.c +++ /dev/null @@ -1,1319 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* linux/drivers/usb/gadget/s3c-hsudc.c - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * S3C24XX USB 2.0 High-speed USB controller gadget driver - * - * The S3C24XX USB 2.0 high-speed USB controller supports upto 9 endpoints. - * Each endpoint can be configured as either in or out endpoint. Endpoints - * can be configured for Bulk or Interrupt transfer mode. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/dma-mapping.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <linux/usb/otg.h> -#include <linux/prefetch.h> -#include <linux/platform_data/s3c-hsudc.h> -#include <linux/regulator/consumer.h> -#include <linux/pm_runtime.h> - -#define S3C_HSUDC_REG(x) (x) - -/* Non-Indexed Registers */ -#define S3C_IR S3C_HSUDC_REG(0x00) /* Index Register */ -#define S3C_EIR S3C_HSUDC_REG(0x04) /* EP Intr Status */ -#define S3C_EIR_EP0 (1<<0) -#define S3C_EIER S3C_HSUDC_REG(0x08) /* EP Intr Enable */ -#define S3C_FAR S3C_HSUDC_REG(0x0c) /* Gadget Address */ -#define S3C_FNR S3C_HSUDC_REG(0x10) /* Frame Number */ -#define S3C_EDR S3C_HSUDC_REG(0x14) /* EP Direction */ -#define S3C_TR S3C_HSUDC_REG(0x18) /* Test Register */ -#define S3C_SSR S3C_HSUDC_REG(0x1c) /* System Status */ -#define S3C_SSR_DTZIEN_EN (0xff8f) -#define S3C_SSR_ERR (0xff80) -#define S3C_SSR_VBUSON (1 << 8) -#define S3C_SSR_HSP (1 << 4) -#define S3C_SSR_SDE (1 << 3) -#define S3C_SSR_RESUME (1 << 2) -#define S3C_SSR_SUSPEND (1 << 1) -#define S3C_SSR_RESET (1 << 0) -#define S3C_SCR S3C_HSUDC_REG(0x20) /* System Control */ -#define S3C_SCR_DTZIEN_EN (1 << 14) -#define S3C_SCR_RRD_EN (1 << 5) -#define S3C_SCR_SUS_EN (1 << 1) -#define S3C_SCR_RST_EN (1 << 0) -#define S3C_EP0SR S3C_HSUDC_REG(0x24) /* EP0 Status */ -#define S3C_EP0SR_EP0_LWO (1 << 6) -#define S3C_EP0SR_STALL (1 << 4) -#define S3C_EP0SR_TX_SUCCESS (1 << 1) -#define S3C_EP0SR_RX_SUCCESS (1 << 0) -#define S3C_EP0CR S3C_HSUDC_REG(0x28) /* EP0 Control */ -#define S3C_BR(_x) S3C_HSUDC_REG(0x60 + (_x * 4)) - -/* Indexed Registers */ -#define S3C_ESR S3C_HSUDC_REG(0x2c) /* EPn Status */ -#define S3C_ESR_FLUSH (1 << 6) -#define S3C_ESR_STALL (1 << 5) -#define S3C_ESR_LWO (1 << 4) -#define S3C_ESR_PSIF_ONE (1 << 2) -#define S3C_ESR_PSIF_TWO (2 << 2) -#define S3C_ESR_TX_SUCCESS (1 << 1) -#define S3C_ESR_RX_SUCCESS (1 << 0) -#define S3C_ECR S3C_HSUDC_REG(0x30) /* EPn Control */ -#define S3C_ECR_DUEN (1 << 7) -#define S3C_ECR_FLUSH (1 << 6) -#define S3C_ECR_STALL (1 << 1) -#define S3C_ECR_IEMS (1 << 0) -#define S3C_BRCR S3C_HSUDC_REG(0x34) /* Read Count */ -#define S3C_BWCR S3C_HSUDC_REG(0x38) /* Write Count */ -#define S3C_MPR S3C_HSUDC_REG(0x3c) /* Max Pkt Size */ - -#define WAIT_FOR_SETUP (0) -#define DATA_STATE_XMIT (1) -#define DATA_STATE_RECV (2) - -static const char * const s3c_hsudc_supply_names[] = { - "vdda", /* analog phy supply, 3.3V */ - "vddi", /* digital phy supply, 1.2V */ - "vddosc", /* oscillator supply, 1.8V - 3.3V */ -}; - -/** - * struct s3c_hsudc_ep - Endpoint representation used by driver. - * @ep: USB gadget layer representation of device endpoint. - * @name: Endpoint name (as required by ep autoconfiguration). - * @dev: Reference to the device controller to which this EP belongs. - * @desc: Endpoint descriptor obtained from the gadget driver. - * @queue: Transfer request queue for the endpoint. - * @stopped: Maintains state of endpoint, set if EP is halted. - * @bEndpointAddress: EP address (including direction bit). - * @fifo: Base address of EP FIFO. - */ -struct s3c_hsudc_ep { - struct usb_ep ep; - char name[20]; - struct s3c_hsudc *dev; - struct list_head queue; - u8 stopped; - u8 wedge; - u8 bEndpointAddress; - void __iomem *fifo; -}; - -/** - * struct s3c_hsudc_req - Driver encapsulation of USB gadget transfer request. - * @req: Reference to USB gadget transfer request. - * @queue: Used for inserting this request to the endpoint request queue. - */ -struct s3c_hsudc_req { - struct usb_request req; - struct list_head queue; -}; - -/** - * struct s3c_hsudc - Driver's abstraction of the device controller. - * @gadget: Instance of usb_gadget which is referenced by gadget driver. - * @driver: Reference to currently active gadget driver. - * @dev: The device reference used by probe function. - * @lock: Lock to synchronize the usage of Endpoints (EP's are indexed). - * @regs: Remapped base address of controller's register space. - * irq: IRQ number used by the controller. - * uclk: Reference to the controller clock. - * ep0state: Current state of EP0. - * ep: List of endpoints supported by the controller. - */ -struct s3c_hsudc { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct device *dev; - struct s3c24xx_hsudc_platdata *pd; - struct usb_phy *transceiver; - struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)]; - spinlock_t lock; - void __iomem *regs; - int irq; - struct clk *uclk; - int ep0state; - struct s3c_hsudc_ep ep[]; -}; - -#define ep_maxpacket(_ep) ((_ep)->ep.maxpacket) -#define ep_is_in(_ep) ((_ep)->bEndpointAddress & USB_DIR_IN) -#define ep_index(_ep) ((_ep)->bEndpointAddress & \ - USB_ENDPOINT_NUMBER_MASK) - -static const char driver_name[] = "s3c-udc"; -static const char ep0name[] = "ep0-control"; - -static inline struct s3c_hsudc_req *our_req(struct usb_request *req) -{ - return container_of(req, struct s3c_hsudc_req, req); -} - -static inline struct s3c_hsudc_ep *our_ep(struct usb_ep *ep) -{ - return container_of(ep, struct s3c_hsudc_ep, ep); -} - -static inline struct s3c_hsudc *to_hsudc(struct usb_gadget *gadget) -{ - return container_of(gadget, struct s3c_hsudc, gadget); -} - -static inline void set_index(struct s3c_hsudc *hsudc, int ep_addr) -{ - ep_addr &= USB_ENDPOINT_NUMBER_MASK; - writel(ep_addr, hsudc->regs + S3C_IR); -} - -static inline void __orr32(void __iomem *ptr, u32 val) -{ - writel(readl(ptr) | val, ptr); -} - -/** - * s3c_hsudc_complete_request - Complete a transfer request. - * @hsep: Endpoint to which the request belongs. - * @hsreq: Transfer request to be completed. - * @status: Transfer completion status for the transfer request. - */ -static void s3c_hsudc_complete_request(struct s3c_hsudc_ep *hsep, - struct s3c_hsudc_req *hsreq, int status) -{ - unsigned int stopped = hsep->stopped; - struct s3c_hsudc *hsudc = hsep->dev; - - list_del_init(&hsreq->queue); - hsreq->req.status = status; - - if (!ep_index(hsep)) { - hsudc->ep0state = WAIT_FOR_SETUP; - hsep->bEndpointAddress &= ~USB_DIR_IN; - } - - hsep->stopped = 1; - spin_unlock(&hsudc->lock); - usb_gadget_giveback_request(&hsep->ep, &hsreq->req); - spin_lock(&hsudc->lock); - hsep->stopped = stopped; -} - -/** - * s3c_hsudc_nuke_ep - Terminate all requests queued for a endpoint. - * @hsep: Endpoint for which queued requests have to be terminated. - * @status: Transfer completion status for the transfer request. - */ -static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status) -{ - struct s3c_hsudc_req *hsreq; - - while (!list_empty(&hsep->queue)) { - hsreq = list_entry(hsep->queue.next, - struct s3c_hsudc_req, queue); - s3c_hsudc_complete_request(hsep, hsreq, status); - } -} - -/** - * s3c_hsudc_stop_activity - Stop activity on all endpoints. - * @hsudc: Device controller for which EP activity is to be stopped. - * - * All the endpoints are stopped and any pending transfer requests if any on - * the endpoint are terminated. - */ -static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc) -{ - struct s3c_hsudc_ep *hsep; - int epnum; - - hsudc->gadget.speed = USB_SPEED_UNKNOWN; - - for (epnum = 0; epnum < hsudc->pd->epnum; epnum++) { - hsep = &hsudc->ep[epnum]; - hsep->stopped = 1; - s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN); - } -} - -/** - * s3c_hsudc_read_setup_pkt - Read the received setup packet from EP0 fifo. - * @hsudc: Device controller from which setup packet is to be read. - * @buf: The buffer into which the setup packet is read. - * - * The setup packet received in the EP0 fifo is read and stored into a - * given buffer address. - */ - -static void s3c_hsudc_read_setup_pkt(struct s3c_hsudc *hsudc, u16 *buf) -{ - int count; - - count = readl(hsudc->regs + S3C_BRCR); - while (count--) - *buf++ = (u16)readl(hsudc->regs + S3C_BR(0)); - - writel(S3C_EP0SR_RX_SUCCESS, hsudc->regs + S3C_EP0SR); -} - -/** - * s3c_hsudc_write_fifo - Write next chunk of transfer data to EP fifo. - * @hsep: Endpoint to which the data is to be written. - * @hsreq: Transfer request from which the next chunk of data is written. - * - * Write the next chunk of data from a transfer request to the endpoint FIFO. - * If the transfer request completes, 1 is returned, otherwise 0 is returned. - */ -static int s3c_hsudc_write_fifo(struct s3c_hsudc_ep *hsep, - struct s3c_hsudc_req *hsreq) -{ - u16 *buf; - u32 max = ep_maxpacket(hsep); - u32 count, length; - bool is_last; - void __iomem *fifo = hsep->fifo; - - buf = hsreq->req.buf + hsreq->req.actual; - prefetch(buf); - - length = hsreq->req.length - hsreq->req.actual; - length = min(length, max); - hsreq->req.actual += length; - - writel(length, hsep->dev->regs + S3C_BWCR); - for (count = 0; count < length; count += 2) - writel(*buf++, fifo); - - if (count != max) { - is_last = true; - } else { - if (hsreq->req.length != hsreq->req.actual || hsreq->req.zero) - is_last = false; - else - is_last = true; - } - - if (is_last) { - s3c_hsudc_complete_request(hsep, hsreq, 0); - return 1; - } - - return 0; -} - -/** - * s3c_hsudc_read_fifo - Read the next chunk of data from EP fifo. - * @hsep: Endpoint from which the data is to be read. - * @hsreq: Transfer request to which the next chunk of data read is written. - * - * Read the next chunk of data from the endpoint FIFO and a write it to the - * transfer request buffer. If the transfer request completes, 1 is returned, - * otherwise 0 is returned. - */ -static int s3c_hsudc_read_fifo(struct s3c_hsudc_ep *hsep, - struct s3c_hsudc_req *hsreq) -{ - struct s3c_hsudc *hsudc = hsep->dev; - u32 csr, offset; - u16 *buf, word; - u32 buflen, rcnt, rlen; - void __iomem *fifo = hsep->fifo; - u32 is_short = 0; - - offset = (ep_index(hsep)) ? S3C_ESR : S3C_EP0SR; - csr = readl(hsudc->regs + offset); - if (!(csr & S3C_ESR_RX_SUCCESS)) - return -EINVAL; - - buf = hsreq->req.buf + hsreq->req.actual; - prefetchw(buf); - buflen = hsreq->req.length - hsreq->req.actual; - - rcnt = readl(hsudc->regs + S3C_BRCR); - rlen = (csr & S3C_ESR_LWO) ? (rcnt * 2 - 1) : (rcnt * 2); - - hsreq->req.actual += min(rlen, buflen); - is_short = (rlen < hsep->ep.maxpacket); - - while (rcnt-- != 0) { - word = (u16)readl(fifo); - if (buflen) { - *buf++ = word; - buflen--; - } else { - hsreq->req.status = -EOVERFLOW; - } - } - - writel(S3C_ESR_RX_SUCCESS, hsudc->regs + offset); - - if (is_short || hsreq->req.actual == hsreq->req.length) { - s3c_hsudc_complete_request(hsep, hsreq, 0); - return 1; - } - - return 0; -} - -/** - * s3c_hsudc_epin_intr - Handle in-endpoint interrupt. - * @hsudc - Device controller for which the interrupt is to be handled. - * @ep_idx - Endpoint number on which an interrupt is pending. - * - * Handles interrupt for a in-endpoint. The interrupts that are handled are - * stall and data transmit complete interrupt. - */ -static void s3c_hsudc_epin_intr(struct s3c_hsudc *hsudc, u32 ep_idx) -{ - struct s3c_hsudc_ep *hsep = &hsudc->ep[ep_idx]; - struct s3c_hsudc_req *hsreq; - u32 csr; - - csr = readl(hsudc->regs + S3C_ESR); - if (csr & S3C_ESR_STALL) { - writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR); - return; - } - - if (csr & S3C_ESR_TX_SUCCESS) { - writel(S3C_ESR_TX_SUCCESS, hsudc->regs + S3C_ESR); - if (list_empty(&hsep->queue)) - return; - - hsreq = list_entry(hsep->queue.next, - struct s3c_hsudc_req, queue); - if ((s3c_hsudc_write_fifo(hsep, hsreq) == 0) && - (csr & S3C_ESR_PSIF_TWO)) - s3c_hsudc_write_fifo(hsep, hsreq); - } -} - -/** - * s3c_hsudc_epout_intr - Handle out-endpoint interrupt. - * @hsudc - Device controller for which the interrupt is to be handled. - * @ep_idx - Endpoint number on which an interrupt is pending. - * - * Handles interrupt for a out-endpoint. The interrupts that are handled are - * stall, flush and data ready interrupt. - */ -static void s3c_hsudc_epout_intr(struct s3c_hsudc *hsudc, u32 ep_idx) -{ - struct s3c_hsudc_ep *hsep = &hsudc->ep[ep_idx]; - struct s3c_hsudc_req *hsreq; - u32 csr; - - csr = readl(hsudc->regs + S3C_ESR); - if (csr & S3C_ESR_STALL) { - writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR); - return; - } - - if (csr & S3C_ESR_FLUSH) { - __orr32(hsudc->regs + S3C_ECR, S3C_ECR_FLUSH); - return; - } - - if (csr & S3C_ESR_RX_SUCCESS) { - if (list_empty(&hsep->queue)) - return; - - hsreq = list_entry(hsep->queue.next, - struct s3c_hsudc_req, queue); - if (((s3c_hsudc_read_fifo(hsep, hsreq)) == 0) && - (csr & S3C_ESR_PSIF_TWO)) - s3c_hsudc_read_fifo(hsep, hsreq); - } -} - -/** s3c_hsudc_set_halt - Set or clear a endpoint halt. - * @_ep: Endpoint on which halt has to be set or cleared. - * @value: 1 for setting halt on endpoint, 0 to clear halt. - * - * Set or clear endpoint halt. If halt is set, the endpoint is stopped. - * If halt is cleared, for in-endpoints, if there are any pending - * transfer requests, transfers are started. - */ -static int s3c_hsudc_set_halt(struct usb_ep *_ep, int value) -{ - struct s3c_hsudc_ep *hsep = our_ep(_ep); - struct s3c_hsudc *hsudc = hsep->dev; - struct s3c_hsudc_req *hsreq; - unsigned long irqflags; - u32 ecr; - u32 offset; - - if (value && ep_is_in(hsep) && !list_empty(&hsep->queue)) - return -EAGAIN; - - spin_lock_irqsave(&hsudc->lock, irqflags); - set_index(hsudc, ep_index(hsep)); - offset = (ep_index(hsep)) ? S3C_ECR : S3C_EP0CR; - ecr = readl(hsudc->regs + offset); - - if (value) { - ecr |= S3C_ECR_STALL; - if (ep_index(hsep)) - ecr |= S3C_ECR_FLUSH; - hsep->stopped = 1; - } else { - ecr &= ~S3C_ECR_STALL; - hsep->stopped = hsep->wedge = 0; - } - writel(ecr, hsudc->regs + offset); - - if (ep_is_in(hsep) && !list_empty(&hsep->queue) && !value) { - hsreq = list_entry(hsep->queue.next, - struct s3c_hsudc_req, queue); - if (hsreq) - s3c_hsudc_write_fifo(hsep, hsreq); - } - - spin_unlock_irqrestore(&hsudc->lock, irqflags); - return 0; -} - -/** s3c_hsudc_set_wedge - Sets the halt feature with the clear requests ignored - * @_ep: Endpoint on which wedge has to be set. - * - * Sets the halt feature with the clear requests ignored. - */ -static int s3c_hsudc_set_wedge(struct usb_ep *_ep) -{ - struct s3c_hsudc_ep *hsep = our_ep(_ep); - - if (!hsep) - return -EINVAL; - - hsep->wedge = 1; - return usb_ep_set_halt(_ep); -} - -/** s3c_hsudc_handle_reqfeat - Handle set feature or clear feature requests. - * @_ep: Device controller on which the set/clear feature needs to be handled. - * @ctrl: Control request as received on the endpoint 0. - * - * Handle set feature or clear feature control requests on the control endpoint. - */ -static int s3c_hsudc_handle_reqfeat(struct s3c_hsudc *hsudc, - struct usb_ctrlrequest *ctrl) -{ - struct s3c_hsudc_ep *hsep; - bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); - u8 ep_num = ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK; - - if (ctrl->bRequestType == USB_RECIP_ENDPOINT) { - hsep = &hsudc->ep[ep_num]; - switch (le16_to_cpu(ctrl->wValue)) { - case USB_ENDPOINT_HALT: - if (set || !hsep->wedge) - s3c_hsudc_set_halt(&hsep->ep, set); - return 0; - } - } - - return -ENOENT; -} - -/** - * s3c_hsudc_process_req_status - Handle get status control request. - * @hsudc: Device controller on which get status request has be handled. - * @ctrl: Control request as received on the endpoint 0. - * - * Handle get status control request received on control endpoint. - */ -static void s3c_hsudc_process_req_status(struct s3c_hsudc *hsudc, - struct usb_ctrlrequest *ctrl) -{ - struct s3c_hsudc_ep *hsep0 = &hsudc->ep[0]; - struct s3c_hsudc_req hsreq; - struct s3c_hsudc_ep *hsep; - __le16 reply; - u8 epnum; - - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - reply = cpu_to_le16(0); - break; - - case USB_RECIP_INTERFACE: - reply = cpu_to_le16(0); - break; - - case USB_RECIP_ENDPOINT: - epnum = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK; - hsep = &hsudc->ep[epnum]; - reply = cpu_to_le16(hsep->stopped ? 1 : 0); - break; - } - - INIT_LIST_HEAD(&hsreq.queue); - hsreq.req.length = 2; - hsreq.req.buf = &reply; - hsreq.req.actual = 0; - hsreq.req.complete = NULL; - s3c_hsudc_write_fifo(hsep0, &hsreq); -} - -/** - * s3c_hsudc_process_setup - Process control request received on endpoint 0. - * @hsudc: Device controller on which control request has been received. - * - * Read the control request received on endpoint 0, decode it and handle - * the request. - */ -static void s3c_hsudc_process_setup(struct s3c_hsudc *hsudc) -{ - struct s3c_hsudc_ep *hsep = &hsudc->ep[0]; - struct usb_ctrlrequest ctrl = {0}; - int ret; - - s3c_hsudc_nuke_ep(hsep, -EPROTO); - s3c_hsudc_read_setup_pkt(hsudc, (u16 *)&ctrl); - - if (ctrl.bRequestType & USB_DIR_IN) { - hsep->bEndpointAddress |= USB_DIR_IN; - hsudc->ep0state = DATA_STATE_XMIT; - } else { - hsep->bEndpointAddress &= ~USB_DIR_IN; - hsudc->ep0state = DATA_STATE_RECV; - } - - switch (ctrl.bRequest) { - case USB_REQ_SET_ADDRESS: - if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) - break; - hsudc->ep0state = WAIT_FOR_SETUP; - return; - - case USB_REQ_GET_STATUS: - if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) - break; - s3c_hsudc_process_req_status(hsudc, &ctrl); - return; - - case USB_REQ_SET_FEATURE: - case USB_REQ_CLEAR_FEATURE: - if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) - break; - s3c_hsudc_handle_reqfeat(hsudc, &ctrl); - hsudc->ep0state = WAIT_FOR_SETUP; - return; - } - - if (hsudc->driver) { - spin_unlock(&hsudc->lock); - ret = hsudc->driver->setup(&hsudc->gadget, &ctrl); - spin_lock(&hsudc->lock); - - if (ctrl.bRequest == USB_REQ_SET_CONFIGURATION) { - hsep->bEndpointAddress &= ~USB_DIR_IN; - hsudc->ep0state = WAIT_FOR_SETUP; - } - - if (ret < 0) { - dev_err(hsudc->dev, "setup failed, returned %d\n", - ret); - s3c_hsudc_set_halt(&hsep->ep, 1); - hsudc->ep0state = WAIT_FOR_SETUP; - hsep->bEndpointAddress &= ~USB_DIR_IN; - } - } -} - -/** s3c_hsudc_handle_ep0_intr - Handle endpoint 0 interrupt. - * @hsudc: Device controller on which endpoint 0 interrupt has occurred. - * - * Handle endpoint 0 interrupt when it occurs. EP0 interrupt could occur - * when a stall handshake is sent to host or data is sent/received on - * endpoint 0. - */ -static void s3c_hsudc_handle_ep0_intr(struct s3c_hsudc *hsudc) -{ - struct s3c_hsudc_ep *hsep = &hsudc->ep[0]; - struct s3c_hsudc_req *hsreq; - u32 csr = readl(hsudc->regs + S3C_EP0SR); - u32 ecr; - - if (csr & S3C_EP0SR_STALL) { - ecr = readl(hsudc->regs + S3C_EP0CR); - ecr &= ~(S3C_ECR_STALL | S3C_ECR_FLUSH); - writel(ecr, hsudc->regs + S3C_EP0CR); - - writel(S3C_EP0SR_STALL, hsudc->regs + S3C_EP0SR); - hsep->stopped = 0; - - s3c_hsudc_nuke_ep(hsep, -ECONNABORTED); - hsudc->ep0state = WAIT_FOR_SETUP; - hsep->bEndpointAddress &= ~USB_DIR_IN; - return; - } - - if (csr & S3C_EP0SR_TX_SUCCESS) { - writel(S3C_EP0SR_TX_SUCCESS, hsudc->regs + S3C_EP0SR); - if (ep_is_in(hsep)) { - if (list_empty(&hsep->queue)) - return; - - hsreq = list_entry(hsep->queue.next, - struct s3c_hsudc_req, queue); - s3c_hsudc_write_fifo(hsep, hsreq); - } - } - - if (csr & S3C_EP0SR_RX_SUCCESS) { - if (hsudc->ep0state == WAIT_FOR_SETUP) - s3c_hsudc_process_setup(hsudc); - else { - if (!ep_is_in(hsep)) { - if (list_empty(&hsep->queue)) - return; - hsreq = list_entry(hsep->queue.next, - struct s3c_hsudc_req, queue); - s3c_hsudc_read_fifo(hsep, hsreq); - } - } - } -} - -/** - * s3c_hsudc_ep_enable - Enable a endpoint. - * @_ep: The endpoint to be enabled. - * @desc: Endpoint descriptor. - * - * Enables a endpoint when called from the gadget driver. Endpoint stall if - * any is cleared, transfer type is configured and endpoint interrupt is - * enabled. - */ -static int s3c_hsudc_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct s3c_hsudc_ep *hsep; - struct s3c_hsudc *hsudc; - unsigned long flags; - u32 ecr = 0; - - hsep = our_ep(_ep); - if (!_ep || !desc || _ep->name == ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT - || hsep->bEndpointAddress != desc->bEndpointAddress - || ep_maxpacket(hsep) < usb_endpoint_maxp(desc)) - return -EINVAL; - - if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK - && usb_endpoint_maxp(desc) != ep_maxpacket(hsep)) - || !desc->wMaxPacketSize) - return -ERANGE; - - hsudc = hsep->dev; - if (!hsudc->driver || hsudc->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - spin_lock_irqsave(&hsudc->lock, flags); - - set_index(hsudc, hsep->bEndpointAddress); - ecr |= ((usb_endpoint_xfer_int(desc)) ? S3C_ECR_IEMS : S3C_ECR_DUEN); - writel(ecr, hsudc->regs + S3C_ECR); - - hsep->stopped = hsep->wedge = 0; - hsep->ep.desc = desc; - hsep->ep.maxpacket = usb_endpoint_maxp(desc); - - s3c_hsudc_set_halt(_ep, 0); - __set_bit(ep_index(hsep), hsudc->regs + S3C_EIER); - - spin_unlock_irqrestore(&hsudc->lock, flags); - return 0; -} - -/** - * s3c_hsudc_ep_disable - Disable a endpoint. - * @_ep: The endpoint to be disabled. - * @desc: Endpoint descriptor. - * - * Disables a endpoint when called from the gadget driver. - */ -static int s3c_hsudc_ep_disable(struct usb_ep *_ep) -{ - struct s3c_hsudc_ep *hsep = our_ep(_ep); - struct s3c_hsudc *hsudc = hsep->dev; - unsigned long flags; - - if (!_ep || !hsep->ep.desc) - return -EINVAL; - - spin_lock_irqsave(&hsudc->lock, flags); - - set_index(hsudc, hsep->bEndpointAddress); - __clear_bit(ep_index(hsep), hsudc->regs + S3C_EIER); - - s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN); - - hsep->ep.desc = NULL; - hsep->stopped = 1; - - spin_unlock_irqrestore(&hsudc->lock, flags); - return 0; -} - -/** - * s3c_hsudc_alloc_request - Allocate a new request. - * @_ep: Endpoint for which request is allocated (not used). - * @gfp_flags: Flags used for the allocation. - * - * Allocates a single transfer request structure when called from gadget driver. - */ -static struct usb_request *s3c_hsudc_alloc_request(struct usb_ep *_ep, - gfp_t gfp_flags) -{ - struct s3c_hsudc_req *hsreq; - - hsreq = kzalloc(sizeof(*hsreq), gfp_flags); - if (!hsreq) - return NULL; - - INIT_LIST_HEAD(&hsreq->queue); - return &hsreq->req; -} - -/** - * s3c_hsudc_free_request - Deallocate a request. - * @ep: Endpoint for which request is deallocated (not used). - * @_req: Request to be deallocated. - * - * Allocates a single transfer request structure when called from gadget driver. - */ -static void s3c_hsudc_free_request(struct usb_ep *ep, struct usb_request *_req) -{ - struct s3c_hsudc_req *hsreq; - - hsreq = our_req(_req); - WARN_ON(!list_empty(&hsreq->queue)); - kfree(hsreq); -} - -/** - * s3c_hsudc_queue - Queue a transfer request for the endpoint. - * @_ep: Endpoint for which the request is queued. - * @_req: Request to be queued. - * @gfp_flags: Not used. - * - * Start or enqueue a request for a endpoint when called from gadget driver. - */ -static int s3c_hsudc_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct s3c_hsudc_req *hsreq; - struct s3c_hsudc_ep *hsep; - struct s3c_hsudc *hsudc; - unsigned long flags; - u32 offset; - u32 csr; - - hsreq = our_req(_req); - if ((!_req || !_req->complete || !_req->buf || - !list_empty(&hsreq->queue))) - return -EINVAL; - - hsep = our_ep(_ep); - hsudc = hsep->dev; - if (!hsudc->driver || hsudc->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - spin_lock_irqsave(&hsudc->lock, flags); - set_index(hsudc, hsep->bEndpointAddress); - - _req->status = -EINPROGRESS; - _req->actual = 0; - - if (!ep_index(hsep) && _req->length == 0) { - hsudc->ep0state = WAIT_FOR_SETUP; - s3c_hsudc_complete_request(hsep, hsreq, 0); - spin_unlock_irqrestore(&hsudc->lock, flags); - return 0; - } - - if (list_empty(&hsep->queue) && !hsep->stopped) { - offset = (ep_index(hsep)) ? S3C_ESR : S3C_EP0SR; - if (ep_is_in(hsep)) { - csr = readl(hsudc->regs + offset); - if (!(csr & S3C_ESR_TX_SUCCESS) && - (s3c_hsudc_write_fifo(hsep, hsreq) == 1)) - hsreq = NULL; - } else { - csr = readl(hsudc->regs + offset); - if ((csr & S3C_ESR_RX_SUCCESS) - && (s3c_hsudc_read_fifo(hsep, hsreq) == 1)) - hsreq = NULL; - } - } - - if (hsreq) - list_add_tail(&hsreq->queue, &hsep->queue); - - spin_unlock_irqrestore(&hsudc->lock, flags); - return 0; -} - -/** - * s3c_hsudc_dequeue - Dequeue a transfer request from an endpoint. - * @_ep: Endpoint from which the request is dequeued. - * @_req: Request to be dequeued. - * - * Dequeue a request from a endpoint when called from gadget driver. - */ -static int s3c_hsudc_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct s3c_hsudc_ep *hsep = our_ep(_ep); - struct s3c_hsudc *hsudc = hsep->dev; - struct s3c_hsudc_req *hsreq = NULL, *iter; - unsigned long flags; - - hsep = our_ep(_ep); - if (!_ep || hsep->ep.name == ep0name) - return -EINVAL; - - spin_lock_irqsave(&hsudc->lock, flags); - - list_for_each_entry(iter, &hsep->queue, queue) { - if (&iter->req != _req) - continue; - hsreq = iter; - break; - } - if (!hsreq) { - spin_unlock_irqrestore(&hsudc->lock, flags); - return -EINVAL; - } - - set_index(hsudc, hsep->bEndpointAddress); - s3c_hsudc_complete_request(hsep, hsreq, -ECONNRESET); - - spin_unlock_irqrestore(&hsudc->lock, flags); - return 0; -} - -static const struct usb_ep_ops s3c_hsudc_ep_ops = { - .enable = s3c_hsudc_ep_enable, - .disable = s3c_hsudc_ep_disable, - .alloc_request = s3c_hsudc_alloc_request, - .free_request = s3c_hsudc_free_request, - .queue = s3c_hsudc_queue, - .dequeue = s3c_hsudc_dequeue, - .set_halt = s3c_hsudc_set_halt, - .set_wedge = s3c_hsudc_set_wedge, -}; - -/** - * s3c_hsudc_initep - Initialize a endpoint to default state. - * @hsudc - Reference to the device controller. - * @hsep - Endpoint to be initialized. - * @epnum - Address to be assigned to the endpoint. - * - * Initialize a endpoint with default configuration. - */ -static void s3c_hsudc_initep(struct s3c_hsudc *hsudc, - struct s3c_hsudc_ep *hsep, int epnum) -{ - char *dir; - - if ((epnum % 2) == 0) { - dir = "out"; - } else { - dir = "in"; - hsep->bEndpointAddress = USB_DIR_IN; - } - - hsep->bEndpointAddress |= epnum; - if (epnum) - snprintf(hsep->name, sizeof(hsep->name), "ep%d%s", epnum, dir); - else - snprintf(hsep->name, sizeof(hsep->name), "%s", ep0name); - - INIT_LIST_HEAD(&hsep->queue); - INIT_LIST_HEAD(&hsep->ep.ep_list); - if (epnum) - list_add_tail(&hsep->ep.ep_list, &hsudc->gadget.ep_list); - - hsep->dev = hsudc; - hsep->ep.name = hsep->name; - usb_ep_set_maxpacket_limit(&hsep->ep, epnum ? 512 : 64); - hsep->ep.ops = &s3c_hsudc_ep_ops; - hsep->fifo = hsudc->regs + S3C_BR(epnum); - hsep->ep.desc = NULL; - hsep->stopped = 0; - hsep->wedge = 0; - - if (epnum == 0) { - hsep->ep.caps.type_control = true; - hsep->ep.caps.dir_in = true; - hsep->ep.caps.dir_out = true; - } else { - hsep->ep.caps.type_iso = true; - hsep->ep.caps.type_bulk = true; - hsep->ep.caps.type_int = true; - } - - if (epnum & 1) - hsep->ep.caps.dir_in = true; - else - hsep->ep.caps.dir_out = true; - - set_index(hsudc, epnum); - writel(hsep->ep.maxpacket, hsudc->regs + S3C_MPR); -} - -/** - * s3c_hsudc_setup_ep - Configure all endpoints to default state. - * @hsudc: Reference to device controller. - * - * Configures all endpoints to default state. - */ -static void s3c_hsudc_setup_ep(struct s3c_hsudc *hsudc) -{ - int epnum; - - hsudc->ep0state = WAIT_FOR_SETUP; - INIT_LIST_HEAD(&hsudc->gadget.ep_list); - for (epnum = 0; epnum < hsudc->pd->epnum; epnum++) - s3c_hsudc_initep(hsudc, &hsudc->ep[epnum], epnum); -} - -/** - * s3c_hsudc_reconfig - Reconfigure the device controller to default state. - * @hsudc: Reference to device controller. - * - * Reconfigures the device controller registers to a default state. - */ -static void s3c_hsudc_reconfig(struct s3c_hsudc *hsudc) -{ - writel(0xAA, hsudc->regs + S3C_EDR); - writel(1, hsudc->regs + S3C_EIER); - writel(0, hsudc->regs + S3C_TR); - writel(S3C_SCR_DTZIEN_EN | S3C_SCR_RRD_EN | S3C_SCR_SUS_EN | - S3C_SCR_RST_EN, hsudc->regs + S3C_SCR); - writel(0, hsudc->regs + S3C_EP0CR); - - s3c_hsudc_setup_ep(hsudc); -} - -/** - * s3c_hsudc_irq - Interrupt handler for device controller. - * @irq: Not used. - * @_dev: Reference to the device controller. - * - * Interrupt handler for the device controller. This handler handles controller - * interrupts and endpoint interrupts. - */ -static irqreturn_t s3c_hsudc_irq(int irq, void *_dev) -{ - struct s3c_hsudc *hsudc = _dev; - struct s3c_hsudc_ep *hsep; - u32 ep_intr; - u32 sys_status; - u32 ep_idx; - - spin_lock(&hsudc->lock); - - sys_status = readl(hsudc->regs + S3C_SSR); - ep_intr = readl(hsudc->regs + S3C_EIR) & 0x3FF; - - if (!ep_intr && !(sys_status & S3C_SSR_DTZIEN_EN)) { - spin_unlock(&hsudc->lock); - return IRQ_HANDLED; - } - - if (sys_status) { - if (sys_status & S3C_SSR_VBUSON) - writel(S3C_SSR_VBUSON, hsudc->regs + S3C_SSR); - - if (sys_status & S3C_SSR_ERR) - writel(S3C_SSR_ERR, hsudc->regs + S3C_SSR); - - if (sys_status & S3C_SSR_SDE) { - writel(S3C_SSR_SDE, hsudc->regs + S3C_SSR); - hsudc->gadget.speed = (sys_status & S3C_SSR_HSP) ? - USB_SPEED_HIGH : USB_SPEED_FULL; - } - - if (sys_status & S3C_SSR_SUSPEND) { - writel(S3C_SSR_SUSPEND, hsudc->regs + S3C_SSR); - if (hsudc->gadget.speed != USB_SPEED_UNKNOWN - && hsudc->driver && hsudc->driver->suspend) - hsudc->driver->suspend(&hsudc->gadget); - } - - if (sys_status & S3C_SSR_RESUME) { - writel(S3C_SSR_RESUME, hsudc->regs + S3C_SSR); - if (hsudc->gadget.speed != USB_SPEED_UNKNOWN - && hsudc->driver && hsudc->driver->resume) - hsudc->driver->resume(&hsudc->gadget); - } - - if (sys_status & S3C_SSR_RESET) { - writel(S3C_SSR_RESET, hsudc->regs + S3C_SSR); - for (ep_idx = 0; ep_idx < hsudc->pd->epnum; ep_idx++) { - hsep = &hsudc->ep[ep_idx]; - hsep->stopped = 1; - s3c_hsudc_nuke_ep(hsep, -ECONNRESET); - } - s3c_hsudc_reconfig(hsudc); - hsudc->ep0state = WAIT_FOR_SETUP; - } - } - - if (ep_intr & S3C_EIR_EP0) { - writel(S3C_EIR_EP0, hsudc->regs + S3C_EIR); - set_index(hsudc, 0); - s3c_hsudc_handle_ep0_intr(hsudc); - } - - ep_intr >>= 1; - ep_idx = 1; - while (ep_intr) { - if (ep_intr & 1) { - hsep = &hsudc->ep[ep_idx]; - set_index(hsudc, ep_idx); - writel(1 << ep_idx, hsudc->regs + S3C_EIR); - if (ep_is_in(hsep)) - s3c_hsudc_epin_intr(hsudc, ep_idx); - else - s3c_hsudc_epout_intr(hsudc, ep_idx); - } - ep_intr >>= 1; - ep_idx++; - } - - spin_unlock(&hsudc->lock); - return IRQ_HANDLED; -} - -static int s3c_hsudc_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct s3c_hsudc *hsudc = to_hsudc(gadget); - int ret; - - if (!driver - || driver->max_speed < USB_SPEED_FULL - || !driver->setup) - return -EINVAL; - - if (!hsudc) - return -ENODEV; - - if (hsudc->driver) - return -EBUSY; - - hsudc->driver = driver; - - ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies), - hsudc->supplies); - if (ret != 0) { - dev_err(hsudc->dev, "failed to enable supplies: %d\n", ret); - goto err_supplies; - } - - /* connect to bus through transceiver */ - if (!IS_ERR_OR_NULL(hsudc->transceiver)) { - ret = otg_set_peripheral(hsudc->transceiver->otg, - &hsudc->gadget); - if (ret) { - dev_err(hsudc->dev, "%s: can't bind to transceiver\n", - hsudc->gadget.name); - goto err_otg; - } - } - - enable_irq(hsudc->irq); - s3c_hsudc_reconfig(hsudc); - - pm_runtime_get_sync(hsudc->dev); - - if (hsudc->pd->phy_init) - hsudc->pd->phy_init(); - if (hsudc->pd->gpio_init) - hsudc->pd->gpio_init(); - - return 0; -err_otg: - regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); -err_supplies: - hsudc->driver = NULL; - return ret; -} - -static int s3c_hsudc_stop(struct usb_gadget *gadget) -{ - struct s3c_hsudc *hsudc = to_hsudc(gadget); - unsigned long flags; - - if (!hsudc) - return -ENODEV; - - spin_lock_irqsave(&hsudc->lock, flags); - hsudc->gadget.speed = USB_SPEED_UNKNOWN; - if (hsudc->pd->phy_uninit) - hsudc->pd->phy_uninit(); - - pm_runtime_put(hsudc->dev); - - if (hsudc->pd->gpio_uninit) - hsudc->pd->gpio_uninit(); - s3c_hsudc_stop_activity(hsudc); - spin_unlock_irqrestore(&hsudc->lock, flags); - - if (!IS_ERR_OR_NULL(hsudc->transceiver)) - (void) otg_set_peripheral(hsudc->transceiver->otg, NULL); - - disable_irq(hsudc->irq); - - regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); - hsudc->driver = NULL; - - return 0; -} - -static inline u32 s3c_hsudc_read_frameno(struct s3c_hsudc *hsudc) -{ - return readl(hsudc->regs + S3C_FNR) & 0x3FF; -} - -static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget) -{ - return s3c_hsudc_read_frameno(to_hsudc(gadget)); -} - -static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - struct s3c_hsudc *hsudc = to_hsudc(gadget); - - if (!hsudc) - return -ENODEV; - - if (!IS_ERR_OR_NULL(hsudc->transceiver)) - return usb_phy_set_power(hsudc->transceiver, mA); - - return -EOPNOTSUPP; -} - -static const struct usb_gadget_ops s3c_hsudc_gadget_ops = { - .get_frame = s3c_hsudc_gadget_getframe, - .udc_start = s3c_hsudc_start, - .udc_stop = s3c_hsudc_stop, - .vbus_draw = s3c_hsudc_vbus_draw, -}; - -static int s3c_hsudc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct s3c_hsudc *hsudc; - struct s3c24xx_hsudc_platdata *pd = dev_get_platdata(&pdev->dev); - int ret, i; - - hsudc = devm_kzalloc(&pdev->dev, struct_size(hsudc, ep, pd->epnum), - GFP_KERNEL); - if (!hsudc) - return -ENOMEM; - - platform_set_drvdata(pdev, dev); - hsudc->dev = dev; - hsudc->pd = dev_get_platdata(&pdev->dev); - - hsudc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); - - for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++) - hsudc->supplies[i].supply = s3c_hsudc_supply_names[i]; - - ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies), - hsudc->supplies); - if (ret != 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to request supplies: %d\n", ret); - goto err_supplies; - } - - hsudc->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(hsudc->regs)) { - ret = PTR_ERR(hsudc->regs); - goto err_res; - } - - spin_lock_init(&hsudc->lock); - - hsudc->gadget.max_speed = USB_SPEED_HIGH; - hsudc->gadget.ops = &s3c_hsudc_gadget_ops; - hsudc->gadget.name = dev_name(dev); - hsudc->gadget.ep0 = &hsudc->ep[0].ep; - hsudc->gadget.is_otg = 0; - hsudc->gadget.is_a_peripheral = 0; - hsudc->gadget.speed = USB_SPEED_UNKNOWN; - - s3c_hsudc_setup_ep(hsudc); - - ret = platform_get_irq(pdev, 0); - if (ret < 0) - goto err_res; - hsudc->irq = ret; - - ret = devm_request_irq(&pdev->dev, hsudc->irq, s3c_hsudc_irq, 0, - driver_name, hsudc); - if (ret < 0) { - dev_err(dev, "irq request failed\n"); - goto err_res; - } - - hsudc->uclk = devm_clk_get(&pdev->dev, "usb-device"); - if (IS_ERR(hsudc->uclk)) { - dev_err(dev, "failed to find usb-device clock source\n"); - ret = PTR_ERR(hsudc->uclk); - goto err_res; - } - clk_enable(hsudc->uclk); - - local_irq_disable(); - - disable_irq(hsudc->irq); - local_irq_enable(); - - ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget); - if (ret) - goto err_add_udc; - - pm_runtime_enable(dev); - - return 0; -err_add_udc: - clk_disable(hsudc->uclk); -err_res: - if (!IS_ERR_OR_NULL(hsudc->transceiver)) - usb_put_phy(hsudc->transceiver); - -err_supplies: - return ret; -} - -static struct platform_driver s3c_hsudc_driver = { - .driver = { - .name = "s3c-hsudc", - }, - .probe = s3c_hsudc_probe, -}; - -module_platform_driver(s3c_hsudc_driver); - -MODULE_DESCRIPTION("Samsung S3C24XX USB high-speed controller driver"); -MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c-hsudc"); diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c deleted file mode 100644 index 8c57b191e52b..000000000000 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ /dev/null @@ -1,1980 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * linux/drivers/usb/gadget/s3c2410_udc.c - * - * Samsung S3C24xx series on-chip full speed USB device controllers - * - * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard - * Additional cleanups by Ben Dooks <ben-linux@fluff.org> - */ - -#define pr_fmt(fmt) "s3c2410_udc: " fmt - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/list.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/gpio/consumer.h> -#include <linux/prefetch.h> -#include <linux/io.h> - -#include <linux/debugfs.h> -#include <linux/seq_file.h> - -#include <linux/usb.h> -#include <linux/usb/gadget.h> - -#include <asm/byteorder.h> -#include <asm/irq.h> -#include <asm/unaligned.h> - -#include <linux/platform_data/usb-s3c2410_udc.h> - -#include "s3c2410_udc.h" -#include "s3c2410_udc_regs.h" - -#define DRIVER_DESC "S3C2410 USB Device Controller Gadget" -#define DRIVER_AUTHOR "Herbert Pötzl <herbert@13thfloor.at>, " \ - "Arnaud Patard <arnaud.patard@rtp-net.org>" - -static const char gadget_name[] = "s3c2410_udc"; -static const char driver_desc[] = DRIVER_DESC; - -static struct s3c2410_udc *the_controller; -static struct clk *udc_clock; -static struct clk *usb_bus_clock; -static void __iomem *base_addr; -static int irq_usbd; -static struct dentry *s3c2410_udc_debugfs_root; - -static inline u32 udc_read(u32 reg) -{ - return readb(base_addr + reg); -} - -static inline void udc_write(u32 value, u32 reg) -{ - writeb(value, base_addr + reg); -} - -static inline void udc_writeb(void __iomem *base, u32 value, u32 reg) -{ - writeb(value, base + reg); -} - -static struct s3c2410_udc_mach_info *udc_info; - -/*************************** DEBUG FUNCTION ***************************/ -#define DEBUG_NORMAL 1 -#define DEBUG_VERBOSE 2 - -#ifdef CONFIG_USB_S3C2410_DEBUG -#define USB_S3C2410_DEBUG_LEVEL 0 - -static uint32_t s3c2410_ticks = 0; - -__printf(2, 3) -static void dprintk(int level, const char *fmt, ...) -{ - static long prevticks; - static int invocation; - struct va_format vaf; - va_list args; - - if (level > USB_S3C2410_DEBUG_LEVEL) - return; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - if (s3c2410_ticks != prevticks) { - prevticks = s3c2410_ticks; - invocation = 0; - } - - pr_debug("%1lu.%02d USB: %pV", prevticks, invocation++, &vaf); - - va_end(args); -} -#else -__printf(2, 3) -static void dprintk(int level, const char *fmt, ...) -{ -} -#endif - -static int s3c2410_udc_debugfs_show(struct seq_file *m, void *p) -{ - u32 addr_reg, pwr_reg, ep_int_reg, usb_int_reg; - u32 ep_int_en_reg, usb_int_en_reg, ep0_csr; - u32 ep1_i_csr1, ep1_i_csr2, ep1_o_csr1, ep1_o_csr2; - u32 ep2_i_csr1, ep2_i_csr2, ep2_o_csr1, ep2_o_csr2; - - addr_reg = udc_read(S3C2410_UDC_FUNC_ADDR_REG); - pwr_reg = udc_read(S3C2410_UDC_PWR_REG); - ep_int_reg = udc_read(S3C2410_UDC_EP_INT_REG); - usb_int_reg = udc_read(S3C2410_UDC_USB_INT_REG); - ep_int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG); - usb_int_en_reg = udc_read(S3C2410_UDC_USB_INT_EN_REG); - udc_write(0, S3C2410_UDC_INDEX_REG); - ep0_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); - udc_write(1, S3C2410_UDC_INDEX_REG); - ep1_i_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); - ep1_i_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); - ep1_o_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); - ep1_o_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); - udc_write(2, S3C2410_UDC_INDEX_REG); - ep2_i_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); - ep2_i_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); - ep2_o_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); - ep2_o_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); - - seq_printf(m, "FUNC_ADDR_REG : 0x%04X\n" - "PWR_REG : 0x%04X\n" - "EP_INT_REG : 0x%04X\n" - "USB_INT_REG : 0x%04X\n" - "EP_INT_EN_REG : 0x%04X\n" - "USB_INT_EN_REG : 0x%04X\n" - "EP0_CSR : 0x%04X\n" - "EP1_I_CSR1 : 0x%04X\n" - "EP1_I_CSR2 : 0x%04X\n" - "EP1_O_CSR1 : 0x%04X\n" - "EP1_O_CSR2 : 0x%04X\n" - "EP2_I_CSR1 : 0x%04X\n" - "EP2_I_CSR2 : 0x%04X\n" - "EP2_O_CSR1 : 0x%04X\n" - "EP2_O_CSR2 : 0x%04X\n", - addr_reg, pwr_reg, ep_int_reg, usb_int_reg, - ep_int_en_reg, usb_int_en_reg, ep0_csr, - ep1_i_csr1, ep1_i_csr2, ep1_o_csr1, ep1_o_csr2, - ep2_i_csr1, ep2_i_csr2, ep2_o_csr1, ep2_o_csr2 - ); - - return 0; -} -DEFINE_SHOW_ATTRIBUTE(s3c2410_udc_debugfs); - -/* io macros */ - -static inline void s3c2410_udc_clear_ep0_opr(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - udc_writeb(base, S3C2410_UDC_EP0_CSR_SOPKTRDY, - S3C2410_UDC_EP0_CSR_REG); -} - -static inline void s3c2410_udc_clear_ep0_sst(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - writeb(0x00, base + S3C2410_UDC_EP0_CSR_REG); -} - -static inline void s3c2410_udc_clear_ep0_se(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - udc_writeb(base, S3C2410_UDC_EP0_CSR_SSE, S3C2410_UDC_EP0_CSR_REG); -} - -static inline void s3c2410_udc_set_ep0_ipr(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - udc_writeb(base, S3C2410_UDC_EP0_CSR_IPKRDY, S3C2410_UDC_EP0_CSR_REG); -} - -static inline void s3c2410_udc_set_ep0_de(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - udc_writeb(base, S3C2410_UDC_EP0_CSR_DE, S3C2410_UDC_EP0_CSR_REG); -} - -static inline void s3c2410_udc_set_ep0_ss(void __iomem *b) -{ - udc_writeb(b, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - udc_writeb(b, S3C2410_UDC_EP0_CSR_SENDSTL, S3C2410_UDC_EP0_CSR_REG); -} - -static inline void s3c2410_udc_set_ep0_de_out(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - - udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY - | S3C2410_UDC_EP0_CSR_DE), - S3C2410_UDC_EP0_CSR_REG); -} - -static inline void s3c2410_udc_set_ep0_de_in(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - udc_writeb(base, (S3C2410_UDC_EP0_CSR_IPKRDY - | S3C2410_UDC_EP0_CSR_DE), - S3C2410_UDC_EP0_CSR_REG); -} - -/*------------------------- I/O ----------------------------------*/ - -/* - * s3c2410_udc_done - */ -static void s3c2410_udc_done(struct s3c2410_ep *ep, - struct s3c2410_request *req, int status) -{ - unsigned halted = ep->halted; - - list_del_init(&req->queue); - - if (likely(req->req.status == -EINPROGRESS)) - req->req.status = status; - else - status = req->req.status; - - ep->halted = 1; - usb_gadget_giveback_request(&ep->ep, &req->req); - ep->halted = halted; -} - -static void s3c2410_udc_nuke(struct s3c2410_udc *udc, - struct s3c2410_ep *ep, int status) -{ - while (!list_empty(&ep->queue)) { - struct s3c2410_request *req; - req = list_entry(ep->queue.next, struct s3c2410_request, - queue); - s3c2410_udc_done(ep, req, status); - } -} - -static inline int s3c2410_udc_fifo_count_out(void) -{ - int tmp; - - tmp = udc_read(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8; - tmp |= udc_read(S3C2410_UDC_OUT_FIFO_CNT1_REG); - return tmp; -} - -/* - * s3c2410_udc_write_packet - */ -static inline int s3c2410_udc_write_packet(int fifo, - struct s3c2410_request *req, - unsigned max) -{ - unsigned len = min(req->req.length - req->req.actual, max); - u8 *buf = req->req.buf + req->req.actual; - - prefetch(buf); - - dprintk(DEBUG_VERBOSE, "%s %d %d %d %d\n", __func__, - req->req.actual, req->req.length, len, req->req.actual + len); - - req->req.actual += len; - - udelay(5); - writesb(base_addr + fifo, buf, len); - return len; -} - -/* - * s3c2410_udc_write_fifo - * - * return: 0 = still running, 1 = completed, negative = errno - */ -static int s3c2410_udc_write_fifo(struct s3c2410_ep *ep, - struct s3c2410_request *req) -{ - unsigned count; - int is_last; - u32 idx; - int fifo_reg; - u32 ep_csr; - - idx = ep->bEndpointAddress & 0x7F; - switch (idx) { - default: - idx = 0; - fallthrough; - case 0: - fifo_reg = S3C2410_UDC_EP0_FIFO_REG; - break; - case 1: - fifo_reg = S3C2410_UDC_EP1_FIFO_REG; - break; - case 2: - fifo_reg = S3C2410_UDC_EP2_FIFO_REG; - break; - case 3: - fifo_reg = S3C2410_UDC_EP3_FIFO_REG; - break; - case 4: - fifo_reg = S3C2410_UDC_EP4_FIFO_REG; - break; - } - - count = s3c2410_udc_write_packet(fifo_reg, req, ep->ep.maxpacket); - - /* last packet is often short (sometimes a zlp) */ - if (count != ep->ep.maxpacket) - is_last = 1; - else if (req->req.length != req->req.actual || req->req.zero) - is_last = 0; - else - is_last = 2; - - /* Only ep0 debug messages are interesting */ - if (idx == 0) - dprintk(DEBUG_NORMAL, - "Written ep%d %d.%d of %d b [last %d,z %d]\n", - idx, count, req->req.actual, req->req.length, - is_last, req->req.zero); - - if (is_last) { - /* The order is important. It prevents sending 2 packets - * at the same time */ - - if (idx == 0) { - /* Reset signal => no need to say 'data sent' */ - if (!(udc_read(S3C2410_UDC_USB_INT_REG) - & S3C2410_UDC_USBINT_RESET)) - s3c2410_udc_set_ep0_de_in(base_addr); - ep->dev->ep0state = EP0_IDLE; - } else { - udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); - udc_write(idx, S3C2410_UDC_INDEX_REG); - udc_write(ep_csr | S3C2410_UDC_ICSR1_PKTRDY, - S3C2410_UDC_IN_CSR1_REG); - } - - s3c2410_udc_done(ep, req, 0); - is_last = 1; - } else { - if (idx == 0) { - /* Reset signal => no need to say 'data sent' */ - if (!(udc_read(S3C2410_UDC_USB_INT_REG) - & S3C2410_UDC_USBINT_RESET)) - s3c2410_udc_set_ep0_ipr(base_addr); - } else { - udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); - udc_write(idx, S3C2410_UDC_INDEX_REG); - udc_write(ep_csr | S3C2410_UDC_ICSR1_PKTRDY, - S3C2410_UDC_IN_CSR1_REG); - } - } - - return is_last; -} - -static inline int s3c2410_udc_read_packet(int fifo, u8 *buf, - struct s3c2410_request *req, unsigned avail) -{ - unsigned len; - - len = min(req->req.length - req->req.actual, avail); - req->req.actual += len; - - readsb(fifo + base_addr, buf, len); - return len; -} - -/* - * return: 0 = still running, 1 = queue empty, negative = errno - */ -static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep, - struct s3c2410_request *req) -{ - u8 *buf; - u32 ep_csr; - unsigned bufferspace; - int is_last = 1; - unsigned avail; - int fifo_count = 0; - u32 idx; - int fifo_reg; - - idx = ep->bEndpointAddress & 0x7F; - - switch (idx) { - default: - idx = 0; - fallthrough; - case 0: - fifo_reg = S3C2410_UDC_EP0_FIFO_REG; - break; - case 1: - fifo_reg = S3C2410_UDC_EP1_FIFO_REG; - break; - case 2: - fifo_reg = S3C2410_UDC_EP2_FIFO_REG; - break; - case 3: - fifo_reg = S3C2410_UDC_EP3_FIFO_REG; - break; - case 4: - fifo_reg = S3C2410_UDC_EP4_FIFO_REG; - break; - } - - if (!req->req.length) - return 1; - - buf = req->req.buf + req->req.actual; - bufferspace = req->req.length - req->req.actual; - if (!bufferspace) { - dprintk(DEBUG_NORMAL, "%s: buffer full!\n", __func__); - return -1; - } - - udc_write(idx, S3C2410_UDC_INDEX_REG); - - fifo_count = s3c2410_udc_fifo_count_out(); - dprintk(DEBUG_NORMAL, "%s fifo count : %d\n", __func__, fifo_count); - - if (fifo_count > ep->ep.maxpacket) - avail = ep->ep.maxpacket; - else - avail = fifo_count; - - fifo_count = s3c2410_udc_read_packet(fifo_reg, buf, req, avail); - - /* checking this with ep0 is not accurate as we already - * read a control request - **/ - if (idx != 0 && fifo_count < ep->ep.maxpacket) { - is_last = 1; - /* overflowed this request? flush extra data */ - if (fifo_count != avail) - req->req.status = -EOVERFLOW; - } else { - is_last = (req->req.length <= req->req.actual) ? 1 : 0; - } - - udc_write(idx, S3C2410_UDC_INDEX_REG); - fifo_count = s3c2410_udc_fifo_count_out(); - - /* Only ep0 debug messages are interesting */ - if (idx == 0) - dprintk(DEBUG_VERBOSE, "%s fifo count : %d [last %d]\n", - __func__, fifo_count, is_last); - - if (is_last) { - if (idx == 0) { - s3c2410_udc_set_ep0_de_out(base_addr); - ep->dev->ep0state = EP0_IDLE; - } else { - udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG); - udc_write(idx, S3C2410_UDC_INDEX_REG); - udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY, - S3C2410_UDC_OUT_CSR1_REG); - } - - s3c2410_udc_done(ep, req, 0); - } else { - if (idx == 0) { - s3c2410_udc_clear_ep0_opr(base_addr); - } else { - udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG); - udc_write(idx, S3C2410_UDC_INDEX_REG); - udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY, - S3C2410_UDC_OUT_CSR1_REG); - } - } - - return is_last; -} - -static int s3c2410_udc_read_fifo_crq(struct usb_ctrlrequest *crq) -{ - unsigned char *outbuf = (unsigned char *)crq; - int bytes_read = 0; - - udc_write(0, S3C2410_UDC_INDEX_REG); - - bytes_read = s3c2410_udc_fifo_count_out(); - - dprintk(DEBUG_NORMAL, "%s: fifo_count=%d\n", __func__, bytes_read); - - if (bytes_read > sizeof(struct usb_ctrlrequest)) - bytes_read = sizeof(struct usb_ctrlrequest); - - readsb(S3C2410_UDC_EP0_FIFO_REG + base_addr, outbuf, bytes_read); - - dprintk(DEBUG_VERBOSE, "%s: len=%d %02x:%02x {%x,%x,%x}\n", __func__, - bytes_read, crq->bRequest, crq->bRequestType, - crq->wValue, crq->wIndex, crq->wLength); - - return bytes_read; -} - -static int s3c2410_udc_get_status(struct s3c2410_udc *dev, - struct usb_ctrlrequest *crq) -{ - u16 status = 0; - u8 ep_num = crq->wIndex & 0x7F; - u8 is_in = crq->wIndex & USB_DIR_IN; - - switch (crq->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_INTERFACE: - break; - - case USB_RECIP_DEVICE: - status = dev->devstatus; - break; - - case USB_RECIP_ENDPOINT: - if (ep_num > 4 || crq->wLength > 2) - return 1; - - if (ep_num == 0) { - udc_write(0, S3C2410_UDC_INDEX_REG); - status = udc_read(S3C2410_UDC_IN_CSR1_REG); - status = status & S3C2410_UDC_EP0_CSR_SENDSTL; - } else { - udc_write(ep_num, S3C2410_UDC_INDEX_REG); - if (is_in) { - status = udc_read(S3C2410_UDC_IN_CSR1_REG); - status = status & S3C2410_UDC_ICSR1_SENDSTL; - } else { - status = udc_read(S3C2410_UDC_OUT_CSR1_REG); - status = status & S3C2410_UDC_OCSR1_SENDSTL; - } - } - - status = status ? 1 : 0; - break; - - default: - return 1; - } - - /* Seems to be needed to get it working. ouch :( */ - udelay(5); - udc_write(status & 0xFF, S3C2410_UDC_EP0_FIFO_REG); - udc_write(status >> 8, S3C2410_UDC_EP0_FIFO_REG); - s3c2410_udc_set_ep0_de_in(base_addr); - - return 0; -} -/*------------------------- usb state machine -------------------------------*/ -static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value); - -static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev, - struct s3c2410_ep *ep, - struct usb_ctrlrequest *crq, - u32 ep0csr) -{ - int len, ret, tmp; - - /* start control request? */ - if (!(ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY)) - return; - - s3c2410_udc_nuke(dev, ep, -EPROTO); - - len = s3c2410_udc_read_fifo_crq(crq); - if (len != sizeof(*crq)) { - dprintk(DEBUG_NORMAL, "setup begin: fifo READ ERROR" - " wanted %d bytes got %d. Stalling out...\n", - sizeof(*crq), len); - s3c2410_udc_set_ep0_ss(base_addr); - return; - } - - dprintk(DEBUG_NORMAL, "bRequest = %d bRequestType %d wLength = %d\n", - crq->bRequest, crq->bRequestType, crq->wLength); - - /* cope with automagic for some standard requests. */ - dev->req_std = (crq->bRequestType & USB_TYPE_MASK) - == USB_TYPE_STANDARD; - dev->req_config = 0; - dev->req_pending = 1; - - switch (crq->bRequest) { - case USB_REQ_SET_CONFIGURATION: - dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ...\n"); - - if (crq->bRequestType == USB_RECIP_DEVICE) { - dev->req_config = 1; - s3c2410_udc_set_ep0_de_out(base_addr); - } - break; - - case USB_REQ_SET_INTERFACE: - dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ...\n"); - - if (crq->bRequestType == USB_RECIP_INTERFACE) { - dev->req_config = 1; - s3c2410_udc_set_ep0_de_out(base_addr); - } - break; - - case USB_REQ_SET_ADDRESS: - dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ...\n"); - - if (crq->bRequestType == USB_RECIP_DEVICE) { - tmp = crq->wValue & 0x7F; - dev->address = tmp; - udc_write((tmp | S3C2410_UDC_FUNCADDR_UPDATE), - S3C2410_UDC_FUNC_ADDR_REG); - s3c2410_udc_set_ep0_de_out(base_addr); - return; - } - break; - - case USB_REQ_GET_STATUS: - dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ...\n"); - s3c2410_udc_clear_ep0_opr(base_addr); - - if (dev->req_std) { - if (!s3c2410_udc_get_status(dev, crq)) - return; - } - break; - - case USB_REQ_CLEAR_FEATURE: - s3c2410_udc_clear_ep0_opr(base_addr); - - if (crq->bRequestType != USB_RECIP_ENDPOINT) - break; - - if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0) - break; - - s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 0); - s3c2410_udc_set_ep0_de_out(base_addr); - return; - - case USB_REQ_SET_FEATURE: - s3c2410_udc_clear_ep0_opr(base_addr); - - if (crq->bRequestType != USB_RECIP_ENDPOINT) - break; - - if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0) - break; - - s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 1); - s3c2410_udc_set_ep0_de_out(base_addr); - return; - - default: - s3c2410_udc_clear_ep0_opr(base_addr); - break; - } - - if (crq->bRequestType & USB_DIR_IN) - dev->ep0state = EP0_IN_DATA_PHASE; - else - dev->ep0state = EP0_OUT_DATA_PHASE; - - if (!dev->driver) - return; - - /* deliver the request to the gadget driver */ - ret = dev->driver->setup(&dev->gadget, crq); - if (ret < 0) { - if (dev->req_config) { - dprintk(DEBUG_NORMAL, "config change %02x fail %d?\n", - crq->bRequest, ret); - return; - } - - if (ret == -EOPNOTSUPP) - dprintk(DEBUG_NORMAL, "Operation not supported\n"); - else - dprintk(DEBUG_NORMAL, - "dev->driver->setup failed. (%d)\n", ret); - - udelay(5); - s3c2410_udc_set_ep0_ss(base_addr); - s3c2410_udc_set_ep0_de_out(base_addr); - dev->ep0state = EP0_IDLE; - /* deferred i/o == no response yet */ - } else if (dev->req_pending) { - dprintk(DEBUG_VERBOSE, "dev->req_pending... what now?\n"); - dev->req_pending = 0; - } - - dprintk(DEBUG_VERBOSE, "ep0state %s\n", ep0states[dev->ep0state]); -} - -static void s3c2410_udc_handle_ep0(struct s3c2410_udc *dev) -{ - u32 ep0csr; - struct s3c2410_ep *ep = &dev->ep[0]; - struct s3c2410_request *req; - struct usb_ctrlrequest crq; - - if (list_empty(&ep->queue)) - req = NULL; - else - req = list_entry(ep->queue.next, struct s3c2410_request, queue); - - /* We make the assumption that S3C2410_UDC_IN_CSR1_REG equal to - * S3C2410_UDC_EP0_CSR_REG when index is zero */ - - udc_write(0, S3C2410_UDC_INDEX_REG); - ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG); - - dprintk(DEBUG_NORMAL, "ep0csr %x ep0state %s\n", - ep0csr, ep0states[dev->ep0state]); - - /* clear stall status */ - if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) { - s3c2410_udc_nuke(dev, ep, -EPIPE); - dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...\n"); - s3c2410_udc_clear_ep0_sst(base_addr); - dev->ep0state = EP0_IDLE; - return; - } - - /* clear setup end */ - if (ep0csr & S3C2410_UDC_EP0_CSR_SE) { - dprintk(DEBUG_NORMAL, "... serviced SETUP_END ...\n"); - s3c2410_udc_nuke(dev, ep, 0); - s3c2410_udc_clear_ep0_se(base_addr); - dev->ep0state = EP0_IDLE; - } - - switch (dev->ep0state) { - case EP0_IDLE: - s3c2410_udc_handle_ep0_idle(dev, ep, &crq, ep0csr); - break; - - case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */ - dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n"); - if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req) - s3c2410_udc_write_fifo(ep, req); - break; - - case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */ - dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n"); - if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req) - s3c2410_udc_read_fifo(ep, req); - break; - - case EP0_END_XFER: - dprintk(DEBUG_NORMAL, "EP0_END_XFER ... what now?\n"); - dev->ep0state = EP0_IDLE; - break; - - case EP0_STALL: - dprintk(DEBUG_NORMAL, "EP0_STALL ... what now?\n"); - dev->ep0state = EP0_IDLE; - break; - } -} - -/* - * handle_ep - Manage I/O endpoints - */ - -static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep) -{ - struct s3c2410_request *req; - int is_in = ep->bEndpointAddress & USB_DIR_IN; - u32 ep_csr1; - u32 idx; - - if (likely(!list_empty(&ep->queue))) - req = list_entry(ep->queue.next, - struct s3c2410_request, queue); - else - req = NULL; - - idx = ep->bEndpointAddress & 0x7F; - - if (is_in) { - udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); - dprintk(DEBUG_VERBOSE, "ep%01d write csr:%02x %d\n", - idx, ep_csr1, req ? 1 : 0); - - if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) { - dprintk(DEBUG_VERBOSE, "st\n"); - udc_write(idx, S3C2410_UDC_INDEX_REG); - udc_write(ep_csr1 & ~S3C2410_UDC_ICSR1_SENTSTL, - S3C2410_UDC_IN_CSR1_REG); - return; - } - - if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req) - s3c2410_udc_write_fifo(ep, req); - } else { - udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr1 = udc_read(S3C2410_UDC_OUT_CSR1_REG); - dprintk(DEBUG_VERBOSE, "ep%01d rd csr:%02x\n", idx, ep_csr1); - - if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) { - udc_write(idx, S3C2410_UDC_INDEX_REG); - udc_write(ep_csr1 & ~S3C2410_UDC_OCSR1_SENTSTL, - S3C2410_UDC_OUT_CSR1_REG); - return; - } - - if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) - s3c2410_udc_read_fifo(ep, req); - } -} - -/* - * s3c2410_udc_irq - interrupt handler - */ -static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev) -{ - struct s3c2410_udc *dev = _dev; - int usb_status; - int usbd_status; - int pwr_reg; - int ep0csr; - int i; - u32 idx, idx2; - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - - /* Driver connected ? */ - if (!dev->driver) { - /* Clear interrupts */ - udc_write(udc_read(S3C2410_UDC_USB_INT_REG), - S3C2410_UDC_USB_INT_REG); - udc_write(udc_read(S3C2410_UDC_EP_INT_REG), - S3C2410_UDC_EP_INT_REG); - } - - /* Save index */ - idx = udc_read(S3C2410_UDC_INDEX_REG); - - /* Read status registers */ - usb_status = udc_read(S3C2410_UDC_USB_INT_REG); - usbd_status = udc_read(S3C2410_UDC_EP_INT_REG); - pwr_reg = udc_read(S3C2410_UDC_PWR_REG); - - udc_writeb(base_addr, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG); - - dprintk(DEBUG_NORMAL, "usbs=%02x, usbds=%02x, pwr=%02x ep0csr=%02x\n", - usb_status, usbd_status, pwr_reg, ep0csr); - - /* - * Now, handle interrupts. There's two types : - * - Reset, Resume, Suspend coming -> usb_int_reg - * - EP -> ep_int_reg - */ - - /* RESET */ - if (usb_status & S3C2410_UDC_USBINT_RESET) { - /* two kind of reset : - * - reset start -> pwr reg = 8 - * - reset end -> pwr reg = 0 - **/ - dprintk(DEBUG_NORMAL, "USB reset csr %x pwr %x\n", - ep0csr, pwr_reg); - - dev->gadget.speed = USB_SPEED_UNKNOWN; - udc_write(0x00, S3C2410_UDC_INDEX_REG); - udc_write((dev->ep[0].ep.maxpacket & 0x7ff) >> 3, - S3C2410_UDC_MAXP_REG); - dev->address = 0; - - dev->ep0state = EP0_IDLE; - dev->gadget.speed = USB_SPEED_FULL; - - /* clear interrupt */ - udc_write(S3C2410_UDC_USBINT_RESET, - S3C2410_UDC_USB_INT_REG); - - udc_write(idx, S3C2410_UDC_INDEX_REG); - spin_unlock_irqrestore(&dev->lock, flags); - return IRQ_HANDLED; - } - - /* RESUME */ - if (usb_status & S3C2410_UDC_USBINT_RESUME) { - dprintk(DEBUG_NORMAL, "USB resume\n"); - - /* clear interrupt */ - udc_write(S3C2410_UDC_USBINT_RESUME, - S3C2410_UDC_USB_INT_REG); - - if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver - && dev->driver->resume) - dev->driver->resume(&dev->gadget); - } - - /* SUSPEND */ - if (usb_status & S3C2410_UDC_USBINT_SUSPEND) { - dprintk(DEBUG_NORMAL, "USB suspend\n"); - - /* clear interrupt */ - udc_write(S3C2410_UDC_USBINT_SUSPEND, - S3C2410_UDC_USB_INT_REG); - - if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver - && dev->driver->suspend) - dev->driver->suspend(&dev->gadget); - - dev->ep0state = EP0_IDLE; - } - - /* EP */ - /* control traffic */ - /* check on ep0csr != 0 is not a good idea as clearing in_pkt_ready - * generate an interrupt - */ - if (usbd_status & S3C2410_UDC_INT_EP0) { - dprintk(DEBUG_VERBOSE, "USB ep0 irq\n"); - /* Clear the interrupt bit by setting it to 1 */ - udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG); - s3c2410_udc_handle_ep0(dev); - } - - /* endpoint data transfers */ - for (i = 1; i < S3C2410_ENDPOINTS; i++) { - u32 tmp = 1 << i; - if (usbd_status & tmp) { - dprintk(DEBUG_VERBOSE, "USB ep%d irq\n", i); - - /* Clear the interrupt bit by setting it to 1 */ - udc_write(tmp, S3C2410_UDC_EP_INT_REG); - s3c2410_udc_handle_ep(&dev->ep[i]); - } - } - - /* what else causes this interrupt? a receive! who is it? */ - if (!usb_status && !usbd_status && !pwr_reg && !ep0csr) { - for (i = 1; i < S3C2410_ENDPOINTS; i++) { - idx2 = udc_read(S3C2410_UDC_INDEX_REG); - udc_write(i, S3C2410_UDC_INDEX_REG); - - if (udc_read(S3C2410_UDC_OUT_CSR1_REG) & 0x1) - s3c2410_udc_handle_ep(&dev->ep[i]); - - /* restore index */ - udc_write(idx2, S3C2410_UDC_INDEX_REG); - } - } - - dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", irq_usbd); - - /* Restore old index */ - udc_write(idx, S3C2410_UDC_INDEX_REG); - - spin_unlock_irqrestore(&dev->lock, flags); - - return IRQ_HANDLED; -} -/*------------------------- s3c2410_ep_ops ----------------------------------*/ - -static inline struct s3c2410_ep *to_s3c2410_ep(struct usb_ep *ep) -{ - return container_of(ep, struct s3c2410_ep, ep); -} - -static inline struct s3c2410_udc *to_s3c2410_udc(struct usb_gadget *gadget) -{ - return container_of(gadget, struct s3c2410_udc, gadget); -} - -static inline struct s3c2410_request *to_s3c2410_req(struct usb_request *req) -{ - return container_of(req, struct s3c2410_request, req); -} - -/* - * s3c2410_udc_ep_enable - */ -static int s3c2410_udc_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct s3c2410_udc *dev; - struct s3c2410_ep *ep; - u32 max, tmp; - unsigned long flags; - u32 csr1, csr2; - u32 int_en_reg; - - ep = to_s3c2410_ep(_ep); - - if (!_ep || !desc - || _ep->name == ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - - dev = ep->dev; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - max = usb_endpoint_maxp(desc); - - local_irq_save(flags); - _ep->maxpacket = max; - ep->ep.desc = desc; - ep->halted = 0; - ep->bEndpointAddress = desc->bEndpointAddress; - - /* set max packet */ - udc_write(ep->num, S3C2410_UDC_INDEX_REG); - udc_write(max >> 3, S3C2410_UDC_MAXP_REG); - - /* set type, direction, address; reset fifo counters */ - if (desc->bEndpointAddress & USB_DIR_IN) { - csr1 = S3C2410_UDC_ICSR1_FFLUSH|S3C2410_UDC_ICSR1_CLRDT; - csr2 = S3C2410_UDC_ICSR2_MODEIN|S3C2410_UDC_ICSR2_DMAIEN; - - udc_write(ep->num, S3C2410_UDC_INDEX_REG); - udc_write(csr1, S3C2410_UDC_IN_CSR1_REG); - udc_write(ep->num, S3C2410_UDC_INDEX_REG); - udc_write(csr2, S3C2410_UDC_IN_CSR2_REG); - } else { - /* don't flush in fifo or it will cause endpoint interrupt */ - csr1 = S3C2410_UDC_ICSR1_CLRDT; - csr2 = S3C2410_UDC_ICSR2_DMAIEN; - - udc_write(ep->num, S3C2410_UDC_INDEX_REG); - udc_write(csr1, S3C2410_UDC_IN_CSR1_REG); - udc_write(ep->num, S3C2410_UDC_INDEX_REG); - udc_write(csr2, S3C2410_UDC_IN_CSR2_REG); - - csr1 = S3C2410_UDC_OCSR1_FFLUSH | S3C2410_UDC_OCSR1_CLRDT; - csr2 = S3C2410_UDC_OCSR2_DMAIEN; - - udc_write(ep->num, S3C2410_UDC_INDEX_REG); - udc_write(csr1, S3C2410_UDC_OUT_CSR1_REG); - udc_write(ep->num, S3C2410_UDC_INDEX_REG); - udc_write(csr2, S3C2410_UDC_OUT_CSR2_REG); - } - - /* enable irqs */ - int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG); - udc_write(int_en_reg | (1 << ep->num), S3C2410_UDC_EP_INT_EN_REG); - - /* print some debug message */ - tmp = desc->bEndpointAddress; - dprintk(DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n", - _ep->name, ep->num, tmp, - desc->bEndpointAddress & USB_DIR_IN ? "in" : "out", max); - - local_irq_restore(flags); - s3c2410_udc_set_halt(_ep, 0); - - return 0; -} - -/* - * s3c2410_udc_ep_disable - */ -static int s3c2410_udc_ep_disable(struct usb_ep *_ep) -{ - struct s3c2410_ep *ep = to_s3c2410_ep(_ep); - unsigned long flags; - u32 int_en_reg; - - if (!_ep || !ep->ep.desc) { - dprintk(DEBUG_NORMAL, "%s not enabled\n", - _ep ? ep->ep.name : NULL); - return -EINVAL; - } - - local_irq_save(flags); - - dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name); - - ep->ep.desc = NULL; - ep->halted = 1; - - s3c2410_udc_nuke(ep->dev, ep, -ESHUTDOWN); - - /* disable irqs */ - int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG); - udc_write(int_en_reg & ~(1<<ep->num), S3C2410_UDC_EP_INT_EN_REG); - - local_irq_restore(flags); - - dprintk(DEBUG_NORMAL, "%s disabled\n", _ep->name); - - return 0; -} - -/* - * s3c2410_udc_alloc_request - */ -static struct usb_request * -s3c2410_udc_alloc_request(struct usb_ep *_ep, gfp_t mem_flags) -{ - struct s3c2410_request *req; - - dprintk(DEBUG_VERBOSE, "%s(%p,%d)\n", __func__, _ep, mem_flags); - - if (!_ep) - return NULL; - - req = kzalloc(sizeof(struct s3c2410_request), mem_flags); - if (!req) - return NULL; - - INIT_LIST_HEAD(&req->queue); - return &req->req; -} - -/* - * s3c2410_udc_free_request - */ -static void -s3c2410_udc_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct s3c2410_ep *ep = to_s3c2410_ep(_ep); - struct s3c2410_request *req = to_s3c2410_req(_req); - - dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req); - - if (!ep || !_req || (!ep->ep.desc && _ep->name != ep0name)) - return; - - WARN_ON(!list_empty(&req->queue)); - kfree(req); -} - -/* - * s3c2410_udc_queue - */ -static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct s3c2410_request *req = to_s3c2410_req(_req); - struct s3c2410_ep *ep = to_s3c2410_ep(_ep); - struct s3c2410_udc *dev; - u32 ep_csr = 0; - int fifo_count = 0; - unsigned long flags; - - if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) { - dprintk(DEBUG_NORMAL, "%s: invalid args\n", __func__); - return -EINVAL; - } - - dev = ep->dev; - if (unlikely(!dev->driver - || dev->gadget.speed == USB_SPEED_UNKNOWN)) { - return -ESHUTDOWN; - } - - local_irq_save(flags); - - if (unlikely(!_req || !_req->complete - || !_req->buf || !list_empty(&req->queue))) { - if (!_req) - dprintk(DEBUG_NORMAL, "%s: 1 X X X\n", __func__); - else { - dprintk(DEBUG_NORMAL, "%s: 0 %01d %01d %01d\n", - __func__, !_req->complete, !_req->buf, - !list_empty(&req->queue)); - } - - local_irq_restore(flags); - return -EINVAL; - } - - _req->status = -EINPROGRESS; - _req->actual = 0; - - dprintk(DEBUG_VERBOSE, "%s: ep%x len %d\n", - __func__, ep->bEndpointAddress, _req->length); - - if (ep->bEndpointAddress) { - udc_write(ep->bEndpointAddress & 0x7F, S3C2410_UDC_INDEX_REG); - - ep_csr = udc_read((ep->bEndpointAddress & USB_DIR_IN) - ? S3C2410_UDC_IN_CSR1_REG - : S3C2410_UDC_OUT_CSR1_REG); - fifo_count = s3c2410_udc_fifo_count_out(); - } else { - udc_write(0, S3C2410_UDC_INDEX_REG); - ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); - fifo_count = s3c2410_udc_fifo_count_out(); - } - - /* kickstart this i/o queue? */ - if (list_empty(&ep->queue) && !ep->halted) { - if (ep->bEndpointAddress == 0 /* ep0 */) { - switch (dev->ep0state) { - case EP0_IN_DATA_PHASE: - if (!(ep_csr&S3C2410_UDC_EP0_CSR_IPKRDY) - && s3c2410_udc_write_fifo(ep, - req)) { - dev->ep0state = EP0_IDLE; - req = NULL; - } - break; - - case EP0_OUT_DATA_PHASE: - if ((!_req->length) - || ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY) - && s3c2410_udc_read_fifo(ep, - req))) { - dev->ep0state = EP0_IDLE; - req = NULL; - } - break; - - default: - local_irq_restore(flags); - return -EL2HLT; - } - } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0 - && (!(ep_csr&S3C2410_UDC_OCSR1_PKTRDY)) - && s3c2410_udc_write_fifo(ep, req)) { - req = NULL; - } else if ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY) - && fifo_count - && s3c2410_udc_read_fifo(ep, req)) { - req = NULL; - } - } - - /* pio or dma irq handler advances the queue. */ - if (likely(req)) - list_add_tail(&req->queue, &ep->queue); - - local_irq_restore(flags); - - dprintk(DEBUG_VERBOSE, "%s ok\n", __func__); - return 0; -} - -/* - * s3c2410_udc_dequeue - */ -static int s3c2410_udc_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct s3c2410_ep *ep = to_s3c2410_ep(_ep); - int retval = -EINVAL; - unsigned long flags; - struct s3c2410_request *req = NULL, *iter; - - dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req); - - if (!the_controller->driver) - return -ESHUTDOWN; - - if (!_ep || !_req) - return retval; - - local_irq_save(flags); - - list_for_each_entry(iter, &ep->queue, queue) { - if (&iter->req != _req) - continue; - list_del_init(&iter->queue); - _req->status = -ECONNRESET; - req = iter; - retval = 0; - break; - } - - if (retval == 0) { - dprintk(DEBUG_VERBOSE, - "dequeued req %p from %s, len %d buf %p\n", - req, _ep->name, _req->length, _req->buf); - - s3c2410_udc_done(ep, req, -ECONNRESET); - } - - local_irq_restore(flags); - return retval; -} - -/* - * s3c2410_udc_set_halt - */ -static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value) -{ - struct s3c2410_ep *ep = to_s3c2410_ep(_ep); - u32 ep_csr = 0; - unsigned long flags; - u32 idx; - - if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) { - dprintk(DEBUG_NORMAL, "%s: inval 2\n", __func__); - return -EINVAL; - } - - local_irq_save(flags); - - idx = ep->bEndpointAddress & 0x7F; - - if (idx == 0) { - s3c2410_udc_set_ep0_ss(base_addr); - s3c2410_udc_set_ep0_de_out(base_addr); - } else { - udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr = udc_read((ep->bEndpointAddress & USB_DIR_IN) - ? S3C2410_UDC_IN_CSR1_REG - : S3C2410_UDC_OUT_CSR1_REG); - - if ((ep->bEndpointAddress & USB_DIR_IN) != 0) { - if (value) - udc_write(ep_csr | S3C2410_UDC_ICSR1_SENDSTL, - S3C2410_UDC_IN_CSR1_REG); - else { - ep_csr &= ~S3C2410_UDC_ICSR1_SENDSTL; - udc_write(ep_csr, S3C2410_UDC_IN_CSR1_REG); - ep_csr |= S3C2410_UDC_ICSR1_CLRDT; - udc_write(ep_csr, S3C2410_UDC_IN_CSR1_REG); - } - } else { - if (value) - udc_write(ep_csr | S3C2410_UDC_OCSR1_SENDSTL, - S3C2410_UDC_OUT_CSR1_REG); - else { - ep_csr &= ~S3C2410_UDC_OCSR1_SENDSTL; - udc_write(ep_csr, S3C2410_UDC_OUT_CSR1_REG); - ep_csr |= S3C2410_UDC_OCSR1_CLRDT; - udc_write(ep_csr, S3C2410_UDC_OUT_CSR1_REG); - } - } - } - - ep->halted = value ? 1 : 0; - local_irq_restore(flags); - - return 0; -} - -static const struct usb_ep_ops s3c2410_ep_ops = { - .enable = s3c2410_udc_ep_enable, - .disable = s3c2410_udc_ep_disable, - - .alloc_request = s3c2410_udc_alloc_request, - .free_request = s3c2410_udc_free_request, - - .queue = s3c2410_udc_queue, - .dequeue = s3c2410_udc_dequeue, - - .set_halt = s3c2410_udc_set_halt, -}; - -/*------------------------- usb_gadget_ops ----------------------------------*/ - -/* - * s3c2410_udc_get_frame - */ -static int s3c2410_udc_get_frame(struct usb_gadget *_gadget) -{ - int tmp; - - dprintk(DEBUG_VERBOSE, "%s()\n", __func__); - - tmp = udc_read(S3C2410_UDC_FRAME_NUM2_REG) << 8; - tmp |= udc_read(S3C2410_UDC_FRAME_NUM1_REG); - return tmp; -} - -/* - * s3c2410_udc_wakeup - */ -static int s3c2410_udc_wakeup(struct usb_gadget *_gadget) -{ - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - return 0; -} - -/* - * s3c2410_udc_set_selfpowered - */ -static int s3c2410_udc_set_selfpowered(struct usb_gadget *gadget, int value) -{ - struct s3c2410_udc *udc = to_s3c2410_udc(gadget); - - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - - gadget->is_selfpowered = (value != 0); - if (value) - udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED); - else - udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); - - return 0; -} - -static void s3c2410_udc_disable(struct s3c2410_udc *dev); -static void s3c2410_udc_enable(struct s3c2410_udc *dev); - -static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on) -{ - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - - if (udc_info && (udc_info->udc_command || udc->pullup_gpiod)) { - - if (is_on) - s3c2410_udc_enable(udc); - else { - if (udc->gadget.speed != USB_SPEED_UNKNOWN) { - if (udc->driver && udc->driver->disconnect) - udc->driver->disconnect(&udc->gadget); - - } - s3c2410_udc_disable(udc); - } - } else { - return -EOPNOTSUPP; - } - - return 0; -} - -static int s3c2410_udc_vbus_session(struct usb_gadget *gadget, int is_active) -{ - struct s3c2410_udc *udc = to_s3c2410_udc(gadget); - - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - - udc->vbus = (is_active != 0); - s3c2410_udc_set_pullup(udc, is_active); - return 0; -} - -static int s3c2410_udc_pullup(struct usb_gadget *gadget, int is_on) -{ - struct s3c2410_udc *udc = to_s3c2410_udc(gadget); - - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - - s3c2410_udc_set_pullup(udc, is_on); - return 0; -} - -static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev) -{ - struct s3c2410_udc *dev = _dev; - unsigned int value; - - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - - value = gpiod_get_value(dev->vbus_gpiod); - - if (value != dev->vbus) - s3c2410_udc_vbus_session(&dev->gadget, value); - - return IRQ_HANDLED; -} - -static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma) -{ - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - - if (udc_info && udc_info->vbus_draw) { - udc_info->vbus_draw(ma); - return 0; - } - - return -ENOTSUPP; -} - -static int s3c2410_udc_start(struct usb_gadget *g, - struct usb_gadget_driver *driver); -static int s3c2410_udc_stop(struct usb_gadget *g); - -static const struct usb_gadget_ops s3c2410_ops = { - .get_frame = s3c2410_udc_get_frame, - .wakeup = s3c2410_udc_wakeup, - .set_selfpowered = s3c2410_udc_set_selfpowered, - .pullup = s3c2410_udc_pullup, - .vbus_session = s3c2410_udc_vbus_session, - .vbus_draw = s3c2410_vbus_draw, - .udc_start = s3c2410_udc_start, - .udc_stop = s3c2410_udc_stop, -}; - -static void s3c2410_udc_command(struct s3c2410_udc *udc, - enum s3c2410_udc_cmd_e cmd) -{ - if (!udc_info) - return; - - if (udc_info->udc_command) { - udc_info->udc_command(cmd); - } else if (udc->pullup_gpiod) { - int value; - - switch (cmd) { - case S3C2410_UDC_P_ENABLE: - value = 1; - break; - case S3C2410_UDC_P_DISABLE: - value = 0; - break; - default: - return; - } - - gpiod_set_value(udc->pullup_gpiod, value); - } -} - -/*------------------------- gadget driver handling---------------------------*/ -/* - * s3c2410_udc_disable - */ -static void s3c2410_udc_disable(struct s3c2410_udc *dev) -{ - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - - /* Disable all interrupts */ - udc_write(0x00, S3C2410_UDC_USB_INT_EN_REG); - udc_write(0x00, S3C2410_UDC_EP_INT_EN_REG); - - /* Clear the interrupt registers */ - udc_write(S3C2410_UDC_USBINT_RESET - | S3C2410_UDC_USBINT_RESUME - | S3C2410_UDC_USBINT_SUSPEND, - S3C2410_UDC_USB_INT_REG); - - udc_write(0x1F, S3C2410_UDC_EP_INT_REG); - - /* Good bye, cruel world */ - s3c2410_udc_command(dev, S3C2410_UDC_P_DISABLE); - - /* Set speed to unknown */ - dev->gadget.speed = USB_SPEED_UNKNOWN; -} - -/* - * s3c2410_udc_reinit - */ -static void s3c2410_udc_reinit(struct s3c2410_udc *dev) -{ - u32 i; - - /* device/ep0 records init */ - INIT_LIST_HEAD(&dev->gadget.ep_list); - INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); - dev->ep0state = EP0_IDLE; - - for (i = 0; i < S3C2410_ENDPOINTS; i++) { - struct s3c2410_ep *ep = &dev->ep[i]; - - if (i != 0) - list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); - - ep->dev = dev; - ep->ep.desc = NULL; - ep->halted = 0; - INIT_LIST_HEAD(&ep->queue); - usb_ep_set_maxpacket_limit(&ep->ep, ep->ep.maxpacket); - } -} - -/* - * s3c2410_udc_enable - */ -static void s3c2410_udc_enable(struct s3c2410_udc *dev) -{ - int i; - - dprintk(DEBUG_NORMAL, "s3c2410_udc_enable called\n"); - - /* dev->gadget.speed = USB_SPEED_UNKNOWN; */ - dev->gadget.speed = USB_SPEED_FULL; - - /* Set MAXP for all endpoints */ - for (i = 0; i < S3C2410_ENDPOINTS; i++) { - udc_write(i, S3C2410_UDC_INDEX_REG); - udc_write((dev->ep[i].ep.maxpacket & 0x7ff) >> 3, - S3C2410_UDC_MAXP_REG); - } - - /* Set default power state */ - udc_write(DEFAULT_POWER_STATE, S3C2410_UDC_PWR_REG); - - /* Enable reset and suspend interrupt interrupts */ - udc_write(S3C2410_UDC_USBINT_RESET | S3C2410_UDC_USBINT_SUSPEND, - S3C2410_UDC_USB_INT_EN_REG); - - /* Enable ep0 interrupt */ - udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG); - - /* time to say "hello, world" */ - s3c2410_udc_command(dev, S3C2410_UDC_P_ENABLE); -} - -static int s3c2410_udc_start(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct s3c2410_udc *udc = to_s3c2410(g); - - dprintk(DEBUG_NORMAL, "%s() '%s'\n", __func__, driver->driver.name); - - /* Hook the driver */ - udc->driver = driver; - - /* Enable udc */ - s3c2410_udc_enable(udc); - - return 0; -} - -static int s3c2410_udc_stop(struct usb_gadget *g) -{ - struct s3c2410_udc *udc = to_s3c2410(g); - - udc->driver = NULL; - - /* Disable udc */ - s3c2410_udc_disable(udc); - - return 0; -} - -/*---------------------------------------------------------------------------*/ -static struct s3c2410_udc memory = { - .gadget = { - .ops = &s3c2410_ops, - .ep0 = &memory.ep[0].ep, - .name = gadget_name, - .dev = { - .init_name = "gadget", - }, - }, - - /* control endpoint */ - .ep[0] = { - .num = 0, - .ep = { - .name = ep0name, - .ops = &s3c2410_ep_ops, - .maxpacket = EP0_FIFO_SIZE, - .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, - USB_EP_CAPS_DIR_ALL), - }, - .dev = &memory, - }, - - /* first group of endpoints */ - .ep[1] = { - .num = 1, - .ep = { - .name = "ep1-bulk", - .ops = &s3c2410_ep_ops, - .maxpacket = EP_FIFO_SIZE, - .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, - USB_EP_CAPS_DIR_ALL), - }, - .dev = &memory, - .fifo_size = EP_FIFO_SIZE, - .bEndpointAddress = 1, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .ep[2] = { - .num = 2, - .ep = { - .name = "ep2-bulk", - .ops = &s3c2410_ep_ops, - .maxpacket = EP_FIFO_SIZE, - .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, - USB_EP_CAPS_DIR_ALL), - }, - .dev = &memory, - .fifo_size = EP_FIFO_SIZE, - .bEndpointAddress = 2, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .ep[3] = { - .num = 3, - .ep = { - .name = "ep3-bulk", - .ops = &s3c2410_ep_ops, - .maxpacket = EP_FIFO_SIZE, - .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, - USB_EP_CAPS_DIR_ALL), - }, - .dev = &memory, - .fifo_size = EP_FIFO_SIZE, - .bEndpointAddress = 3, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .ep[4] = { - .num = 4, - .ep = { - .name = "ep4-bulk", - .ops = &s3c2410_ep_ops, - .maxpacket = EP_FIFO_SIZE, - .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, - USB_EP_CAPS_DIR_ALL), - }, - .dev = &memory, - .fifo_size = EP_FIFO_SIZE, - .bEndpointAddress = 4, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - } - -}; - -/* - * probe - binds to the platform device - */ -static int s3c2410_udc_probe(struct platform_device *pdev) -{ - struct s3c2410_udc *udc = &memory; - struct device *dev = &pdev->dev; - int retval; - int irq; - - dev_dbg(dev, "%s()\n", __func__); - - usb_bus_clock = clk_get(NULL, "usb-bus-gadget"); - if (IS_ERR(usb_bus_clock)) { - dev_err(dev, "failed to get usb bus clock source\n"); - return PTR_ERR(usb_bus_clock); - } - - clk_prepare_enable(usb_bus_clock); - - udc_clock = clk_get(NULL, "usb-device"); - if (IS_ERR(udc_clock)) { - dev_err(dev, "failed to get udc clock source\n"); - retval = PTR_ERR(udc_clock); - goto err_usb_bus_clk; - } - - clk_prepare_enable(udc_clock); - - mdelay(10); - - dev_dbg(dev, "got and enabled clocks\n"); - - if (strncmp(pdev->name, "s3c2440", 7) == 0) { - dev_info(dev, "S3C2440: increasing FIFO to 128 bytes\n"); - memory.ep[1].fifo_size = S3C2440_EP_FIFO_SIZE; - memory.ep[2].fifo_size = S3C2440_EP_FIFO_SIZE; - memory.ep[3].fifo_size = S3C2440_EP_FIFO_SIZE; - memory.ep[4].fifo_size = S3C2440_EP_FIFO_SIZE; - } - - spin_lock_init(&udc->lock); - udc_info = dev_get_platdata(&pdev->dev); - - base_addr = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base_addr)) { - retval = PTR_ERR(base_addr); - goto err_udc_clk; - } - - the_controller = udc; - platform_set_drvdata(pdev, udc); - - s3c2410_udc_disable(udc); - s3c2410_udc_reinit(udc); - - irq_usbd = platform_get_irq(pdev, 0); - if (irq_usbd < 0) { - retval = irq_usbd; - goto err_udc_clk; - } - - /* irq setup after old hardware state is cleaned up */ - retval = request_irq(irq_usbd, s3c2410_udc_irq, - 0, gadget_name, udc); - - if (retval != 0) { - dev_err(dev, "cannot get irq %i, err %d\n", irq_usbd, retval); - retval = -EBUSY; - goto err_udc_clk; - } - - dev_dbg(dev, "got irq %i\n", irq_usbd); - - udc->vbus_gpiod = gpiod_get_optional(dev, "vbus", GPIOD_IN); - if (IS_ERR(udc->vbus_gpiod)) { - retval = PTR_ERR(udc->vbus_gpiod); - goto err_int; - } - if (udc->vbus_gpiod) { - gpiod_set_consumer_name(udc->vbus_gpiod, "udc vbus"); - - irq = gpiod_to_irq(udc->vbus_gpiod); - if (irq < 0) { - dev_err(dev, "no irq for gpio vbus pin\n"); - retval = irq; - goto err_gpio_claim; - } - - retval = request_irq(irq, s3c2410_udc_vbus_irq, - IRQF_TRIGGER_RISING - | IRQF_TRIGGER_FALLING | IRQF_SHARED, - gadget_name, udc); - - if (retval != 0) { - dev_err(dev, "can't get vbus irq %d, err %d\n", - irq, retval); - retval = -EBUSY; - goto err_gpio_claim; - } - - dev_dbg(dev, "got irq %i\n", irq); - } else { - udc->vbus = 1; - } - - udc->pullup_gpiod = gpiod_get_optional(dev, "pullup", GPIOD_OUT_LOW); - if (IS_ERR(udc->pullup_gpiod)) { - retval = PTR_ERR(udc->pullup_gpiod); - goto err_vbus_irq; - } - gpiod_set_consumer_name(udc->pullup_gpiod, "udc pullup"); - - retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); - if (retval) - goto err_add_udc; - - debugfs_create_file("registers", S_IRUGO, s3c2410_udc_debugfs_root, udc, - &s3c2410_udc_debugfs_fops); - - dev_dbg(dev, "probe ok\n"); - - return 0; - -err_add_udc: -err_vbus_irq: - if (udc->vbus_gpiod) - free_irq(gpiod_to_irq(udc->vbus_gpiod), udc); -err_gpio_claim: -err_int: - free_irq(irq_usbd, udc); -err_udc_clk: - clk_disable_unprepare(udc_clock); - clk_put(udc_clock); - udc_clock = NULL; -err_usb_bus_clk: - clk_disable_unprepare(usb_bus_clock); - clk_put(usb_bus_clock); - usb_bus_clock = NULL; - - return retval; -} - -/* - * s3c2410_udc_remove - */ -static int s3c2410_udc_remove(struct platform_device *pdev) -{ - struct s3c2410_udc *udc = platform_get_drvdata(pdev); - - dev_dbg(&pdev->dev, "%s()\n", __func__); - - if (udc->driver) - return -EBUSY; - - usb_del_gadget_udc(&udc->gadget); - debugfs_remove(debugfs_lookup("registers", s3c2410_udc_debugfs_root)); - - if (udc->vbus_gpiod) - free_irq(gpiod_to_irq(udc->vbus_gpiod), udc); - - free_irq(irq_usbd, udc); - - if (!IS_ERR(udc_clock) && udc_clock != NULL) { - clk_disable_unprepare(udc_clock); - clk_put(udc_clock); - udc_clock = NULL; - } - - if (!IS_ERR(usb_bus_clock) && usb_bus_clock != NULL) { - clk_disable_unprepare(usb_bus_clock); - clk_put(usb_bus_clock); - usb_bus_clock = NULL; - } - - dev_dbg(&pdev->dev, "%s: remove ok\n", __func__); - return 0; -} - -#ifdef CONFIG_PM -static int -s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message) -{ - struct s3c2410_udc *udc = platform_get_drvdata(pdev); - - s3c2410_udc_command(udc, S3C2410_UDC_P_DISABLE); - - return 0; -} - -static int s3c2410_udc_resume(struct platform_device *pdev) -{ - struct s3c2410_udc *udc = platform_get_drvdata(pdev); - - s3c2410_udc_command(udc, S3C2410_UDC_P_ENABLE); - - return 0; -} -#else -#define s3c2410_udc_suspend NULL -#define s3c2410_udc_resume NULL -#endif - -static const struct platform_device_id s3c_udc_ids[] = { - { "s3c2410-usbgadget", }, - { "s3c2440-usbgadget", }, - { } -}; -MODULE_DEVICE_TABLE(platform, s3c_udc_ids); - -static struct platform_driver udc_driver_24x0 = { - .driver = { - .name = "s3c24x0-usbgadget", - }, - .probe = s3c2410_udc_probe, - .remove = s3c2410_udc_remove, - .suspend = s3c2410_udc_suspend, - .resume = s3c2410_udc_resume, - .id_table = s3c_udc_ids, -}; - -static int __init udc_init(void) -{ - int retval; - - dprintk(DEBUG_NORMAL, "%s\n", gadget_name); - - s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, - usb_debug_root); - - retval = platform_driver_register(&udc_driver_24x0); - if (retval) - goto err; - - return 0; - -err: - debugfs_remove(s3c2410_udc_debugfs_root); - return retval; -} - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver_24x0); - debugfs_remove_recursive(s3c2410_udc_debugfs_root); -} - -module_init(udc_init); -module_exit(udc_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/udc/s3c2410_udc.h b/drivers/usb/gadget/udc/s3c2410_udc.h deleted file mode 100644 index cdbf202e5ee8..000000000000 --- a/drivers/usb/gadget/udc/s3c2410_udc.h +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * linux/drivers/usb/gadget/s3c2410_udc.h - * Samsung on-chip full speed USB device controllers - * - * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard - * Additional cleanups by Ben Dooks <ben-linux@fluff.org> - */ - -#ifndef _S3C2410_UDC_H -#define _S3C2410_UDC_H - -struct s3c2410_ep { - struct list_head queue; - unsigned long last_io; /* jiffies timestamp */ - struct usb_gadget *gadget; - struct s3c2410_udc *dev; - struct usb_ep ep; - u8 num; - - unsigned short fifo_size; - u8 bEndpointAddress; - u8 bmAttributes; - - unsigned halted : 1; - unsigned already_seen : 1; - unsigned setup_stage : 1; -}; - - -/* Warning : ep0 has a fifo of 16 bytes */ -/* Don't try to set 32 or 64 */ -/* also testusb 14 fails wit 16 but is */ -/* fine with 8 */ -#define EP0_FIFO_SIZE 8 -#define EP_FIFO_SIZE 64 -#define DEFAULT_POWER_STATE 0x00 - -#define S3C2440_EP_FIFO_SIZE 128 - -static const char ep0name [] = "ep0"; - -static const char *const ep_name[] = { - ep0name, /* everyone has ep0 */ - /* s3c2410 four bidirectional bulk endpoints */ - "ep1-bulk", "ep2-bulk", "ep3-bulk", "ep4-bulk", -}; - -#define S3C2410_ENDPOINTS ARRAY_SIZE(ep_name) - -struct s3c2410_request { - struct list_head queue; /* ep's requests */ - struct usb_request req; -}; - -enum ep0_state { - EP0_IDLE, - EP0_IN_DATA_PHASE, - EP0_OUT_DATA_PHASE, - EP0_END_XFER, - EP0_STALL, -}; - -static const char *ep0states[]= { - "EP0_IDLE", - "EP0_IN_DATA_PHASE", - "EP0_OUT_DATA_PHASE", - "EP0_END_XFER", - "EP0_STALL", -}; - -struct s3c2410_udc { - spinlock_t lock; - - struct s3c2410_ep ep[S3C2410_ENDPOINTS]; - int address; - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct s3c2410_request fifo_req; - u8 fifo_buf[EP_FIFO_SIZE]; - u16 devstatus; - - u32 port_status; - int ep0state; - - struct gpio_desc *vbus_gpiod; - struct gpio_desc *pullup_gpiod; - - unsigned got_irq : 1; - - unsigned req_std : 1; - unsigned req_config : 1; - unsigned req_pending : 1; - u8 vbus; - int irq; -}; -#define to_s3c2410(g) (container_of((g), struct s3c2410_udc, gadget)) - -#endif diff --git a/drivers/usb/gadget/udc/s3c2410_udc_regs.h b/drivers/usb/gadget/udc/s3c2410_udc_regs.h deleted file mode 100644 index d8d2eeaca088..000000000000 --- a/drivers/usb/gadget/udc/s3c2410_udc_regs.h +++ /dev/null @@ -1,146 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2004 Herbert Poetzl <herbert@13thfloor.at> - */ - -#ifndef __ASM_ARCH_REGS_UDC_H -#define __ASM_ARCH_REGS_UDC_H - -#define S3C2410_USBDREG(x) (x) - -#define S3C2410_UDC_FUNC_ADDR_REG S3C2410_USBDREG(0x0140) -#define S3C2410_UDC_PWR_REG S3C2410_USBDREG(0x0144) -#define S3C2410_UDC_EP_INT_REG S3C2410_USBDREG(0x0148) - -#define S3C2410_UDC_USB_INT_REG S3C2410_USBDREG(0x0158) -#define S3C2410_UDC_EP_INT_EN_REG S3C2410_USBDREG(0x015c) - -#define S3C2410_UDC_USB_INT_EN_REG S3C2410_USBDREG(0x016c) - -#define S3C2410_UDC_FRAME_NUM1_REG S3C2410_USBDREG(0x0170) -#define S3C2410_UDC_FRAME_NUM2_REG S3C2410_USBDREG(0x0174) - -#define S3C2410_UDC_EP0_FIFO_REG S3C2410_USBDREG(0x01c0) -#define S3C2410_UDC_EP1_FIFO_REG S3C2410_USBDREG(0x01c4) -#define S3C2410_UDC_EP2_FIFO_REG S3C2410_USBDREG(0x01c8) -#define S3C2410_UDC_EP3_FIFO_REG S3C2410_USBDREG(0x01cc) -#define S3C2410_UDC_EP4_FIFO_REG S3C2410_USBDREG(0x01d0) - -#define S3C2410_UDC_EP1_DMA_CON S3C2410_USBDREG(0x0200) -#define S3C2410_UDC_EP1_DMA_UNIT S3C2410_USBDREG(0x0204) -#define S3C2410_UDC_EP1_DMA_FIFO S3C2410_USBDREG(0x0208) -#define S3C2410_UDC_EP1_DMA_TTC_L S3C2410_USBDREG(0x020c) -#define S3C2410_UDC_EP1_DMA_TTC_M S3C2410_USBDREG(0x0210) -#define S3C2410_UDC_EP1_DMA_TTC_H S3C2410_USBDREG(0x0214) - -#define S3C2410_UDC_EP2_DMA_CON S3C2410_USBDREG(0x0218) -#define S3C2410_UDC_EP2_DMA_UNIT S3C2410_USBDREG(0x021c) -#define S3C2410_UDC_EP2_DMA_FIFO S3C2410_USBDREG(0x0220) -#define S3C2410_UDC_EP2_DMA_TTC_L S3C2410_USBDREG(0x0224) -#define S3C2410_UDC_EP2_DMA_TTC_M S3C2410_USBDREG(0x0228) -#define S3C2410_UDC_EP2_DMA_TTC_H S3C2410_USBDREG(0x022c) - -#define S3C2410_UDC_EP3_DMA_CON S3C2410_USBDREG(0x0240) -#define S3C2410_UDC_EP3_DMA_UNIT S3C2410_USBDREG(0x0244) -#define S3C2410_UDC_EP3_DMA_FIFO S3C2410_USBDREG(0x0248) -#define S3C2410_UDC_EP3_DMA_TTC_L S3C2410_USBDREG(0x024c) -#define S3C2410_UDC_EP3_DMA_TTC_M S3C2410_USBDREG(0x0250) -#define S3C2410_UDC_EP3_DMA_TTC_H S3C2410_USBDREG(0x0254) - -#define S3C2410_UDC_EP4_DMA_CON S3C2410_USBDREG(0x0258) -#define S3C2410_UDC_EP4_DMA_UNIT S3C2410_USBDREG(0x025c) -#define S3C2410_UDC_EP4_DMA_FIFO S3C2410_USBDREG(0x0260) -#define S3C2410_UDC_EP4_DMA_TTC_L S3C2410_USBDREG(0x0264) -#define S3C2410_UDC_EP4_DMA_TTC_M S3C2410_USBDREG(0x0268) -#define S3C2410_UDC_EP4_DMA_TTC_H S3C2410_USBDREG(0x026c) - -#define S3C2410_UDC_INDEX_REG S3C2410_USBDREG(0x0178) - -/* indexed registers */ - -#define S3C2410_UDC_MAXP_REG S3C2410_USBDREG(0x0180) - -#define S3C2410_UDC_EP0_CSR_REG S3C2410_USBDREG(0x0184) - -#define S3C2410_UDC_IN_CSR1_REG S3C2410_USBDREG(0x0184) -#define S3C2410_UDC_IN_CSR2_REG S3C2410_USBDREG(0x0188) - -#define S3C2410_UDC_OUT_CSR1_REG S3C2410_USBDREG(0x0190) -#define S3C2410_UDC_OUT_CSR2_REG S3C2410_USBDREG(0x0194) -#define S3C2410_UDC_OUT_FIFO_CNT1_REG S3C2410_USBDREG(0x0198) -#define S3C2410_UDC_OUT_FIFO_CNT2_REG S3C2410_USBDREG(0x019c) - -#define S3C2410_UDC_FUNCADDR_UPDATE (1 << 7) - -#define S3C2410_UDC_PWR_ISOUP (1 << 7) /* R/W */ -#define S3C2410_UDC_PWR_RESET (1 << 3) /* R */ -#define S3C2410_UDC_PWR_RESUME (1 << 2) /* R/W */ -#define S3C2410_UDC_PWR_SUSPEND (1 << 1) /* R */ -#define S3C2410_UDC_PWR_ENSUSPEND (1 << 0) /* R/W */ - -#define S3C2410_UDC_PWR_DEFAULT (0x00) - -#define S3C2410_UDC_INT_EP4 (1 << 4) /* R/W (clear only) */ -#define S3C2410_UDC_INT_EP3 (1 << 3) /* R/W (clear only) */ -#define S3C2410_UDC_INT_EP2 (1 << 2) /* R/W (clear only) */ -#define S3C2410_UDC_INT_EP1 (1 << 1) /* R/W (clear only) */ -#define S3C2410_UDC_INT_EP0 (1 << 0) /* R/W (clear only) */ - -#define S3C2410_UDC_USBINT_RESET (1 << 2) /* R/W (clear only) */ -#define S3C2410_UDC_USBINT_RESUME (1 << 1) /* R/W (clear only) */ -#define S3C2410_UDC_USBINT_SUSPEND (1 << 0) /* R/W (clear only) */ - -#define S3C2410_UDC_INTE_EP4 (1 << 4) /* R/W */ -#define S3C2410_UDC_INTE_EP3 (1 << 3) /* R/W */ -#define S3C2410_UDC_INTE_EP2 (1 << 2) /* R/W */ -#define S3C2410_UDC_INTE_EP1 (1 << 1) /* R/W */ -#define S3C2410_UDC_INTE_EP0 (1 << 0) /* R/W */ - -#define S3C2410_UDC_USBINTE_RESET (1 << 2) /* R/W */ -#define S3C2410_UDC_USBINTE_SUSPEND (1 << 0) /* R/W */ - -#define S3C2410_UDC_INDEX_EP0 (0x00) -#define S3C2410_UDC_INDEX_EP1 (0x01) -#define S3C2410_UDC_INDEX_EP2 (0x02) -#define S3C2410_UDC_INDEX_EP3 (0x03) -#define S3C2410_UDC_INDEX_EP4 (0x04) - -#define S3C2410_UDC_ICSR1_CLRDT (1 << 6) /* R/W */ -#define S3C2410_UDC_ICSR1_SENTSTL (1 << 5) /* R/W (clear only) */ -#define S3C2410_UDC_ICSR1_SENDSTL (1 << 4) /* R/W */ -#define S3C2410_UDC_ICSR1_FFLUSH (1 << 3) /* W (set only) */ -#define S3C2410_UDC_ICSR1_UNDRUN (1 << 2) /* R/W (clear only) */ -#define S3C2410_UDC_ICSR1_PKTRDY (1 << 0) /* R/W (set only) */ - -#define S3C2410_UDC_ICSR2_AUTOSET (1 << 7) /* R/W */ -#define S3C2410_UDC_ICSR2_ISO (1 << 6) /* R/W */ -#define S3C2410_UDC_ICSR2_MODEIN (1 << 5) /* R/W */ -#define S3C2410_UDC_ICSR2_DMAIEN (1 << 4) /* R/W */ - -#define S3C2410_UDC_OCSR1_CLRDT (1 << 7) /* R/W */ -#define S3C2410_UDC_OCSR1_SENTSTL (1 << 6) /* R/W (clear only) */ -#define S3C2410_UDC_OCSR1_SENDSTL (1 << 5) /* R/W */ -#define S3C2410_UDC_OCSR1_FFLUSH (1 << 4) /* R/W */ -#define S3C2410_UDC_OCSR1_DERROR (1 << 3) /* R */ -#define S3C2410_UDC_OCSR1_OVRRUN (1 << 2) /* R/W (clear only) */ -#define S3C2410_UDC_OCSR1_PKTRDY (1 << 0) /* R/W (clear only) */ - -#define S3C2410_UDC_OCSR2_AUTOCLR (1 << 7) /* R/W */ -#define S3C2410_UDC_OCSR2_ISO (1 << 6) /* R/W */ -#define S3C2410_UDC_OCSR2_DMAIEN (1 << 5) /* R/W */ - -#define S3C2410_UDC_EP0_CSR_OPKRDY (1 << 0) -#define S3C2410_UDC_EP0_CSR_IPKRDY (1 << 1) -#define S3C2410_UDC_EP0_CSR_SENTSTL (1 << 2) -#define S3C2410_UDC_EP0_CSR_DE (1 << 3) -#define S3C2410_UDC_EP0_CSR_SE (1 << 4) -#define S3C2410_UDC_EP0_CSR_SENDSTL (1 << 5) -#define S3C2410_UDC_EP0_CSR_SOPKTRDY (1 << 6) -#define S3C2410_UDC_EP0_CSR_SSE (1 << 7) - -#define S3C2410_UDC_MAXP_8 (1 << 0) -#define S3C2410_UDC_MAXP_16 (1 << 1) -#define S3C2410_UDC_MAXP_32 (1 << 2) -#define S3C2410_UDC_MAXP_64 (1 << 3) - -#endif diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c index 52ea4dcf6a92..2fc5d4d277bc 100644 --- a/drivers/usb/gadget/udc/snps_udc_core.c +++ b/drivers/usb/gadget/udc/snps_udc_core.c @@ -1933,7 +1933,6 @@ static int amd5536_udc_start(struct usb_gadget *g, struct udc *dev = to_amd5536_udc(g); u32 tmp; - driver->driver.bus = NULL; dev->driver = driver; /* Some gadget drivers use both ep0 directions. diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 8d799d23c476..a97923897c8e 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -316,18 +316,6 @@ config USB_OCTEON_HCD To compile this driver as a module, choose M here. The module will be called octeon-hcd. -config USB_CNS3XXX_EHCI - bool "Cavium CNS3XXX EHCI Module (DEPRECATED)" - depends on ARCH_CNS3XXX || COMPILE_TEST - select USB_EHCI_HCD_PLATFORM - help - This option is deprecated now and the driver was removed, use - USB_EHCI_HCD_PLATFORM instead. - - Enable support for the CNS3XXX SOC's on-chip EHCI controller. - It is needed for high-speed (480Mbit/sec) USB 2.0 device - support. - config USB_EHCI_HCD_PLATFORM tristate "Generic EHCI driver for a platform device" help @@ -421,7 +409,6 @@ if USB_OHCI_HCD config USB_OHCI_HCD_OMAP1 tristate "OHCI support for OMAP1/2 chips" depends on ARCH_OMAP1 - depends on ISP1301_OMAP || !(MACH_OMAP_H2 || MACH_OMAP_H3) default y help Enables support for the OHCI controller on OMAP1/2 chips. @@ -444,12 +431,12 @@ config USB_OHCI_HCD_STI STMicroelectronics consumer electronics SoC's. config USB_OHCI_HCD_S3C2410 - tristate "OHCI support for Samsung S3C24xx/S3C64xx SoC series" - depends on USB_OHCI_HCD && (ARCH_S3C24XX || ARCH_S3C64XX || COMPILE_TEST) - default y if (ARCH_S3C24XX || ARCH_S3C64XX) + tristate "OHCI support for Samsung S3C64xx SoC series" + depends on USB_OHCI_HCD && (ARCH_S3C64XX || COMPILE_TEST) + default ARCH_S3C64XX help Enables support for the on-chip OHCI controller on - S3C24xx/S3C64xx chips. + S3C64xx chips. config USB_OHCI_HCD_LPC32XX tristate "Support for LPC on-chip OHCI USB controller" @@ -566,17 +553,6 @@ config USB_OHCI_EXYNOS Enable support for the Samsung S5Pv210 and Exynos SOC's on-chip OHCI controller. -config USB_CNS3XXX_OHCI - bool "Cavium CNS3XXX OHCI Module (DEPRECATED)" - depends on ARCH_CNS3XXX || COMPILE_TEST - select USB_OHCI_HCD_PLATFORM - help - This option is deprecated now and the driver was removed, use - USB_OHCI_HCD_PLATFORM instead. - - Enable support for the CNS3XXX SOC's on-chip OHCI controller. - It is needed for low-speed USB 1.0 device support. - config USB_OHCI_HCD_PLATFORM tristate "Generic OHCI driver for a platform device" help diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 9cea785934e5..38d06e5abfbb 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -29,7 +29,7 @@ #include "ehci-fsl.h" #define DRIVER_DESC "Freescale EHCI Host controller driver" -#define DRV_NAME "ehci-fsl" +#define DRV_NAME "fsl-ehci" static struct hc_driver __read_mostly fsl_ehci_hc_driver; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 0457dd9f6c19..4f9982ecfb58 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1264,11 +1264,6 @@ MODULE_LICENSE ("GPL"); #define SM501_OHCI_DRIVER ohci_hcd_sm501_driver #endif -#ifdef CONFIG_MFD_TC6393XB -#include "ohci-tmio.c" -#define TMIO_OHCI_DRIVER ohci_hcd_tmio_driver -#endif - static int __init ohci_hcd_mod_init(void) { int retval = 0; @@ -1306,19 +1301,9 @@ static int __init ohci_hcd_mod_init(void) goto error_sm501; #endif -#ifdef TMIO_OHCI_DRIVER - retval = platform_driver_register(&TMIO_OHCI_DRIVER); - if (retval < 0) - goto error_tmio; -#endif - return retval; /* Error path */ -#ifdef TMIO_OHCI_DRIVER - platform_driver_unregister(&TMIO_OHCI_DRIVER); - error_tmio: -#endif #ifdef SM501_OHCI_DRIVER platform_driver_unregister(&SM501_OHCI_DRIVER); error_sm501: @@ -1345,9 +1330,6 @@ module_init(ohci_hcd_mod_init); static void __exit ohci_hcd_mod_exit(void) { -#ifdef TMIO_OHCI_DRIVER - platform_driver_unregister(&TMIO_OHCI_DRIVER); -#endif #ifdef SM501_OHCI_DRIVER platform_driver_unregister(&SM501_OHCI_DRIVER); #endif diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index cb29701df911..c82121602511 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -67,8 +67,6 @@ static void omap_ohci_clock_power(struct ohci_omap_priv *priv, int on) } } -#ifdef CONFIG_USB_OTG - static void start_hnp(struct ohci_hcd *ohci) { struct usb_hcd *hcd = ohci_to_hcd(ohci); @@ -87,8 +85,6 @@ static void start_hnp(struct ohci_hcd *ohci) local_irq_restore(flags); } -#endif - /*-------------------------------------------------------------------------*/ static int ohci_omap_reset(struct usb_hcd *hcd) @@ -107,16 +103,11 @@ static int ohci_omap_reset(struct usb_hcd *hcd) hcd->power_budget = 8; } - /* boards can use OTG transceivers in non-OTG modes */ - need_transceiver = need_transceiver - || machine_is_omap_h2() || machine_is_omap_h3(); - /* XXX OMAP16xx only */ if (config->ocpi_enable) config->ocpi_enable(); -#ifdef CONFIG_USB_OTG - if (need_transceiver) { + if (IS_ENABLED(CONFIG_USB_OTG) && need_transceiver) { hcd->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2); if (!IS_ERR_OR_NULL(hcd->usb_phy)) { int status = otg_set_host(hcd->usb_phy->otg, @@ -133,7 +124,6 @@ static int ohci_omap_reset(struct usb_hcd *hcd) hcd->skip_phy_initialization = 1; ohci->start_hnp = start_hnp; } -#endif omap_ohci_clock_power(priv, 1); @@ -150,7 +140,7 @@ static int ohci_omap_reset(struct usb_hcd *hcd) } /* board-specific power switching and overcurrent support */ - if (machine_is_omap_osk() || machine_is_omap_innovator()) { + if (machine_is_omap_osk()) { u32 rh = roothub_a (ohci); /* power switching (ganged by default) */ diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index a1dad8745622..0bc7e96bcc93 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -29,7 +29,6 @@ #include <linux/of_platform.h> #include <linux/of_gpio.h> #include <linux/platform_data/usb-ohci-pxa27x.h> -#include <linux/platform_data/usb-pxa3xx-ulpi.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/signal.h> @@ -275,7 +274,6 @@ static int pxa27x_start_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev) int retval; struct pxaohci_platform_data *inf; uint32_t uhchr; - struct usb_hcd *hcd = dev_get_drvdata(dev); inf = dev_get_platdata(dev); @@ -301,9 +299,6 @@ static int pxa27x_start_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev) return retval; } - if (cpu_is_pxa3xx()) - pxa3xx_u2d_start_hc(&hcd->self); - uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR) & ~UHCHR_SSE; __raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR); __raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, pxa_ohci->mmio_base + UHCHIE); @@ -316,14 +311,10 @@ static int pxa27x_start_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev) static void pxa27x_stop_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev) { struct pxaohci_platform_data *inf; - struct usb_hcd *hcd = dev_get_drvdata(dev); uint32_t uhccoms; inf = dev_get_platdata(dev); - if (cpu_is_pxa3xx()) - pxa3xx_u2d_stop_hc(&hcd->self); - if (inf->exit) inf->exit(dev); diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 75c2b28b3379..aca0338a2983 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -125,10 +125,7 @@ static int sa1111_start_hc(struct sa1111_dev *dev) dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n"); - if (machine_is_xp860() || - machine_is_assabet() || - machine_is_pfs168() || - machine_is_badge4()) + if (machine_is_assabet()) usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW; /* diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c deleted file mode 100644 index 49539b9f0e94..000000000000 --- a/drivers/usb/host/ohci-tmio.c +++ /dev/null @@ -1,364 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * OHCI HCD(Host Controller Driver) for USB. - * - *(C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> - *(C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> - *(C) Copyright 2002 Hewlett-Packard Company - * - * Bus glue for Toshiba Mobile IO(TMIO) Controller's OHCI core - * (C) Copyright 2005 Chris Humbert <mahadri-usb@drigon.com> - * (C) Copyright 2007, 2008 Dmitry Baryshkov <dbaryshkov@gmail.com> - * - * This is known to work with the following variants: - * TC6393XB revision 3 (32kB SRAM) - * - * The TMIO's OHCI core DMAs through a small internal buffer that - * is directly addressable by the CPU. - * - * Written from sparse documentation from Toshiba and Sharp's driver - * for the 2.4 kernel, - * usb-ohci-tc6393.c(C) Copyright 2004 Lineo Solutions, Inc. - */ - -#include <linux/platform_device.h> -#include <linux/mfd/core.h> -#include <linux/mfd/tmio.h> -#include <linux/dma-mapping.h> - -/*-------------------------------------------------------------------------*/ - -/* - * USB Host Controller Configuration Register - */ -#define CCR_REVID 0x08 /* b Revision ID */ -#define CCR_BASE 0x10 /* l USB Control Register Base Address Low */ -#define CCR_ILME 0x40 /* b Internal Local Memory Enable */ -#define CCR_PM 0x4c /* w Power Management */ -#define CCR_INTC 0x50 /* b INT Control */ -#define CCR_LMW1L 0x54 /* w Local Memory Window 1 LMADRS Low */ -#define CCR_LMW1H 0x56 /* w Local Memory Window 1 LMADRS High */ -#define CCR_LMW1BL 0x58 /* w Local Memory Window 1 Base Address Low */ -#define CCR_LMW1BH 0x5A /* w Local Memory Window 1 Base Address High */ -#define CCR_LMW2L 0x5C /* w Local Memory Window 2 LMADRS Low */ -#define CCR_LMW2H 0x5E /* w Local Memory Window 2 LMADRS High */ -#define CCR_LMW2BL 0x60 /* w Local Memory Window 2 Base Address Low */ -#define CCR_LMW2BH 0x62 /* w Local Memory Window 2 Base Address High */ -#define CCR_MISC 0xFC /* b MISC */ - -#define CCR_PM_GKEN 0x0001 -#define CCR_PM_CKRNEN 0x0002 -#define CCR_PM_USBPW1 0x0004 -#define CCR_PM_USBPW2 0x0008 -#define CCR_PM_USBPW3 0x0010 -#define CCR_PM_PMEE 0x0100 -#define CCR_PM_PMES 0x8000 - -/*-------------------------------------------------------------------------*/ - -struct tmio_hcd { - void __iomem *ccr; - spinlock_t lock; /* protects RMW cycles */ -}; - -#define hcd_to_tmio(hcd) ((struct tmio_hcd *)(hcd_to_ohci(hcd) + 1)) - -/*-------------------------------------------------------------------------*/ - -static void tmio_write_pm(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct tmio_hcd *tmio = hcd_to_tmio(hcd); - u16 pm; - unsigned long flags; - - spin_lock_irqsave(&tmio->lock, flags); - - pm = CCR_PM_GKEN | CCR_PM_CKRNEN | - CCR_PM_PMEE | CCR_PM_PMES; - - tmio_iowrite16(pm, tmio->ccr + CCR_PM); - spin_unlock_irqrestore(&tmio->lock, flags); -} - -static void tmio_stop_hc(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct tmio_hcd *tmio = hcd_to_tmio(hcd); - u16 pm; - - pm = CCR_PM_GKEN | CCR_PM_CKRNEN; - switch (ohci->num_ports) { - default: - dev_err(&dev->dev, "Unsupported amount of ports: %d\n", ohci->num_ports); - fallthrough; - case 3: - pm |= CCR_PM_USBPW3; - fallthrough; - case 2: - pm |= CCR_PM_USBPW2; - fallthrough; - case 1: - pm |= CCR_PM_USBPW1; - } - tmio_iowrite8(0, tmio->ccr + CCR_INTC); - tmio_iowrite8(0, tmio->ccr + CCR_ILME); - tmio_iowrite16(0, tmio->ccr + CCR_BASE); - tmio_iowrite16(0, tmio->ccr + CCR_BASE + 2); - tmio_iowrite16(pm, tmio->ccr + CCR_PM); -} - -static void tmio_start_hc(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct tmio_hcd *tmio = hcd_to_tmio(hcd); - unsigned long base = hcd->rsrc_start; - - tmio_write_pm(dev); - tmio_iowrite16(base, tmio->ccr + CCR_BASE); - tmio_iowrite16(base >> 16, tmio->ccr + CCR_BASE + 2); - tmio_iowrite8(1, tmio->ccr + CCR_ILME); - tmio_iowrite8(2, tmio->ccr + CCR_INTC); - - dev_info(&dev->dev, "revision %d @ 0x%08llx, irq %d\n", - tmio_ioread8(tmio->ccr + CCR_REVID), - (u64) hcd->rsrc_start, hcd->irq); -} - -static int ohci_tmio_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run(ohci)) < 0) { - dev_err(hcd->self.controller, "can't start %s\n", - hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - -static const struct hc_driver ohci_tmio_hc_driver = { - .description = hcd_name, - .product_desc = "TMIO OHCI USB Host Controller", - .hcd_priv_size = sizeof(struct ohci_hcd) + sizeof (struct tmio_hcd), - - /* generic hardware linkage */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* basic lifecycle operations */ - .start = ohci_tmio_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* managing i/o requests and associated device resources */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* scheduling support */ - .get_frame_number = ohci_get_frame, - - /* root hub support */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ -static struct platform_driver ohci_hcd_tmio_driver; - -static int ohci_hcd_tmio_drv_probe(struct platform_device *dev) -{ - const struct mfd_cell *cell = mfd_get_cell(dev); - struct resource *regs = platform_get_resource(dev, IORESOURCE_MEM, 0); - struct resource *config = platform_get_resource(dev, IORESOURCE_MEM, 1); - struct resource *sram = platform_get_resource(dev, IORESOURCE_MEM, 2); - int irq = platform_get_irq(dev, 0); - struct tmio_hcd *tmio; - struct ohci_hcd *ohci; - struct usb_hcd *hcd; - int ret; - - if (usb_disabled()) - return -ENODEV; - - if (!cell || !regs || !config || !sram) - return -EINVAL; - - if (irq < 0) - return irq; - - hcd = usb_create_hcd(&ohci_tmio_hc_driver, &dev->dev, dev_name(&dev->dev)); - if (!hcd) { - ret = -ENOMEM; - goto err_usb_create_hcd; - } - - hcd->rsrc_start = regs->start; - hcd->rsrc_len = resource_size(regs); - - tmio = hcd_to_tmio(hcd); - - spin_lock_init(&tmio->lock); - - tmio->ccr = ioremap(config->start, resource_size(config)); - if (!tmio->ccr) { - ret = -ENOMEM; - goto err_ioremap_ccr; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - ret = -ENOMEM; - goto err_ioremap_regs; - } - - if (cell->enable) { - ret = cell->enable(dev); - if (ret) - goto err_enable; - } - - tmio_start_hc(dev); - ohci = hcd_to_ohci(hcd); - ohci_hcd_init(ohci); - - ret = usb_hcd_setup_local_mem(hcd, sram->start, sram->start, - resource_size(sram)); - if (ret < 0) - goto err_enable; - - ret = usb_add_hcd(hcd, irq, 0); - if (ret) - goto err_add_hcd; - - device_wakeup_enable(hcd->self.controller); - if (ret == 0) - return ret; - - usb_remove_hcd(hcd); - -err_add_hcd: - tmio_stop_hc(dev); - if (cell->disable) - cell->disable(dev); -err_enable: - iounmap(hcd->regs); -err_ioremap_regs: - iounmap(tmio->ccr); -err_ioremap_ccr: - usb_put_hcd(hcd); -err_usb_create_hcd: - - return ret; -} - -static int ohci_hcd_tmio_drv_remove(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct tmio_hcd *tmio = hcd_to_tmio(hcd); - const struct mfd_cell *cell = mfd_get_cell(dev); - - usb_remove_hcd(hcd); - tmio_stop_hc(dev); - if (cell->disable) - cell->disable(dev); - iounmap(hcd->regs); - iounmap(tmio->ccr); - usb_put_hcd(hcd); - - return 0; -} - -#ifdef CONFIG_PM -static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state) -{ - const struct mfd_cell *cell = mfd_get_cell(dev); - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct tmio_hcd *tmio = hcd_to_tmio(hcd); - unsigned long flags; - u8 misc; - int ret; - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - spin_lock_irqsave(&tmio->lock, flags); - - misc = tmio_ioread8(tmio->ccr + CCR_MISC); - misc |= 1 << 3; /* USSUSP */ - tmio_iowrite8(misc, tmio->ccr + CCR_MISC); - - spin_unlock_irqrestore(&tmio->lock, flags); - - if (cell->suspend) { - ret = cell->suspend(dev); - if (ret) - return ret; - } - return 0; -} - -static int ohci_hcd_tmio_drv_resume(struct platform_device *dev) -{ - const struct mfd_cell *cell = mfd_get_cell(dev); - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct tmio_hcd *tmio = hcd_to_tmio(hcd); - unsigned long flags; - u8 misc; - int ret; - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - if (cell->resume) { - ret = cell->resume(dev); - if (ret) - return ret; - } - - tmio_start_hc(dev); - - spin_lock_irqsave(&tmio->lock, flags); - - misc = tmio_ioread8(tmio->ccr + CCR_MISC); - misc &= ~(1 << 3); /* USSUSP */ - tmio_iowrite8(misc, tmio->ccr + CCR_MISC); - - spin_unlock_irqrestore(&tmio->lock, flags); - - ohci_resume(hcd, false); - - return 0; -} -#else -#define ohci_hcd_tmio_drv_suspend NULL -#define ohci_hcd_tmio_drv_resume NULL -#endif - -static struct platform_driver ohci_hcd_tmio_driver = { - .probe = ohci_hcd_tmio_drv_probe, - .remove = ohci_hcd_tmio_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .suspend = ohci_hcd_tmio_drv_suspend, - .resume = ohci_hcd_tmio_drv_resume, - .driver = { - .name = "tmio-ohci", - }, -}; diff --git a/drivers/usb/host/xen-hcd.c b/drivers/usb/host/xen-hcd.c index de1b09158318..46fdab940092 100644 --- a/drivers/usb/host/xen-hcd.c +++ b/drivers/usb/host/xen-hcd.c @@ -1530,15 +1530,13 @@ static void xenhcd_backend_changed(struct xenbus_device *dev, } } -static int xenhcd_remove(struct xenbus_device *dev) +static void xenhcd_remove(struct xenbus_device *dev) { struct xenhcd_info *info = dev_get_drvdata(&dev->dev); struct usb_hcd *hcd = xenhcd_info_to_hcd(info); xenhcd_destroy_rings(info); usb_put_hcd(hcd); - - return 0; } static int xenhcd_probe(struct xenbus_device *dev, diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 79d679b3e076..fb988e4ea924 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -78,9 +78,12 @@ static const char hcd_name[] = "xhci_hcd"; static struct hc_driver __read_mostly xhci_pci_hc_driver; static int xhci_pci_setup(struct usb_hcd *hcd); +static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, + struct usb_tt *tt, gfp_t mem_flags); static const struct xhci_driver_overrides xhci_pci_overrides __initconst = { .reset = xhci_pci_setup, + .update_hub_device = xhci_pci_update_hub_device, }; /* called after powerup, by probe or system-pm "wakeup" */ @@ -352,8 +355,38 @@ static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) NULL); ACPI_FREE(obj); } + +static void xhci_find_lpm_incapable_ports(struct usb_hcd *hcd, struct usb_device *hdev) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct xhci_hub *rhub = &xhci->usb3_rhub; + int ret; + int i; + + /* This is not the usb3 roothub we are looking for */ + if (hcd != rhub->hcd) + return; + + if (hdev->maxchild > rhub->num_ports) { + dev_err(&hdev->dev, "USB3 roothub port number mismatch\n"); + return; + } + + for (i = 0; i < hdev->maxchild; i++) { + ret = usb_acpi_port_lpm_incapable(hdev, i); + + dev_dbg(&hdev->dev, "port-%d disable U1/U2 _DSM: %d\n", i + 1, ret); + + if (ret >= 0) { + rhub->ports[i]->lpm_incapable = ret; + continue; + } + } +} + #else static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { } +static void xhci_find_lpm_incapable_ports(struct usb_hcd *hcd, struct usb_device *hdev) { } #endif /* CONFIG_ACPI */ /* called during probe() after chip reset completes */ @@ -386,6 +419,16 @@ static int xhci_pci_setup(struct usb_hcd *hcd) return xhci_pci_reinit(xhci, pdev); } +static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, + struct usb_tt *tt, gfp_t mem_flags) +{ + /* Check if acpi claims some USB3 roothub ports are lpm incapable */ + if (!hdev->parent) + xhci_find_lpm_incapable_ports(hcd, hdev); + + return xhci_update_hub_device(hcd, hdev, tt, mem_flags); +} + /* * We need to register our own PCI probe function (instead of the USB core's * function) in order to create a second roothub under xHCI. @@ -455,6 +498,8 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW) pm_runtime_allow(&dev->dev); + dma_set_max_seg_size(&dev->dev, UINT_MAX); + return 0; put_usb3_hcd: diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index ddc30037f9ce..f5b0e1ce22af 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1169,7 +1169,10 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, struct xhci_virt_ep *ep; struct xhci_ring *ring; - ep = &xhci->devs[slot_id]->eps[ep_index]; + ep = xhci_get_virt_ep(xhci, slot_id, ep_index); + if (!ep) + return; + if ((ep->ep_state & EP_HAS_STREAMS) || (ep->ep_state & EP_GETTING_NO_STREAMS)) { int stream_id; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 79d7931c048a..2b280beb0011 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3974,6 +3974,7 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_virt_device *virt_dev; struct xhci_slot_ctx *slot_ctx; + unsigned long flags; int i, ret; /* @@ -4000,7 +4001,11 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) virt_dev->eps[i].ep_state &= ~EP_STOP_CMD_PENDING; virt_dev->udev = NULL; xhci_disable_slot(xhci, udev->slot_id); + + spin_lock_irqsave(&xhci->lock, flags); xhci_free_virt_device(xhci, udev->slot_id); + spin_unlock_irqrestore(&xhci->lock, flags); + } int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id) @@ -5044,6 +5049,7 @@ static int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd, struct usb_device *udev, enum usb3_link_state state) { struct xhci_hcd *xhci; + struct xhci_port *port; u16 hub_encoded_timeout; int mel; int ret; @@ -5060,6 +5066,13 @@ static int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd, if (xhci_check_tier_policy(xhci, udev, state) < 0) return USB3_LPM_DISABLED; + /* If connected to root port then check port can handle lpm */ + if (udev->parent && !udev->parent->parent) { + port = xhci->usb3_rhub.ports[udev->portnum - 1]; + if (port->lpm_incapable) + return USB3_LPM_DISABLED; + } + hub_encoded_timeout = xhci_calculate_lpm_timeout(hcd, udev, state); mel = calculate_max_exit_latency(udev, state, hub_encoded_timeout); if (mel < 0) { @@ -5119,7 +5132,7 @@ static int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd, /* Once a hub descriptor is fetched for a device, we need to update the xHC's * internal data structures for the device. */ -static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, +int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, struct usb_tt *tt, gfp_t mem_flags) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); @@ -5219,6 +5232,7 @@ static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, xhci_free_command(xhci, config_cmd); return ret; } +EXPORT_SYMBOL_GPL(xhci_update_hub_device); static int xhci_get_frame(struct usb_hcd *hcd) { @@ -5502,6 +5516,8 @@ void xhci_init_driver(struct hc_driver *drv, drv->check_bandwidth = over->check_bandwidth; if (over->reset_bandwidth) drv->reset_bandwidth = over->reset_bandwidth; + if (over->update_hub_device) + drv->update_hub_device = over->update_hub_device; } } EXPORT_SYMBOL_GPL(xhci_init_driver); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index c9f06c5e4e9d..dcee7f3207ad 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1735,6 +1735,7 @@ struct xhci_port { int hcd_portnum; struct xhci_hub *rhub; struct xhci_port_cap *port_cap; + unsigned int lpm_incapable:1; }; struct xhci_hub { @@ -1943,6 +1944,8 @@ struct xhci_driver_overrides { struct usb_host_endpoint *ep); int (*check_bandwidth)(struct usb_hcd *, struct usb_device *); void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); + int (*update_hub_device)(struct usb_hcd *hcd, struct usb_device *hdev, + struct usb_tt *tt, gfp_t mem_flags); }; #define XHCI_CFC_DELAY 10 @@ -2122,6 +2125,8 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); +int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, + struct usb_tt *tt, gfp_t mem_flags); int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id); int xhci_ext_cap_init(struct xhci_hcd *xhci); diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index f9427a67789c..1e3df27bab58 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -814,7 +814,7 @@ static int iowarrior_probe(struct usb_interface *interface, break; case USB_DEVICE_ID_CODEMERCS_IOW100: - dev->report_size = 13; + dev->report_size = 12; break; } } diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c index 94e7966e199d..969c4c4f2ae9 100644 --- a/drivers/usb/misc/onboard_usb_hub.c +++ b/drivers/usb/misc/onboard_usb_hub.c @@ -27,7 +27,10 @@ #include "onboard_usb_hub.h" +static void onboard_hub_attach_usb_driver(struct work_struct *work); + static struct usb_device_driver onboard_hub_usbdev_driver; +static DECLARE_WORK(attach_usb_driver_work, onboard_hub_attach_usb_driver); /************************** Platform driver **************************/ @@ -45,7 +48,6 @@ struct onboard_hub { bool is_powered_on; bool going_away; struct list_head udev_list; - struct work_struct attach_usb_driver_work; struct mutex lock; }; @@ -271,8 +273,7 @@ static int onboard_hub_probe(struct platform_device *pdev) * This needs to be done deferred to avoid self-deadlocks on systems * with nested onboard hubs. */ - INIT_WORK(&hub->attach_usb_driver_work, onboard_hub_attach_usb_driver); - schedule_work(&hub->attach_usb_driver_work); + schedule_work(&attach_usb_driver_work); return 0; } @@ -285,9 +286,6 @@ static int onboard_hub_remove(struct platform_device *pdev) hub->going_away = true; - if (&hub->attach_usb_driver_work != current_work()) - cancel_work_sync(&hub->attach_usb_driver_work); - mutex_lock(&hub->lock); /* unbind the USB devices to avoid dangling references to this device */ @@ -433,13 +431,13 @@ static int __init onboard_hub_init(void) { int ret; - ret = platform_driver_register(&onboard_hub_driver); + ret = usb_register_device_driver(&onboard_hub_usbdev_driver, THIS_MODULE); if (ret) return ret; - ret = usb_register_device_driver(&onboard_hub_usbdev_driver, THIS_MODULE); + ret = platform_driver_register(&onboard_hub_driver); if (ret) - platform_driver_unregister(&onboard_hub_driver); + usb_deregister_device_driver(&onboard_hub_usbdev_driver); return ret; } @@ -449,6 +447,8 @@ static void __exit onboard_hub_exit(void) { usb_deregister_device_driver(&onboard_hub_usbdev_driver); platform_driver_unregister(&onboard_hub_driver); + + cancel_work_sync(&attach_usb_driver_work); } module_exit(onboard_hub_exit); diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 476f55d1fec3..44a21ec865fb 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -411,8 +411,10 @@ static int omap2430_probe(struct platform_device *pdev) memset(musb_res, 0, sizeof(*musb_res) * ARRAY_SIZE(musb_res)); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) + if (!res) { + ret = -EINVAL; goto err2; + } musb_res[i].start = res->start; musb_res[i].end = res->end; diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 915df5726a5c..5f629d7cad64 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -28,23 +28,6 @@ config FSL_USB2_OTG help Enable this to support Freescale USB OTG transceiver. -config ISP1301_OMAP - tristate "Philips ISP1301 with OMAP OTG" - depends on I2C - depends on ARCH_OMAP_OTG || (ARM && COMPILE_TEST) - depends on USB - depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' - select USB_PHY - help - If you say yes here you get support for the Philips ISP1301 - USB-On-The-Go transceiver working with the OMAP OTG controller. - The ISP1301 is a full speed USB transceiver which is used in - products including H2, H3, and H4 development boards for Texas - Instruments OMAP processors. - - This driver can also be built as a module. If so, the module - will be called phy-isp1301-omap. - config KEYSTONE_USB_PHY tristate "Keystone USB PHY Driver" depends on ARCH_KEYSTONE || COMPILE_TEST diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index df1d99010079..e5d619b4d8f6 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_OF) += of.o obj-$(CONFIG_AB8500_USB) += phy-ab8500-usb.o obj-$(CONFIG_FSL_USB2_OTG) += phy-fsl-usb.o -obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301-omap.o obj-$(CONFIG_NOP_USB_XCEIV) += phy-generic.o obj-$(CONFIG_TAHVO_USB) += phy-tahvo.o obj-$(CONFIG_AM335X_CONTROL_USB) += phy-am335x-control.o diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c deleted file mode 100644 index 931610b76f3d..000000000000 --- a/drivers/usb/phy/phy-isp1301-omap.c +++ /dev/null @@ -1,1639 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * isp1301_omap - ISP 1301 USB transceiver, talking to OMAP OTG controller - * - * Copyright (C) 2004 Texas Instruments - * Copyright (C) 2004 David Brownell - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/gpio/consumer.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <linux/usb.h> -#include <linux/usb/otg.h> -#include <linux/i2c.h> -#include <linux/workqueue.h> - -#include <asm/irq.h> -#include <asm/mach-types.h> - -#include <linux/soc/ti/omap1-mux.h> -#include <linux/soc/ti/omap1-usb.h> -#include <linux/soc/ti/omap1-io.h> - -#undef VERBOSE - - -#define DRIVER_VERSION "24 August 2004" -#define DRIVER_NAME (isp1301_driver.driver.name) - -MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver"); -MODULE_LICENSE("GPL"); - -struct isp1301 { - struct usb_phy phy; - struct i2c_client *client; - void (*i2c_release)(struct device *dev); - - int irq_type; - - u32 last_otg_ctrl; - unsigned working:1; - - struct timer_list timer; - - /* use keventd context to change the state for us */ - struct work_struct work; - - unsigned long todo; -# define WORK_UPDATE_ISP 0 /* update ISP from OTG */ -# define WORK_UPDATE_OTG 1 /* update OTG from ISP */ -# define WORK_HOST_RESUME 4 /* resume host */ -# define WORK_TIMER 6 /* timer fired */ -# define WORK_STOP 7 /* don't resubmit */ -}; - - -/* bits in OTG_CTRL */ - -#define OTG_XCEIV_OUTPUTS \ - (OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID) -#define OTG_XCEIV_INPUTS \ - (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID) -#define OTG_CTRL_BITS \ - (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP) - /* and OTG_PULLUP is sometimes written */ - -#define OTG_CTRL_MASK (OTG_DRIVER_SEL| \ - OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS| \ - OTG_CTRL_BITS) - - -/*-------------------------------------------------------------------------*/ - -/* board-specific PM hooks */ - -#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3) - -#if IS_REACHABLE(CONFIG_TPS65010) - -#include <linux/mfd/tps65010.h> - -#else - -static inline int tps65010_set_vbus_draw(unsigned mA) -{ - pr_debug("tps65010: draw %d mA (STUB)\n", mA); - return 0; -} - -#endif - -static void enable_vbus_draw(struct isp1301 *isp, unsigned mA) -{ - int status = tps65010_set_vbus_draw(mA); - if (status < 0) - pr_debug(" VBUS %d mA error %d\n", mA, status); -} - -#else - -static void enable_vbus_draw(struct isp1301 *isp, unsigned mA) -{ - /* H4 controls this by DIP switch S2.4; no soft control. - * ON means the charger is always enabled. Leave it OFF - * unless the OTG port is used only in B-peripheral mode. - */ -} - -#endif - -static void enable_vbus_source(struct isp1301 *isp) -{ - /* this board won't supply more than 8mA vbus power. - * some boards can switch a 100ma "unit load" (or more). - */ -} - - -/* products will deliver OTG messages with LEDs, GUI, etc */ -static inline void notresponding(struct isp1301 *isp) -{ - printk(KERN_NOTICE "OTG device not responding.\n"); -} - - -/*-------------------------------------------------------------------------*/ - -static struct i2c_driver isp1301_driver; - -/* smbus apis are used for portability */ - -static inline u8 -isp1301_get_u8(struct isp1301 *isp, u8 reg) -{ - return i2c_smbus_read_byte_data(isp->client, reg + 0); -} - -static inline int -isp1301_get_u16(struct isp1301 *isp, u8 reg) -{ - return i2c_smbus_read_word_data(isp->client, reg); -} - -static inline int -isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits) -{ - return i2c_smbus_write_byte_data(isp->client, reg + 0, bits); -} - -static inline int -isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits) -{ - return i2c_smbus_write_byte_data(isp->client, reg + 1, bits); -} - -/*-------------------------------------------------------------------------*/ - -/* identification */ -#define ISP1301_VENDOR_ID 0x00 /* u16 read */ -#define ISP1301_PRODUCT_ID 0x02 /* u16 read */ -#define ISP1301_BCD_DEVICE 0x14 /* u16 read */ - -#define I2C_VENDOR_ID_PHILIPS 0x04cc -#define I2C_PRODUCT_ID_PHILIPS_1301 0x1301 - -/* operational registers */ -#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */ -# define MC1_SPEED (1 << 0) -# define MC1_SUSPEND (1 << 1) -# define MC1_DAT_SE0 (1 << 2) -# define MC1_TRANSPARENT (1 << 3) -# define MC1_BDIS_ACON_EN (1 << 4) -# define MC1_OE_INT_EN (1 << 5) -# define MC1_UART_EN (1 << 6) -# define MC1_MASK 0x7f -#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */ -# define MC2_GLOBAL_PWR_DN (1 << 0) -# define MC2_SPD_SUSP_CTRL (1 << 1) -# define MC2_BI_DI (1 << 2) -# define MC2_TRANSP_BDIR0 (1 << 3) -# define MC2_TRANSP_BDIR1 (1 << 4) -# define MC2_AUDIO_EN (1 << 5) -# define MC2_PSW_EN (1 << 6) -# define MC2_EN2V7 (1 << 7) -#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */ -# define OTG1_DP_PULLUP (1 << 0) -# define OTG1_DM_PULLUP (1 << 1) -# define OTG1_DP_PULLDOWN (1 << 2) -# define OTG1_DM_PULLDOWN (1 << 3) -# define OTG1_ID_PULLDOWN (1 << 4) -# define OTG1_VBUS_DRV (1 << 5) -# define OTG1_VBUS_DISCHRG (1 << 6) -# define OTG1_VBUS_CHRG (1 << 7) -#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */ -# define OTG_B_SESS_END (1 << 6) -# define OTG_B_SESS_VLD (1 << 7) - -#define ISP1301_INTERRUPT_SOURCE 0x08 /* u8 read */ -#define ISP1301_INTERRUPT_LATCH 0x0A /* u8 read, set, +1 clear */ - -#define ISP1301_INTERRUPT_FALLING 0x0C /* u8 read, set, +1 clear */ -#define ISP1301_INTERRUPT_RISING 0x0E /* u8 read, set, +1 clear */ - -/* same bitfields in all interrupt registers */ -# define INTR_VBUS_VLD (1 << 0) -# define INTR_SESS_VLD (1 << 1) -# define INTR_DP_HI (1 << 2) -# define INTR_ID_GND (1 << 3) -# define INTR_DM_HI (1 << 4) -# define INTR_ID_FLOAT (1 << 5) -# define INTR_BDIS_ACON (1 << 6) -# define INTR_CR_INT (1 << 7) - -/*-------------------------------------------------------------------------*/ - -static inline const char *state_name(struct isp1301 *isp) -{ - return usb_otg_state_string(isp->phy.otg->state); -} - -/*-------------------------------------------------------------------------*/ - -/* NOTE: some of this ISP1301 setup is specific to H2 boards; - * not everything is guarded by board-specific checks, or even using - * omap_usb_config data to deduce MC1_DAT_SE0 and MC2_BI_DI. - * - * ALSO: this currently doesn't use ISP1301 low-power modes - * while OTG is running. - */ - -static void power_down(struct isp1301 *isp) -{ - isp->phy.otg->state = OTG_STATE_UNDEFINED; - - // isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND); - - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_ID_PULLDOWN); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); -} - -static void __maybe_unused power_up(struct isp1301 *isp) -{ - // isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND); - - /* do this only when cpu is driving transceiver, - * so host won't see a low speed device... - */ - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); -} - -#define NO_HOST_SUSPEND - -static int host_suspend(struct isp1301 *isp) -{ -#ifdef NO_HOST_SUSPEND - return 0; -#else - struct device *dev; - - if (!isp->phy.otg->host) - return -ENODEV; - - /* Currently ASSUMES only the OTG port matters; - * other ports could be active... - */ - dev = isp->phy.otg->host->controller; - return dev->driver->suspend(dev, 3, 0); -#endif -} - -static int host_resume(struct isp1301 *isp) -{ -#ifdef NO_HOST_SUSPEND - return 0; -#else - struct device *dev; - - if (!isp->phy.otg->host) - return -ENODEV; - - dev = isp->phy.otg->host->controller; - return dev->driver->resume(dev, 0); -#endif -} - -static int gadget_suspend(struct isp1301 *isp) -{ - isp->phy.otg->gadget->b_hnp_enable = 0; - isp->phy.otg->gadget->a_hnp_support = 0; - isp->phy.otg->gadget->a_alt_hnp_support = 0; - return usb_gadget_vbus_disconnect(isp->phy.otg->gadget); -} - -/*-------------------------------------------------------------------------*/ - -#define TIMER_MINUTES 10 -#define TIMER_JIFFIES (TIMER_MINUTES * 60 * HZ) - -/* Almost all our I2C messaging comes from a work queue's task context. - * NOTE: guaranteeing certain response times might mean we shouldn't - * share keventd's work queue; a realtime task might be safest. - */ -static void isp1301_defer_work(struct isp1301 *isp, int work) -{ - int status; - - if (isp && !test_and_set_bit(work, &isp->todo)) { - (void) get_device(&isp->client->dev); - status = schedule_work(&isp->work); - if (!status && !isp->working) - dev_vdbg(&isp->client->dev, - "work item %d may be lost\n", work); - } -} - -/* called from irq handlers */ -static void a_idle(struct isp1301 *isp, const char *tag) -{ - u32 l; - - if (isp->phy.otg->state == OTG_STATE_A_IDLE) - return; - - isp->phy.otg->default_a = 1; - if (isp->phy.otg->host) { - isp->phy.otg->host->is_b_host = 0; - host_suspend(isp); - } - if (isp->phy.otg->gadget) { - isp->phy.otg->gadget->is_a_peripheral = 1; - gadget_suspend(isp); - } - isp->phy.otg->state = OTG_STATE_A_IDLE; - l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; - omap_writel(l, OTG_CTRL); - isp->last_otg_ctrl = l; - pr_debug(" --> %s/%s\n", state_name(isp), tag); -} - -/* called from irq handlers */ -static void b_idle(struct isp1301 *isp, const char *tag) -{ - u32 l; - - if (isp->phy.otg->state == OTG_STATE_B_IDLE) - return; - - isp->phy.otg->default_a = 0; - if (isp->phy.otg->host) { - isp->phy.otg->host->is_b_host = 1; - host_suspend(isp); - } - if (isp->phy.otg->gadget) { - isp->phy.otg->gadget->is_a_peripheral = 0; - gadget_suspend(isp); - } - isp->phy.otg->state = OTG_STATE_B_IDLE; - l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; - omap_writel(l, OTG_CTRL); - isp->last_otg_ctrl = l; - pr_debug(" --> %s/%s\n", state_name(isp), tag); -} - -static void -dump_regs(struct isp1301 *isp, const char *label) -{ - u8 ctrl = isp1301_get_u8(isp, ISP1301_OTG_CONTROL_1); - u8 status = isp1301_get_u8(isp, ISP1301_OTG_STATUS); - u8 src = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE); - - pr_debug("otg: %06x, %s %s, otg/%02x stat/%02x.%02x\n", - omap_readl(OTG_CTRL), label, state_name(isp), - ctrl, status, src); - /* mode control and irq enables don't change much */ -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_OTG - -/* - * The OMAP OTG controller handles most of the OTG state transitions. - * - * We translate isp1301 outputs (mostly voltage comparator status) into - * OTG inputs; OTG outputs (mostly pullup/pulldown controls) and HNP state - * flags into isp1301 inputs ... and infer state transitions. - */ - -#ifdef VERBOSE - -static void check_state(struct isp1301 *isp, const char *tag) -{ - enum usb_otg_state state = OTG_STATE_UNDEFINED; - u8 fsm = omap_readw(OTG_TEST) & 0x0ff; - unsigned extra = 0; - - switch (fsm) { - - /* default-b */ - case 0x0: - state = OTG_STATE_B_IDLE; - break; - case 0x3: - case 0x7: - extra = 1; - case 0x1: - state = OTG_STATE_B_PERIPHERAL; - break; - case 0x11: - state = OTG_STATE_B_SRP_INIT; - break; - - /* extra dual-role default-b states */ - case 0x12: - case 0x13: - case 0x16: - extra = 1; - case 0x17: - state = OTG_STATE_B_WAIT_ACON; - break; - case 0x34: - state = OTG_STATE_B_HOST; - break; - - /* default-a */ - case 0x36: - state = OTG_STATE_A_IDLE; - break; - case 0x3c: - state = OTG_STATE_A_WAIT_VFALL; - break; - case 0x7d: - state = OTG_STATE_A_VBUS_ERR; - break; - case 0x9e: - case 0x9f: - extra = 1; - case 0x89: - state = OTG_STATE_A_PERIPHERAL; - break; - case 0xb7: - state = OTG_STATE_A_WAIT_VRISE; - break; - case 0xb8: - state = OTG_STATE_A_WAIT_BCON; - break; - case 0xb9: - state = OTG_STATE_A_HOST; - break; - case 0xba: - state = OTG_STATE_A_SUSPEND; - break; - default: - break; - } - if (isp->phy.otg->state == state && !extra) - return; - pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag, - usb_otg_state_string(state), fsm, state_name(isp), - omap_readl(OTG_CTRL)); -} - -#else - -static inline void check_state(struct isp1301 *isp, const char *tag) { } - -#endif - -/* outputs from ISP1301_INTERRUPT_SOURCE */ -static void update_otg1(struct isp1301 *isp, u8 int_src) -{ - u32 otg_ctrl; - - otg_ctrl = omap_readl(OTG_CTRL) & OTG_CTRL_MASK; - otg_ctrl &= ~OTG_XCEIV_INPUTS; - otg_ctrl &= ~(OTG_ID|OTG_ASESSVLD|OTG_VBUSVLD); - - if (int_src & INTR_SESS_VLD) - otg_ctrl |= OTG_ASESSVLD; - else if (isp->phy.otg->state == OTG_STATE_A_WAIT_VFALL) { - a_idle(isp, "vfall"); - otg_ctrl &= ~OTG_CTRL_BITS; - } - if (int_src & INTR_VBUS_VLD) - otg_ctrl |= OTG_VBUSVLD; - if (int_src & INTR_ID_GND) { /* default-A */ - if (isp->phy.otg->state == OTG_STATE_B_IDLE - || isp->phy.otg->state - == OTG_STATE_UNDEFINED) { - a_idle(isp, "init"); - return; - } - } else { /* default-B */ - otg_ctrl |= OTG_ID; - if (isp->phy.otg->state == OTG_STATE_A_IDLE - || isp->phy.otg->state == OTG_STATE_UNDEFINED) { - b_idle(isp, "init"); - return; - } - } - omap_writel(otg_ctrl, OTG_CTRL); -} - -/* outputs from ISP1301_OTG_STATUS */ -static void update_otg2(struct isp1301 *isp, u8 otg_status) -{ - u32 otg_ctrl; - - otg_ctrl = omap_readl(OTG_CTRL) & OTG_CTRL_MASK; - otg_ctrl &= ~OTG_XCEIV_INPUTS; - otg_ctrl &= ~(OTG_BSESSVLD | OTG_BSESSEND); - if (otg_status & OTG_B_SESS_VLD) - otg_ctrl |= OTG_BSESSVLD; - else if (otg_status & OTG_B_SESS_END) - otg_ctrl |= OTG_BSESSEND; - omap_writel(otg_ctrl, OTG_CTRL); -} - -/* inputs going to ISP1301 */ -static void otg_update_isp(struct isp1301 *isp) -{ - u32 otg_ctrl, otg_change; - u8 set = OTG1_DM_PULLDOWN, clr = OTG1_DM_PULLUP; - - otg_ctrl = omap_readl(OTG_CTRL); - otg_change = otg_ctrl ^ isp->last_otg_ctrl; - isp->last_otg_ctrl = otg_ctrl; - otg_ctrl = otg_ctrl & OTG_XCEIV_INPUTS; - - switch (isp->phy.otg->state) { - case OTG_STATE_B_IDLE: - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_SRP_INIT: - if (!(otg_ctrl & OTG_PULLUP)) { - // if (otg_ctrl & OTG_B_HNPEN) { - if (isp->phy.otg->gadget->b_hnp_enable) { - isp->phy.otg->state = OTG_STATE_B_WAIT_ACON; - pr_debug(" --> b_wait_acon\n"); - } - goto pulldown; - } -pullup: - set |= OTG1_DP_PULLUP; - clr |= OTG1_DP_PULLDOWN; - break; - case OTG_STATE_A_SUSPEND: - case OTG_STATE_A_PERIPHERAL: - if (otg_ctrl & OTG_PULLUP) - goto pullup; - fallthrough; - // case OTG_STATE_B_WAIT_ACON: - default: -pulldown: - set |= OTG1_DP_PULLDOWN; - clr |= OTG1_DP_PULLUP; - break; - } - -# define toggle(OTG,ISP) do { \ - if (otg_ctrl & OTG) set |= ISP; \ - else clr |= ISP; \ - } while (0) - - if (!(isp->phy.otg->host)) - otg_ctrl &= ~OTG_DRV_VBUS; - - switch (isp->phy.otg->state) { - case OTG_STATE_A_SUSPEND: - if (otg_ctrl & OTG_DRV_VBUS) { - set |= OTG1_VBUS_DRV; - break; - } - /* HNP failed for some reason (A_AIDL_BDIS timeout) */ - notresponding(isp); - - fallthrough; - case OTG_STATE_A_VBUS_ERR: - isp->phy.otg->state = OTG_STATE_A_WAIT_VFALL; - pr_debug(" --> a_wait_vfall\n"); - fallthrough; - case OTG_STATE_A_WAIT_VFALL: - /* FIXME usbcore thinks port power is still on ... */ - clr |= OTG1_VBUS_DRV; - break; - case OTG_STATE_A_IDLE: - if (otg_ctrl & OTG_DRV_VBUS) { - isp->phy.otg->state = OTG_STATE_A_WAIT_VRISE; - pr_debug(" --> a_wait_vrise\n"); - } - fallthrough; - default: - toggle(OTG_DRV_VBUS, OTG1_VBUS_DRV); - } - - toggle(OTG_PU_VBUS, OTG1_VBUS_CHRG); - toggle(OTG_PD_VBUS, OTG1_VBUS_DISCHRG); - -# undef toggle - - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, set); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, clr); - - /* HNP switch to host or peripheral; and SRP */ - if (otg_change & OTG_PULLUP) { - u32 l; - - switch (isp->phy.otg->state) { - case OTG_STATE_B_IDLE: - if (clr & OTG1_DP_PULLUP) - break; - isp->phy.otg->state = OTG_STATE_B_PERIPHERAL; - pr_debug(" --> b_peripheral\n"); - break; - case OTG_STATE_A_SUSPEND: - if (clr & OTG1_DP_PULLUP) - break; - isp->phy.otg->state = OTG_STATE_A_PERIPHERAL; - pr_debug(" --> a_peripheral\n"); - break; - default: - break; - } - l = omap_readl(OTG_CTRL); - l |= OTG_PULLUP; - omap_writel(l, OTG_CTRL); - } - - check_state(isp, __func__); - dump_regs(isp, "otg->isp1301"); -} - -static irqreturn_t omap_otg_irq(int irq, void *_isp) -{ - u16 otg_irq = omap_readw(OTG_IRQ_SRC); - u32 otg_ctrl; - int ret = IRQ_NONE; - struct isp1301 *isp = _isp; - struct usb_otg *otg = isp->phy.otg; - - /* update ISP1301 transceiver from OTG controller */ - if (otg_irq & OPRT_CHG) { - omap_writew(OPRT_CHG, OTG_IRQ_SRC); - isp1301_defer_work(isp, WORK_UPDATE_ISP); - ret = IRQ_HANDLED; - - /* SRP to become b_peripheral failed */ - } else if (otg_irq & B_SRP_TMROUT) { - pr_debug("otg: B_SRP_TIMEOUT, %06x\n", omap_readl(OTG_CTRL)); - notresponding(isp); - - /* gadget drivers that care should monitor all kinds of - * remote wakeup (SRP, normal) using their own timer - * to give "check cable and A-device" messages. - */ - if (isp->phy.otg->state == OTG_STATE_B_SRP_INIT) - b_idle(isp, "srp_timeout"); - - omap_writew(B_SRP_TMROUT, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* HNP to become b_host failed */ - } else if (otg_irq & B_HNP_FAIL) { - pr_debug("otg: %s B_HNP_FAIL, %06x\n", - state_name(isp), omap_readl(OTG_CTRL)); - notresponding(isp); - - otg_ctrl = omap_readl(OTG_CTRL); - otg_ctrl |= OTG_BUSDROP; - otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - omap_writel(otg_ctrl, OTG_CTRL); - - /* subset of b_peripheral()... */ - isp->phy.otg->state = OTG_STATE_B_PERIPHERAL; - pr_debug(" --> b_peripheral\n"); - - omap_writew(B_HNP_FAIL, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* detect SRP from B-device ... */ - } else if (otg_irq & A_SRP_DETECT) { - pr_debug("otg: %s SRP_DETECT, %06x\n", - state_name(isp), omap_readl(OTG_CTRL)); - - isp1301_defer_work(isp, WORK_UPDATE_OTG); - switch (isp->phy.otg->state) { - case OTG_STATE_A_IDLE: - if (!otg->host) - break; - isp1301_defer_work(isp, WORK_HOST_RESUME); - otg_ctrl = omap_readl(OTG_CTRL); - otg_ctrl |= OTG_A_BUSREQ; - otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ) - & ~OTG_XCEIV_INPUTS - & OTG_CTRL_MASK; - omap_writel(otg_ctrl, OTG_CTRL); - break; - default: - break; - } - - omap_writew(A_SRP_DETECT, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* timer expired: T(a_wait_bcon) and maybe T(a_wait_vrise) - * we don't track them separately - */ - } else if (otg_irq & A_REQ_TMROUT) { - otg_ctrl = omap_readl(OTG_CTRL); - pr_info("otg: BCON_TMOUT from %s, %06x\n", - state_name(isp), otg_ctrl); - notresponding(isp); - - otg_ctrl |= OTG_BUSDROP; - otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - omap_writel(otg_ctrl, OTG_CTRL); - isp->phy.otg->state = OTG_STATE_A_WAIT_VFALL; - - omap_writew(A_REQ_TMROUT, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* A-supplied voltage fell too low; overcurrent */ - } else if (otg_irq & A_VBUS_ERR) { - otg_ctrl = omap_readl(OTG_CTRL); - printk(KERN_ERR "otg: %s, VBUS_ERR %04x ctrl %06x\n", - state_name(isp), otg_irq, otg_ctrl); - - otg_ctrl |= OTG_BUSDROP; - otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - omap_writel(otg_ctrl, OTG_CTRL); - isp->phy.otg->state = OTG_STATE_A_VBUS_ERR; - - omap_writew(A_VBUS_ERR, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* switch driver; the transceiver code activates it, - * ungating the udc clock or resuming OHCI. - */ - } else if (otg_irq & DRIVER_SWITCH) { - int kick = 0; - - otg_ctrl = omap_readl(OTG_CTRL); - printk(KERN_NOTICE "otg: %s, SWITCH to %s, ctrl %06x\n", - state_name(isp), - (otg_ctrl & OTG_DRIVER_SEL) - ? "gadget" : "host", - otg_ctrl); - isp1301_defer_work(isp, WORK_UPDATE_ISP); - - /* role is peripheral */ - if (otg_ctrl & OTG_DRIVER_SEL) { - switch (isp->phy.otg->state) { - case OTG_STATE_A_IDLE: - b_idle(isp, __func__); - break; - default: - break; - } - isp1301_defer_work(isp, WORK_UPDATE_ISP); - - /* role is host */ - } else { - if (!(otg_ctrl & OTG_ID)) { - otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - omap_writel(otg_ctrl | OTG_A_BUSREQ, OTG_CTRL); - } - - if (otg->host) { - switch (isp->phy.otg->state) { - case OTG_STATE_B_WAIT_ACON: - isp->phy.otg->state = OTG_STATE_B_HOST; - pr_debug(" --> b_host\n"); - kick = 1; - break; - case OTG_STATE_A_WAIT_BCON: - isp->phy.otg->state = OTG_STATE_A_HOST; - pr_debug(" --> a_host\n"); - break; - case OTG_STATE_A_PERIPHERAL: - isp->phy.otg->state = OTG_STATE_A_WAIT_BCON; - pr_debug(" --> a_wait_bcon\n"); - break; - default: - break; - } - isp1301_defer_work(isp, WORK_HOST_RESUME); - } - } - - omap_writew(DRIVER_SWITCH, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - if (kick) - usb_bus_start_enum(otg->host, otg->host->otg_port); - } - - check_state(isp, __func__); - return ret; -} - -static struct platform_device *otg_dev; - -static int isp1301_otg_init(struct isp1301 *isp) -{ - u32 l; - - if (!otg_dev) - return -ENODEV; - - dump_regs(isp, __func__); - /* some of these values are board-specific... */ - l = omap_readl(OTG_SYSCON_2); - l |= OTG_EN - /* for B-device: */ - | SRP_GPDATA /* 9msec Bdev D+ pulse */ - | SRP_GPDVBUS /* discharge after VBUS pulse */ - // | (3 << 24) /* 2msec VBUS pulse */ - /* for A-device: */ - | (0 << 20) /* 200ms nominal A_WAIT_VRISE timer */ - | SRP_DPW /* detect 167+ns SRP pulses */ - | SRP_DATA | SRP_VBUS /* accept both kinds of SRP pulse */ - ; - omap_writel(l, OTG_SYSCON_2); - - update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE)); - update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); - - check_state(isp, __func__); - pr_debug("otg: %s, %s %06x\n", - state_name(isp), __func__, omap_readl(OTG_CTRL)); - - omap_writew(DRIVER_SWITCH | OPRT_CHG - | B_SRP_TMROUT | B_HNP_FAIL - | A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT, OTG_IRQ_EN); - - l = omap_readl(OTG_SYSCON_2); - l |= OTG_EN; - omap_writel(l, OTG_SYSCON_2); - - return 0; -} - -static int otg_probe(struct platform_device *dev) -{ - // struct omap_usb_config *config = dev->platform_data; - - otg_dev = dev; - return 0; -} - -static int otg_remove(struct platform_device *dev) -{ - otg_dev = NULL; - return 0; -} - -static struct platform_driver omap_otg_driver = { - .probe = otg_probe, - .remove = otg_remove, - .driver = { - .name = "omap_otg", - }, -}; - -static int otg_bind(struct isp1301 *isp) -{ - int status; - - if (otg_dev) - return -EBUSY; - - status = platform_driver_register(&omap_otg_driver); - if (status < 0) - return status; - - if (otg_dev) - status = request_irq(otg_dev->resource[1].start, omap_otg_irq, - 0, DRIVER_NAME, isp); - else - status = -ENODEV; - - if (status < 0) - platform_driver_unregister(&omap_otg_driver); - return status; -} - -static void otg_unbind(struct isp1301 *isp) -{ - if (!otg_dev) - return; - free_irq(otg_dev->resource[1].start, isp); -} - -#else - -/* OTG controller isn't clocked */ - -#endif /* CONFIG_USB_OTG */ - -/*-------------------------------------------------------------------------*/ - -static void b_peripheral(struct isp1301 *isp) -{ - u32 l; - - l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; - omap_writel(l, OTG_CTRL); - - usb_gadget_vbus_connect(isp->phy.otg->gadget); - -#ifdef CONFIG_USB_OTG - enable_vbus_draw(isp, 8); - otg_update_isp(isp); -#else - enable_vbus_draw(isp, 100); - /* UDC driver just set OTG_BSESSVLD */ - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN); - isp->phy.otg->state = OTG_STATE_B_PERIPHERAL; - pr_debug(" --> b_peripheral\n"); - dump_regs(isp, "2periph"); -#endif -} - -static void isp_update_otg(struct isp1301 *isp, u8 stat) -{ - struct usb_otg *otg = isp->phy.otg; - u8 isp_stat, isp_bstat; - enum usb_otg_state state = isp->phy.otg->state; - - if (stat & INTR_BDIS_ACON) - pr_debug("OTG: BDIS_ACON, %s\n", state_name(isp)); - - /* start certain state transitions right away */ - isp_stat = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE); - if (isp_stat & INTR_ID_GND) { - if (otg->default_a) { - switch (state) { - case OTG_STATE_B_IDLE: - a_idle(isp, "idle"); - fallthrough; - case OTG_STATE_A_IDLE: - enable_vbus_source(isp); - fallthrough; - case OTG_STATE_A_WAIT_VRISE: - /* we skip over OTG_STATE_A_WAIT_BCON, since - * the HC will transition to A_HOST (or - * A_SUSPEND!) without our noticing except - * when HNP is used. - */ - if (isp_stat & INTR_VBUS_VLD) - isp->phy.otg->state = OTG_STATE_A_HOST; - break; - case OTG_STATE_A_WAIT_VFALL: - if (!(isp_stat & INTR_SESS_VLD)) - a_idle(isp, "vfell"); - break; - default: - if (!(isp_stat & INTR_VBUS_VLD)) - isp->phy.otg->state = OTG_STATE_A_VBUS_ERR; - break; - } - isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS); - } else { - switch (state) { - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_HOST: - case OTG_STATE_B_WAIT_ACON: - usb_gadget_vbus_disconnect(otg->gadget); - break; - default: - break; - } - if (state != OTG_STATE_A_IDLE) - a_idle(isp, "id"); - if (otg->host && state == OTG_STATE_A_IDLE) - isp1301_defer_work(isp, WORK_HOST_RESUME); - isp_bstat = 0; - } - } else { - u32 l; - - /* if user unplugged mini-A end of cable, - * don't bypass A_WAIT_VFALL. - */ - if (otg->default_a) { - switch (state) { - default: - isp->phy.otg->state = OTG_STATE_A_WAIT_VFALL; - break; - case OTG_STATE_A_WAIT_VFALL: - state = OTG_STATE_A_IDLE; - /* hub_wq may take a while to notice and - * handle this disconnect, so don't go - * to B_IDLE quite yet. - */ - break; - case OTG_STATE_A_IDLE: - host_suspend(isp); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, - MC1_BDIS_ACON_EN); - isp->phy.otg->state = OTG_STATE_B_IDLE; - l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK; - l &= ~OTG_CTRL_BITS; - omap_writel(l, OTG_CTRL); - break; - case OTG_STATE_B_IDLE: - break; - } - } - isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS); - - switch (isp->phy.otg->state) { - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_WAIT_ACON: - case OTG_STATE_B_HOST: - if (likely(isp_bstat & OTG_B_SESS_VLD)) - break; - enable_vbus_draw(isp, 0); -#ifndef CONFIG_USB_OTG - /* UDC driver will clear OTG_BSESSVLD */ - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, - OTG1_DP_PULLDOWN); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, - OTG1_DP_PULLUP); - dump_regs(isp, __func__); -#endif - fallthrough; - case OTG_STATE_B_SRP_INIT: - b_idle(isp, __func__); - l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; - omap_writel(l, OTG_CTRL); - fallthrough; - case OTG_STATE_B_IDLE: - if (otg->gadget && (isp_bstat & OTG_B_SESS_VLD)) { -#ifdef CONFIG_USB_OTG - update_otg1(isp, isp_stat); - update_otg2(isp, isp_bstat); -#endif - b_peripheral(isp); - } else if (!(isp_stat & (INTR_VBUS_VLD|INTR_SESS_VLD))) - isp_bstat |= OTG_B_SESS_END; - break; - case OTG_STATE_A_WAIT_VFALL: - break; - default: - pr_debug("otg: unsupported b-device %s\n", - state_name(isp)); - break; - } - } - - if (state != isp->phy.otg->state) - pr_debug(" isp, %s -> %s\n", - usb_otg_state_string(state), state_name(isp)); - -#ifdef CONFIG_USB_OTG - /* update the OTG controller state to match the isp1301; may - * trigger OPRT_CHG irqs for changes going to the isp1301. - */ - update_otg1(isp, isp_stat); - update_otg2(isp, isp_bstat); - check_state(isp, __func__); -#endif - - dump_regs(isp, "isp1301->otg"); -} - -/*-------------------------------------------------------------------------*/ - -static u8 isp1301_clear_latch(struct isp1301 *isp) -{ - u8 latch = isp1301_get_u8(isp, ISP1301_INTERRUPT_LATCH); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, latch); - return latch; -} - -static void -isp1301_work(struct work_struct *work) -{ - struct isp1301 *isp = container_of(work, struct isp1301, work); - int stop; - - /* implicit lock: we're the only task using this device */ - isp->working = 1; - do { - stop = test_bit(WORK_STOP, &isp->todo); - -#ifdef CONFIG_USB_OTG - /* transfer state from otg engine to isp1301 */ - if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) { - otg_update_isp(isp); - put_device(&isp->client->dev); - } -#endif - /* transfer state from isp1301 to otg engine */ - if (test_and_clear_bit(WORK_UPDATE_OTG, &isp->todo)) { - u8 stat = isp1301_clear_latch(isp); - - isp_update_otg(isp, stat); - put_device(&isp->client->dev); - } - - if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) { - u32 otg_ctrl; - - /* - * skip A_WAIT_VRISE; hc transitions invisibly - * skip A_WAIT_BCON; same. - */ - switch (isp->phy.otg->state) { - case OTG_STATE_A_WAIT_BCON: - case OTG_STATE_A_WAIT_VRISE: - isp->phy.otg->state = OTG_STATE_A_HOST; - pr_debug(" --> a_host\n"); - otg_ctrl = omap_readl(OTG_CTRL); - otg_ctrl |= OTG_A_BUSREQ; - otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ) - & OTG_CTRL_MASK; - omap_writel(otg_ctrl, OTG_CTRL); - break; - case OTG_STATE_B_WAIT_ACON: - isp->phy.otg->state = OTG_STATE_B_HOST; - pr_debug(" --> b_host (acon)\n"); - break; - case OTG_STATE_B_HOST: - case OTG_STATE_B_IDLE: - case OTG_STATE_A_IDLE: - break; - default: - pr_debug(" host resume in %s\n", - state_name(isp)); - } - host_resume(isp); - // mdelay(10); - put_device(&isp->client->dev); - } - - if (test_and_clear_bit(WORK_TIMER, &isp->todo)) { -#ifdef VERBOSE - dump_regs(isp, "timer"); - if (!stop) - mod_timer(&isp->timer, jiffies + TIMER_JIFFIES); -#endif - put_device(&isp->client->dev); - } - - if (isp->todo) - dev_vdbg(&isp->client->dev, - "work done, todo = 0x%lx\n", - isp->todo); - if (stop) { - dev_dbg(&isp->client->dev, "stop\n"); - break; - } - } while (isp->todo); - isp->working = 0; -} - -static irqreturn_t isp1301_irq(int irq, void *isp) -{ - isp1301_defer_work(isp, WORK_UPDATE_OTG); - return IRQ_HANDLED; -} - -static void isp1301_timer(struct timer_list *t) -{ - struct isp1301 *isp = from_timer(isp, t, timer); - - isp1301_defer_work(isp, WORK_TIMER); -} - -/*-------------------------------------------------------------------------*/ - -static void isp1301_release(struct device *dev) -{ - struct isp1301 *isp; - - isp = dev_get_drvdata(dev); - - /* FIXME -- not with a "new style" driver, it doesn't!! */ - - /* ugly -- i2c hijacks our memory hook to wait_for_completion() */ - if (isp->i2c_release) - isp->i2c_release(dev); - kfree(isp->phy.otg); - kfree (isp); -} - -static struct isp1301 *the_transceiver; - -static void isp1301_remove(struct i2c_client *i2c) -{ - struct isp1301 *isp; - - isp = i2c_get_clientdata(i2c); - - isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0); - free_irq(i2c->irq, isp); -#ifdef CONFIG_USB_OTG - otg_unbind(isp); -#endif - set_bit(WORK_STOP, &isp->todo); - del_timer_sync(&isp->timer); - flush_work(&isp->work); - - put_device(&i2c->dev); - the_transceiver = NULL; -} - -/*-------------------------------------------------------------------------*/ - -/* NOTE: three modes are possible here, only one of which - * will be standards-conformant on any given system: - * - * - OTG mode (dual-role), required if there's a Mini-AB connector - * - HOST mode, for when there's one or more A (host) connectors - * - DEVICE mode, for when there's a B/Mini-B (device) connector - * - * As a rule, you won't have an isp1301 chip unless it's there to - * support the OTG mode. Other modes help testing USB controllers - * in isolation from (full) OTG support, or maybe so later board - * revisions can help to support those feature. - */ - -#ifdef CONFIG_USB_OTG - -static int isp1301_otg_enable(struct isp1301 *isp) -{ - power_up(isp); - isp1301_otg_init(isp); - - /* NOTE: since we don't change this, this provides - * a few more interrupts than are strictly needed. - */ - isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, - INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND); - isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, - INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND); - - dev_info(&isp->client->dev, "ready for dual-role USB ...\n"); - - return 0; -} - -#endif - -/* add or disable the host device+driver */ -static int -isp1301_set_host(struct usb_otg *otg, struct usb_bus *host) -{ - struct isp1301 *isp = container_of(otg->usb_phy, struct isp1301, phy); - - if (isp != the_transceiver) - return -ENODEV; - - if (!host) { - omap_writew(0, OTG_IRQ_EN); - power_down(isp); - otg->host = NULL; - return 0; - } - -#ifdef CONFIG_USB_OTG - otg->host = host; - dev_dbg(&isp->client->dev, "registered host\n"); - host_suspend(isp); - if (otg->gadget) - return isp1301_otg_enable(isp); - return 0; - -#elif !IS_ENABLED(CONFIG_USB_OMAP) - // FIXME update its refcount - otg->host = host; - - power_up(isp); - - if (machine_is_omap_h2()) - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); - - dev_info(&isp->client->dev, "A-Host sessions ok\n"); - isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, - INTR_ID_GND); - isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, - INTR_ID_GND); - - /* If this has a Mini-AB connector, this mode is highly - * nonstandard ... but can be handy for testing, especially with - * the Mini-A end of an OTG cable. (Or something nonstandard - * like MiniB-to-StandardB, maybe built with a gender mender.) - */ - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV); - - dump_regs(isp, __func__); - - return 0; - -#else - dev_dbg(&isp->client->dev, "host sessions not allowed\n"); - return -EINVAL; -#endif - -} - -static int -isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) -{ - struct isp1301 *isp = container_of(otg->usb_phy, struct isp1301, phy); - - if (isp != the_transceiver) - return -ENODEV; - - if (!gadget) { - omap_writew(0, OTG_IRQ_EN); - if (!otg->default_a) - enable_vbus_draw(isp, 0); - usb_gadget_vbus_disconnect(otg->gadget); - otg->gadget = NULL; - power_down(isp); - return 0; - } - -#ifdef CONFIG_USB_OTG - otg->gadget = gadget; - dev_dbg(&isp->client->dev, "registered gadget\n"); - /* gadget driver may be suspended until vbus_connect () */ - if (otg->host) - return isp1301_otg_enable(isp); - return 0; - -#elif !defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OHCI_HCD_MODULE) - otg->gadget = gadget; - // FIXME update its refcount - - { - u32 l; - - l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK; - l &= ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS); - l |= OTG_ID; - omap_writel(l, OTG_CTRL); - } - - power_up(isp); - isp->phy.otg->state = OTG_STATE_B_IDLE; - - if (machine_is_omap_h2() || machine_is_omap_h3()) - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); - - isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, - INTR_SESS_VLD); - isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, - INTR_VBUS_VLD); - dev_info(&isp->client->dev, "B-Peripheral sessions ok\n"); - dump_regs(isp, __func__); - - /* If this has a Mini-AB connector, this mode is highly - * nonstandard ... but can be handy for testing, so long - * as you don't plug a Mini-A cable into the jack. - */ - if (isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE) & INTR_VBUS_VLD) - b_peripheral(isp); - - return 0; - -#else - dev_dbg(&isp->client->dev, "peripheral sessions not allowed\n"); - return -EINVAL; -#endif -} - - -/*-------------------------------------------------------------------------*/ - -static int -isp1301_set_power(struct usb_phy *dev, unsigned mA) -{ - if (!the_transceiver) - return -ENODEV; - if (dev->otg->state == OTG_STATE_B_PERIPHERAL) - enable_vbus_draw(the_transceiver, mA); - return 0; -} - -static int -isp1301_start_srp(struct usb_otg *otg) -{ - struct isp1301 *isp = container_of(otg->usb_phy, struct isp1301, phy); - u32 otg_ctrl; - - if (isp != the_transceiver || isp->phy.otg->state != OTG_STATE_B_IDLE) - return -ENODEV; - - otg_ctrl = omap_readl(OTG_CTRL); - if (!(otg_ctrl & OTG_BSESSEND)) - return -EINVAL; - - otg_ctrl |= OTG_B_BUSREQ; - otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK; - omap_writel(otg_ctrl, OTG_CTRL); - isp->phy.otg->state = OTG_STATE_B_SRP_INIT; - - pr_debug("otg: SRP, %s ... %06x\n", state_name(isp), - omap_readl(OTG_CTRL)); -#ifdef CONFIG_USB_OTG - check_state(isp, __func__); -#endif - return 0; -} - -static int -isp1301_start_hnp(struct usb_otg *otg) -{ -#ifdef CONFIG_USB_OTG - struct isp1301 *isp = container_of(otg->usb_phy, struct isp1301, phy); - u32 l; - - if (isp != the_transceiver) - return -ENODEV; - if (otg->default_a && (otg->host == NULL || !otg->host->b_hnp_enable)) - return -ENOTCONN; - if (!otg->default_a && (otg->gadget == NULL - || !otg->gadget->b_hnp_enable)) - return -ENOTCONN; - - /* We want hardware to manage most HNP protocol timings. - * So do this part as early as possible... - */ - switch (isp->phy.otg->state) { - case OTG_STATE_B_HOST: - isp->phy.otg->state = OTG_STATE_B_PERIPHERAL; - /* caller will suspend next */ - break; - case OTG_STATE_A_HOST: -#if 0 - /* autoconnect mode avoids irq latency bugs */ - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, - MC1_BDIS_ACON_EN); -#endif - /* caller must suspend then clear A_BUSREQ */ - usb_gadget_vbus_connect(otg->gadget); - l = omap_readl(OTG_CTRL); - l |= OTG_A_SETB_HNPEN; - omap_writel(l, OTG_CTRL); - - break; - case OTG_STATE_A_PERIPHERAL: - /* initiated by B-Host suspend */ - break; - default: - return -EILSEQ; - } - pr_debug("otg: HNP %s, %06x ...\n", - state_name(isp), omap_readl(OTG_CTRL)); - check_state(isp, __func__); - return 0; -#else - /* srp-only */ - return -EINVAL; -#endif -} - -/*-------------------------------------------------------------------------*/ - -static int -isp1301_probe(struct i2c_client *i2c) -{ - int status; - struct isp1301 *isp; - int irq; - - if (the_transceiver) - return 0; - - isp = kzalloc(sizeof *isp, GFP_KERNEL); - if (!isp) - return 0; - - isp->phy.otg = kzalloc(sizeof *isp->phy.otg, GFP_KERNEL); - if (!isp->phy.otg) { - kfree(isp); - return 0; - } - - INIT_WORK(&isp->work, isp1301_work); - timer_setup(&isp->timer, isp1301_timer, 0); - - i2c_set_clientdata(i2c, isp); - isp->client = i2c; - - /* verify the chip (shouldn't be necessary) */ - status = isp1301_get_u16(isp, ISP1301_VENDOR_ID); - if (status != I2C_VENDOR_ID_PHILIPS) { - dev_dbg(&i2c->dev, "not philips id: %d\n", status); - goto fail; - } - status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID); - if (status != I2C_PRODUCT_ID_PHILIPS_1301) { - dev_dbg(&i2c->dev, "not isp1301, %d\n", status); - goto fail; - } - isp->i2c_release = i2c->dev.release; - i2c->dev.release = isp1301_release; - - /* initial development used chiprev 2.00 */ - status = i2c_smbus_read_word_data(i2c, ISP1301_BCD_DEVICE); - dev_info(&i2c->dev, "chiprev %x.%02x, driver " DRIVER_VERSION "\n", - status >> 8, status & 0xff); - - /* make like power-on reset */ - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_MASK); - - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_BI_DI); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, ~MC2_BI_DI); - - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, - OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, - ~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN)); - - isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, ~0); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0); - -#ifdef CONFIG_USB_OTG - status = otg_bind(isp); - if (status < 0) { - dev_dbg(&i2c->dev, "can't bind OTG\n"); - goto fail; - } -#endif - - if (machine_is_omap_h2()) { - struct gpio_desc *gpiod; - - /* full speed signaling by default */ - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, - MC1_SPEED); - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, - MC2_SPD_SUSP_CTRL); - - gpiod = devm_gpiod_get(&i2c->dev, NULL, GPIOD_IN); - if (IS_ERR(gpiod)) { - dev_err(&i2c->dev, "cannot obtain H2 GPIO\n"); - goto fail; - } - gpiod_set_consumer_name(gpiod, "isp1301"); - irq = gpiod_to_irq(gpiod); - isp->irq_type = IRQF_TRIGGER_FALLING; - } else { - irq = i2c->irq; - } - - status = request_irq(irq, isp1301_irq, - isp->irq_type, DRIVER_NAME, isp); - if (status < 0) { - dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n", - i2c->irq, status); - goto fail; - } - - isp->phy.dev = &i2c->dev; - isp->phy.label = DRIVER_NAME; - isp->phy.set_power = isp1301_set_power; - - isp->phy.otg->usb_phy = &isp->phy; - isp->phy.otg->set_host = isp1301_set_host; - isp->phy.otg->set_peripheral = isp1301_set_peripheral; - isp->phy.otg->start_srp = isp1301_start_srp; - isp->phy.otg->start_hnp = isp1301_start_hnp; - - enable_vbus_draw(isp, 0); - power_down(isp); - the_transceiver = isp; - -#ifdef CONFIG_USB_OTG - update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE)); - update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); -#endif - - dump_regs(isp, __func__); - -#ifdef VERBOSE - mod_timer(&isp->timer, jiffies + TIMER_JIFFIES); - dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES); -#endif - - status = usb_add_phy(&isp->phy, USB_PHY_TYPE_USB2); - if (status < 0) - dev_err(&i2c->dev, "can't register transceiver, %d\n", - status); - - return 0; - -fail: - kfree(isp->phy.otg); - kfree(isp); - return -ENODEV; -} - -static const struct i2c_device_id isp1301_id[] = { - { "isp1301_omap", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, isp1301_id); - -static struct i2c_driver isp1301_driver = { - .driver = { - .name = "isp1301_omap", - }, - .probe_new = isp1301_probe, - .remove = isp1301_remove, - .id_table = isp1301_id, -}; - -/*-------------------------------------------------------------------------*/ - -static int __init isp_init(void) -{ - return i2c_add_driver(&isp1301_driver); -} -subsys_initcall(isp_init); - -static void __exit isp_exit(void) -{ - if (the_transceiver) - usb_remove_phy(&the_transceiver->phy); - i2c_del_driver(&isp1301_driver); -} -module_exit(isp_exit); - diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 67372acc2352..832ad592b7ef 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -60,6 +60,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */ { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ + { USB_DEVICE(0x0908, 0x0070) }, /* Siemens SCALANCE LPE-9000 USB Serial Console */ { USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */ { USB_DEVICE(0x0988, 0x0578) }, /* Teraoka AD2000 */ { USB_DEVICE(0x0B00, 0x3070) }, /* Ingenico 3070 */ diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index dee79c7d82d5..ee5ac4ef7e16 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -255,10 +255,16 @@ static void option_instat_callback(struct urb *urb); #define QUECTEL_PRODUCT_EP06 0x0306 #define QUECTEL_PRODUCT_EM05G 0x030a #define QUECTEL_PRODUCT_EM060K 0x030b +#define QUECTEL_PRODUCT_EM05G_CS 0x030c +#define QUECTEL_PRODUCT_EM05CN_SG 0x0310 #define QUECTEL_PRODUCT_EM05G_SG 0x0311 +#define QUECTEL_PRODUCT_EM05CN 0x0312 +#define QUECTEL_PRODUCT_EM05G_GR 0x0313 +#define QUECTEL_PRODUCT_EM05G_RS 0x0314 #define QUECTEL_PRODUCT_EM12 0x0512 #define QUECTEL_PRODUCT_RM500Q 0x0800 #define QUECTEL_PRODUCT_RM520N 0x0801 +#define QUECTEL_PRODUCT_EC200U 0x0901 #define QUECTEL_PRODUCT_EC200S_CN 0x6002 #define QUECTEL_PRODUCT_EC200T 0x6026 #define QUECTEL_PRODUCT_RM500K 0x7001 @@ -1159,8 +1165,18 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff), .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) }, + { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05CN, 0xff), + .driver_info = RSVD(6) | ZLP }, + { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05CN_SG, 0xff), + .driver_info = RSVD(6) | ZLP }, { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G, 0xff), .driver_info = RSVD(6) | ZLP }, + { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_CS, 0xff), + .driver_info = RSVD(6) | ZLP }, + { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_GR, 0xff), + .driver_info = RSVD(6) | ZLP }, + { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_RS, 0xff), + .driver_info = RSVD(6) | ZLP }, { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_SG, 0xff), .driver_info = RSVD(6) | ZLP }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0x00, 0x40) }, @@ -1180,6 +1196,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200U, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200S_CN, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200T, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500K, 0xff, 0x00, 0x00) }, diff --git a/drivers/usb/storage/uas-detect.h b/drivers/usb/storage/uas-detect.h index 3f720faa6f97..d73282c0ec50 100644 --- a/drivers/usb/storage/uas-detect.h +++ b/drivers/usb/storage/uas-detect.h @@ -116,6 +116,19 @@ static int uas_use_uas_driver(struct usb_interface *intf, if (le16_to_cpu(udev->descriptor.idVendor) == 0x0bc2) flags |= US_FL_NO_ATA_1X; + /* + * RTL9210-based enclosure from HIKSEMI, MD202 reportedly have issues + * with UAS. This isn't distinguishable with just idVendor and + * idProduct, use manufacturer and product too. + * + * Reported-by: Hongling Zeng <zenghongling@kylinos.cn> + */ + if (le16_to_cpu(udev->descriptor.idVendor) == 0x0bda && + le16_to_cpu(udev->descriptor.idProduct) == 0x9210 && + (udev->manufacturer && !strcmp(udev->manufacturer, "HIKSEMI")) && + (udev->product && !strcmp(udev->product, "MD202"))) + flags |= US_FL_IGNORE_UAS; + usb_stor_adjust_quirks(udev, &flags); if (flags & US_FL_IGNORE_UAS) { diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index 251778d14e2d..c7b763d6d102 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -83,13 +83,6 @@ UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_REPORT_LUNS), -/* Reported-by: Hongling Zeng <zenghongling@kylinos.cn> */ -UNUSUAL_DEV(0x0bda, 0x9210, 0x0000, 0x9999, - "Hiksemi", - "External HDD", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_UAS), - /* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */ UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999, "Initio Corporation", diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index de66a2949e33..50b24096eb7f 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -419,6 +419,18 @@ static const char * const pin_assignments[] = { [DP_PIN_ASSIGN_F] = "F", }; +/* + * Helper function to extract a peripheral's currently supported + * Pin Assignments from its DisplayPort alternate mode state. + */ +static u8 get_current_pin_assignments(struct dp_altmode *dp) +{ + if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_UFP_U_AS_DFP_D) + return DP_CAP_PIN_ASSIGN_DFP_D(dp->alt->vdo); + else + return DP_CAP_PIN_ASSIGN_UFP_D(dp->alt->vdo); +} + static ssize_t pin_assignment_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) @@ -445,10 +457,7 @@ pin_assignment_store(struct device *dev, struct device_attribute *attr, goto out_unlock; } - if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_DFP_D) - assignments = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo); - else - assignments = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo); + assignments = get_current_pin_assignments(dp); if (!(DP_CONF_GET_PIN_ASSIGN(conf) & assignments)) { ret = -EINVAL; @@ -485,10 +494,7 @@ static ssize_t pin_assignment_show(struct device *dev, cur = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf)); - if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_DFP_D) - assignments = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo); - else - assignments = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo); + assignments = get_current_pin_assignments(dp); for (i = 0; assignments; assignments >>= 1, i++) { if (assignments & 1) { @@ -529,10 +535,10 @@ int dp_altmode_probe(struct typec_altmode *alt) /* FIXME: Port can only be DFP_U. */ /* Make sure we have compatiple pin configurations */ - if (!(DP_CAP_DFP_D_PIN_ASSIGN(port->vdo) & - DP_CAP_UFP_D_PIN_ASSIGN(alt->vdo)) && - !(DP_CAP_UFP_D_PIN_ASSIGN(port->vdo) & - DP_CAP_DFP_D_PIN_ASSIGN(alt->vdo))) + if (!(DP_CAP_PIN_ASSIGN_DFP_D(port->vdo) & + DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo)) && + !(DP_CAP_PIN_ASSIGN_UFP_D(port->vdo) & + DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo))) return -ENODEV; ret = sysfs_create_group(&alt->dev.kobj, &dp_altmode_group); diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 904c7b4ce2f0..59b366b5c614 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -4594,14 +4594,13 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_state(port, ready_state(port), 0); break; case DR_SWAP_CHANGE_DR: - if (port->data_role == TYPEC_HOST) { - tcpm_unregister_altmodes(port); + tcpm_unregister_altmodes(port); + if (port->data_role == TYPEC_HOST) tcpm_set_roles(port, true, port->pwr_role, TYPEC_DEVICE); - } else { + else tcpm_set_roles(port, true, port->pwr_role, TYPEC_HOST); - } tcpm_ams_finish(port); tcpm_set_state(port, ready_state(port), 0); break; diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index eabe519013e7..1cf8947c6d66 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -187,6 +187,7 @@ EXPORT_SYMBOL_GPL(ucsi_send_command); struct ucsi_work { struct delayed_work work; + struct list_head node; unsigned long delay; unsigned int count; struct ucsi_connector *con; @@ -202,6 +203,7 @@ static void ucsi_poll_worker(struct work_struct *work) mutex_lock(&con->lock); if (!con->partner) { + list_del(&uwork->node); mutex_unlock(&con->lock); kfree(uwork); return; @@ -209,10 +211,12 @@ static void ucsi_poll_worker(struct work_struct *work) ret = uwork->cb(con); - if (uwork->count-- && (ret == -EBUSY || ret == -ETIMEDOUT)) + if (uwork->count-- && (ret == -EBUSY || ret == -ETIMEDOUT)) { queue_delayed_work(con->wq, &uwork->work, uwork->delay); - else + } else { + list_del(&uwork->node); kfree(uwork); + } mutex_unlock(&con->lock); } @@ -236,6 +240,7 @@ static int ucsi_partner_task(struct ucsi_connector *con, uwork->con = con; uwork->cb = cb; + list_add_tail(&uwork->node, &con->partner_tasks); queue_delayed_work(con->wq, &uwork->work, delay); return 0; @@ -1056,6 +1061,7 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) INIT_WORK(&con->work, ucsi_handle_connector_change); init_completion(&con->complete); mutex_init(&con->lock); + INIT_LIST_HEAD(&con->partner_tasks); con->num = index + 1; con->ucsi = ucsi; @@ -1263,6 +1269,9 @@ err_unregister: con->port = NULL; } + kfree(ucsi->connector); + ucsi->connector = NULL; + err_reset: memset(&ucsi->cap, 0, sizeof(ucsi->cap)); ucsi_reset_ppm(ucsi); @@ -1294,7 +1303,8 @@ static void ucsi_resume_work(struct work_struct *work) int ucsi_resume(struct ucsi *ucsi) { - queue_work(system_long_wq, &ucsi->resume_work); + if (ucsi->connector) + queue_work(system_long_wq, &ucsi->resume_work); return 0; } EXPORT_SYMBOL_GPL(ucsi_resume); @@ -1414,14 +1424,29 @@ void ucsi_unregister(struct ucsi *ucsi) /* Disable notifications */ ucsi->ops->async_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd)); + if (!ucsi->connector) + return; + for (i = 0; i < ucsi->cap.num_connectors; i++) { cancel_work_sync(&ucsi->connector[i].work); ucsi_unregister_partner(&ucsi->connector[i]); ucsi_unregister_altmodes(&ucsi->connector[i], UCSI_RECIPIENT_CON); ucsi_unregister_port_psy(&ucsi->connector[i]); - if (ucsi->connector[i].wq) + + if (ucsi->connector[i].wq) { + struct ucsi_work *uwork; + + mutex_lock(&ucsi->connector[i].lock); + /* + * queue delayed items immediately so they can execute + * and free themselves before the wq is destroyed + */ + list_for_each_entry(uwork, &ucsi->connector[i].partner_tasks, node) + mod_delayed_work(ucsi->connector[i].wq, &uwork->work, 0); + mutex_unlock(&ucsi->connector[i].lock); destroy_workqueue(ucsi->connector[i].wq); + } typec_unregister_port(ucsi->connector[i].port); } diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index c968474ee547..60ce9fb6e745 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -322,6 +322,7 @@ struct ucsi_connector { struct work_struct work; struct completion complete; struct workqueue_struct *wq; + struct list_head partner_tasks; struct typec_port *port; struct typec_partner *partner; diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c index f9c0044c6442..44b29289aa19 100644 --- a/drivers/vdpa/ifcvf/ifcvf_main.c +++ b/drivers/vdpa/ifcvf/ifcvf_main.c @@ -849,7 +849,7 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id) ret = ifcvf_init_hw(vf, pdev); if (ret) { IFCVF_ERR(pdev, "Failed to init IFCVF hw\n"); - return ret; + goto err; } for (i = 0; i < vf->nr_vring; i++) diff --git a/drivers/vdpa/mlx5/core/mlx5_vdpa.h b/drivers/vdpa/mlx5/core/mlx5_vdpa.h index 6af9fdbb86b7..058fbe28107e 100644 --- a/drivers/vdpa/mlx5/core/mlx5_vdpa.h +++ b/drivers/vdpa/mlx5/core/mlx5_vdpa.h @@ -116,8 +116,9 @@ int mlx5_vdpa_create_mkey(struct mlx5_vdpa_dev *mvdev, u32 *mkey, u32 *in, int inlen); int mlx5_vdpa_destroy_mkey(struct mlx5_vdpa_dev *mvdev, u32 mkey); int mlx5_vdpa_handle_set_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb, - bool *change_map); -int mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb); + bool *change_map, unsigned int asid); +int mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb, + unsigned int asid); void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev); #define mlx5_vdpa_warn(__dev, format, ...) \ diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c index a639b9208d41..0a1e0b0dc37e 100644 --- a/drivers/vdpa/mlx5/core/mr.c +++ b/drivers/vdpa/mlx5/core/mr.c @@ -311,7 +311,6 @@ static int add_direct_chain(struct mlx5_vdpa_dev *mvdev, u64 start, u64 size, u8 u64 st; u64 sz; int err; - int i = 0; st = start; while (size) { @@ -336,7 +335,6 @@ static int add_direct_chain(struct mlx5_vdpa_dev *mvdev, u64 start, u64 size, u8 mr->num_directs++; mr->num_klms++; st += sz; - i++; } list_splice_tail(&tmp, &mr->head); return 0; @@ -511,7 +509,8 @@ out: mutex_unlock(&mr->mkey_mtx); } -static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb) +static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, + struct vhost_iotlb *iotlb, unsigned int asid) { struct mlx5_vdpa_mr *mr = &mvdev->mr; int err; @@ -519,42 +518,49 @@ static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb if (mr->initialized) return 0; - if (iotlb) - err = create_user_mr(mvdev, iotlb); - else - err = create_dma_mr(mvdev, mr); + if (mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP] == asid) { + if (iotlb) + err = create_user_mr(mvdev, iotlb); + else + err = create_dma_mr(mvdev, mr); - if (err) - return err; + if (err) + return err; + } - err = dup_iotlb(mvdev, iotlb); - if (err) - goto out_err; + if (mvdev->group2asid[MLX5_VDPA_CVQ_GROUP] == asid) { + err = dup_iotlb(mvdev, iotlb); + if (err) + goto out_err; + } mr->initialized = true; return 0; out_err: - if (iotlb) - destroy_user_mr(mvdev, mr); - else - destroy_dma_mr(mvdev, mr); + if (mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP] == asid) { + if (iotlb) + destroy_user_mr(mvdev, mr); + else + destroy_dma_mr(mvdev, mr); + } return err; } -int mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb) +int mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb, + unsigned int asid) { int err; mutex_lock(&mvdev->mr.mkey_mtx); - err = _mlx5_vdpa_create_mr(mvdev, iotlb); + err = _mlx5_vdpa_create_mr(mvdev, iotlb, asid); mutex_unlock(&mvdev->mr.mkey_mtx); return err; } int mlx5_vdpa_handle_set_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb, - bool *change_map) + bool *change_map, unsigned int asid) { struct mlx5_vdpa_mr *mr = &mvdev->mr; int err = 0; @@ -566,7 +572,7 @@ int mlx5_vdpa_handle_set_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *io *change_map = true; } if (!*change_map) - err = _mlx5_vdpa_create_mr(mvdev, iotlb); + err = _mlx5_vdpa_create_mr(mvdev, iotlb, asid); mutex_unlock(&mr->mkey_mtx); return err; diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 90913365def4..3a6dbbc6440d 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -1468,11 +1468,13 @@ static int mlx5_vdpa_add_mac_vlan_rules(struct mlx5_vdpa_net *ndev, u8 *mac, dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v, outer_headers.dmac_47_16); eth_broadcast_addr(dmac_c); ether_addr_copy(dmac_v, mac); - MLX5_SET(fte_match_set_lyr_2_4, headers_c, cvlan_tag, 1); + if (ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VLAN)) { + MLX5_SET(fte_match_set_lyr_2_4, headers_c, cvlan_tag, 1); + MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, first_vid); + } if (tagged) { MLX5_SET(fte_match_set_lyr_2_4, headers_v, cvlan_tag, 1); - MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, first_vid); - MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_vid, vid); + MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, vid); } flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR; @@ -1684,7 +1686,7 @@ static virtio_net_ctrl_ack handle_ctrl_mac(struct mlx5_vdpa_dev *mvdev, u8 cmd) /* Need recreate the flow table entry, so that the packet could forward back */ - mac_vlan_del(ndev, ndev->config.mac, 0, false); + mac_vlan_del(ndev, mac_back, 0, false); if (mac_vlan_add(ndev, ndev->config.mac, 0, false)) { mlx5_vdpa_warn(mvdev, "failed to insert forward rules, try to restore\n"); @@ -1821,6 +1823,9 @@ static virtio_net_ctrl_ack handle_ctrl_vlan(struct mlx5_vdpa_dev *mvdev, u8 cmd) size_t read; u16 id; + if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VLAN))) + return status; + switch (cmd) { case VIRTIO_NET_CTRL_VLAN_ADD: read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, &vlan, sizeof(vlan)); @@ -2389,7 +2394,8 @@ static void restore_channels_info(struct mlx5_vdpa_net *ndev) } } -static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb) +static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, + struct vhost_iotlb *iotlb, unsigned int asid) { struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); int err; @@ -2401,7 +2407,7 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb teardown_driver(ndev); mlx5_vdpa_destroy_mr(mvdev); - err = mlx5_vdpa_create_mr(mvdev, iotlb); + err = mlx5_vdpa_create_mr(mvdev, iotlb, asid); if (err) goto err_mr; @@ -2582,7 +2588,7 @@ static int mlx5_vdpa_reset(struct vdpa_device *vdev) ++mvdev->generation; if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) { - if (mlx5_vdpa_create_mr(mvdev, NULL)) + if (mlx5_vdpa_create_mr(mvdev, NULL, 0)) mlx5_vdpa_warn(mvdev, "create MR failed\n"); } up_write(&ndev->reslock); @@ -2618,41 +2624,20 @@ static u32 mlx5_vdpa_get_generation(struct vdpa_device *vdev) return mvdev->generation; } -static int set_map_control(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb) -{ - u64 start = 0ULL, last = 0ULL - 1; - struct vhost_iotlb_map *map; - int err = 0; - - spin_lock(&mvdev->cvq.iommu_lock); - vhost_iotlb_reset(mvdev->cvq.iotlb); - - for (map = vhost_iotlb_itree_first(iotlb, start, last); map; - map = vhost_iotlb_itree_next(map, start, last)) { - err = vhost_iotlb_add_range(mvdev->cvq.iotlb, map->start, - map->last, map->addr, map->perm); - if (err) - goto out; - } - -out: - spin_unlock(&mvdev->cvq.iommu_lock); - return err; -} - -static int set_map_data(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb) +static int set_map_data(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb, + unsigned int asid) { bool change_map; int err; - err = mlx5_vdpa_handle_set_map(mvdev, iotlb, &change_map); + err = mlx5_vdpa_handle_set_map(mvdev, iotlb, &change_map, asid); if (err) { mlx5_vdpa_warn(mvdev, "set map failed(%d)\n", err); return err; } if (change_map) - err = mlx5_vdpa_change_map(mvdev, iotlb); + err = mlx5_vdpa_change_map(mvdev, iotlb, asid); return err; } @@ -2665,16 +2650,7 @@ static int mlx5_vdpa_set_map(struct vdpa_device *vdev, unsigned int asid, int err = -EINVAL; down_write(&ndev->reslock); - if (mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP] == asid) { - err = set_map_data(mvdev, iotlb); - if (err) - goto out; - } - - if (mvdev->group2asid[MLX5_VDPA_CVQ_GROUP] == asid) - err = set_map_control(mvdev, iotlb); - -out: + err = set_map_data(mvdev, iotlb, asid); up_write(&ndev->reslock); return err; } @@ -2840,8 +2816,8 @@ static int mlx5_vdpa_suspend(struct vdpa_device *vdev) int i; down_write(&ndev->reslock); - mlx5_notifier_unregister(mvdev->mdev, &ndev->nb); ndev->nb_registered = false; + mlx5_notifier_unregister(mvdev->mdev, &ndev->nb); flush_workqueue(ndev->mvdev.wq); for (i = 0; i < ndev->cur_num_vqs; i++) { mvq = &ndev->vqs[i]; @@ -3019,7 +2995,7 @@ static void update_carrier(struct work_struct *work) else ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP); - if (ndev->config_cb.callback) + if (ndev->nb_registered && ndev->config_cb.callback) ndev->config_cb.callback(ndev->config_cb.private); kfree(wqent); @@ -3036,21 +3012,13 @@ static int event_handler(struct notifier_block *nb, unsigned long event, void *p switch (eqe->sub_type) { case MLX5_PORT_CHANGE_SUBTYPE_DOWN: case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE: - down_read(&ndev->reslock); - if (!ndev->nb_registered) { - up_read(&ndev->reslock); - return NOTIFY_DONE; - } wqent = kzalloc(sizeof(*wqent), GFP_ATOMIC); - if (!wqent) { - up_read(&ndev->reslock); + if (!wqent) return NOTIFY_DONE; - } wqent->mvdev = &ndev->mvdev; INIT_WORK(&wqent->work, update_carrier); queue_work(ndev->mvdev.wq, &wqent->work); - up_read(&ndev->reslock); ret = NOTIFY_OK; break; default: @@ -3185,7 +3153,7 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, goto err_mpfs; if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) { - err = mlx5_vdpa_create_mr(mvdev, NULL); + err = mlx5_vdpa_create_mr(mvdev, NULL, 0); if (err) goto err_res; } @@ -3237,8 +3205,8 @@ static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device * struct workqueue_struct *wq; if (ndev->nb_registered) { - mlx5_notifier_unregister(mvdev->mdev, &ndev->nb); ndev->nb_registered = false; + mlx5_notifier_unregister(mvdev->mdev, &ndev->nb); } wq = mvdev->wq; mvdev->wq = NULL; diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c index febdc99b51a7..8ef7aa1365cc 100644 --- a/drivers/vdpa/vdpa.c +++ b/drivers/vdpa/vdpa.c @@ -855,7 +855,7 @@ static int vdpa_dev_net_config_fill(struct vdpa_device *vdev, struct sk_buff *ms features_device = vdev->config->get_device_features(vdev); - if (nla_put_u64_64bit(msg, VDPA_ATTR_VDPA_DEV_SUPPORTED_FEATURES, features_device, + if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_FEATURES, features_device, VDPA_ATTR_PAD)) return -EMSGSIZE; @@ -935,7 +935,6 @@ static int vdpa_fill_stats_rec(struct vdpa_device *vdev, struct sk_buff *msg, { struct virtio_net_config config = {}; u64 features; - u16 max_vqp; u8 status; int err; @@ -946,15 +945,15 @@ static int vdpa_fill_stats_rec(struct vdpa_device *vdev, struct sk_buff *msg, } vdpa_get_config_unlocked(vdev, 0, &config, sizeof(config)); - max_vqp = __virtio16_to_cpu(true, config.max_virtqueue_pairs); - if (nla_put_u16(msg, VDPA_ATTR_DEV_NET_CFG_MAX_VQP, max_vqp)) - return -EMSGSIZE; - features = vdev->config->get_driver_features(vdev); if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_NEGOTIATED_FEATURES, features, VDPA_ATTR_PAD)) return -EMSGSIZE; + err = vdpa_dev_net_mq_config_fill(msg, features, &config); + if (err) + return err; + if (nla_put_u32(msg, VDPA_ATTR_DEV_QUEUE_INDEX, index)) return -EMSGSIZE; diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c index b071f0d842fb..cb88891b44a8 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c @@ -67,8 +67,7 @@ static void vdpasim_queue_ready(struct vdpasim *vdpasim, unsigned int idx) { struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; - vringh_init_iotlb(&vq->vring, vdpasim->dev_attr.supported_features, - VDPASIM_QUEUE_MAX, false, + vringh_init_iotlb(&vq->vring, vdpasim->features, vq->num, false, (struct vring_desc *)(uintptr_t)vq->desc_addr, (struct vring_avail *) (uintptr_t)vq->driver_addr, @@ -690,7 +689,9 @@ static void vdpasim_free(struct vdpa_device *vdpa) } kvfree(vdpasim->buffer); - vhost_iotlb_free(vdpasim->iommu); + for (i = 0; i < vdpasim->dev_attr.nas; i++) + vhost_iotlb_reset(&vdpasim->iommu[i]); + kfree(vdpasim->iommu); kfree(vdpasim->vqs); kfree(vdpasim->config); } diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c index c6db1a1baf76..f745926237a8 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c @@ -427,8 +427,10 @@ static int __init vdpasim_blk_init(void) int ret; ret = device_register(&vdpasim_blk_mgmtdev); - if (ret) + if (ret) { + put_device(&vdpasim_blk_mgmtdev); return ret; + } ret = vdpa_mgmtdev_register(&mgmt_dev); if (ret) diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c index c3cb225ea469..584b975a98a7 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c @@ -62,6 +62,9 @@ static bool receive_filter(struct vdpasim *vdpasim, size_t len) if (len < ETH_ALEN + hdr_len) return false; + if (is_broadcast_ether_addr(vdpasim->buffer + hdr_len) || + is_multicast_ether_addr(vdpasim->buffer + hdr_len)) + return true; if (!strncmp(vdpasim->buffer + hdr_len, vio_config->mac, ETH_ALEN)) return true; @@ -305,8 +308,10 @@ static int __init vdpasim_net_init(void) int ret; ret = device_register(&vdpasim_net_mgmtdev); - if (ret) + if (ret) { + put_device(&vdpasim_net_mgmtdev); return ret; + } ret = vdpa_mgmtdev_register(&mgmt_dev); if (ret) diff --git a/drivers/vdpa/vdpa_user/iova_domain.h b/drivers/vdpa/vdpa_user/iova_domain.h index 4e0e50e7ac15..173e979b84a9 100644 --- a/drivers/vdpa/vdpa_user/iova_domain.h +++ b/drivers/vdpa/vdpa_user/iova_domain.h @@ -14,7 +14,6 @@ #include <linux/iova.h> #include <linux/dma-mapping.h> #include <linux/vhost_iotlb.h> -#include <linux/rwlock.h> #define IOVA_START_PFN 1 diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index 0dd3c1f291da..0c3b48616a9f 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -1440,6 +1440,9 @@ static bool vduse_validate_config(struct vduse_dev_config *config) if (config->config_size > PAGE_SIZE) return false; + if (config->vq_num > 0xffff) + return false; + if (!device_is_allowed(config->device_id)) return false; diff --git a/drivers/vdpa/virtio_pci/vp_vdpa.c b/drivers/vdpa/virtio_pci/vp_vdpa.c index d448db0c4de3..8fe267ca3e76 100644 --- a/drivers/vdpa/virtio_pci/vp_vdpa.c +++ b/drivers/vdpa/virtio_pci/vp_vdpa.c @@ -647,7 +647,7 @@ static void vp_vdpa_remove(struct pci_dev *pdev) mdev = vp_vdpa_mgtdev->mdev; vp_modern_remove(mdev); vdpa_mgmtdev_unregister(&vp_vdpa_mgtdev->mgtdev); - kfree(&vp_vdpa_mgtdev->mgtdev.id_table); + kfree(vp_vdpa_mgtdev->mgtdev.id_table); kfree(mdev); kfree(vp_vdpa_mgtdev); } diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 23c24fe98c00..2209372f236d 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -1856,24 +1856,33 @@ unwind: * significantly boosts non-hugetlbfs mappings and doesn't seem to hurt when * hugetlbfs is in use. */ -static void vfio_test_domain_fgsp(struct vfio_domain *domain) +static void vfio_test_domain_fgsp(struct vfio_domain *domain, struct list_head *regions) { - struct page *pages; int ret, order = get_order(PAGE_SIZE * 2); + struct vfio_iova *region; + struct page *pages; + dma_addr_t start; pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order); if (!pages) return; - ret = iommu_map(domain->domain, 0, page_to_phys(pages), PAGE_SIZE * 2, - IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE); - if (!ret) { - size_t unmapped = iommu_unmap(domain->domain, 0, PAGE_SIZE); + list_for_each_entry(region, regions, list) { + start = ALIGN(region->start, PAGE_SIZE * 2); + if (start >= region->end || (region->end - start < PAGE_SIZE * 2)) + continue; - if (unmapped == PAGE_SIZE) - iommu_unmap(domain->domain, PAGE_SIZE, PAGE_SIZE); - else - domain->fgsp = true; + ret = iommu_map(domain->domain, start, page_to_phys(pages), PAGE_SIZE * 2, + IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE); + if (!ret) { + size_t unmapped = iommu_unmap(domain->domain, start, PAGE_SIZE); + + if (unmapped == PAGE_SIZE) + iommu_unmap(domain->domain, start + PAGE_SIZE, PAGE_SIZE); + else + domain->fgsp = true; + } + break; } __free_pages(pages, order); @@ -2326,7 +2335,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data, } } - vfio_test_domain_fgsp(domain); + vfio_test_domain_fgsp(domain, &iova_copy); /* replay mappings on new domains */ ret = vfio_iommu_replay(iommu, domain); diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 9af19b0cf3b7..4c538b30fd76 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -1511,6 +1511,9 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) nvq = &n->vqs[index]; mutex_lock(&vq->mutex); + if (fd == -1) + vhost_clear_msg(&n->dev); + /* Verify that ring has been setup correctly. */ if (!vhost_vq_access_ok(vq)) { r = -EFAULT; diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index dca6346d75b3..d5ecb8876fc9 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -80,7 +80,7 @@ struct vhost_scsi_cmd { struct scatterlist *tvc_prot_sgl; struct page **tvc_upages; /* Pointer to response header iovec */ - struct iovec tvc_resp_iov; + struct iovec *tvc_resp_iov; /* Pointer to vhost_scsi for our device */ struct vhost_scsi *tvc_vhost; /* Pointer to vhost_virtqueue for the cmd */ @@ -563,7 +563,7 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work) memcpy(v_rsp.sense, cmd->tvc_sense_buf, se_cmd->scsi_sense_length); - iov_iter_init(&iov_iter, ITER_DEST, &cmd->tvc_resp_iov, + iov_iter_init(&iov_iter, ITER_DEST, cmd->tvc_resp_iov, cmd->tvc_in_iovs, sizeof(v_rsp)); ret = copy_to_iter(&v_rsp, sizeof(v_rsp), &iov_iter); if (likely(ret == sizeof(v_rsp))) { @@ -594,6 +594,7 @@ vhost_scsi_get_cmd(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg, struct vhost_scsi_cmd *cmd; struct vhost_scsi_nexus *tv_nexus; struct scatterlist *sg, *prot_sg; + struct iovec *tvc_resp_iov; struct page **pages; int tag; @@ -613,6 +614,7 @@ vhost_scsi_get_cmd(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg, sg = cmd->tvc_sgl; prot_sg = cmd->tvc_prot_sgl; pages = cmd->tvc_upages; + tvc_resp_iov = cmd->tvc_resp_iov; memset(cmd, 0, sizeof(*cmd)); cmd->tvc_sgl = sg; cmd->tvc_prot_sgl = prot_sg; @@ -625,6 +627,7 @@ vhost_scsi_get_cmd(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg, cmd->tvc_data_direction = data_direction; cmd->tvc_nexus = tv_nexus; cmd->inflight = vhost_scsi_get_inflight(vq); + cmd->tvc_resp_iov = tvc_resp_iov; memcpy(cmd->tvc_cdb, cdb, VHOST_SCSI_MAX_CDB_SIZE); @@ -935,7 +938,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) struct iov_iter in_iter, prot_iter, data_iter; u64 tag; u32 exp_data_len, data_direction; - int ret, prot_bytes, c = 0; + int ret, prot_bytes, i, c = 0; u16 lun; u8 task_attr; bool t10_pi = vhost_has_feature(vq, VIRTIO_SCSI_F_T10_PI); @@ -1092,7 +1095,8 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) } cmd->tvc_vhost = vs; cmd->tvc_vq = vq; - cmd->tvc_resp_iov = vq->iov[vc.out]; + for (i = 0; i < vc.in ; i++) + cmd->tvc_resp_iov[i] = vq->iov[vc.out + i]; cmd->tvc_in_iovs = vc.in; pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n", @@ -1461,6 +1465,7 @@ static void vhost_scsi_destroy_vq_cmds(struct vhost_virtqueue *vq) kfree(tv_cmd->tvc_sgl); kfree(tv_cmd->tvc_prot_sgl); kfree(tv_cmd->tvc_upages); + kfree(tv_cmd->tvc_resp_iov); } sbitmap_free(&svq->scsi_tags); @@ -1508,6 +1513,14 @@ static int vhost_scsi_setup_vq_cmds(struct vhost_virtqueue *vq, int max_cmds) goto out; } + tv_cmd->tvc_resp_iov = kcalloc(UIO_MAXIOV, + sizeof(struct iovec), + GFP_KERNEL); + if (!tv_cmd->tvc_resp_iov) { + pr_err("Unable to allocate tv_cmd->tvc_resp_iov\n"); + goto out; + } + tv_cmd->tvc_prot_sgl = kcalloc(VHOST_SCSI_PREALLOC_PROT_SGLS, sizeof(struct scatterlist), GFP_KERNEL); diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index 166044642fd5..ec32f785dfde 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -65,6 +65,10 @@ static DEFINE_IDA(vhost_vdpa_ida); static dev_t vhost_vdpa_major; +static void vhost_vdpa_iotlb_unmap(struct vhost_vdpa *v, + struct vhost_iotlb *iotlb, u64 start, + u64 last, u32 asid); + static inline u32 iotlb_to_asid(struct vhost_iotlb *iotlb) { struct vhost_vdpa_as *as = container_of(iotlb, struct @@ -135,7 +139,7 @@ static int vhost_vdpa_remove_as(struct vhost_vdpa *v, u32 asid) return -EINVAL; hlist_del(&as->hash_link); - vhost_iotlb_reset(&as->iotlb); + vhost_vdpa_iotlb_unmap(v, &as->iotlb, 0ULL, 0ULL - 1, asid); kfree(as); return 0; @@ -683,10 +687,20 @@ static long vhost_vdpa_unlocked_ioctl(struct file *filep, mutex_unlock(&d->mutex); return r; } +static void vhost_vdpa_general_unmap(struct vhost_vdpa *v, + struct vhost_iotlb_map *map, u32 asid) +{ + struct vdpa_device *vdpa = v->vdpa; + const struct vdpa_config_ops *ops = vdpa->config; + if (ops->dma_map) { + ops->dma_unmap(vdpa, asid, map->start, map->size); + } else if (ops->set_map == NULL) { + iommu_unmap(v->domain, map->start, map->size); + } +} -static void vhost_vdpa_pa_unmap(struct vhost_vdpa *v, - struct vhost_iotlb *iotlb, - u64 start, u64 last) +static void vhost_vdpa_pa_unmap(struct vhost_vdpa *v, struct vhost_iotlb *iotlb, + u64 start, u64 last, u32 asid) { struct vhost_dev *dev = &v->vdev; struct vhost_iotlb_map *map; @@ -703,13 +717,13 @@ static void vhost_vdpa_pa_unmap(struct vhost_vdpa *v, unpin_user_page(page); } atomic64_sub(PFN_DOWN(map->size), &dev->mm->pinned_vm); + vhost_vdpa_general_unmap(v, map, asid); vhost_iotlb_map_free(iotlb, map); } } -static void vhost_vdpa_va_unmap(struct vhost_vdpa *v, - struct vhost_iotlb *iotlb, - u64 start, u64 last) +static void vhost_vdpa_va_unmap(struct vhost_vdpa *v, struct vhost_iotlb *iotlb, + u64 start, u64 last, u32 asid) { struct vhost_iotlb_map *map; struct vdpa_map_file *map_file; @@ -718,20 +732,21 @@ static void vhost_vdpa_va_unmap(struct vhost_vdpa *v, map_file = (struct vdpa_map_file *)map->opaque; fput(map_file->file); kfree(map_file); + vhost_vdpa_general_unmap(v, map, asid); vhost_iotlb_map_free(iotlb, map); } } static void vhost_vdpa_iotlb_unmap(struct vhost_vdpa *v, - struct vhost_iotlb *iotlb, - u64 start, u64 last) + struct vhost_iotlb *iotlb, u64 start, + u64 last, u32 asid) { struct vdpa_device *vdpa = v->vdpa; if (vdpa->use_va) - return vhost_vdpa_va_unmap(v, iotlb, start, last); + return vhost_vdpa_va_unmap(v, iotlb, start, last, asid); - return vhost_vdpa_pa_unmap(v, iotlb, start, last); + return vhost_vdpa_pa_unmap(v, iotlb, start, last, asid); } static int perm_to_iommu_flags(u32 perm) @@ -798,17 +813,12 @@ static void vhost_vdpa_unmap(struct vhost_vdpa *v, const struct vdpa_config_ops *ops = vdpa->config; u32 asid = iotlb_to_asid(iotlb); - vhost_vdpa_iotlb_unmap(v, iotlb, iova, iova + size - 1); + vhost_vdpa_iotlb_unmap(v, iotlb, iova, iova + size - 1, asid); - if (ops->dma_map) { - ops->dma_unmap(vdpa, asid, iova, size); - } else if (ops->set_map) { + if (ops->set_map) { if (!v->in_batch) ops->set_map(vdpa, asid, iotlb); - } else { - iommu_unmap(v->domain, iova, size); } - /* If we are in the middle of batch processing, delay the free * of AS until BATCH_END. */ @@ -1162,14 +1172,14 @@ static void vhost_vdpa_cleanup(struct vhost_vdpa *v) struct vhost_vdpa_as *as; u32 asid; - vhost_dev_cleanup(&v->vdev); - kfree(v->vdev.vqs); - for (asid = 0; asid < v->vdpa->nas; asid++) { as = asid_to_as(v, asid); if (as) vhost_vdpa_remove_as(v, asid); } + + vhost_dev_cleanup(&v->vdev); + kfree(v->vdev.vqs); } static int vhost_vdpa_open(struct inode *inode, struct file *filep) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 5c9fe3c9c364..43c9770b86e5 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -661,7 +661,7 @@ void vhost_dev_stop(struct vhost_dev *dev) } EXPORT_SYMBOL_GPL(vhost_dev_stop); -static void vhost_clear_msg(struct vhost_dev *dev) +void vhost_clear_msg(struct vhost_dev *dev) { struct vhost_msg_node *node, *n; @@ -679,6 +679,7 @@ static void vhost_clear_msg(struct vhost_dev *dev) spin_unlock(&dev->iotlb_lock); } +EXPORT_SYMBOL_GPL(vhost_clear_msg); void vhost_dev_cleanup(struct vhost_dev *dev) { @@ -2053,7 +2054,7 @@ static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len, struct vhost_dev *dev = vq->dev; struct vhost_iotlb *umem = dev->iotlb ? dev->iotlb : dev->umem; struct iovec *_iov; - u64 s = 0; + u64 s = 0, last = addr + len - 1; int ret = 0; while ((u64)len > s) { @@ -2063,7 +2064,7 @@ static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len, break; } - map = vhost_iotlb_itree_first(umem, addr, addr + len - 1); + map = vhost_iotlb_itree_first(umem, addr, last); if (map == NULL || map->start > addr) { if (umem != dev->iotlb) { ret = -EFAULT; diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index d9109107af08..790b296271f1 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -181,6 +181,7 @@ long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, void __user *argp); long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp); bool vhost_vq_access_ok(struct vhost_virtqueue *vq); bool vhost_log_access_ok(struct vhost_dev *); +void vhost_clear_msg(struct vhost_dev *dev); int vhost_get_vq_desc(struct vhost_virtqueue *, struct iovec iov[], unsigned int iov_count, diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c index c9f5c8ea3afb..a1e27da54481 100644 --- a/drivers/vhost/vringh.c +++ b/drivers/vhost/vringh.c @@ -1102,7 +1102,7 @@ static int iotlb_translate(const struct vringh *vrh, struct vhost_iotlb_map *map; struct vhost_iotlb *iotlb = vrh->iotlb; int ret = 0; - u64 s = 0; + u64 s = 0, last = addr + len - 1; spin_lock(vrh->iotlb_lock); @@ -1114,8 +1114,7 @@ static int iotlb_translate(const struct vringh *vrh, break; } - map = vhost_iotlb_itree_first(iotlb, addr, - addr + len - 1); + map = vhost_iotlb_itree_first(iotlb, addr, last); if (!map || map->start > addr) { ret = -EINVAL; break; @@ -1127,9 +1126,8 @@ static int iotlb_translate(const struct vringh *vrh, size = map->size - addr + map->start; pa = map->addr + addr - map->start; pfn = pa >> PAGE_SHIFT; - iov[ret].bv_page = pfn_to_page(pfn); - iov[ret].bv_len = min(len - s, size); - iov[ret].bv_offset = pa & (PAGE_SIZE - 1); + bvec_set_page(&iov[ret], pfn_to_page(pfn), min(len - s, size), + pa & (PAGE_SIZE - 1)); s += size; addr += size; ++ret; diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index cd6f7776013a..a2b374372363 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -959,7 +959,14 @@ static int __init vhost_vsock_init(void) VSOCK_TRANSPORT_F_H2G); if (ret < 0) return ret; - return misc_register(&vhost_vsock_misc); + + ret = misc_register(&vhost_vsock_misc); + if (ret) { + vsock_core_unregister(&vhost_transport.transport); + return ret; + } + + return 0; }; static void __exit vhost_vsock_exit(void) diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index 0468ea82159f..346d3e29a843 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c @@ -95,8 +95,6 @@ void locomolcd_power(int on) /* read comadj */ if (comadj == -1 && machine_is_collie()) comadj = 128; - if (comadj == -1 && machine_is_poodle()) - comadj = 118; if (on) locomolcd_on(comadj); @@ -181,14 +179,6 @@ static int locomolcd_probe(struct locomo_dev *ldev) locomo_gpio_set_dir(ldev->dev.parent, LOCOMO_GPIO_FL_VR, 0); - /* - * the poodle_lcd_power function is called for the first time - * from fs_initcall, which is before locomo is activated. - * We need to recall poodle_lcd_power here - */ - if (machine_is_poodle()) - locomolcd_power(1); - local_irq_restore(flags); memset(&props, 0, sizeof(struct backlight_properties)); diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index df6e09f7d242..ff3646c30d0d 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -456,8 +456,8 @@ config FB_ATARI chipset found in Ataris. config FB_OF - bool "Open Firmware frame buffer device support" - depends on (FB = y) && PPC && (!PPC_PSERIES || PCI) + tristate "Open Firmware frame buffer device support" + depends on FB && PPC && (!PPC_PSERIES || PCI) depends on !DRM_OFDRM select APERTURE_HELPERS select FB_CFB_FILLRECT @@ -1841,23 +1841,6 @@ config FB_FSL_DIU help Framebuffer driver for the Freescale SoC DIU -config FB_W100 - tristate "W100 frame buffer support" - depends on FB && HAS_IOMEM && (ARCH_PXA || COMPILE_TEST) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Frame buffer driver for the w100 as found on the Sharp SL-Cxx series. - It can also drive the w3220 chip found on iPAQ hx4700. - - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called w100fb. If you want to compile it as a module, - say M here and read <file:Documentation/kbuild/modules.rst>. - - If unsure, say N. - config FB_SH_MOBILE_LCDC tristate "SuperH Mobile LCDC framebuffer support" depends on FB && HAVE_CLK && HAS_IOMEM @@ -1871,44 +1854,20 @@ config FB_SH_MOBILE_LCDC help Frame buffer driver for the on-chip SH-Mobile LCD controller. -config FB_TMIO - tristate "Toshiba Mobile IO FrameBuffer support" - depends on FB && (MFD_TMIO || COMPILE_TEST) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Frame buffer driver for the Toshiba Mobile IO integrated as found - on the Sharp SL-6000 series - - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called tmiofb. If you want to compile it as a module, - say M here and read <file:Documentation/kbuild/modules.rst>. - - If unsure, say N. - -config FB_TMIO_ACCELL - bool "tmiofb acceleration" - depends on FB_TMIO - default y - config FB_S3C tristate "Samsung S3C framebuffer support" depends on FB && HAVE_CLK && HAS_IOMEM - depends on (CPU_S3C2416 || ARCH_S3C64XX) || COMPILE_TEST + depends on ARCH_S3C64XX || COMPILE_TEST select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT help Frame buffer driver for the built-in FB controller in the Samsung - SoC line from the S3C2443 onwards, including the S3C2416, S3C2450, - and the S3C64XX series such as the S3C6400 and S3C6410. + SoC line such as the S3C6400 and S3C6410. These chips all have the same basic framebuffer design with the - actual capabilities depending on the chip. For instance the S3C6400 - and S3C6410 support 4 hardware windows whereas the S3C24XX series - currently only have two. + actual capabilities depending on the chip. The S3C6400 + and S3C6410 support 4 hardware windows. Currently the support is only for the S3C6400 and S3C6410 SoCs. @@ -1918,29 +1877,6 @@ config FB_S3C_DEBUG_REGWRITE help Show all register writes via pr_debug() -config FB_S3C2410 - tristate "S3C2410 LCD framebuffer support" - depends on FB && ARCH_S3C24XX - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Frame buffer driver for the built-in LCD controller in the Samsung - S3C2410 processor. - - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called s3c2410fb. If you want to compile it as a module, - say M here and read <file:Documentation/kbuild/modules.rst>. - - If unsure, say N. -config FB_S3C2410_DEBUG - bool "S3C2410 lcd debug messages" - depends on FB_S3C2410 - help - Turn on debugging messages. Note that you can set/unset at run time - through sysfs - config FB_SM501 tristate "Silicon Motion SM501 framebuffer support" depends on FB && MFD_SM501 diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index 7795c4126706..e6b0ae094b8b 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -84,8 +84,6 @@ obj-$(CONFIG_FB_PXA) += pxafb.o obj-$(CONFIG_FB_PXA168) += pxa168fb.o obj-$(CONFIG_PXA3XX_GCU) += pxa3xx-gcu.o obj-$(CONFIG_MMP_DISP) += mmp/ -obj-$(CONFIG_FB_W100) += w100fb.o -obj-$(CONFIG_FB_TMIO) += tmiofb.o obj-$(CONFIG_FB_AU1100) += au1100fb.o obj-$(CONFIG_FB_AU1200) += au1200fb.o obj-$(CONFIG_FB_VT8500) += vt8500lcdfb.o @@ -100,7 +98,6 @@ obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o obj-$(CONFIG_FB_SH7760) += sh7760fb.o obj-$(CONFIG_FB_IMX) += imxfb.o obj-$(CONFIG_FB_S3C) += s3c-fb.o -obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index 1fc8de4ecbeb..8187a7c4f910 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -49,7 +49,6 @@ struct atmel_lcdfb_info { struct clk *lcdc_clk; struct backlight_device *backlight; - u8 bl_power; u8 saved_lcdcon; u32 pseudo_palette[16]; @@ -109,22 +108,7 @@ static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8 static int atmel_bl_update_status(struct backlight_device *bl) { struct atmel_lcdfb_info *sinfo = bl_get_data(bl); - int power = sinfo->bl_power; - int brightness = bl->props.brightness; - - /* REVISIT there may be a meaningful difference between - * fb_blank and power ... there seem to be some cases - * this doesn't handle correctly. - */ - if (bl->props.fb_blank != sinfo->bl_power) - power = bl->props.fb_blank; - else if (bl->props.power != sinfo->bl_power) - power = bl->props.power; - - if (brightness < 0 && power == FB_BLANK_UNBLANK) - brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); - else if (power != FB_BLANK_UNBLANK) - brightness = 0; + int brightness = backlight_get_brightness(bl); lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE) @@ -133,8 +117,6 @@ static int atmel_bl_update_status(struct backlight_device *bl) else lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); - bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; - return 0; } @@ -155,8 +137,6 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo) struct backlight_properties props; struct backlight_device *bl; - sinfo->bl_power = FB_BLANK_UNBLANK; - if (sinfo->backlight) return; diff --git a/drivers/video/fbdev/aty/aty128fb.c b/drivers/video/fbdev/aty/aty128fb.c index dd31b9d7d337..36a9ac05a340 100644 --- a/drivers/video/fbdev/aty/aty128fb.c +++ b/drivers/video/fbdev/aty/aty128fb.c @@ -1766,12 +1766,10 @@ static int aty128_bl_update_status(struct backlight_device *bd) unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); int level; - if (bd->props.power != FB_BLANK_UNBLANK || - bd->props.fb_blank != FB_BLANK_UNBLANK || - !par->lcd_on) + if (!par->lcd_on) level = 0; else - level = bd->props.brightness; + level = backlight_get_brightness(bd); reg |= LVDS_BL_MOD_EN | LVDS_BLON; if (level > 0) { diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index 0ccf5d401ecb..b02e4e645035 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -2219,13 +2219,7 @@ static int aty_bl_update_status(struct backlight_device *bd) { struct atyfb_par *par = bl_get_data(bd); unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par); - int level; - - if (bd->props.power != FB_BLANK_UNBLANK || - bd->props.fb_blank != FB_BLANK_UNBLANK) - level = 0; - else - level = bd->props.brightness; + int level = backlight_get_brightness(bd); reg |= (BLMOD_EN | BIASMOD_EN); if (level > 0) { @@ -3192,8 +3186,7 @@ static void aty_init_lcd(struct atyfb_par *par, u32 bios_base) * which we print to the screen. */ id = *(u8 *)par->lcd_table; - strncpy(model, (char *)par->lcd_table+1, 24); - model[23] = 0; + strscpy(model, (char *)par->lcd_table+1, sizeof(model)); width = par->lcd_width = *(u16 *)(par->lcd_table+25); height = par->lcd_height = *(u16 *)(par->lcd_table+27); diff --git a/drivers/video/fbdev/aty/radeon_backlight.c b/drivers/video/fbdev/aty/radeon_backlight.c index d2c1263ad260..427adc838f77 100644 --- a/drivers/video/fbdev/aty/radeon_backlight.c +++ b/drivers/video/fbdev/aty/radeon_backlight.c @@ -57,11 +57,7 @@ static int radeon_bl_update_status(struct backlight_device *bd) * backlight. This provides some greater power saving and the display * is useless without backlight anyway. */ - if (bd->props.power != FB_BLANK_UNBLANK || - bd->props.fb_blank != FB_BLANK_UNBLANK) - level = 0; - else - level = bd->props.brightness; + level = backlight_get_brightness(bd); del_timer_sync(&rinfo->lvds_timer); radeon_engine_idle(); diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c index c730253ab85c..583cbcf09446 100644 --- a/drivers/video/fbdev/core/fb_defio.c +++ b/drivers/video/fbdev/core/fb_defio.c @@ -313,7 +313,7 @@ void fb_deferred_io_open(struct fb_info *info, } EXPORT_SYMBOL_GPL(fb_deferred_io_open); -void fb_deferred_io_cleanup(struct fb_info *info) +void fb_deferred_io_release(struct fb_info *info) { struct fb_deferred_io *fbdefio = info->fbdefio; struct page *page; @@ -327,6 +327,14 @@ void fb_deferred_io_cleanup(struct fb_info *info) page = fb_deferred_io_page(info, i); page->mapping = NULL; } +} +EXPORT_SYMBOL_GPL(fb_deferred_io_release); + +void fb_deferred_io_cleanup(struct fb_info *info) +{ + struct fb_deferred_io *fbdefio = info->fbdefio; + + fb_deferred_io_release(info); kvfree(info->pagerefs); mutex_destroy(&fbdefio->lock); diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 14a7d404062c..1b14c21af2b7 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2495,9 +2495,12 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, h > FBCON_SWAP(info->var.rotate, info->var.yres, info->var.xres)) return -EINVAL; + if (font->width > 32 || font->height > 32) + return -EINVAL; + /* Make sure drawing engine can handle the font */ - if (!(info->pixmap.blit_x & (1 << (font->width - 1))) || - !(info->pixmap.blit_y & (1 << (font->height - 1)))) + if (!(info->pixmap.blit_x & BIT(font->width - 1)) || + !(info->pixmap.blit_y & BIT(font->height - 1))) return -EINVAL; /* Make sure driver can handle the font length */ diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 3a6c8458eb8d..ab3545a00abc 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1454,6 +1454,10 @@ __releases(&info->lock) struct fb_info * const info = file->private_data; lock_fb_info(info); +#if IS_ENABLED(CONFIG_FB_DEFERRED_IO) + if (info->fbdefio) + fb_deferred_io_release(info); +#endif if (info->fbops->fb_release) info->fbops->fb_release(info,1); module_put(info->fbops->owner); diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c index b0e690f41025..79e5bfbdd34c 100644 --- a/drivers/video/fbdev/core/fbmon.c +++ b/drivers/video/fbdev/core/fbmon.c @@ -1050,7 +1050,7 @@ static u32 fb_get_vblank(u32 hfreq) } /** - * fb_get_hblank_by_freq - get horizontal blank time given hfreq + * fb_get_hblank_by_hfreq - get horizontal blank time given hfreq * @hfreq: horizontal freq * @xres: horizontal resolution in pixels * diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbdev/matrox/matroxfb_base.c index 0d3cee7ae726..a043a737ea9f 100644 --- a/drivers/video/fbdev/matrox/matroxfb_base.c +++ b/drivers/video/fbdev/matrox/matroxfb_base.c @@ -1378,8 +1378,8 @@ static struct video_board vbG200 = { .lowlevel = &matrox_G100 }; static struct video_board vbG200eW = { - .maxvram = 0x100000, - .maxdisplayable = 0x800000, + .maxvram = 0x1000000, + .maxdisplayable = 0x0800000, .accelID = FB_ACCEL_MATROX_MGAG200, .lowlevel = &matrox_G100 }; diff --git a/drivers/video/fbdev/mx3fb.c b/drivers/video/fbdev/mx3fb.c index b945b68984b9..76771e126d0a 100644 --- a/drivers/video/fbdev/mx3fb.c +++ b/drivers/video/fbdev/mx3fb.c @@ -283,12 +283,7 @@ static int mx3fb_bl_get_brightness(struct backlight_device *bl) static int mx3fb_bl_update_status(struct backlight_device *bl) { struct mx3fb_data *fbd = bl_get_data(bl); - int brightness = bl->props.brightness; - - if (bl->props.power != FB_BLANK_UNBLANK) - brightness = 0; - if (bl->props.fb_blank != FB_BLANK_UNBLANK) - brightness = 0; + int brightness = backlight_get_brightness(bl); fbd->backlight_level = (fbd->backlight_level & ~0xFF) | brightness; diff --git a/drivers/video/fbdev/nvidia/nv_backlight.c b/drivers/video/fbdev/nvidia/nv_backlight.c index 2ce53529f636..503a7a683855 100644 --- a/drivers/video/fbdev/nvidia/nv_backlight.c +++ b/drivers/video/fbdev/nvidia/nv_backlight.c @@ -49,17 +49,11 @@ static int nvidia_bl_update_status(struct backlight_device *bd) { struct nvidia_par *par = bl_get_data(bd); u32 tmp_pcrt, tmp_pmc, fpcontrol; - int level; + int level = backlight_get_brightness(bd); if (!par->FlatPanel) return 0; - if (bd->props.power != FB_BLANK_UNBLANK || - bd->props.fb_blank != FB_BLANK_UNBLANK) - level = 0; - else - level = bd->props.brightness; - tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF; tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC; fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC; diff --git a/drivers/video/fbdev/nvidia/nvidia.c b/drivers/video/fbdev/nvidia/nvidia.c index 1960916098d4..e60a276b4855 100644 --- a/drivers/video/fbdev/nvidia/nvidia.c +++ b/drivers/video/fbdev/nvidia/nvidia.c @@ -1197,17 +1197,17 @@ static int nvidia_set_fbinfo(struct fb_info *info) return nvidiafb_check_var(&info->var, info); } -static u32 nvidia_get_chipset(struct fb_info *info) +static u32 nvidia_get_chipset(struct pci_dev *pci_dev, + volatile u32 __iomem *REGS) { - struct nvidia_par *par = info->par; - u32 id = (par->pci_dev->vendor << 16) | par->pci_dev->device; + u32 id = (pci_dev->vendor << 16) | pci_dev->device; printk(KERN_INFO PFX "Device ID: %x \n", id); if ((id & 0xfff0) == 0x00f0 || (id & 0xfff0) == 0x02e0) { /* pci-e */ - id = NV_RD32(par->REGS, 0x1800); + id = NV_RD32(REGS, 0x1800); if ((id & 0x0000ffff) == 0x000010DE) id = 0x10DE0000 | (id >> 16); @@ -1220,12 +1220,11 @@ static u32 nvidia_get_chipset(struct fb_info *info) return id; } -static u32 nvidia_get_arch(struct fb_info *info) +static u32 nvidia_get_arch(u32 Chipset) { - struct nvidia_par *par = info->par; u32 arch = 0; - switch (par->Chipset & 0x0ff0) { + switch (Chipset & 0x0ff0) { case 0x0100: /* GeForce 256 */ case 0x0110: /* GeForce2 MX */ case 0x0150: /* GeForce2 */ @@ -1278,16 +1277,44 @@ static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) struct fb_info *info; unsigned short cmd; int ret; + volatile u32 __iomem *REGS; + int Chipset; + u32 Architecture; NVTRACE_ENTER(); assert(pd != NULL); + if (pci_enable_device(pd)) { + printk(KERN_ERR PFX "cannot enable PCI device\n"); + return -ENODEV; + } + + /* enable IO and mem if not already done */ + pci_read_config_word(pd, PCI_COMMAND, &cmd); + cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_write_config_word(pd, PCI_COMMAND, cmd); + + nvidiafb_fix.mmio_start = pci_resource_start(pd, 0); + nvidiafb_fix.mmio_len = pci_resource_len(pd, 0); + + REGS = ioremap(nvidiafb_fix.mmio_start, nvidiafb_fix.mmio_len); + if (!REGS) { + printk(KERN_ERR PFX "cannot ioremap MMIO base\n"); + return -ENODEV; + } + + Chipset = nvidia_get_chipset(pd, REGS); + Architecture = nvidia_get_arch(Chipset); + if (Architecture == 0) { + printk(KERN_ERR PFX "unknown NV_ARCH\n"); + goto err_out; + } + ret = aperture_remove_conflicting_pci_devices(pd, "nvidiafb"); if (ret) - return ret; + goto err_out; info = framebuffer_alloc(sizeof(struct nvidia_par), &pd->dev); - if (!info) goto err_out; @@ -1298,11 +1325,6 @@ static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) if (info->pixmap.addr == NULL) goto err_out_kfree; - if (pci_enable_device(pd)) { - printk(KERN_ERR PFX "cannot enable PCI device\n"); - goto err_out_enable; - } - if (pci_request_regions(pd, "nvidiafb")) { printk(KERN_ERR PFX "cannot request PCI regions\n"); goto err_out_enable; @@ -1318,34 +1340,17 @@ static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) par->paneltweak = paneltweak; par->reverse_i2c = reverse_i2c; - /* enable IO and mem if not already done */ - pci_read_config_word(pd, PCI_COMMAND, &cmd); - cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); - pci_write_config_word(pd, PCI_COMMAND, cmd); - - nvidiafb_fix.mmio_start = pci_resource_start(pd, 0); nvidiafb_fix.smem_start = pci_resource_start(pd, 1); - nvidiafb_fix.mmio_len = pci_resource_len(pd, 0); - - par->REGS = ioremap(nvidiafb_fix.mmio_start, nvidiafb_fix.mmio_len); - if (!par->REGS) { - printk(KERN_ERR PFX "cannot ioremap MMIO base\n"); - goto err_out_free_base0; - } + par->REGS = REGS; - par->Chipset = nvidia_get_chipset(info); - par->Architecture = nvidia_get_arch(info); - - if (par->Architecture == 0) { - printk(KERN_ERR PFX "unknown NV_ARCH\n"); - goto err_out_arch; - } + par->Chipset = Chipset; + par->Architecture = Architecture; sprintf(nvidiafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4); if (NVCommonSetup(info)) - goto err_out_arch; + goto err_out_free_base0; par->FbAddress = nvidiafb_fix.smem_start; par->FbMapSize = par->RamAmountKBytes * 1024; @@ -1401,7 +1406,6 @@ static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) goto err_out_iounmap_fb; } - printk(KERN_INFO PFX "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n", info->fix.id, @@ -1415,15 +1419,14 @@ err_out_iounmap_fb: err_out_free_base1: fb_destroy_modedb(info->monspecs.modedb); nvidia_delete_i2c_busses(par); -err_out_arch: - iounmap(par->REGS); - err_out_free_base0: +err_out_free_base0: pci_release_regions(pd); err_out_enable: kfree(info->pixmap.addr); err_out_kfree: framebuffer_release(info); err_out: + iounmap(REGS); return -ENODEV; } diff --git a/drivers/video/fbdev/omap/Kconfig b/drivers/video/fbdev/omap/Kconfig index b1786cf1b486..a6548283451f 100644 --- a/drivers/video/fbdev/omap/Kconfig +++ b/drivers/video/fbdev/omap/Kconfig @@ -40,15 +40,6 @@ config FB_OMAP_LCD_MIPID the Mobile Industry Processor Interface DBI-C/DCS specification. (Supported LCDs: Philips LPH8923, Sharp LS041Y3) -config FB_OMAP_LCD_H3 - bool "TPS65010 LCD controller on OMAP-H3" - depends on MACH_OMAP_H3 || COMPILE_TEST - depends on TPS65010=y - default y - help - Say Y here if you want to have support for the LCD on the - H3 board. - config FB_OMAP_DMA_TUNE bool "Set DMA SDRAM access priority high" depends on FB_OMAP diff --git a/drivers/video/fbdev/omap/Makefile b/drivers/video/fbdev/omap/Makefile index b88e02f5cb1f..504edb9c09dd 100644 --- a/drivers/video/fbdev/omap/Makefile +++ b/drivers/video/fbdev/omap/Makefile @@ -17,16 +17,10 @@ objs-y$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o lcds-y$(CONFIG_MACH_AMS_DELTA) += lcd_ams_delta.o -lcds-y$(CONFIG_FB_OMAP_LCD_H3) += lcd_h3.o lcds-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o -lcds-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o -lcds-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o -lcds-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o -lcds-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o lcds-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o lcds-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o -lcds-y$(CONFIG_MACH_HERALD) += lcd_htcherald.o omapfb-objs := $(objs-yy) diff --git a/drivers/video/fbdev/omap/lcd_h3.c b/drivers/video/fbdev/omap/lcd_h3.c deleted file mode 100644 index 1766dff767bb..000000000000 --- a/drivers/video/fbdev/omap/lcd_h3.c +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * LCD panel support for the TI OMAP H3 board - * - * Copyright (C) 2004 Nokia Corporation - * Author: Imre Deak <imre.deak@nokia.com> - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/mfd/tps65010.h> -#include <linux/gpio.h> - -#include "omapfb.h" - -#define MODULE_NAME "omapfb-lcd_h3" - -static int h3_panel_enable(struct lcd_panel *panel) -{ - int r = 0; - - /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */ - r = tps65010_set_gpio_out_value(GPIO1, HIGH); - if (!r) - r = tps65010_set_gpio_out_value(GPIO2, HIGH); - if (r) - pr_err(MODULE_NAME ": Unable to turn on LCD panel\n"); - - return r; -} - -static void h3_panel_disable(struct lcd_panel *panel) -{ - int r = 0; - - /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */ - r = tps65010_set_gpio_out_value(GPIO1, LOW); - if (!r) - tps65010_set_gpio_out_value(GPIO2, LOW); - if (r) - pr_err(MODULE_NAME ": Unable to turn off LCD panel\n"); -} - -static struct lcd_panel h3_panel = { - .name = "h3", - .config = OMAP_LCDC_PANEL_TFT, - - .data_lines = 16, - .bpp = 16, - .x_res = 240, - .y_res = 320, - .pixel_clock = 12000, - .hsw = 12, - .hfp = 14, - .hbp = 72 - 12, - .vsw = 1, - .vfp = 1, - .vbp = 0, - .pcd = 0, - - .enable = h3_panel_enable, - .disable = h3_panel_disable, -}; - -static int h3_panel_probe(struct platform_device *pdev) -{ - omapfb_register_panel(&h3_panel); - return 0; -} - -static struct platform_driver h3_panel_driver = { - .probe = h3_panel_probe, - .driver = { - .name = "lcd_h3", - }, -}; - -module_platform_driver(h3_panel_driver); - -MODULE_AUTHOR("Imre Deak"); -MODULE_DESCRIPTION("LCD panel support for the TI OMAP H3 board"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/omap/lcd_htcherald.c b/drivers/video/fbdev/omap/lcd_htcherald.c deleted file mode 100644 index d1c615c516dd..000000000000 --- a/drivers/video/fbdev/omap/lcd_htcherald.c +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * File: drivers/video/omap/lcd-htcherald.c - * - * LCD panel support for the HTC Herald - * - * Copyright (C) 2009 Cory Maccarrone <darkstar6262@gmail.com> - * Copyright (C) 2009 Wing Linux - * - * Based on the lcd_htcwizard.c file from the linwizard project: - * Copyright (C) linwizard.sourceforge.net - * Author: Angelo Arrifano <miknix@gmail.com> - * Based on lcd_h4 by Imre Deak <imre.deak@nokia.com> - */ - -#include <linux/module.h> -#include <linux/platform_device.h> - -#include "omapfb.h" - -/* Found on WIZ200 (miknix) and some HERA110 models (darkstar62) */ -static struct lcd_panel htcherald_panel_1 = { - .name = "lcd_herald", - .config = OMAP_LCDC_PANEL_TFT | - OMAP_LCDC_INV_HSYNC | - OMAP_LCDC_INV_VSYNC | - OMAP_LCDC_INV_PIX_CLOCK, - .bpp = 16, - .data_lines = 16, - .x_res = 240, - .y_res = 320, - .pixel_clock = 6093, - .pcd = 0, /* 15 */ - .hsw = 10, - .hfp = 10, - .hbp = 20, - .vsw = 3, - .vfp = 2, - .vbp = 2, -}; - -static int htcherald_panel_probe(struct platform_device *pdev) -{ - omapfb_register_panel(&htcherald_panel_1); - return 0; -} - -static struct platform_driver htcherald_panel_driver = { - .probe = htcherald_panel_probe, - .driver = { - .name = "lcd_htcherald", - }, -}; - -module_platform_driver(htcherald_panel_driver); - -MODULE_AUTHOR("Cory Maccarrone"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("LCD panel support for the HTC Herald"); diff --git a/drivers/video/fbdev/omap/lcd_inn1510.c b/drivers/video/fbdev/omap/lcd_inn1510.c deleted file mode 100644 index bb915637e9b6..000000000000 --- a/drivers/video/fbdev/omap/lcd_inn1510.c +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * LCD panel support for the TI OMAP1510 Innovator board - * - * Copyright (C) 2004 Nokia Corporation - * Author: Imre Deak <imre.deak@nokia.com> - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/io.h> - -#include <linux/soc/ti/omap1-soc.h> - -#include "omapfb.h" - -static void __iomem *omap1510_fpga_lcd_panel_control; - -static int innovator1510_panel_enable(struct lcd_panel *panel) -{ - __raw_writeb(0x7, omap1510_fpga_lcd_panel_control); - return 0; -} - -static void innovator1510_panel_disable(struct lcd_panel *panel) -{ - __raw_writeb(0x0, omap1510_fpga_lcd_panel_control); -} - -static struct lcd_panel innovator1510_panel = { - .name = "inn1510", - .config = OMAP_LCDC_PANEL_TFT, - - .bpp = 16, - .data_lines = 16, - .x_res = 240, - .y_res = 320, - .pixel_clock = 12500, - .hsw = 40, - .hfp = 40, - .hbp = 72, - .vsw = 1, - .vfp = 1, - .vbp = 0, - .pcd = 12, - - .enable = innovator1510_panel_enable, - .disable = innovator1510_panel_disable, -}; - -static int innovator1510_panel_probe(struct platform_device *pdev) -{ - omap1510_fpga_lcd_panel_control = (void __iomem *)pdev->dev.platform_data; - omapfb_register_panel(&innovator1510_panel); - return 0; -} - -static struct platform_driver innovator1510_panel_driver = { - .probe = innovator1510_panel_probe, - .driver = { - .name = "lcd_inn1510", - }, -}; - -module_platform_driver(innovator1510_panel_driver); - -MODULE_AUTHOR("Imre Deak"); -MODULE_DESCRIPTION("LCD panel support for the TI OMAP1510 Innovator board"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/omap/lcd_inn1610.c b/drivers/video/fbdev/omap/lcd_inn1610.c deleted file mode 100644 index 901b28f35fab..000000000000 --- a/drivers/video/fbdev/omap/lcd_inn1610.c +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * LCD panel support for the TI OMAP1610 Innovator board - * - * Copyright (C) 2004 Nokia Corporation - * Author: Imre Deak <imre.deak@nokia.com> - */ - -#include <linux/module.h> -#include <linux/platform_device.h> - -#include <linux/gpio.h> -#include "omapfb.h" - -#define MODULE_NAME "omapfb-lcd_h3" - -static int innovator1610_panel_init(struct lcd_panel *panel, - struct omapfb_device *fbdev) -{ - int r = 0; - - /* configure GPIO(14, 15) as outputs */ - if (gpio_request_one(14, GPIOF_OUT_INIT_LOW, "lcd_en0")) { - pr_err(MODULE_NAME ": can't request GPIO 14\n"); - r = -1; - goto exit; - } - if (gpio_request_one(15, GPIOF_OUT_INIT_LOW, "lcd_en1")) { - pr_err(MODULE_NAME ": can't request GPIO 15\n"); - gpio_free(14); - r = -1; - goto exit; - } -exit: - return r; -} - -static void innovator1610_panel_cleanup(struct lcd_panel *panel) -{ - gpio_free(15); - gpio_free(14); -} - -static int innovator1610_panel_enable(struct lcd_panel *panel) -{ - /* set GPIO14 and GPIO15 high */ - gpio_set_value(14, 1); - gpio_set_value(15, 1); - return 0; -} - -static void innovator1610_panel_disable(struct lcd_panel *panel) -{ - /* set GPIO13, GPIO14 and GPIO15 low */ - gpio_set_value(14, 0); - gpio_set_value(15, 0); -} - -static struct lcd_panel innovator1610_panel = { - .name = "inn1610", - .config = OMAP_LCDC_PANEL_TFT, - - .bpp = 16, - .data_lines = 16, - .x_res = 320, - .y_res = 240, - .pixel_clock = 12500, - .hsw = 40, - .hfp = 40, - .hbp = 72, - .vsw = 1, - .vfp = 1, - .vbp = 0, - .pcd = 12, - - .init = innovator1610_panel_init, - .cleanup = innovator1610_panel_cleanup, - .enable = innovator1610_panel_enable, - .disable = innovator1610_panel_disable, -}; - -static int innovator1610_panel_probe(struct platform_device *pdev) -{ - omapfb_register_panel(&innovator1610_panel); - return 0; -} - -static struct platform_driver innovator1610_panel_driver = { - .probe = innovator1610_panel_probe, - .driver = { - .name = "lcd_inn1610", - }, -}; - -module_platform_driver(innovator1610_panel_driver); - -MODULE_AUTHOR("Imre Deak"); -MODULE_DESCRIPTION("LCD panel support for the TI OMAP1610 Innovator board"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/omap/lcd_palmtt.c b/drivers/video/fbdev/omap/lcd_palmtt.c deleted file mode 100644 index 703af0bc5c92..000000000000 --- a/drivers/video/fbdev/omap/lcd_palmtt.c +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * LCD panel support for Palm Tungsten|T - * Current version : Marek Vasut <marek.vasut@gmail.com> - * - * Modified from lcd_inn1510.c - */ - -/* -GPIO11 - backlight -GPIO12 - screen blanking -GPIO13 - screen blanking -*/ - -#include <linux/platform_device.h> -#include <linux/module.h> -#include <linux/io.h> -#include <linux/gpio.h> - -#include "omapfb.h" - -static unsigned long palmtt_panel_get_caps(struct lcd_panel *panel) -{ - return OMAPFB_CAPS_SET_BACKLIGHT; -} - -static struct lcd_panel palmtt_panel = { - .name = "palmtt", - .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC | - OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE | - OMAP_LCDC_HSVS_OPPOSITE, - .bpp = 16, - .data_lines = 16, - .x_res = 320, - .y_res = 320, - .pixel_clock = 10000, - .hsw = 4, - .hfp = 8, - .hbp = 28, - .vsw = 1, - .vfp = 8, - .vbp = 7, - .pcd = 0, - - .get_caps = palmtt_panel_get_caps, -}; - -static int palmtt_panel_probe(struct platform_device *pdev) -{ - omapfb_register_panel(&palmtt_panel); - return 0; -} - -static struct platform_driver palmtt_panel_driver = { - .probe = palmtt_panel_probe, - .driver = { - .name = "lcd_palmtt", - }, -}; - -module_platform_driver(palmtt_panel_driver); - -MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); -MODULE_DESCRIPTION("LCD panel support for Palm Tungsten|T"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/omap/lcd_palmz71.c b/drivers/video/fbdev/omap/lcd_palmz71.c deleted file mode 100644 index a955c908ab14..000000000000 --- a/drivers/video/fbdev/omap/lcd_palmz71.c +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * LCD panel support for the Palm Zire71 - * - * Original version : Romain Goyet - * Current version : Laurent Gonzalez - * Modified for zire71 : Marek Vasut - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/io.h> - -#include "omapfb.h" - -static unsigned long palmz71_panel_get_caps(struct lcd_panel *panel) -{ - return OMAPFB_CAPS_SET_BACKLIGHT; -} - -static struct lcd_panel palmz71_panel = { - .name = "palmz71", - .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC | - OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE | - OMAP_LCDC_HSVS_OPPOSITE, - .data_lines = 16, - .bpp = 16, - .pixel_clock = 24000, - .x_res = 320, - .y_res = 320, - .hsw = 4, - .hfp = 8, - .hbp = 28, - .vsw = 1, - .vfp = 8, - .vbp = 7, - .pcd = 0, - - .get_caps = palmz71_panel_get_caps, -}; - -static int palmz71_panel_probe(struct platform_device *pdev) -{ - omapfb_register_panel(&palmz71_panel); - return 0; -} - -static struct platform_driver palmz71_panel_driver = { - .probe = palmz71_panel_probe, - .driver = { - .name = "lcd_palmz71", - }, -}; - -module_platform_driver(palmz71_panel_driver); - -MODULE_AUTHOR("Romain Goyet, Laurent Gonzalez, Marek Vasut"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("LCD panel support for the Palm Zire71"); diff --git a/drivers/video/fbdev/omap/lcdc.c b/drivers/video/fbdev/omap/lcdc.c index e7ce783e5215..abb8b11464e8 100644 --- a/drivers/video/fbdev/omap/lcdc.c +++ b/drivers/video/fbdev/omap/lcdc.c @@ -706,8 +706,6 @@ static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode, if (machine_is_ams_delta()) rate /= 4; - if (machine_is_omap_h3()) - rate /= 3; r = clk_set_rate(lcdc.lcd_ck, rate); if (r) { dev_err(fbdev->dev, "failed to adjust LCD rate\n"); diff --git a/drivers/video/fbdev/omap/omapfb_main.c b/drivers/video/fbdev/omap/omapfb_main.c index 17cda5765683..1f3df2055ff0 100644 --- a/drivers/video/fbdev/omap/omapfb_main.c +++ b/drivers/video/fbdev/omap/omapfb_main.c @@ -1447,7 +1447,7 @@ static int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info) info->fbops = &omapfb_ops; info->flags = FBINFO_FLAG_DEFAULT; - strncpy(fix->id, MODULE_NAME, sizeof(fix->id)); + strscpy(fix->id, MODULE_NAME, sizeof(fix->id)); info->pseudo_palette = fbdev->pseudo_palette; @@ -1573,8 +1573,7 @@ static int omapfb_find_ctrl(struct omapfb_device *fbdev) fbdev->ctrl = NULL; - strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1); - name[sizeof(name) - 1] = '\0'; + strscpy(name, conf->lcd.ctrl_name, sizeof(name)); if (strcmp(name, "internal") == 0) { fbdev->ctrl = fbdev->int_ctrl; 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 4fc4b26a8d30..ba94a0a7bd4f 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c @@ -331,13 +331,7 @@ static int dsicm_bl_update_status(struct backlight_device *dev) struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev); struct omap_dss_device *in = ddata->in; int r; - int level; - - if (dev->props.fb_blank == FB_BLANK_UNBLANK && - dev->props.power == FB_BLANK_UNBLANK) - level = dev->props.brightness; - else - level = 0; + int level = backlight_get_brightness(dev); dev_dbg(&ddata->pdev->dev, "update brightness to %d\n", level); diff --git a/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c index bc5a44c2a144..ae937854403b 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c @@ -10,6 +10,7 @@ #define DSS_SUBSYS_NAME "DISPLAY" #include <linux/kernel.h> +#include <linux/kstrtox.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/sysfs.h> @@ -36,7 +37,7 @@ static ssize_t display_enabled_store(struct omap_dss_device *dssdev, int r; bool enable; - r = strtobool(buf, &enable); + r = kstrtobool(buf, &enable); if (r) return r; @@ -73,7 +74,7 @@ static ssize_t display_tear_store(struct omap_dss_device *dssdev, if (!dssdev->driver->enable_te || !dssdev->driver->get_te) return -ENOENT; - r = strtobool(buf, &te); + r = kstrtobool(buf, &te); if (r) return r; @@ -183,7 +184,7 @@ static ssize_t display_mirror_store(struct omap_dss_device *dssdev, if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror) return -ENOENT; - r = strtobool(buf, &mirror); + r = kstrtobool(buf, &mirror); if (r) return r; diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dsi.c b/drivers/video/fbdev/omap2/omapfb/dss/dsi.c index 54b0f034c2ed..7cddb7b8ae34 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dsi.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dsi.c @@ -1536,22 +1536,28 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; - struct dsi_irq_stats stats; + struct dsi_irq_stats *stats; + + stats = kzalloc(sizeof(*stats), GFP_KERNEL); + if (!stats) { + seq_printf(s, "out of memory\n"); + return; + } spin_lock_irqsave(&dsi->irq_stats_lock, flags); - stats = dsi->irq_stats; + *stats = dsi->irq_stats; memset(&dsi->irq_stats, 0, sizeof(dsi->irq_stats)); dsi->irq_stats.last_reset = jiffies; spin_unlock_irqrestore(&dsi->irq_stats_lock, flags); seq_printf(s, "period %u ms\n", - jiffies_to_msecs(jiffies - stats.last_reset)); + jiffies_to_msecs(jiffies - stats->last_reset)); - seq_printf(s, "irqs %d\n", stats.irq_count); + seq_printf(s, "irqs %d\n", stats->irq_count); #define PIS(x) \ - seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]) + seq_printf(s, "%-20s %10d\n", #x, stats->dsi_irqs[ffs(DSI_IRQ_##x)-1]) seq_printf(s, "-- DSI%d interrupts --\n", dsi->module_id + 1); PIS(VC0); @@ -1575,10 +1581,10 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, #define PIS(x) \ seq_printf(s, "%-20s %10d %10d %10d %10d\n", #x, \ - stats.vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \ - stats.vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \ - stats.vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \ - stats.vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]); + stats->vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \ + stats->vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \ + stats->vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \ + stats->vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]); seq_printf(s, "-- VC interrupts --\n"); PIS(CS); @@ -1594,7 +1600,7 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, #define PIS(x) \ seq_printf(s, "%-20s %10d\n", #x, \ - stats.cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]); + stats->cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]); seq_printf(s, "-- CIO interrupts --\n"); PIS(ERRSYNCESC1); @@ -1618,6 +1624,8 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, PIS(ULPSACTIVENOT_ALL0); PIS(ULPSACTIVENOT_ALL1); #undef PIS + + kfree(stats); } static void dsi1_dump_irqs(struct seq_file *s) diff --git a/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c index ba21c4a2633d..1b644be5fe2e 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c @@ -10,6 +10,7 @@ #define DSS_SUBSYS_NAME "MANAGER" #include <linux/kernel.h> +#include <linux/kstrtox.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -246,7 +247,7 @@ static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, bool enable; int r; - r = strtobool(buf, &enable); + r = kstrtobool(buf, &enable); if (r) return r; @@ -290,7 +291,7 @@ static ssize_t manager_alpha_blending_enabled_store( if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) return -ENODEV; - r = strtobool(buf, &enable); + r = kstrtobool(buf, &enable); if (r) return r; @@ -329,7 +330,7 @@ static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, if (!dss_has_feature(FEAT_CPR)) return -ENODEV; - r = strtobool(buf, &enable); + r = kstrtobool(buf, &enable); if (r) return r; diff --git a/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c index 601c0beb6de9..1da4fb1c77b4 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c @@ -13,6 +13,7 @@ #include <linux/err.h> #include <linux/sysfs.h> #include <linux/kobject.h> +#include <linux/kstrtox.h> #include <linux/platform_device.h> #include <video/omapfb_dss.h> @@ -210,7 +211,7 @@ static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, int r; bool enable; - r = strtobool(buf, &enable); + r = kstrtobool(buf, &enable); if (r) return r; diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c b/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c index 06dc41aa0354..831b2c2fbdf9 100644 --- a/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c @@ -15,6 +15,7 @@ #include <linux/uaccess.h> #include <linux/platform_device.h> #include <linux/kernel.h> +#include <linux/kstrtox.h> #include <linux/mm.h> #include <linux/omapfb.h> @@ -96,7 +97,7 @@ static ssize_t store_mirror(struct device *dev, int r; struct fb_var_screeninfo new_var; - r = strtobool(buf, &mirror); + r = kstrtobool(buf, &mirror); if (r) return r; diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c index 644278146d3b..41edc6e79460 100644 --- a/drivers/video/fbdev/riva/fbdev.c +++ b/drivers/video/fbdev/riva/fbdev.c @@ -293,13 +293,7 @@ static int riva_bl_update_status(struct backlight_device *bd) { struct riva_par *par = bl_get_data(bd); U032 tmp_pcrt, tmp_pmc; - int level; - - if (bd->props.power != FB_BLANK_UNBLANK || - bd->props.fb_blank != FB_BLANK_UNBLANK) - level = 0; - else - level = bd->props.brightness; + int level = backlight_get_brightness(bd); tmp_pmc = NV_RD32(par->riva.PMC, 0x10F0) & 0x0000FFFF; tmp_pcrt = NV_RD32(par->riva.PCRTC0, 0x081C) & 0xFFFFFFFC; diff --git a/drivers/video/fbdev/s3c2410fb-regs-lcd.h b/drivers/video/fbdev/s3c2410fb-regs-lcd.h deleted file mode 100644 index 1e46f7a788e5..000000000000 --- a/drivers/video/fbdev/s3c2410fb-regs-lcd.h +++ /dev/null @@ -1,143 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> - * http://www.simtec.co.uk/products/SWLINUX/ - */ - -#ifndef ___ASM_ARCH_REGS_LCD_H -#define ___ASM_ARCH_REGS_LCD_H - -/* - * a couple of values are used as platform data in - * include/linux/platform_data/fb-s3c2410.h and not - * duplicated here. - */ -#include <linux/platform_data/fb-s3c2410.h> - -#define S3C2410_LCDREG(x) (x) - -/* LCD control registers */ -#define S3C2410_LCDCON1 S3C2410_LCDREG(0x00) -#define S3C2410_LCDCON2 S3C2410_LCDREG(0x04) -#define S3C2410_LCDCON3 S3C2410_LCDREG(0x08) -#define S3C2410_LCDCON4 S3C2410_LCDREG(0x0C) -#define S3C2410_LCDCON5 S3C2410_LCDREG(0x10) - -#define S3C2410_LCDCON1_CLKVAL(x) ((x) << 8) -#define S3C2410_LCDCON1_MMODE (1<<7) -#define S3C2410_LCDCON1_DSCAN4 (0<<5) -#define S3C2410_LCDCON1_STN4 (1<<5) -#define S3C2410_LCDCON1_STN8 (2<<5) -#define S3C2410_LCDCON1_TFT (3<<5) - -#define S3C2410_LCDCON1_STN1BPP (0<<1) -#define S3C2410_LCDCON1_STN2GREY (1<<1) -#define S3C2410_LCDCON1_STN4GREY (2<<1) -#define S3C2410_LCDCON1_STN8BPP (3<<1) -#define S3C2410_LCDCON1_STN12BPP (4<<1) - -#define S3C2410_LCDCON1_ENVID (1) - -#define S3C2410_LCDCON1_MODEMASK 0x1E - -#define S3C2410_LCDCON2_VBPD(x) ((x) << 24) -#define S3C2410_LCDCON2_LINEVAL(x) ((x) << 14) -#define S3C2410_LCDCON2_VFPD(x) ((x) << 6) -#define S3C2410_LCDCON2_VSPW(x) ((x) << 0) - -#define S3C2410_LCDCON2_GET_VBPD(x) ( ((x) >> 24) & 0xFF) -#define S3C2410_LCDCON2_GET_VFPD(x) ( ((x) >> 6) & 0xFF) -#define S3C2410_LCDCON2_GET_VSPW(x) ( ((x) >> 0) & 0x3F) - -#define S3C2410_LCDCON3_HBPD(x) ((x) << 19) -#define S3C2410_LCDCON3_WDLY(x) ((x) << 19) -#define S3C2410_LCDCON3_HOZVAL(x) ((x) << 8) -#define S3C2410_LCDCON3_HFPD(x) ((x) << 0) -#define S3C2410_LCDCON3_LINEBLANK(x)((x) << 0) - -#define S3C2410_LCDCON3_GET_HBPD(x) ( ((x) >> 19) & 0x7F) -#define S3C2410_LCDCON3_GET_HFPD(x) ( ((x) >> 0) & 0xFF) - -/* LDCCON4 changes for STN mode on the S3C2412 */ - -#define S3C2410_LCDCON4_MVAL(x) ((x) << 8) -#define S3C2410_LCDCON4_HSPW(x) ((x) << 0) -#define S3C2410_LCDCON4_WLH(x) ((x) << 0) - -#define S3C2410_LCDCON4_GET_HSPW(x) ( ((x) >> 0) & 0xFF) - -/* framebuffer start addressed */ -#define S3C2410_LCDSADDR1 S3C2410_LCDREG(0x14) -#define S3C2410_LCDSADDR2 S3C2410_LCDREG(0x18) -#define S3C2410_LCDSADDR3 S3C2410_LCDREG(0x1C) - -#define S3C2410_LCDBANK(x) ((x) << 21) -#define S3C2410_LCDBASEU(x) (x) - -#define S3C2410_OFFSIZE(x) ((x) << 11) -#define S3C2410_PAGEWIDTH(x) (x) - -/* colour lookup and miscellaneous controls */ - -#define S3C2410_REDLUT S3C2410_LCDREG(0x20) -#define S3C2410_GREENLUT S3C2410_LCDREG(0x24) -#define S3C2410_BLUELUT S3C2410_LCDREG(0x28) - -#define S3C2410_DITHMODE S3C2410_LCDREG(0x4C) -#define S3C2410_TPAL S3C2410_LCDREG(0x50) - -#define S3C2410_TPAL_EN (1<<24) - -/* interrupt info */ -#define S3C2410_LCDINTPND S3C2410_LCDREG(0x54) -#define S3C2410_LCDSRCPND S3C2410_LCDREG(0x58) -#define S3C2410_LCDINTMSK S3C2410_LCDREG(0x5C) -#define S3C2410_LCDINT_FIWSEL (1<<2) -#define S3C2410_LCDINT_FRSYNC (1<<1) -#define S3C2410_LCDINT_FICNT (1<<0) - -/* s3c2442 extra stn registers */ - -#define S3C2442_REDLUT S3C2410_LCDREG(0x20) -#define S3C2442_GREENLUT S3C2410_LCDREG(0x24) -#define S3C2442_BLUELUT S3C2410_LCDREG(0x28) -#define S3C2442_DITHMODE S3C2410_LCDREG(0x20) - -#define S3C2410_LPCSEL S3C2410_LCDREG(0x60) - -#define S3C2410_TFTPAL(x) S3C2410_LCDREG((0x400 + (x)*4)) - -/* S3C2412 registers */ - -#define S3C2412_TPAL S3C2410_LCDREG(0x20) - -#define S3C2412_LCDINTPND S3C2410_LCDREG(0x24) -#define S3C2412_LCDSRCPND S3C2410_LCDREG(0x28) -#define S3C2412_LCDINTMSK S3C2410_LCDREG(0x2C) - -#define S3C2412_TCONSEL S3C2410_LCDREG(0x30) - -#define S3C2412_LCDCON6 S3C2410_LCDREG(0x34) -#define S3C2412_LCDCON7 S3C2410_LCDREG(0x38) -#define S3C2412_LCDCON8 S3C2410_LCDREG(0x3C) -#define S3C2412_LCDCON9 S3C2410_LCDREG(0x40) - -#define S3C2412_REDLUT(x) S3C2410_LCDREG(0x44 + ((x)*4)) -#define S3C2412_GREENLUT(x) S3C2410_LCDREG(0x60 + ((x)*4)) -#define S3C2412_BLUELUT(x) S3C2410_LCDREG(0x98 + ((x)*4)) - -#define S3C2412_FRCPAT(x) S3C2410_LCDREG(0xB4 + ((x)*4)) - -/* general registers */ - -/* base of the LCD registers, where INTPND, INTSRC and then INTMSK - * are available. */ - -#define S3C2410_LCDINTBASE S3C2410_LCDREG(0x54) -#define S3C2412_LCDINTBASE S3C2410_LCDREG(0x24) - -#define S3C24XX_LCDINTPND (0x00) -#define S3C24XX_LCDSRCPND (0x04) -#define S3C24XX_LCDINTMSK (0x08) - -#endif /* ___ASM_ARCH_REGS_LCD_H */ diff --git a/drivers/video/fbdev/s3c2410fb.c b/drivers/video/fbdev/s3c2410fb.c deleted file mode 100644 index d8ae5258de46..000000000000 --- a/drivers/video/fbdev/s3c2410fb.c +++ /dev/null @@ -1,1142 +0,0 @@ -/* linux/drivers/video/s3c2410fb.c - * Copyright (c) 2004,2005 Arnaud Patard - * Copyright (c) 2004-2008 Ben Dooks - * - * S3C2410 LCD Framebuffer Driver - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - * Driver based on skeletonfb.c, sa1100fb.c and others. -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/err.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/dma-mapping.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/cpufreq.h> -#include <linux/io.h> -#include <linux/platform_data/fb-s3c2410.h> - -#include <asm/div64.h> - -#include <asm/mach/map.h> - -#ifdef CONFIG_PM -#include <linux/pm.h> -#endif - -#include "s3c2410fb.h" -#include "s3c2410fb-regs-lcd.h" - -/* Debugging stuff */ -static int debug = IS_BUILTIN(CONFIG_FB_S3C2410_DEBUG); - -#define dprintk(msg...) \ -do { \ - if (debug) \ - pr_debug(msg); \ -} while (0) - -/* useful functions */ - -static int is_s3c2412(struct s3c2410fb_info *fbi) -{ - return (fbi->drv_type == DRV_S3C2412); -} - -/* s3c2410fb_set_lcdaddr - * - * initialise lcd controller address pointers - */ -static void s3c2410fb_set_lcdaddr(struct fb_info *info) -{ - unsigned long saddr1, saddr2, saddr3; - struct s3c2410fb_info *fbi = info->par; - void __iomem *regs = fbi->io; - - saddr1 = info->fix.smem_start >> 1; - saddr2 = info->fix.smem_start; - saddr2 += info->fix.line_length * info->var.yres; - saddr2 >>= 1; - - saddr3 = S3C2410_OFFSIZE(0) | - S3C2410_PAGEWIDTH((info->fix.line_length / 2) & 0x3ff); - - dprintk("LCDSADDR1 = 0x%08lx\n", saddr1); - dprintk("LCDSADDR2 = 0x%08lx\n", saddr2); - dprintk("LCDSADDR3 = 0x%08lx\n", saddr3); - - writel(saddr1, regs + S3C2410_LCDSADDR1); - writel(saddr2, regs + S3C2410_LCDSADDR2); - writel(saddr3, regs + S3C2410_LCDSADDR3); -} - -/* s3c2410fb_calc_pixclk() - * - * calculate divisor for clk->pixclk - */ -static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi, - unsigned long pixclk) -{ - unsigned long clk = fbi->clk_rate; - unsigned long long div; - - /* pixclk is in picoseconds, our clock is in Hz - * - * Hz -> picoseconds is / 10^-12 - */ - - div = (unsigned long long)clk * pixclk; - div >>= 12; /* div / 2^12 */ - do_div(div, 625 * 625UL * 625); /* div / 5^12 */ - - dprintk("pixclk %ld, divisor is %ld\n", pixclk, (long)div); - return div; -} - -/* - * s3c2410fb_check_var(): - * Get the video params out of 'var'. If a value doesn't fit, round it up, - * if it's too big, return -EINVAL. - * - */ -static int s3c2410fb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - struct s3c2410fb_info *fbi = info->par; - struct s3c2410fb_mach_info *mach_info = dev_get_platdata(fbi->dev); - struct s3c2410fb_display *display = NULL; - struct s3c2410fb_display *default_display = mach_info->displays + - mach_info->default_display; - int type = default_display->type; - unsigned i; - - dprintk("check_var(var=%p, info=%p)\n", var, info); - - /* validate x/y resolution */ - /* choose default mode if possible */ - if (var->yres == default_display->yres && - var->xres == default_display->xres && - var->bits_per_pixel == default_display->bpp) - display = default_display; - else - for (i = 0; i < mach_info->num_displays; i++) - if (type == mach_info->displays[i].type && - var->yres == mach_info->displays[i].yres && - var->xres == mach_info->displays[i].xres && - var->bits_per_pixel == mach_info->displays[i].bpp) { - display = mach_info->displays + i; - break; - } - - if (!display) { - dprintk("wrong resolution or depth %dx%d at %d bpp\n", - var->xres, var->yres, var->bits_per_pixel); - return -EINVAL; - } - - /* it is always the size as the display */ - var->xres_virtual = display->xres; - var->yres_virtual = display->yres; - var->height = display->height; - var->width = display->width; - - /* copy lcd settings */ - var->pixclock = display->pixclock; - var->left_margin = display->left_margin; - var->right_margin = display->right_margin; - var->upper_margin = display->upper_margin; - var->lower_margin = display->lower_margin; - var->vsync_len = display->vsync_len; - var->hsync_len = display->hsync_len; - - fbi->regs.lcdcon5 = display->lcdcon5; - /* set display type */ - fbi->regs.lcdcon1 = display->type; - - var->transp.offset = 0; - var->transp.length = 0; - /* set r/g/b positions */ - switch (var->bits_per_pixel) { - case 1: - case 2: - case 4: - var->red.offset = 0; - var->red.length = var->bits_per_pixel; - var->green = var->red; - var->blue = var->red; - break; - case 8: - if (display->type != S3C2410_LCDCON1_TFT) { - /* 8 bpp 332 */ - var->red.length = 3; - var->red.offset = 5; - var->green.length = 3; - var->green.offset = 2; - var->blue.length = 2; - var->blue.offset = 0; - } else { - var->red.offset = 0; - var->red.length = 8; - var->green = var->red; - var->blue = var->red; - } - break; - case 12: - /* 12 bpp 444 */ - var->red.length = 4; - var->red.offset = 8; - var->green.length = 4; - var->green.offset = 4; - var->blue.length = 4; - var->blue.offset = 0; - break; - - default: - case 16: - if (display->lcdcon5 & S3C2410_LCDCON5_FRM565) { - /* 16 bpp, 565 format */ - var->red.offset = 11; - var->green.offset = 5; - var->blue.offset = 0; - var->red.length = 5; - var->green.length = 6; - var->blue.length = 5; - } else { - /* 16 bpp, 5551 format */ - var->red.offset = 11; - var->green.offset = 6; - var->blue.offset = 1; - var->red.length = 5; - var->green.length = 5; - var->blue.length = 5; - } - break; - case 32: - /* 24 bpp 888 and 8 dummy */ - var->red.length = 8; - var->red.offset = 16; - var->green.length = 8; - var->green.offset = 8; - var->blue.length = 8; - var->blue.offset = 0; - break; - } - return 0; -} - -/* s3c2410fb_calculate_stn_lcd_regs - * - * calculate register values from var settings - */ -static void s3c2410fb_calculate_stn_lcd_regs(const struct fb_info *info, - struct s3c2410fb_hw *regs) -{ - const struct s3c2410fb_info *fbi = info->par; - const struct fb_var_screeninfo *var = &info->var; - int type = regs->lcdcon1 & ~S3C2410_LCDCON1_TFT; - int hs = var->xres >> 2; - unsigned wdly = (var->left_margin >> 4) - 1; - unsigned wlh = (var->hsync_len >> 4) - 1; - - if (type != S3C2410_LCDCON1_STN4) - hs >>= 1; - - switch (var->bits_per_pixel) { - case 1: - regs->lcdcon1 |= S3C2410_LCDCON1_STN1BPP; - break; - case 2: - regs->lcdcon1 |= S3C2410_LCDCON1_STN2GREY; - break; - case 4: - regs->lcdcon1 |= S3C2410_LCDCON1_STN4GREY; - break; - case 8: - regs->lcdcon1 |= S3C2410_LCDCON1_STN8BPP; - hs *= 3; - break; - case 12: - regs->lcdcon1 |= S3C2410_LCDCON1_STN12BPP; - hs *= 3; - break; - - default: - /* invalid pixel depth */ - dev_err(fbi->dev, "invalid bpp %d\n", - var->bits_per_pixel); - } - /* update X/Y info */ - dprintk("setting horz: lft=%d, rt=%d, sync=%d\n", - var->left_margin, var->right_margin, var->hsync_len); - - regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1); - - if (wdly > 3) - wdly = 3; - - if (wlh > 3) - wlh = 3; - - regs->lcdcon3 = S3C2410_LCDCON3_WDLY(wdly) | - S3C2410_LCDCON3_LINEBLANK(var->right_margin / 8) | - S3C2410_LCDCON3_HOZVAL(hs - 1); - - regs->lcdcon4 = S3C2410_LCDCON4_WLH(wlh); -} - -/* s3c2410fb_calculate_tft_lcd_regs - * - * calculate register values from var settings - */ -static void s3c2410fb_calculate_tft_lcd_regs(const struct fb_info *info, - struct s3c2410fb_hw *regs) -{ - const struct s3c2410fb_info *fbi = info->par; - const struct fb_var_screeninfo *var = &info->var; - - switch (var->bits_per_pixel) { - case 1: - regs->lcdcon1 |= S3C2410_LCDCON1_TFT1BPP; - break; - case 2: - regs->lcdcon1 |= S3C2410_LCDCON1_TFT2BPP; - break; - case 4: - regs->lcdcon1 |= S3C2410_LCDCON1_TFT4BPP; - break; - case 8: - regs->lcdcon1 |= S3C2410_LCDCON1_TFT8BPP; - regs->lcdcon5 |= S3C2410_LCDCON5_BSWP | - S3C2410_LCDCON5_FRM565; - regs->lcdcon5 &= ~S3C2410_LCDCON5_HWSWP; - break; - case 16: - regs->lcdcon1 |= S3C2410_LCDCON1_TFT16BPP; - regs->lcdcon5 &= ~S3C2410_LCDCON5_BSWP; - regs->lcdcon5 |= S3C2410_LCDCON5_HWSWP; - break; - case 32: - regs->lcdcon1 |= S3C2410_LCDCON1_TFT24BPP; - regs->lcdcon5 &= ~(S3C2410_LCDCON5_BSWP | - S3C2410_LCDCON5_HWSWP | - S3C2410_LCDCON5_BPP24BL); - break; - default: - /* invalid pixel depth */ - dev_err(fbi->dev, "invalid bpp %d\n", - var->bits_per_pixel); - } - /* update X/Y info */ - dprintk("setting vert: up=%d, low=%d, sync=%d\n", - var->upper_margin, var->lower_margin, var->vsync_len); - - dprintk("setting horz: lft=%d, rt=%d, sync=%d\n", - var->left_margin, var->right_margin, var->hsync_len); - - regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1) | - S3C2410_LCDCON2_VBPD(var->upper_margin - 1) | - S3C2410_LCDCON2_VFPD(var->lower_margin - 1) | - S3C2410_LCDCON2_VSPW(var->vsync_len - 1); - - regs->lcdcon3 = S3C2410_LCDCON3_HBPD(var->right_margin - 1) | - S3C2410_LCDCON3_HFPD(var->left_margin - 1) | - S3C2410_LCDCON3_HOZVAL(var->xres - 1); - - regs->lcdcon4 = S3C2410_LCDCON4_HSPW(var->hsync_len - 1); -} - -/* s3c2410fb_activate_var - * - * activate (set) the controller from the given framebuffer - * information - */ -static void s3c2410fb_activate_var(struct fb_info *info) -{ - struct s3c2410fb_info *fbi = info->par; - void __iomem *regs = fbi->io; - int type = fbi->regs.lcdcon1 & S3C2410_LCDCON1_TFT; - struct fb_var_screeninfo *var = &info->var; - int clkdiv; - - clkdiv = DIV_ROUND_UP(s3c2410fb_calc_pixclk(fbi, var->pixclock), 2); - - dprintk("%s: var->xres = %d\n", __func__, var->xres); - dprintk("%s: var->yres = %d\n", __func__, var->yres); - dprintk("%s: var->bpp = %d\n", __func__, var->bits_per_pixel); - - if (type == S3C2410_LCDCON1_TFT) { - s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs); - --clkdiv; - if (clkdiv < 0) - clkdiv = 0; - } else { - s3c2410fb_calculate_stn_lcd_regs(info, &fbi->regs); - if (clkdiv < 2) - clkdiv = 2; - } - - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv); - - /* write new registers */ - - dprintk("new register set:\n"); - dprintk("lcdcon[1] = 0x%08lx\n", fbi->regs.lcdcon1); - dprintk("lcdcon[2] = 0x%08lx\n", fbi->regs.lcdcon2); - dprintk("lcdcon[3] = 0x%08lx\n", fbi->regs.lcdcon3); - dprintk("lcdcon[4] = 0x%08lx\n", fbi->regs.lcdcon4); - dprintk("lcdcon[5] = 0x%08lx\n", fbi->regs.lcdcon5); - - writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID, - regs + S3C2410_LCDCON1); - writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2); - writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3); - writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4); - writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5); - - /* set lcd address pointers */ - s3c2410fb_set_lcdaddr(info); - - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID, - writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1); -} - -/* - * s3c2410fb_set_par - Alters the hardware state. - * @info: frame buffer structure that represents a single frame buffer - * - */ -static int s3c2410fb_set_par(struct fb_info *info) -{ - struct fb_var_screeninfo *var = &info->var; - - switch (var->bits_per_pixel) { - case 32: - case 16: - case 12: - info->fix.visual = FB_VISUAL_TRUECOLOR; - break; - case 1: - info->fix.visual = FB_VISUAL_MONO01; - break; - default: - info->fix.visual = FB_VISUAL_PSEUDOCOLOR; - break; - } - - info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8; - - /* activate this new configuration */ - - s3c2410fb_activate_var(info); - return 0; -} - -static void schedule_palette_update(struct s3c2410fb_info *fbi, - unsigned int regno, unsigned int val) -{ - unsigned long flags; - unsigned long irqen; - void __iomem *irq_base = fbi->irq_base; - - local_irq_save(flags); - - fbi->palette_buffer[regno] = val; - - if (!fbi->palette_ready) { - fbi->palette_ready = 1; - - /* enable IRQ */ - irqen = readl(irq_base + S3C24XX_LCDINTMSK); - irqen &= ~S3C2410_LCDINT_FRSYNC; - writel(irqen, irq_base + S3C24XX_LCDINTMSK); - } - - local_irq_restore(flags); -} - -/* from pxafb.c */ -static inline unsigned int chan_to_field(unsigned int chan, - struct fb_bitfield *bf) -{ - chan &= 0xffff; - chan >>= 16 - bf->length; - return chan << bf->offset; -} - -static int s3c2410fb_setcolreg(unsigned regno, - unsigned red, unsigned green, unsigned blue, - unsigned transp, struct fb_info *info) -{ - struct s3c2410fb_info *fbi = info->par; - void __iomem *regs = fbi->io; - unsigned int val; - - /* dprintk("setcol: regno=%d, rgb=%d,%d,%d\n", - regno, red, green, blue); */ - - switch (info->fix.visual) { - case FB_VISUAL_TRUECOLOR: - /* true-colour, use pseudo-palette */ - - if (regno < 16) { - u32 *pal = info->pseudo_palette; - - val = chan_to_field(red, &info->var.red); - val |= chan_to_field(green, &info->var.green); - val |= chan_to_field(blue, &info->var.blue); - - pal[regno] = val; - } - break; - - case FB_VISUAL_PSEUDOCOLOR: - if (regno < 256) { - /* currently assume RGB 5-6-5 mode */ - - val = (red >> 0) & 0xf800; - val |= (green >> 5) & 0x07e0; - val |= (blue >> 11) & 0x001f; - - writel(val, regs + S3C2410_TFTPAL(regno)); - schedule_palette_update(fbi, regno, val); - } - - break; - - default: - return 1; /* unknown type */ - } - - return 0; -} - -/* s3c2410fb_lcd_enable - * - * shutdown the lcd controller - */ -static void s3c2410fb_lcd_enable(struct s3c2410fb_info *fbi, int enable) -{ - unsigned long flags; - - local_irq_save(flags); - - if (enable) - fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID; - else - fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID; - - writel(fbi->regs.lcdcon1, fbi->io + S3C2410_LCDCON1); - - local_irq_restore(flags); -} - - -/* - * s3c2410fb_blank - * @blank_mode: the blank mode we want. - * @info: frame buffer structure that represents a single frame buffer - * - * Blank the screen if blank_mode != 0, else unblank. Return 0 if - * blanking succeeded, != 0 if un-/blanking failed due to e.g. a - * video mode which doesn't support it. Implements VESA suspend - * and powerdown modes on hardware that supports disabling hsync/vsync: - * - * Returns negative errno on error, or zero on success. - * - */ -static int s3c2410fb_blank(int blank_mode, struct fb_info *info) -{ - struct s3c2410fb_info *fbi = info->par; - void __iomem *tpal_reg = fbi->io; - - dprintk("blank(mode=%d, info=%p)\n", blank_mode, info); - - tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL; - - if (blank_mode == FB_BLANK_POWERDOWN) - s3c2410fb_lcd_enable(fbi, 0); - else - s3c2410fb_lcd_enable(fbi, 1); - - if (blank_mode == FB_BLANK_UNBLANK) - writel(0x0, tpal_reg); - else { - dprintk("setting TPAL to output 0x000000\n"); - writel(S3C2410_TPAL_EN, tpal_reg); - } - - return 0; -} - -static int s3c2410fb_debug_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", debug ? "on" : "off"); -} - -static int s3c2410fb_debug_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - if (len < 1) - return -EINVAL; - - if (strncasecmp(buf, "on", 2) == 0 || - strncasecmp(buf, "1", 1) == 0) { - debug = 1; - dev_dbg(dev, "s3c2410fb: Debug On"); - } else if (strncasecmp(buf, "off", 3) == 0 || - strncasecmp(buf, "0", 1) == 0) { - debug = 0; - dev_dbg(dev, "s3c2410fb: Debug Off"); - } else { - return -EINVAL; - } - - return len; -} - -static DEVICE_ATTR(debug, 0664, s3c2410fb_debug_show, s3c2410fb_debug_store); - -static const struct fb_ops s3c2410fb_ops = { - .owner = THIS_MODULE, - .fb_check_var = s3c2410fb_check_var, - .fb_set_par = s3c2410fb_set_par, - .fb_blank = s3c2410fb_blank, - .fb_setcolreg = s3c2410fb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, -}; - -/* - * s3c2410fb_map_video_memory(): - * Allocates the DRAM memory for the frame buffer. This buffer is - * remapped into a non-cached, non-buffered, memory region to - * allow palette and pixel writes to occur without flushing the - * cache. Once this area is remapped, all virtual memory - * access to the video memory should occur at the new region. - */ -static int s3c2410fb_map_video_memory(struct fb_info *info) -{ - struct s3c2410fb_info *fbi = info->par; - dma_addr_t map_dma; - unsigned map_size = PAGE_ALIGN(info->fix.smem_len); - - dprintk("map_video_memory(fbi=%p) map_size %u\n", fbi, map_size); - - info->screen_base = dma_alloc_wc(fbi->dev, map_size, &map_dma, - GFP_KERNEL); - - if (info->screen_base) { - /* prevent initial garbage on screen */ - dprintk("map_video_memory: clear %p:%08x\n", - info->screen_base, map_size); - memset(info->screen_base, 0x00, map_size); - - info->fix.smem_start = map_dma; - - dprintk("map_video_memory: dma=%08lx cpu=%p size=%08x\n", - info->fix.smem_start, info->screen_base, map_size); - } - - return info->screen_base ? 0 : -ENOMEM; -} - -static inline void s3c2410fb_unmap_video_memory(struct fb_info *info) -{ - struct s3c2410fb_info *fbi = info->par; - - dma_free_wc(fbi->dev, PAGE_ALIGN(info->fix.smem_len), - info->screen_base, info->fix.smem_start); -} - -static inline void modify_gpio(void __iomem *reg, - unsigned long set, unsigned long mask) -{ - unsigned long tmp; - - if (!reg) - return; - - tmp = readl(reg) & ~mask; - writel(tmp | set, reg); -} - -/* - * s3c2410fb_init_registers - Initialise all LCD-related registers - */ -static int s3c2410fb_init_registers(struct fb_info *info) -{ - struct s3c2410fb_info *fbi = info->par; - struct s3c2410fb_mach_info *mach_info = dev_get_platdata(fbi->dev); - unsigned long flags; - void __iomem *regs = fbi->io; - void __iomem *tpal; - void __iomem *lpcsel; - - if (is_s3c2412(fbi)) { - tpal = regs + S3C2412_TPAL; - lpcsel = regs + S3C2412_TCONSEL; - } else { - tpal = regs + S3C2410_TPAL; - lpcsel = regs + S3C2410_LPCSEL; - } - - /* Initialise LCD with values from haret */ - - local_irq_save(flags); - - /* modify the gpio(s) with interrupts set (bjd) */ - - modify_gpio(mach_info->gpcup_reg, mach_info->gpcup, mach_info->gpcup_mask); - modify_gpio(mach_info->gpccon_reg, mach_info->gpccon, mach_info->gpccon_mask); - modify_gpio(mach_info->gpdup_reg, mach_info->gpdup, mach_info->gpdup_mask); - modify_gpio(mach_info->gpdcon_reg, mach_info->gpdcon, mach_info->gpdcon_mask); - - local_irq_restore(flags); - - dprintk("LPCSEL = 0x%08lx\n", mach_info->lpcsel); - writel(mach_info->lpcsel, lpcsel); - - dprintk("replacing TPAL %08x\n", readl(tpal)); - - /* ensure temporary palette disabled */ - writel(0x00, tpal); - - return 0; -} - -static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi) -{ - unsigned int i; - void __iomem *regs = fbi->io; - - fbi->palette_ready = 0; - - for (i = 0; i < 256; i++) { - unsigned long ent = fbi->palette_buffer[i]; - if (ent == PALETTE_BUFF_CLEAR) - continue; - - writel(ent, regs + S3C2410_TFTPAL(i)); - - /* it seems the only way to know exactly - * if the palette wrote ok, is to check - * to see if the value verifies ok - */ - - if (readw(regs + S3C2410_TFTPAL(i)) == ent) - fbi->palette_buffer[i] = PALETTE_BUFF_CLEAR; - else - fbi->palette_ready = 1; /* retry */ - } -} - -static irqreturn_t s3c2410fb_irq(int irq, void *dev_id) -{ - struct s3c2410fb_info *fbi = dev_id; - void __iomem *irq_base = fbi->irq_base; - unsigned long lcdirq = readl(irq_base + S3C24XX_LCDINTPND); - - if (lcdirq & S3C2410_LCDINT_FRSYNC) { - if (fbi->palette_ready) - s3c2410fb_write_palette(fbi); - - writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDINTPND); - writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDSRCPND); - } - - return IRQ_HANDLED; -} - -#ifdef CONFIG_ARM_S3C24XX_CPUFREQ - -static int s3c2410fb_cpufreq_transition(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct s3c2410fb_info *info; - struct fb_info *fbinfo; - long delta_f; - - info = container_of(nb, struct s3c2410fb_info, freq_transition); - fbinfo = dev_get_drvdata(info->dev); - - /* work out change, <0 for speed-up */ - delta_f = info->clk_rate - clk_get_rate(info->clk); - - if ((val == CPUFREQ_POSTCHANGE && delta_f > 0) || - (val == CPUFREQ_PRECHANGE && delta_f < 0)) { - info->clk_rate = clk_get_rate(info->clk); - s3c2410fb_activate_var(fbinfo); - } - - return 0; -} - -static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info) -{ - info->freq_transition.notifier_call = s3c2410fb_cpufreq_transition; - - return cpufreq_register_notifier(&info->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info) -{ - cpufreq_unregister_notifier(&info->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -#else -static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info) -{ - return 0; -} - -static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info) -{ -} -#endif - - -static const char driver_name[] = "s3c2410fb"; - -static int s3c24xxfb_probe(struct platform_device *pdev, - enum s3c_drv_type drv_type) -{ - struct s3c2410fb_info *info; - struct s3c2410fb_display *display; - struct fb_info *fbinfo; - struct s3c2410fb_mach_info *mach_info; - struct resource *res; - int ret; - int irq; - int i; - int size; - u32 lcdcon1; - - mach_info = dev_get_platdata(&pdev->dev); - if (mach_info == NULL) { - dev_err(&pdev->dev, - "no platform data for lcd, cannot attach\n"); - return -EINVAL; - } - - if (mach_info->default_display >= mach_info->num_displays) { - dev_err(&pdev->dev, "default is %d but only %d displays\n", - mach_info->default_display, mach_info->num_displays); - return -EINVAL; - } - - display = mach_info->displays + mach_info->default_display; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq for device\n"); - return -ENOENT; - } - - fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev); - if (!fbinfo) - return -ENOMEM; - - platform_set_drvdata(pdev, fbinfo); - - info = fbinfo->par; - info->dev = &pdev->dev; - info->drv_type = drv_type; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "failed to get memory registers\n"); - ret = -ENXIO; - goto dealloc_fb; - } - - size = resource_size(res); - info->mem = request_mem_region(res->start, size, pdev->name); - if (info->mem == NULL) { - dev_err(&pdev->dev, "failed to get memory region\n"); - ret = -ENOENT; - goto dealloc_fb; - } - - info->io = ioremap(res->start, size); - if (info->io == NULL) { - dev_err(&pdev->dev, "ioremap() of registers failed\n"); - ret = -ENXIO; - goto release_mem; - } - - if (drv_type == DRV_S3C2412) - info->irq_base = info->io + S3C2412_LCDINTBASE; - else - info->irq_base = info->io + S3C2410_LCDINTBASE; - - dprintk("devinit\n"); - - strcpy(fbinfo->fix.id, driver_name); - - /* Stop the video */ - lcdcon1 = readl(info->io + S3C2410_LCDCON1); - writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1); - - fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; - fbinfo->fix.type_aux = 0; - fbinfo->fix.xpanstep = 0; - fbinfo->fix.ypanstep = 0; - fbinfo->fix.ywrapstep = 0; - fbinfo->fix.accel = FB_ACCEL_NONE; - - fbinfo->var.nonstd = 0; - fbinfo->var.activate = FB_ACTIVATE_NOW; - fbinfo->var.accel_flags = 0; - fbinfo->var.vmode = FB_VMODE_NONINTERLACED; - - fbinfo->fbops = &s3c2410fb_ops; - fbinfo->flags = FBINFO_FLAG_DEFAULT; - fbinfo->pseudo_palette = &info->pseudo_pal; - - for (i = 0; i < 256; i++) - info->palette_buffer[i] = PALETTE_BUFF_CLEAR; - - ret = request_irq(irq, s3c2410fb_irq, 0, pdev->name, info); - if (ret) { - dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret); - ret = -EBUSY; - goto release_regs; - } - - info->clk = clk_get(NULL, "lcd"); - if (IS_ERR(info->clk)) { - dev_err(&pdev->dev, "failed to get lcd clock source\n"); - ret = PTR_ERR(info->clk); - goto release_irq; - } - - clk_prepare_enable(info->clk); - dprintk("got and enabled clock\n"); - - usleep_range(1000, 1100); - - info->clk_rate = clk_get_rate(info->clk); - - /* find maximum required memory size for display */ - for (i = 0; i < mach_info->num_displays; i++) { - unsigned long smem_len = mach_info->displays[i].xres; - - smem_len *= mach_info->displays[i].yres; - smem_len *= mach_info->displays[i].bpp; - smem_len >>= 3; - if (fbinfo->fix.smem_len < smem_len) - fbinfo->fix.smem_len = smem_len; - } - - /* Initialize video memory */ - ret = s3c2410fb_map_video_memory(fbinfo); - if (ret) { - dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret); - ret = -ENOMEM; - goto release_clock; - } - - dprintk("got video memory\n"); - - fbinfo->var.xres = display->xres; - fbinfo->var.yres = display->yres; - fbinfo->var.bits_per_pixel = display->bpp; - - s3c2410fb_init_registers(fbinfo); - - s3c2410fb_check_var(&fbinfo->var, fbinfo); - - ret = s3c2410fb_cpufreq_register(info); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to register cpufreq\n"); - goto free_video_memory; - } - - ret = register_framebuffer(fbinfo); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to register framebuffer device: %d\n", - ret); - goto free_cpufreq; - } - - /* create device files */ - ret = device_create_file(&pdev->dev, &dev_attr_debug); - if (ret) - dev_err(&pdev->dev, "failed to add debug attribute\n"); - - dev_info(&pdev->dev, "fb%d: %s frame buffer device\n", - fbinfo->node, fbinfo->fix.id); - - return 0; - - free_cpufreq: - s3c2410fb_cpufreq_deregister(info); -free_video_memory: - s3c2410fb_unmap_video_memory(fbinfo); -release_clock: - clk_disable_unprepare(info->clk); - clk_put(info->clk); -release_irq: - free_irq(irq, info); -release_regs: - iounmap(info->io); -release_mem: - release_mem_region(res->start, size); -dealloc_fb: - framebuffer_release(fbinfo); - return ret; -} - -static int s3c2410fb_probe(struct platform_device *pdev) -{ - return s3c24xxfb_probe(pdev, DRV_S3C2410); -} - -static int s3c2412fb_probe(struct platform_device *pdev) -{ - return s3c24xxfb_probe(pdev, DRV_S3C2412); -} - - -/* - * Cleanup - */ -static int s3c2410fb_remove(struct platform_device *pdev) -{ - struct fb_info *fbinfo = platform_get_drvdata(pdev); - struct s3c2410fb_info *info = fbinfo->par; - int irq; - - unregister_framebuffer(fbinfo); - s3c2410fb_cpufreq_deregister(info); - - s3c2410fb_lcd_enable(info, 0); - usleep_range(1000, 1100); - - s3c2410fb_unmap_video_memory(fbinfo); - - if (info->clk) { - clk_disable_unprepare(info->clk); - clk_put(info->clk); - info->clk = NULL; - } - - irq = platform_get_irq(pdev, 0); - free_irq(irq, info); - - iounmap(info->io); - - release_mem_region(info->mem->start, resource_size(info->mem)); - - framebuffer_release(fbinfo); - - return 0; -} - -#ifdef CONFIG_PM - -/* suspend and resume support for the lcd controller */ -static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state) -{ - struct fb_info *fbinfo = platform_get_drvdata(dev); - struct s3c2410fb_info *info = fbinfo->par; - - s3c2410fb_lcd_enable(info, 0); - - /* sleep before disabling the clock, we need to ensure - * the LCD DMA engine is not going to get back on the bus - * before the clock goes off again (bjd) */ - - usleep_range(1000, 1100); - clk_disable_unprepare(info->clk); - - return 0; -} - -static int s3c2410fb_resume(struct platform_device *dev) -{ - struct fb_info *fbinfo = platform_get_drvdata(dev); - struct s3c2410fb_info *info = fbinfo->par; - - clk_prepare_enable(info->clk); - usleep_range(1000, 1100); - - s3c2410fb_init_registers(fbinfo); - - /* re-activate our display after resume */ - s3c2410fb_activate_var(fbinfo); - s3c2410fb_blank(FB_BLANK_UNBLANK, fbinfo); - - return 0; -} - -#else -#define s3c2410fb_suspend NULL -#define s3c2410fb_resume NULL -#endif - -static struct platform_driver s3c2410fb_driver = { - .probe = s3c2410fb_probe, - .remove = s3c2410fb_remove, - .suspend = s3c2410fb_suspend, - .resume = s3c2410fb_resume, - .driver = { - .name = "s3c2410-lcd", - }, -}; - -static struct platform_driver s3c2412fb_driver = { - .probe = s3c2412fb_probe, - .remove = s3c2410fb_remove, - .suspend = s3c2410fb_suspend, - .resume = s3c2410fb_resume, - .driver = { - .name = "s3c2412-lcd", - }, -}; - -int __init s3c2410fb_init(void) -{ - int ret = platform_driver_register(&s3c2410fb_driver); - - if (ret == 0) - ret = platform_driver_register(&s3c2412fb_driver); - - return ret; -} - -static void __exit s3c2410fb_cleanup(void) -{ - platform_driver_unregister(&s3c2410fb_driver); - platform_driver_unregister(&s3c2412fb_driver); -} - -module_init(s3c2410fb_init); -module_exit(s3c2410fb_cleanup); - -MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); -MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>"); -MODULE_DESCRIPTION("Framebuffer driver for the s3c2410"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c2410-lcd"); -MODULE_ALIAS("platform:s3c2412-lcd"); diff --git a/drivers/video/fbdev/s3c2410fb.h b/drivers/video/fbdev/s3c2410fb.h deleted file mode 100644 index cdd11e2f8859..000000000000 --- a/drivers/video/fbdev/s3c2410fb.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * linux/drivers/video/s3c2410fb.h - * Copyright (c) 2004 Arnaud Patard - * - * S3C2410 LCD Framebuffer Driver - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * -*/ - -#ifndef __S3C2410FB_H -#define __S3C2410FB_H - -enum s3c_drv_type { - DRV_S3C2410, - DRV_S3C2412, -}; - -struct s3c2410fb_info { - struct device *dev; - struct clk *clk; - - struct resource *mem; - void __iomem *io; - void __iomem *irq_base; - - enum s3c_drv_type drv_type; - struct s3c2410fb_hw regs; - - unsigned long clk_rate; - unsigned int palette_ready; - -#ifdef CONFIG_ARM_S3C24XX_CPUFREQ - struct notifier_block freq_transition; -#endif - - /* keep these registers in case we need to re-write palette */ - u32 palette_buffer[256]; - u32 pseudo_pal[16]; -}; - -#define PALETTE_BUFF_CLEAR (0x80000000) /* entry is clear/invalid */ - -int s3c2410fb_init(void); - -#endif diff --git a/drivers/video/fbdev/sa1100fb.c b/drivers/video/fbdev/sa1100fb.c index 017c8efe8267..b1b8ccdbac4a 100644 --- a/drivers/video/fbdev/sa1100fb.c +++ b/drivers/video/fbdev/sa1100fb.c @@ -184,7 +184,6 @@ #include <mach/hardware.h> #include <asm/mach-types.h> -#include <mach/shannon.h> /* * Complain if VAR is out of range. diff --git a/drivers/video/fbdev/tmiofb.c b/drivers/video/fbdev/tmiofb.c deleted file mode 100644 index 50111966c981..000000000000 --- a/drivers/video/fbdev/tmiofb.c +++ /dev/null @@ -1,1040 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Frame Buffer Device for Toshiba Mobile IO(TMIO) controller - * - * Copyright(C) 2005-2006 Chris Humbert - * Copyright(C) 2005 Dirk Opfer - * Copytight(C) 2007,2008 Dmitry Baryshkov - * - * Based on: - * drivers/video/w100fb.c - * code written by Sharp/Lineo for 2.4 kernels - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/fb.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -/* Why should fb driver call console functions? because console_lock() */ -#include <linux/console.h> -#include <linux/mfd/core.h> -#include <linux/mfd/tmio.h> -#include <linux/uaccess.h> - -/* - * accelerator commands - */ -#define TMIOFB_ACC_CSADR(x) (0x00000000 | ((x) & 0x001ffffe)) -#define TMIOFB_ACC_CHPIX(x) (0x01000000 | ((x) & 0x000003ff)) -#define TMIOFB_ACC_CVPIX(x) (0x02000000 | ((x) & 0x000003ff)) -#define TMIOFB_ACC_PSADR(x) (0x03000000 | ((x) & 0x00fffffe)) -#define TMIOFB_ACC_PHPIX(x) (0x04000000 | ((x) & 0x000003ff)) -#define TMIOFB_ACC_PVPIX(x) (0x05000000 | ((x) & 0x000003ff)) -#define TMIOFB_ACC_PHOFS(x) (0x06000000 | ((x) & 0x000003ff)) -#define TMIOFB_ACC_PVOFS(x) (0x07000000 | ((x) & 0x000003ff)) -#define TMIOFB_ACC_POADR(x) (0x08000000 | ((x) & 0x00fffffe)) -#define TMIOFB_ACC_RSTR(x) (0x09000000 | ((x) & 0x000000ff)) -#define TMIOFB_ACC_TCLOR(x) (0x0A000000 | ((x) & 0x0000ffff)) -#define TMIOFB_ACC_FILL(x) (0x0B000000 | ((x) & 0x0000ffff)) -#define TMIOFB_ACC_DSADR(x) (0x0C000000 | ((x) & 0x00fffffe)) -#define TMIOFB_ACC_SSADR(x) (0x0D000000 | ((x) & 0x00fffffe)) -#define TMIOFB_ACC_DHPIX(x) (0x0E000000 | ((x) & 0x000003ff)) -#define TMIOFB_ACC_DVPIX(x) (0x0F000000 | ((x) & 0x000003ff)) -#define TMIOFB_ACC_SHPIX(x) (0x10000000 | ((x) & 0x000003ff)) -#define TMIOFB_ACC_SVPIX(x) (0x11000000 | ((x) & 0x000003ff)) -#define TMIOFB_ACC_LBINI(x) (0x12000000 | ((x) & 0x0000ffff)) -#define TMIOFB_ACC_LBK2(x) (0x13000000 | ((x) & 0x0000ffff)) -#define TMIOFB_ACC_SHBINI(x) (0x14000000 | ((x) & 0x0000ffff)) -#define TMIOFB_ACC_SHBK2(x) (0x15000000 | ((x) & 0x0000ffff)) -#define TMIOFB_ACC_SVBINI(x) (0x16000000 | ((x) & 0x0000ffff)) -#define TMIOFB_ACC_SVBK2(x) (0x17000000 | ((x) & 0x0000ffff)) - -#define TMIOFB_ACC_CMGO 0x20000000 -#define TMIOFB_ACC_CMGO_CEND 0x00000001 -#define TMIOFB_ACC_CMGO_INT 0x00000002 -#define TMIOFB_ACC_CMGO_CMOD 0x00000010 -#define TMIOFB_ACC_CMGO_CDVRV 0x00000020 -#define TMIOFB_ACC_CMGO_CDHRV 0x00000040 -#define TMIOFB_ACC_CMGO_RUND 0x00008000 -#define TMIOFB_ACC_SCGO 0x21000000 -#define TMIOFB_ACC_SCGO_CEND 0x00000001 -#define TMIOFB_ACC_SCGO_INT 0x00000002 -#define TMIOFB_ACC_SCGO_ROP3 0x00000004 -#define TMIOFB_ACC_SCGO_TRNS 0x00000008 -#define TMIOFB_ACC_SCGO_DVRV 0x00000010 -#define TMIOFB_ACC_SCGO_DHRV 0x00000020 -#define TMIOFB_ACC_SCGO_SVRV 0x00000040 -#define TMIOFB_ACC_SCGO_SHRV 0x00000080 -#define TMIOFB_ACC_SCGO_DSTXY 0x00008000 -#define TMIOFB_ACC_SBGO 0x22000000 -#define TMIOFB_ACC_SBGO_CEND 0x00000001 -#define TMIOFB_ACC_SBGO_INT 0x00000002 -#define TMIOFB_ACC_SBGO_DVRV 0x00000010 -#define TMIOFB_ACC_SBGO_DHRV 0x00000020 -#define TMIOFB_ACC_SBGO_SVRV 0x00000040 -#define TMIOFB_ACC_SBGO_SHRV 0x00000080 -#define TMIOFB_ACC_SBGO_SBMD 0x00000100 -#define TMIOFB_ACC_FLGO 0x23000000 -#define TMIOFB_ACC_FLGO_CEND 0x00000001 -#define TMIOFB_ACC_FLGO_INT 0x00000002 -#define TMIOFB_ACC_FLGO_ROP3 0x00000004 -#define TMIOFB_ACC_LDGO 0x24000000 -#define TMIOFB_ACC_LDGO_CEND 0x00000001 -#define TMIOFB_ACC_LDGO_INT 0x00000002 -#define TMIOFB_ACC_LDGO_ROP3 0x00000004 -#define TMIOFB_ACC_LDGO_ENDPX 0x00000008 -#define TMIOFB_ACC_LDGO_LVRV 0x00000010 -#define TMIOFB_ACC_LDGO_LHRV 0x00000020 -#define TMIOFB_ACC_LDGO_LDMOD 0x00000040 - -/* a FIFO is always allocated, even if acceleration is not used */ -#define TMIOFB_FIFO_SIZE 512 - -/* - * LCD Host Controller Configuration Register - * - * This iomem area supports only 16-bit IO. - */ -#define CCR_CMD 0x04 /* Command */ -#define CCR_REVID 0x08 /* Revision ID */ -#define CCR_BASEL 0x10 /* LCD Control Reg Base Addr Low */ -#define CCR_BASEH 0x12 /* LCD Control Reg Base Addr High */ -#define CCR_UGCC 0x40 /* Unified Gated Clock Control */ -#define CCR_GCC 0x42 /* Gated Clock Control */ -#define CCR_USC 0x50 /* Unified Software Clear */ -#define CCR_VRAMRTC 0x60 /* VRAM Timing Control */ - /* 0x61 VRAM Refresh Control */ -#define CCR_VRAMSAC 0x62 /* VRAM Access Control */ - /* 0x63 VRAM Status */ -#define CCR_VRAMBC 0x64 /* VRAM Block Control */ - -/* - * LCD Control Register - * - * This iomem area supports only 16-bit IO. - */ -#define LCR_UIS 0x000 /* Unified Interrupt Status */ -#define LCR_VHPN 0x008 /* VRAM Horizontal Pixel Number */ -#define LCR_CFSAL 0x00a /* Command FIFO Start Address Low */ -#define LCR_CFSAH 0x00c /* Command FIFO Start Address High */ -#define LCR_CFS 0x00e /* Command FIFO Size */ -#define LCR_CFWS 0x010 /* Command FIFO Writeable Size */ -#define LCR_BBIE 0x012 /* BitBLT Interrupt Enable */ -#define LCR_BBISC 0x014 /* BitBLT Interrupt Status and Clear */ -#define LCR_CCS 0x016 /* Command Count Status */ -#define LCR_BBES 0x018 /* BitBLT Execution Status */ -#define LCR_CMDL 0x01c /* Command Low */ -#define LCR_CMDH 0x01e /* Command High */ -#define LCR_CFC 0x022 /* Command FIFO Clear */ -#define LCR_CCIFC 0x024 /* CMOS Camera IF Control */ -#define LCR_HWT 0x026 /* Hardware Test */ -#define LCR_LCDCCRC 0x100 /* LCDC Clock and Reset Control */ -#define LCR_LCDCC 0x102 /* LCDC Control */ -#define LCR_LCDCOPC 0x104 /* LCDC Output Pin Control */ -#define LCR_LCDIS 0x108 /* LCD Interrupt Status */ -#define LCR_LCDIM 0x10a /* LCD Interrupt Mask */ -#define LCR_LCDIE 0x10c /* LCD Interrupt Enable */ -#define LCR_GDSAL 0x122 /* Graphics Display Start Address Low */ -#define LCR_GDSAH 0x124 /* Graphics Display Start Address High */ -#define LCR_VHPCL 0x12a /* VRAM Horizontal Pixel Count Low */ -#define LCR_VHPCH 0x12c /* VRAM Horizontal Pixel Count High */ -#define LCR_GM 0x12e /* Graphic Mode(VRAM access enable) */ -#define LCR_HT 0x140 /* Horizontal Total */ -#define LCR_HDS 0x142 /* Horizontal Display Start */ -#define LCR_HSS 0x144 /* H-Sync Start */ -#define LCR_HSE 0x146 /* H-Sync End */ -#define LCR_HNP 0x14c /* Horizontal Number of Pixels */ -#define LCR_VT 0x150 /* Vertical Total */ -#define LCR_VDS 0x152 /* Vertical Display Start */ -#define LCR_VSS 0x154 /* V-Sync Start */ -#define LCR_VSE 0x156 /* V-Sync End */ -#define LCR_CDLN 0x160 /* Current Display Line Number */ -#define LCR_ILN 0x162 /* Interrupt Line Number */ -#define LCR_SP 0x164 /* Sync Polarity */ -#define LCR_MISC 0x166 /* MISC(RGB565 mode) */ -#define LCR_VIHSS 0x16a /* Video Interface H-Sync Start */ -#define LCR_VIVS 0x16c /* Video Interface Vertical Start */ -#define LCR_VIVE 0x16e /* Video Interface Vertical End */ -#define LCR_VIVSS 0x170 /* Video Interface V-Sync Start */ -#define LCR_VCCIS 0x17e /* Video / CMOS Camera Interface Select */ -#define LCR_VIDWSAL 0x180 /* VI Data Write Start Address Low */ -#define LCR_VIDWSAH 0x182 /* VI Data Write Start Address High */ -#define LCR_VIDRSAL 0x184 /* VI Data Read Start Address Low */ -#define LCR_VIDRSAH 0x186 /* VI Data Read Start Address High */ -#define LCR_VIPDDST 0x188 /* VI Picture Data Display Start Timing */ -#define LCR_VIPDDET 0x186 /* VI Picture Data Display End Timing */ -#define LCR_VIE 0x18c /* Video Interface Enable */ -#define LCR_VCS 0x18e /* Video/Camera Select */ -#define LCR_VPHWC 0x194 /* Video Picture Horizontal Wait Count */ -#define LCR_VPHS 0x196 /* Video Picture Horizontal Size */ -#define LCR_VPVWC 0x198 /* Video Picture Vertical Wait Count */ -#define LCR_VPVS 0x19a /* Video Picture Vertical Size */ -#define LCR_PLHPIX 0x1a0 /* PLHPIX */ -#define LCR_XS 0x1a2 /* XStart */ -#define LCR_XCKHW 0x1a4 /* XCK High Width */ -#define LCR_STHS 0x1a8 /* STH Start */ -#define LCR_VT2 0x1aa /* Vertical Total */ -#define LCR_YCKSW 0x1ac /* YCK Start Wait */ -#define LCR_YSTS 0x1ae /* YST Start */ -#define LCR_PPOLS 0x1b0 /* #PPOL Start */ -#define LCR_PRECW 0x1b2 /* PREC Width */ -#define LCR_VCLKHW 0x1b4 /* VCLK High Width */ -#define LCR_OC 0x1b6 /* Output Control */ - -static char *mode_option; - -struct tmiofb_par { - u32 pseudo_palette[16]; - -#ifdef CONFIG_FB_TMIO_ACCELL - wait_queue_head_t wait_acc; - bool use_polling; -#endif - - void __iomem *ccr; - void __iomem *lcr; -}; - -/*--------------------------------------------------------------------------*/ - -/* - * reasons for an interrupt: - * uis bbisc lcdis - * 0100 0001 accelerator command completed - * 2000 0001 vsync start - * 2000 0002 display start - * 2000 0004 line number match(0x1ff mask???) - */ -static irqreturn_t tmiofb_irq(int irq, void *__info) -{ - struct fb_info *info = __info; - struct tmiofb_par *par = info->par; - unsigned int bbisc = tmio_ioread16(par->lcr + LCR_BBISC); - - - tmio_iowrite16(bbisc, par->lcr + LCR_BBISC); - -#ifdef CONFIG_FB_TMIO_ACCELL - /* - * We were in polling mode and now we got correct irq. - * Switch back to IRQ-based sync of command FIFO - */ - if (unlikely(par->use_polling && irq != -1)) { - printk(KERN_INFO "tmiofb: switching to waitq\n"); - par->use_polling = false; - } - - if (bbisc & 1) - wake_up(&par->wait_acc); -#endif - - return IRQ_HANDLED; -} - - -/*--------------------------------------------------------------------------*/ - - -/* - * Turns off the LCD controller and LCD host controller. - */ -static int tmiofb_hw_stop(struct platform_device *dev) -{ - struct tmio_fb_data *data = dev_get_platdata(&dev->dev); - struct fb_info *info = platform_get_drvdata(dev); - struct tmiofb_par *par = info->par; - - tmio_iowrite16(0, par->ccr + CCR_UGCC); - tmio_iowrite16(0, par->lcr + LCR_GM); - data->lcd_set_power(dev, 0); - tmio_iowrite16(0x0010, par->lcr + LCR_LCDCCRC); - - return 0; -} - -/* - * Initializes the LCD host controller. - */ -static int tmiofb_hw_init(struct platform_device *dev) -{ - const struct mfd_cell *cell = mfd_get_cell(dev); - struct fb_info *info = platform_get_drvdata(dev); - struct tmiofb_par *par = info->par; - const struct resource *nlcr = &cell->resources[0]; - const struct resource *vram = &cell->resources[2]; - unsigned long base; - - if (nlcr == NULL || vram == NULL) - return -EINVAL; - - base = nlcr->start; - - tmio_iowrite16(0x003a, par->ccr + CCR_UGCC); - tmio_iowrite16(0x003a, par->ccr + CCR_GCC); - tmio_iowrite16(0x3f00, par->ccr + CCR_USC); - - msleep(2); /* wait for device to settle */ - - tmio_iowrite16(0x0000, par->ccr + CCR_USC); - tmio_iowrite16(base >> 16, par->ccr + CCR_BASEH); - tmio_iowrite16(base, par->ccr + CCR_BASEL); - tmio_iowrite16(0x0002, par->ccr + CCR_CMD); /* base address enable */ - tmio_iowrite16(0x40a8, par->ccr + CCR_VRAMRTC); /* VRAMRC, VRAMTC */ - tmio_iowrite16(0x0018, par->ccr + CCR_VRAMSAC); /* VRAMSTS, VRAMAC */ - tmio_iowrite16(0x0002, par->ccr + CCR_VRAMBC); - msleep(2); /* wait for device to settle */ - tmio_iowrite16(0x000b, par->ccr + CCR_VRAMBC); - - base = vram->start + info->screen_size; - tmio_iowrite16(base >> 16, par->lcr + LCR_CFSAH); - tmio_iowrite16(base, par->lcr + LCR_CFSAL); - tmio_iowrite16(TMIOFB_FIFO_SIZE - 1, par->lcr + LCR_CFS); - tmio_iowrite16(1, par->lcr + LCR_CFC); - tmio_iowrite16(1, par->lcr + LCR_BBIE); - tmio_iowrite16(0, par->lcr + LCR_CFWS); - - return 0; -} - -/* - * Sets the LCD controller's output resolution and pixel clock - */ -static void tmiofb_hw_mode(struct platform_device *dev) -{ - struct tmio_fb_data *data = dev_get_platdata(&dev->dev); - struct fb_info *info = platform_get_drvdata(dev); - struct fb_videomode *mode = info->mode; - struct tmiofb_par *par = info->par; - unsigned int i; - - tmio_iowrite16(0, par->lcr + LCR_GM); - data->lcd_set_power(dev, 0); - tmio_iowrite16(0x0010, par->lcr + LCR_LCDCCRC); - data->lcd_mode(dev, mode); - data->lcd_set_power(dev, 1); - - tmio_iowrite16(info->fix.line_length, par->lcr + LCR_VHPN); - tmio_iowrite16(0, par->lcr + LCR_GDSAH); - tmio_iowrite16(0, par->lcr + LCR_GDSAL); - tmio_iowrite16(info->fix.line_length >> 16, par->lcr + LCR_VHPCH); - tmio_iowrite16(info->fix.line_length, par->lcr + LCR_VHPCL); - tmio_iowrite16(i = 0, par->lcr + LCR_HSS); - tmio_iowrite16(i += mode->hsync_len, par->lcr + LCR_HSE); - tmio_iowrite16(i += mode->left_margin, par->lcr + LCR_HDS); - tmio_iowrite16(i += mode->xres + mode->right_margin, par->lcr + LCR_HT); - tmio_iowrite16(mode->xres, par->lcr + LCR_HNP); - tmio_iowrite16(i = 0, par->lcr + LCR_VSS); - tmio_iowrite16(i += mode->vsync_len, par->lcr + LCR_VSE); - tmio_iowrite16(i += mode->upper_margin, par->lcr + LCR_VDS); - tmio_iowrite16(i += mode->yres, par->lcr + LCR_ILN); - tmio_iowrite16(i += mode->lower_margin, par->lcr + LCR_VT); - tmio_iowrite16(3, par->lcr + LCR_MISC); /* RGB565 mode */ - tmio_iowrite16(1, par->lcr + LCR_GM); /* VRAM enable */ - tmio_iowrite16(0x4007, par->lcr + LCR_LCDCC); - tmio_iowrite16(3, par->lcr + LCR_SP); /* sync polarity */ - - tmio_iowrite16(0x0010, par->lcr + LCR_LCDCCRC); - msleep(5); /* wait for device to settle */ - tmio_iowrite16(0x0014, par->lcr + LCR_LCDCCRC); /* STOP_CKP */ - msleep(5); /* wait for device to settle */ - tmio_iowrite16(0x0015, par->lcr + LCR_LCDCCRC); /* STOP_CKP|SOFT_RESET*/ - tmio_iowrite16(0xfffa, par->lcr + LCR_VCS); -} - -/*--------------------------------------------------------------------------*/ - -#ifdef CONFIG_FB_TMIO_ACCELL -static int __must_check -tmiofb_acc_wait(struct fb_info *info, unsigned int ccs) -{ - struct tmiofb_par *par = info->par; - /* - * This code can be called with interrupts disabled. - * So instead of relaying on irq to trigger the event, - * poll the state till the necessary command is executed. - */ - if (irqs_disabled() || par->use_polling) { - int i = 0; - while (tmio_ioread16(par->lcr + LCR_CCS) > ccs) { - udelay(1); - i++; - if (i > 10000) { - pr_err("tmiofb: timeout waiting for %d\n", - ccs); - return -ETIMEDOUT; - } - tmiofb_irq(-1, info); - } - } else { - if (!wait_event_interruptible_timeout(par->wait_acc, - tmio_ioread16(par->lcr + LCR_CCS) <= ccs, - 1000)) { - pr_err("tmiofb: timeout waiting for %d\n", ccs); - return -ETIMEDOUT; - } - } - - return 0; -} - -/* - * Writes an accelerator command to the accelerator's FIFO. - */ -static int -tmiofb_acc_write(struct fb_info *info, const u32 *cmd, unsigned int count) -{ - struct tmiofb_par *par = info->par; - int ret; - - ret = tmiofb_acc_wait(info, TMIOFB_FIFO_SIZE - count); - if (ret) - return ret; - - for (; count; count--, cmd++) { - tmio_iowrite16(*cmd >> 16, par->lcr + LCR_CMDH); - tmio_iowrite16(*cmd, par->lcr + LCR_CMDL); - } - - return ret; -} - -/* - * Wait for the accelerator to finish its operations before writing - * to the framebuffer for consistent display output. - */ -static int tmiofb_sync(struct fb_info *fbi) -{ - struct tmiofb_par *par = fbi->par; - - int ret; - int i = 0; - - ret = tmiofb_acc_wait(fbi, 0); - - while (tmio_ioread16(par->lcr + LCR_BBES) & 2) { /* blit active */ - udelay(1); - i++ ; - if (i > 10000) { - printk(KERN_ERR "timeout waiting for blit to end!\n"); - return -ETIMEDOUT; - } - } - - return ret; -} - -static void -tmiofb_fillrect(struct fb_info *fbi, const struct fb_fillrect *rect) -{ - const u32 cmd[] = { - TMIOFB_ACC_DSADR((rect->dy * fbi->mode->xres + rect->dx) * 2), - TMIOFB_ACC_DHPIX(rect->width - 1), - TMIOFB_ACC_DVPIX(rect->height - 1), - TMIOFB_ACC_FILL(rect->color), - TMIOFB_ACC_FLGO, - }; - - if (fbi->state != FBINFO_STATE_RUNNING || - fbi->flags & FBINFO_HWACCEL_DISABLED) { - cfb_fillrect(fbi, rect); - return; - } - - tmiofb_acc_write(fbi, cmd, ARRAY_SIZE(cmd)); -} - -static void -tmiofb_copyarea(struct fb_info *fbi, const struct fb_copyarea *area) -{ - const u32 cmd[] = { - TMIOFB_ACC_DSADR((area->dy * fbi->mode->xres + area->dx) * 2), - TMIOFB_ACC_DHPIX(area->width - 1), - TMIOFB_ACC_DVPIX(area->height - 1), - TMIOFB_ACC_SSADR((area->sy * fbi->mode->xres + area->sx) * 2), - TMIOFB_ACC_SCGO, - }; - - if (fbi->state != FBINFO_STATE_RUNNING || - fbi->flags & FBINFO_HWACCEL_DISABLED) { - cfb_copyarea(fbi, area); - return; - } - - tmiofb_acc_write(fbi, cmd, ARRAY_SIZE(cmd)); -} -#endif - -static void tmiofb_clearscreen(struct fb_info *info) -{ - const struct fb_fillrect rect = { - .dx = 0, - .dy = 0, - .width = info->mode->xres, - .height = info->mode->yres, - .color = 0, - .rop = ROP_COPY, - }; - - info->fbops->fb_fillrect(info, &rect); -} - -static int tmiofb_vblank(struct fb_info *fbi, struct fb_vblank *vblank) -{ - struct tmiofb_par *par = fbi->par; - struct fb_videomode *mode = fbi->mode; - unsigned int vcount = tmio_ioread16(par->lcr + LCR_CDLN); - unsigned int vds = mode->vsync_len + mode->upper_margin; - - vblank->vcount = vcount; - vblank->flags = FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_VCOUNT - | FB_VBLANK_HAVE_VSYNC; - - if (vcount < mode->vsync_len) - vblank->flags |= FB_VBLANK_VSYNCING; - - if (vcount < vds || vcount > vds + mode->yres) - vblank->flags |= FB_VBLANK_VBLANKING; - - return 0; -} - - -static int tmiofb_ioctl(struct fb_info *fbi, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case FBIOGET_VBLANK: { - struct fb_vblank vblank = {0}; - void __user *argp = (void __user *) arg; - - tmiofb_vblank(fbi, &vblank); - if (copy_to_user(argp, &vblank, sizeof vblank)) - return -EFAULT; - return 0; - } - -#ifdef CONFIG_FB_TMIO_ACCELL - case FBIO_TMIO_ACC_SYNC: - tmiofb_sync(fbi); - return 0; - - case FBIO_TMIO_ACC_WRITE: { - u32 __user *argp = (void __user *) arg; - u32 len; - u32 acc[16]; - - if (get_user(len, argp)) - return -EFAULT; - if (len > ARRAY_SIZE(acc)) - return -EINVAL; - if (copy_from_user(acc, argp + 1, sizeof(u32) * len)) - return -EFAULT; - - return tmiofb_acc_write(fbi, acc, len); - } -#endif - } - - return -ENOTTY; -} - -/*--------------------------------------------------------------------------*/ - -/* Select the smallest mode that allows the desired resolution to be - * displayed. If desired, the x and y parameters can be rounded up to - * match the selected mode. - */ -static struct fb_videomode * -tmiofb_find_mode(struct fb_info *info, struct fb_var_screeninfo *var) -{ - struct tmio_fb_data *data = dev_get_platdata(info->device); - struct fb_videomode *best = NULL; - int i; - - for (i = 0; i < data->num_modes; i++) { - struct fb_videomode *mode = data->modes + i; - - if (mode->xres >= var->xres && mode->yres >= var->yres - && (!best || (mode->xres < best->xres - && mode->yres < best->yres))) - best = mode; - } - - return best; -} - -static int tmiofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -{ - - struct fb_videomode *mode; - struct tmio_fb_data *data = dev_get_platdata(info->device); - - mode = tmiofb_find_mode(info, var); - if (!mode || var->bits_per_pixel > 16) - return -EINVAL; - - fb_videomode_to_var(var, mode); - - var->xres_virtual = mode->xres; - var->yres_virtual = info->screen_size / (mode->xres * 2); - - if (var->yres_virtual < var->yres) - return -EINVAL; - - var->xoffset = 0; - var->yoffset = 0; - var->bits_per_pixel = 16; - var->grayscale = 0; - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - var->nonstd = 0; - var->height = data->height; /* mm */ - var->width = data->width; /* mm */ - var->rotate = 0; - return 0; -} - -static int tmiofb_set_par(struct fb_info *info) -{ - struct fb_var_screeninfo *var = &info->var; - struct fb_videomode *mode; - - mode = tmiofb_find_mode(info, var); - if (!mode) - return -EINVAL; - - info->mode = mode; - info->fix.line_length = info->mode->xres * - var->bits_per_pixel / 8; - - tmiofb_hw_mode(to_platform_device(info->device)); - tmiofb_clearscreen(info); - return 0; -} - -static int tmiofb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) -{ - struct tmiofb_par *par = info->par; - - if (regno < ARRAY_SIZE(par->pseudo_palette)) { - par->pseudo_palette[regno] = - ((red & 0xf800)) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - return 0; - } - - return -EINVAL; -} - -static int tmiofb_blank(int blank, struct fb_info *info) -{ - /* - * everything is done in lcd/bl drivers. - * this is purely to make sysfs happy and work. - */ - return 0; -} - -static const struct fb_ops tmiofb_ops = { - .owner = THIS_MODULE, - - .fb_ioctl = tmiofb_ioctl, - .fb_check_var = tmiofb_check_var, - .fb_set_par = tmiofb_set_par, - .fb_setcolreg = tmiofb_setcolreg, - .fb_blank = tmiofb_blank, - .fb_imageblit = cfb_imageblit, -#ifdef CONFIG_FB_TMIO_ACCELL - .fb_sync = tmiofb_sync, - .fb_fillrect = tmiofb_fillrect, - .fb_copyarea = tmiofb_copyarea, -#else - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, -#endif -}; - -/*--------------------------------------------------------------------------*/ - -static int tmiofb_probe(struct platform_device *dev) -{ - const struct mfd_cell *cell = mfd_get_cell(dev); - struct tmio_fb_data *data = dev_get_platdata(&dev->dev); - struct resource *ccr = platform_get_resource(dev, IORESOURCE_MEM, 1); - struct resource *lcr = platform_get_resource(dev, IORESOURCE_MEM, 0); - struct resource *vram = platform_get_resource(dev, IORESOURCE_MEM, 2); - int irq = platform_get_irq(dev, 0); - struct fb_info *info; - struct tmiofb_par *par; - int retval; - - /* - * This is the only way ATM to disable the fb - */ - if (data == NULL) { - dev_err(&dev->dev, "NULL platform data!\n"); - return -EINVAL; - } - if (ccr == NULL || lcr == NULL || vram == NULL || irq < 0) { - dev_err(&dev->dev, "missing resources\n"); - return -EINVAL; - } - - info = framebuffer_alloc(sizeof(struct tmiofb_par), &dev->dev); - - if (!info) - return -ENOMEM; - - par = info->par; - -#ifdef CONFIG_FB_TMIO_ACCELL - init_waitqueue_head(&par->wait_acc); - - par->use_polling = true; - - info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA - | FBINFO_HWACCEL_FILLRECT; -#else - info->flags = FBINFO_DEFAULT; -#endif - - info->fbops = &tmiofb_ops; - - strcpy(info->fix.id, "tmio-fb"); - info->fix.smem_start = vram->start; - info->fix.smem_len = resource_size(vram); - info->fix.type = FB_TYPE_PACKED_PIXELS; - info->fix.visual = FB_VISUAL_TRUECOLOR; - info->fix.mmio_start = lcr->start; - info->fix.mmio_len = resource_size(lcr); - info->fix.accel = FB_ACCEL_NONE; - info->screen_size = info->fix.smem_len - (4 * TMIOFB_FIFO_SIZE); - info->pseudo_palette = par->pseudo_palette; - - par->ccr = ioremap(ccr->start, resource_size(ccr)); - if (!par->ccr) { - retval = -ENOMEM; - goto err_ioremap_ccr; - } - - par->lcr = ioremap(info->fix.mmio_start, info->fix.mmio_len); - if (!par->lcr) { - retval = -ENOMEM; - goto err_ioremap_lcr; - } - - info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); - if (!info->screen_base) { - retval = -ENOMEM; - goto err_ioremap_vram; - } - - retval = request_irq(irq, &tmiofb_irq, 0, - dev_name(&dev->dev), info); - - if (retval) - goto err_request_irq; - - platform_set_drvdata(dev, info); - - retval = fb_find_mode(&info->var, info, mode_option, - data->modes, data->num_modes, - data->modes, 16); - if (!retval) { - retval = -EINVAL; - goto err_find_mode; - } - - if (cell->enable) { - retval = cell->enable(dev); - if (retval) - goto err_enable; - } - - retval = tmiofb_hw_init(dev); - if (retval) - goto err_hw_init; - - fb_videomode_to_modelist(data->modes, data->num_modes, - &info->modelist); - - retval = register_framebuffer(info); - if (retval < 0) - goto err_register_framebuffer; - - fb_info(info, "%s frame buffer device\n", info->fix.id); - - return 0; - -err_register_framebuffer: -/*err_set_par:*/ - tmiofb_hw_stop(dev); -err_hw_init: - if (cell->disable) - cell->disable(dev); -err_enable: -err_find_mode: - free_irq(irq, info); -err_request_irq: - iounmap(info->screen_base); -err_ioremap_vram: - iounmap(par->lcr); -err_ioremap_lcr: - iounmap(par->ccr); -err_ioremap_ccr: - framebuffer_release(info); - return retval; -} - -static int tmiofb_remove(struct platform_device *dev) -{ - const struct mfd_cell *cell = mfd_get_cell(dev); - struct fb_info *info = platform_get_drvdata(dev); - int irq = platform_get_irq(dev, 0); - struct tmiofb_par *par; - - if (info) { - par = info->par; - unregister_framebuffer(info); - - tmiofb_hw_stop(dev); - - if (cell->disable) - cell->disable(dev); - - free_irq(irq, info); - - iounmap(info->screen_base); - iounmap(par->lcr); - iounmap(par->ccr); - - framebuffer_release(info); - } - - return 0; -} - -#ifdef DEBUG -static void tmiofb_dump_regs(struct platform_device *dev) -{ - struct fb_info *info = platform_get_drvdata(dev); - struct tmiofb_par *par = info->par; - - printk(KERN_DEBUG "lhccr:\n"); -#define CCR_PR(n) printk(KERN_DEBUG "\t" #n " = \t%04x\n",\ - tmio_ioread16(par->ccr + CCR_ ## n)); - CCR_PR(CMD); - CCR_PR(REVID); - CCR_PR(BASEL); - CCR_PR(BASEH); - CCR_PR(UGCC); - CCR_PR(GCC); - CCR_PR(USC); - CCR_PR(VRAMRTC); - CCR_PR(VRAMSAC); - CCR_PR(VRAMBC); -#undef CCR_PR - - printk(KERN_DEBUG "lcr: \n"); -#define LCR_PR(n) printk(KERN_DEBUG "\t" #n " = \t%04x\n",\ - tmio_ioread16(par->lcr + LCR_ ## n)); - LCR_PR(UIS); - LCR_PR(VHPN); - LCR_PR(CFSAL); - LCR_PR(CFSAH); - LCR_PR(CFS); - LCR_PR(CFWS); - LCR_PR(BBIE); - LCR_PR(BBISC); - LCR_PR(CCS); - LCR_PR(BBES); - LCR_PR(CMDL); - LCR_PR(CMDH); - LCR_PR(CFC); - LCR_PR(CCIFC); - LCR_PR(HWT); - LCR_PR(LCDCCRC); - LCR_PR(LCDCC); - LCR_PR(LCDCOPC); - LCR_PR(LCDIS); - LCR_PR(LCDIM); - LCR_PR(LCDIE); - LCR_PR(GDSAL); - LCR_PR(GDSAH); - LCR_PR(VHPCL); - LCR_PR(VHPCH); - LCR_PR(GM); - LCR_PR(HT); - LCR_PR(HDS); - LCR_PR(HSS); - LCR_PR(HSE); - LCR_PR(HNP); - LCR_PR(VT); - LCR_PR(VDS); - LCR_PR(VSS); - LCR_PR(VSE); - LCR_PR(CDLN); - LCR_PR(ILN); - LCR_PR(SP); - LCR_PR(MISC); - LCR_PR(VIHSS); - LCR_PR(VIVS); - LCR_PR(VIVE); - LCR_PR(VIVSS); - LCR_PR(VCCIS); - LCR_PR(VIDWSAL); - LCR_PR(VIDWSAH); - LCR_PR(VIDRSAL); - LCR_PR(VIDRSAH); - LCR_PR(VIPDDST); - LCR_PR(VIPDDET); - LCR_PR(VIE); - LCR_PR(VCS); - LCR_PR(VPHWC); - LCR_PR(VPHS); - LCR_PR(VPVWC); - LCR_PR(VPVS); - LCR_PR(PLHPIX); - LCR_PR(XS); - LCR_PR(XCKHW); - LCR_PR(STHS); - LCR_PR(VT2); - LCR_PR(YCKSW); - LCR_PR(YSTS); - LCR_PR(PPOLS); - LCR_PR(PRECW); - LCR_PR(VCLKHW); - LCR_PR(OC); -#undef LCR_PR -} -#endif - -#ifdef CONFIG_PM -static int tmiofb_suspend(struct platform_device *dev, pm_message_t state) -{ - struct fb_info *info = platform_get_drvdata(dev); -#ifdef CONFIG_FB_TMIO_ACCELL - struct tmiofb_par *par = info->par; -#endif - const struct mfd_cell *cell = mfd_get_cell(dev); - int retval = 0; - - console_lock(); - - fb_set_suspend(info, 1); - - if (info->fbops->fb_sync) - info->fbops->fb_sync(info); - - -#ifdef CONFIG_FB_TMIO_ACCELL - /* - * The fb should be usable even if interrupts are disabled (and they are - * during suspend/resume). Switch temporary to forced polling. - */ - printk(KERN_INFO "tmiofb: switching to polling\n"); - par->use_polling = true; -#endif - tmiofb_hw_stop(dev); - - if (cell->suspend) - retval = cell->suspend(dev); - - console_unlock(); - - return retval; -} - -static int tmiofb_resume(struct platform_device *dev) -{ - struct fb_info *info = platform_get_drvdata(dev); - const struct mfd_cell *cell = mfd_get_cell(dev); - int retval = 0; - - console_lock(); - - if (cell->resume) { - retval = cell->resume(dev); - if (retval) - goto out; - } - - tmiofb_irq(-1, info); - - tmiofb_hw_init(dev); - - tmiofb_hw_mode(dev); - - fb_set_suspend(info, 0); -out: - console_unlock(); - return retval; -} -#else -#define tmiofb_suspend NULL -#define tmiofb_resume NULL -#endif - -static struct platform_driver tmiofb_driver = { - .driver.name = "tmio-fb", - .driver.owner = THIS_MODULE, - .probe = tmiofb_probe, - .remove = tmiofb_remove, - .suspend = tmiofb_suspend, - .resume = tmiofb_resume, -}; - -/*--------------------------------------------------------------------------*/ - -#ifndef MODULE -static void __init tmiofb_setup(char *options) -{ - char *this_opt; - - if (!options || !*options) - return; - - while ((this_opt = strsep(&options, ",")) != NULL) { - if (!*this_opt) - continue; - /* - * FIXME - */ - } -} -#endif - -static int __init tmiofb_init(void) -{ -#ifndef MODULE - char *option = NULL; - - if (fb_get_options("tmiofb", &option)) - return -ENODEV; - tmiofb_setup(option); -#endif - return platform_driver_register(&tmiofb_driver); -} - -static void __exit tmiofb_cleanup(void) -{ - platform_driver_unregister(&tmiofb_driver); -} - -module_init(tmiofb_init); -module_exit(tmiofb_cleanup); - -MODULE_DESCRIPTION("TMIO framebuffer driver"); -MODULE_AUTHOR("Chris Humbert, Dirk Opfer, Dmitry Baryshkov"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/w100fb.c b/drivers/video/fbdev/w100fb.c deleted file mode 100644 index 4e641a780726..000000000000 --- a/drivers/video/fbdev/w100fb.c +++ /dev/null @@ -1,1644 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/drivers/video/w100fb.c - * - * Frame Buffer Device for ATI Imageon w100 (Wallaby) - * - * Copyright (C) 2002, ATI Corp. - * Copyright (C) 2004-2006 Richard Purdie - * Copyright (c) 2005 Ian Molton - * Copyright (c) 2006 Alberto Mardegan - * - * Rewritten for 2.6 by Richard Purdie <rpurdie@rpsys.net> - * - * Generic platform support by Ian Molton <spyro@f2s.com> - * and Richard Purdie <rpurdie@rpsys.net> - * - * w32xx support by Ian Molton - * - * Hardware acceleration support by Alberto Mardegan - * <mardy@users.sourceforge.net> - */ - -#include <linux/delay.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/vmalloc.h> -#include <linux/module.h> -#include <asm/io.h> -#include <linux/uaccess.h> -#include <video/w100fb.h> -#include "w100fb.h" - -/* - * Prototypes - */ -static void w100_suspend(u32 mode); -static void w100_vsync(void); -static void w100_hw_init(struct w100fb_par*); -static void w100_pwm_setup(struct w100fb_par*); -static void w100_init_clocks(struct w100fb_par*); -static void w100_setup_memory(struct w100fb_par*); -static void w100_init_lcd(struct w100fb_par*); -static void w100_set_dispregs(struct w100fb_par*); -static void w100_update_enable(void); -static void w100_update_disable(void); -static void calc_hsync(struct w100fb_par *par); -static void w100_init_graphic_engine(struct w100fb_par *par); -struct w100_pll_info *w100_get_xtal_table(unsigned int freq); - -/* Pseudo palette size */ -#define MAX_PALETTES 16 - -#define W100_SUSPEND_EXTMEM 0 -#define W100_SUSPEND_ALL 1 - -#define BITS_PER_PIXEL 16 - -/* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */ -static void __iomem *remapped_base; -static void __iomem *remapped_regs; -static void __iomem *remapped_fbuf; - -#define REMAPPED_FB_LEN 0x15ffff - -/* This is the offset in the w100's address space we map the current - framebuffer memory to. We use the position of external memory as - we can remap internal memory to there if external isn't present. */ -#define W100_FB_BASE MEM_EXT_BASE_VALUE - - -/* - * Sysfs functions - */ -static ssize_t flip_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct fb_info *info = dev_get_drvdata(dev); - struct w100fb_par *par=info->par; - - return sprintf(buf, "%d\n",par->flip); -} - -static ssize_t flip_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned int flip; - struct fb_info *info = dev_get_drvdata(dev); - struct w100fb_par *par=info->par; - - flip = simple_strtoul(buf, NULL, 10); - - if (flip > 0) - par->flip = 1; - else - par->flip = 0; - - w100_update_disable(); - w100_set_dispregs(par); - w100_update_enable(); - - calc_hsync(par); - - return count; -} - -static DEVICE_ATTR_RW(flip); - -static ssize_t w100fb_reg_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned long regs, param; - regs = simple_strtoul(buf, NULL, 16); - param = readl(remapped_regs + regs); - printk("Read Register 0x%08lX: 0x%08lX\n", regs, param); - return count; -} - -static DEVICE_ATTR(reg_read, 0200, NULL, w100fb_reg_read); - -static ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned long regs, param; - sscanf(buf, "%lx %lx", ®s, ¶m); - - if (regs <= 0x2000) { - printk("Write Register 0x%08lX: 0x%08lX\n", regs, param); - writel(param, remapped_regs + regs); - } - - return count; -} - -static DEVICE_ATTR(reg_write, 0200, NULL, w100fb_reg_write); - - -static ssize_t fastpllclk_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct fb_info *info = dev_get_drvdata(dev); - struct w100fb_par *par=info->par; - - return sprintf(buf, "%d\n",par->fastpll_mode); -} - -static ssize_t fastpllclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct fb_info *info = dev_get_drvdata(dev); - struct w100fb_par *par=info->par; - - if (simple_strtoul(buf, NULL, 10) > 0) { - par->fastpll_mode=1; - printk("w100fb: Using fast system clock (if possible)\n"); - } else { - par->fastpll_mode=0; - printk("w100fb: Using normal system clock\n"); - } - - w100_init_clocks(par); - calc_hsync(par); - - return count; -} - -static DEVICE_ATTR_RW(fastpllclk); - -static struct attribute *w100fb_attrs[] = { - &dev_attr_fastpllclk.attr, - &dev_attr_reg_read.attr, - &dev_attr_reg_write.attr, - &dev_attr_flip.attr, - NULL, -}; -ATTRIBUTE_GROUPS(w100fb); - -/* - * Some touchscreens need hsync information from the video driver to - * function correctly. We export it here. - */ -unsigned long w100fb_get_hsynclen(struct device *dev) -{ - struct fb_info *info = dev_get_drvdata(dev); - struct w100fb_par *par=info->par; - - /* If display is blanked/suspended, hsync isn't active */ - if (par->blanked) - return 0; - else - return par->hsync_len; -} -EXPORT_SYMBOL(w100fb_get_hsynclen); - -static void w100fb_clear_screen(struct w100fb_par *par) -{ - memset_io(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), 0, (par->xres * par->yres * BITS_PER_PIXEL/8)); -} - - -/* - * Set a palette value from rgb components - */ -static int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int trans, struct fb_info *info) -{ - unsigned int val; - int ret = 1; - - /* - * If greyscale is true, then we convert the RGB value - * to greyscale no matter what visual we are using. - */ - if (info->var.grayscale) - red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16; - - /* - * 16-bit True Colour. We encode the RGB value - * according to the RGB bitfield information. - */ - if (regno < MAX_PALETTES) { - u32 *pal = info->pseudo_palette; - - val = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); - pal[regno] = val; - ret = 0; - } - return ret; -} - - -/* - * Blank the display based on value in blank_mode - */ -static int w100fb_blank(int blank_mode, struct fb_info *info) -{ - struct w100fb_par *par = info->par; - struct w100_tg_info *tg = par->mach->tg; - - switch(blank_mode) { - - case FB_BLANK_NORMAL: /* Normal blanking */ - case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ - case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ - case FB_BLANK_POWERDOWN: /* Poweroff */ - if (par->blanked == 0) { - if(tg && tg->suspend) - tg->suspend(par); - par->blanked = 1; - } - break; - - case FB_BLANK_UNBLANK: /* Unblanking */ - if (par->blanked != 0) { - if(tg && tg->resume) - tg->resume(par); - par->blanked = 0; - } - break; - } - return 0; -} - - -static void w100_fifo_wait(int entries) -{ - union rbbm_status_u status; - int i; - - for (i = 0; i < 2000000; i++) { - status.val = readl(remapped_regs + mmRBBM_STATUS); - if (status.f.cmdfifo_avail >= entries) - return; - udelay(1); - } - printk(KERN_ERR "w100fb: FIFO Timeout!\n"); -} - - -static int w100fb_sync(struct fb_info *info) -{ - union rbbm_status_u status; - int i; - - for (i = 0; i < 2000000; i++) { - status.val = readl(remapped_regs + mmRBBM_STATUS); - if (!status.f.gui_active) - return 0; - udelay(1); - } - printk(KERN_ERR "w100fb: Graphic engine timeout!\n"); - return -EBUSY; -} - - -static void w100_init_graphic_engine(struct w100fb_par *par) -{ - union dp_gui_master_cntl_u gmc; - union dp_mix_u dp_mix; - union dp_datatype_u dp_datatype; - union dp_cntl_u dp_cntl; - - w100_fifo_wait(4); - writel(W100_FB_BASE, remapped_regs + mmDST_OFFSET); - writel(par->xres, remapped_regs + mmDST_PITCH); - writel(W100_FB_BASE, remapped_regs + mmSRC_OFFSET); - writel(par->xres, remapped_regs + mmSRC_PITCH); - - w100_fifo_wait(3); - writel(0, remapped_regs + mmSC_TOP_LEFT); - writel((par->yres << 16) | par->xres, remapped_regs + mmSC_BOTTOM_RIGHT); - writel(0x1fff1fff, remapped_regs + mmSRC_SC_BOTTOM_RIGHT); - - w100_fifo_wait(4); - dp_cntl.val = 0; - dp_cntl.f.dst_x_dir = 1; - dp_cntl.f.dst_y_dir = 1; - dp_cntl.f.src_x_dir = 1; - dp_cntl.f.src_y_dir = 1; - dp_cntl.f.dst_major_x = 1; - dp_cntl.f.src_major_x = 1; - writel(dp_cntl.val, remapped_regs + mmDP_CNTL); - - gmc.val = 0; - gmc.f.gmc_src_pitch_offset_cntl = 1; - gmc.f.gmc_dst_pitch_offset_cntl = 1; - gmc.f.gmc_src_clipping = 1; - gmc.f.gmc_dst_clipping = 1; - gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE; - gmc.f.gmc_dst_datatype = 3; /* from DstType_16Bpp_444 */ - gmc.f.gmc_src_datatype = SRC_DATATYPE_EQU_DST; - gmc.f.gmc_byte_pix_order = 1; - gmc.f.gmc_default_sel = 0; - gmc.f.gmc_rop3 = ROP3_SRCCOPY; - gmc.f.gmc_dp_src_source = DP_SRC_MEM_RECTANGULAR; - gmc.f.gmc_clr_cmp_fcn_dis = 1; - gmc.f.gmc_wr_msk_dis = 1; - gmc.f.gmc_dp_op = DP_OP_ROP; - writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL); - - dp_datatype.val = dp_mix.val = 0; - dp_datatype.f.dp_dst_datatype = gmc.f.gmc_dst_datatype; - dp_datatype.f.dp_brush_datatype = gmc.f.gmc_brush_datatype; - dp_datatype.f.dp_src2_type = 0; - dp_datatype.f.dp_src2_datatype = gmc.f.gmc_src_datatype; - dp_datatype.f.dp_src_datatype = gmc.f.gmc_src_datatype; - dp_datatype.f.dp_byte_pix_order = gmc.f.gmc_byte_pix_order; - writel(dp_datatype.val, remapped_regs + mmDP_DATATYPE); - - dp_mix.f.dp_src_source = gmc.f.gmc_dp_src_source; - dp_mix.f.dp_src2_source = 1; - dp_mix.f.dp_rop3 = gmc.f.gmc_rop3; - dp_mix.f.dp_op = gmc.f.gmc_dp_op; - writel(dp_mix.val, remapped_regs + mmDP_MIX); -} - - -static void w100fb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - union dp_gui_master_cntl_u gmc; - - if (info->state != FBINFO_STATE_RUNNING) - return; - if (info->flags & FBINFO_HWACCEL_DISABLED) { - cfb_fillrect(info, rect); - return; - } - - gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL); - gmc.f.gmc_rop3 = ROP3_PATCOPY; - gmc.f.gmc_brush_datatype = GMC_BRUSH_SOLID_COLOR; - w100_fifo_wait(2); - writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL); - writel(rect->color, remapped_regs + mmDP_BRUSH_FRGD_CLR); - - w100_fifo_wait(2); - writel((rect->dy << 16) | (rect->dx & 0xffff), remapped_regs + mmDST_Y_X); - writel((rect->width << 16) | (rect->height & 0xffff), - remapped_regs + mmDST_WIDTH_HEIGHT); -} - - -static void w100fb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; - u32 h = area->height, w = area->width; - union dp_gui_master_cntl_u gmc; - - if (info->state != FBINFO_STATE_RUNNING) - return; - if (info->flags & FBINFO_HWACCEL_DISABLED) { - cfb_copyarea(info, area); - return; - } - - gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL); - gmc.f.gmc_rop3 = ROP3_SRCCOPY; - gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE; - w100_fifo_wait(1); - writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL); - - w100_fifo_wait(3); - writel((sy << 16) | (sx & 0xffff), remapped_regs + mmSRC_Y_X); - writel((dy << 16) | (dx & 0xffff), remapped_regs + mmDST_Y_X); - writel((w << 16) | (h & 0xffff), remapped_regs + mmDST_WIDTH_HEIGHT); -} - - -/* - * Change the resolution by calling the appropriate hardware functions - */ -static void w100fb_activate_var(struct w100fb_par *par) -{ - struct w100_tg_info *tg = par->mach->tg; - - w100_pwm_setup(par); - w100_setup_memory(par); - w100_init_clocks(par); - w100fb_clear_screen(par); - w100_vsync(); - - w100_update_disable(); - w100_init_lcd(par); - w100_set_dispregs(par); - w100_update_enable(); - w100_init_graphic_engine(par); - - calc_hsync(par); - - if (!par->blanked && tg && tg->change) - tg->change(par); -} - - -/* Select the smallest mode that allows the desired resolution to be - * displayed. If desired, the x and y parameters can be rounded up to - * match the selected mode. - */ -static struct w100_mode *w100fb_get_mode(struct w100fb_par *par, unsigned int *x, unsigned int *y, int saveval) -{ - struct w100_mode *mode = NULL; - struct w100_mode *modelist = par->mach->modelist; - unsigned int best_x = 0xffffffff, best_y = 0xffffffff; - unsigned int i; - - for (i = 0 ; i < par->mach->num_modes ; i++) { - if (modelist[i].xres >= *x && modelist[i].yres >= *y && - modelist[i].xres < best_x && modelist[i].yres < best_y) { - best_x = modelist[i].xres; - best_y = modelist[i].yres; - mode = &modelist[i]; - } else if(modelist[i].xres >= *y && modelist[i].yres >= *x && - modelist[i].xres < best_y && modelist[i].yres < best_x) { - best_x = modelist[i].yres; - best_y = modelist[i].xres; - mode = &modelist[i]; - } - } - - if (mode && saveval) { - *x = best_x; - *y = best_y; - } - - return mode; -} - - -/* - * w100fb_check_var(): - * Get the video params out of 'var'. If a value doesn't fit, round it up, - * if it's too big, return -EINVAL. - */ -static int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -{ - struct w100fb_par *par=info->par; - - if(!w100fb_get_mode(par, &var->xres, &var->yres, 1)) - return -EINVAL; - - if (par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (par->mach->mem->size+1))) - return -EINVAL; - - if (!par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1))) - return -EINVAL; - - var->xres_virtual = max(var->xres_virtual, var->xres); - var->yres_virtual = max(var->yres_virtual, var->yres); - - if (var->bits_per_pixel > BITS_PER_PIXEL) - return -EINVAL; - else - var->bits_per_pixel = BITS_PER_PIXEL; - - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = var->transp.length = 0; - - var->nonstd = 0; - var->height = -1; - var->width = -1; - var->vmode = FB_VMODE_NONINTERLACED; - var->sync = 0; - var->pixclock = 0x04; /* 171521; */ - - return 0; -} - - -/* - * w100fb_set_par(): - * Set the user defined part of the display for the specified console - * by looking at the values in info.var - */ -static int w100fb_set_par(struct fb_info *info) -{ - struct w100fb_par *par=info->par; - - if (par->xres != info->var.xres || par->yres != info->var.yres) { - par->xres = info->var.xres; - par->yres = info->var.yres; - par->mode = w100fb_get_mode(par, &par->xres, &par->yres, 0); - - info->fix.visual = FB_VISUAL_TRUECOLOR; - info->fix.ypanstep = 0; - info->fix.ywrapstep = 0; - info->fix.line_length = par->xres * BITS_PER_PIXEL / 8; - - mutex_lock(&info->mm_lock); - if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) { - par->extmem_active = 1; - info->fix.smem_len = par->mach->mem->size+1; - } else { - par->extmem_active = 0; - info->fix.smem_len = MEM_INT_SIZE+1; - } - mutex_unlock(&info->mm_lock); - - w100fb_activate_var(par); - } - return 0; -} - - -/* - * Frame buffer operations - */ -static const struct fb_ops w100fb_ops = { - .owner = THIS_MODULE, - .fb_check_var = w100fb_check_var, - .fb_set_par = w100fb_set_par, - .fb_setcolreg = w100fb_setcolreg, - .fb_blank = w100fb_blank, - .fb_fillrect = w100fb_fillrect, - .fb_copyarea = w100fb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_sync = w100fb_sync, -}; - -#ifdef CONFIG_PM -static void w100fb_save_vidmem(struct w100fb_par *par) -{ - int memsize; - - if (par->extmem_active) { - memsize=par->mach->mem->size; - par->saved_extmem = vmalloc(memsize); - if (par->saved_extmem) - memcpy_fromio(par->saved_extmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize); - } - memsize=MEM_INT_SIZE; - par->saved_intmem = vmalloc(memsize); - if (par->saved_intmem && par->extmem_active) - memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), memsize); - else if (par->saved_intmem) - memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize); -} - -static void w100fb_restore_vidmem(struct w100fb_par *par) -{ - int memsize; - - if (par->extmem_active && par->saved_extmem) { - memsize=par->mach->mem->size; - memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_extmem, memsize); - vfree(par->saved_extmem); - par->saved_extmem = NULL; - } - if (par->saved_intmem) { - memsize=MEM_INT_SIZE; - if (par->extmem_active) - memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), par->saved_intmem, memsize); - else - memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_intmem, memsize); - vfree(par->saved_intmem); - par->saved_intmem = NULL; - } -} - -static int w100fb_suspend(struct platform_device *dev, pm_message_t state) -{ - struct fb_info *info = platform_get_drvdata(dev); - struct w100fb_par *par=info->par; - struct w100_tg_info *tg = par->mach->tg; - - w100fb_save_vidmem(par); - if(tg && tg->suspend) - tg->suspend(par); - w100_suspend(W100_SUSPEND_ALL); - par->blanked = 1; - - return 0; -} - -static int w100fb_resume(struct platform_device *dev) -{ - struct fb_info *info = platform_get_drvdata(dev); - struct w100fb_par *par=info->par; - struct w100_tg_info *tg = par->mach->tg; - - w100_hw_init(par); - w100fb_activate_var(par); - w100fb_restore_vidmem(par); - if(tg && tg->resume) - tg->resume(par); - par->blanked = 0; - - return 0; -} -#else -#define w100fb_suspend NULL -#define w100fb_resume NULL -#endif - - -static int w100fb_probe(struct platform_device *pdev) -{ - int err = -EIO; - struct w100fb_mach_info *inf; - struct fb_info *info = NULL; - struct w100fb_par *par; - struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - unsigned int chip_id; - - if (!mem) - return -EINVAL; - - /* Remap the chip base address */ - remapped_base = ioremap(mem->start+W100_CFG_BASE, W100_CFG_LEN); - if (remapped_base == NULL) - goto out; - - /* Map the register space */ - remapped_regs = ioremap(mem->start+W100_REG_BASE, W100_REG_LEN); - if (remapped_regs == NULL) - goto out; - - /* Identify the chip */ - printk("Found "); - chip_id = readl(remapped_regs + mmCHIP_ID); - switch(chip_id) { - case CHIP_ID_W100: printk("w100"); break; - case CHIP_ID_W3200: printk("w3200"); break; - case CHIP_ID_W3220: printk("w3220"); break; - default: - printk("Unknown imageon chip ID\n"); - err = -ENODEV; - goto out; - } - printk(" at 0x%08lx.\n", (unsigned long) mem->start+W100_CFG_BASE); - - /* Remap the framebuffer */ - remapped_fbuf = ioremap(mem->start+MEM_WINDOW_BASE, MEM_WINDOW_SIZE); - if (remapped_fbuf == NULL) - goto out; - - info=framebuffer_alloc(sizeof(struct w100fb_par), &pdev->dev); - if (!info) { - err = -ENOMEM; - goto out; - } - - par = info->par; - platform_set_drvdata(pdev, info); - - inf = dev_get_platdata(&pdev->dev); - par->chip_id = chip_id; - par->mach = inf; - par->fastpll_mode = 0; - par->blanked = 0; - - par->pll_table=w100_get_xtal_table(inf->xtal_freq); - if (!par->pll_table) { - printk(KERN_ERR "No matching Xtal definition found\n"); - err = -EINVAL; - goto out; - } - - info->pseudo_palette = kmalloc_array(MAX_PALETTES, sizeof(u32), - GFP_KERNEL); - if (!info->pseudo_palette) { - err = -ENOMEM; - goto out; - } - - info->fbops = &w100fb_ops; - info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | - FBINFO_HWACCEL_FILLRECT; - info->node = -1; - info->screen_base = remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE); - info->screen_size = REMAPPED_FB_LEN; - - strcpy(info->fix.id, "w100fb"); - info->fix.type = FB_TYPE_PACKED_PIXELS; - info->fix.type_aux = 0; - info->fix.accel = FB_ACCEL_NONE; - info->fix.smem_start = mem->start+W100_FB_BASE; - info->fix.mmio_start = mem->start+W100_REG_BASE; - info->fix.mmio_len = W100_REG_LEN; - - if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { - err = -ENOMEM; - goto out; - } - - par->mode = &inf->modelist[0]; - if(inf->init_mode & INIT_MODE_ROTATED) { - info->var.xres = par->mode->yres; - info->var.yres = par->mode->xres; - } - else { - info->var.xres = par->mode->xres; - info->var.yres = par->mode->yres; - } - - if(inf->init_mode &= INIT_MODE_FLIPPED) - par->flip = 1; - else - par->flip = 0; - - info->var.xres_virtual = info->var.xres; - info->var.yres_virtual = info->var.yres; - info->var.pixclock = 0x04; /* 171521; */ - info->var.sync = 0; - info->var.grayscale = 0; - info->var.xoffset = info->var.yoffset = 0; - info->var.accel_flags = 0; - info->var.activate = FB_ACTIVATE_NOW; - - w100_hw_init(par); - - if (w100fb_check_var(&info->var, info) < 0) { - err = -EINVAL; - goto out; - } - - if (register_framebuffer(info) < 0) { - err = -EINVAL; - goto out; - } - - fb_info(info, "%s frame buffer device\n", info->fix.id); - return 0; -out: - if (info) { - fb_dealloc_cmap(&info->cmap); - kfree(info->pseudo_palette); - } - if (remapped_fbuf != NULL) { - iounmap(remapped_fbuf); - remapped_fbuf = NULL; - } - if (remapped_regs != NULL) { - iounmap(remapped_regs); - remapped_regs = NULL; - } - if (remapped_base != NULL) { - iounmap(remapped_base); - remapped_base = NULL; - } - if (info) - framebuffer_release(info); - return err; -} - - -static int w100fb_remove(struct platform_device *pdev) -{ - struct fb_info *info = platform_get_drvdata(pdev); - struct w100fb_par *par=info->par; - - unregister_framebuffer(info); - - vfree(par->saved_intmem); - vfree(par->saved_extmem); - kfree(info->pseudo_palette); - fb_dealloc_cmap(&info->cmap); - - iounmap(remapped_base); - remapped_base = NULL; - iounmap(remapped_regs); - remapped_regs = NULL; - iounmap(remapped_fbuf); - remapped_fbuf = NULL; - - framebuffer_release(info); - - return 0; -} - - -/* ------------------- chipset specific functions -------------------------- */ - - -static void w100_soft_reset(void) -{ - u16 val = readw((u16 __iomem *)remapped_base + cfgSTATUS); - - writew(val | 0x08, (u16 __iomem *)remapped_base + cfgSTATUS); - udelay(100); - writew(0x00, (u16 __iomem *)remapped_base + cfgSTATUS); - udelay(100); -} - -static void w100_update_disable(void) -{ - union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl; - - /* Prevent display updates */ - disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e; - disp_db_buf_wr_cntl.f.update_db_buf = 0; - disp_db_buf_wr_cntl.f.en_db_buf = 0; - writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL); -} - -static void w100_update_enable(void) -{ - union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl; - - /* Enable display updates */ - disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e; - disp_db_buf_wr_cntl.f.update_db_buf = 1; - disp_db_buf_wr_cntl.f.en_db_buf = 1; - writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL); -} - -unsigned long w100fb_gpio_read(int port) -{ - unsigned long value; - - if (port==W100_GPIO_PORT_A) - value = readl(remapped_regs + mmGPIO_DATA); - else - value = readl(remapped_regs + mmGPIO_DATA2); - - return value; -} - -void w100fb_gpio_write(int port, unsigned long value) -{ - if (port==W100_GPIO_PORT_A) - writel(value, remapped_regs + mmGPIO_DATA); - else - writel(value, remapped_regs + mmGPIO_DATA2); -} -EXPORT_SYMBOL(w100fb_gpio_read); -EXPORT_SYMBOL(w100fb_gpio_write); - -/* - * Initialization of critical w100 hardware - */ -static void w100_hw_init(struct w100fb_par *par) -{ - u32 temp32; - union cif_cntl_u cif_cntl; - union intf_cntl_u intf_cntl; - union cfgreg_base_u cfgreg_base; - union wrap_top_dir_u wrap_top_dir; - union cif_read_dbg_u cif_read_dbg; - union cpu_defaults_u cpu_default; - union cif_write_dbg_u cif_write_dbg; - union wrap_start_dir_u wrap_start_dir; - union cif_io_u cif_io; - struct w100_gpio_regs *gpio = par->mach->gpio; - - w100_soft_reset(); - - /* This is what the fpga_init code does on reset. May be wrong - but there is little info available */ - writel(0x31, remapped_regs + mmSCRATCH_UMSK); - for (temp32 = 0; temp32 < 10000; temp32++) - readl(remapped_regs + mmSCRATCH_UMSK); - writel(0x30, remapped_regs + mmSCRATCH_UMSK); - - /* Set up CIF */ - cif_io.val = defCIF_IO; - writel((u32)(cif_io.val), remapped_regs + mmCIF_IO); - - cif_write_dbg.val = readl(remapped_regs + mmCIF_WRITE_DBG); - cif_write_dbg.f.dis_packer_ful_during_rbbm_timeout = 0; - cif_write_dbg.f.en_dword_split_to_rbbm = 1; - cif_write_dbg.f.dis_timeout_during_rbbm = 1; - writel((u32) (cif_write_dbg.val), remapped_regs + mmCIF_WRITE_DBG); - - cif_read_dbg.val = readl(remapped_regs + mmCIF_READ_DBG); - cif_read_dbg.f.dis_rd_same_byte_to_trig_fetch = 1; - writel((u32) (cif_read_dbg.val), remapped_regs + mmCIF_READ_DBG); - - cif_cntl.val = readl(remapped_regs + mmCIF_CNTL); - cif_cntl.f.dis_system_bits = 1; - cif_cntl.f.dis_mr = 1; - cif_cntl.f.en_wait_to_compensate_dq_prop_dly = 0; - cif_cntl.f.intb_oe = 1; - cif_cntl.f.interrupt_active_high = 1; - writel((u32) (cif_cntl.val), remapped_regs + mmCIF_CNTL); - - /* Setup cfgINTF_CNTL and cfgCPU defaults */ - intf_cntl.val = defINTF_CNTL; - intf_cntl.f.ad_inc_a = 1; - intf_cntl.f.ad_inc_b = 1; - intf_cntl.f.rd_data_rdy_a = 0; - intf_cntl.f.rd_data_rdy_b = 0; - writeb((u8) (intf_cntl.val), remapped_base + cfgINTF_CNTL); - - cpu_default.val = defCPU_DEFAULTS; - cpu_default.f.access_ind_addr_a = 1; - cpu_default.f.access_ind_addr_b = 1; - cpu_default.f.access_scratch_reg = 1; - cpu_default.f.transition_size = 0; - writeb((u8) (cpu_default.val), remapped_base + cfgCPU_DEFAULTS); - - /* set up the apertures */ - writeb((u8) (W100_REG_BASE >> 16), remapped_base + cfgREG_BASE); - - cfgreg_base.val = defCFGREG_BASE; - cfgreg_base.f.cfgreg_base = W100_CFG_BASE; - writel((u32) (cfgreg_base.val), remapped_regs + mmCFGREG_BASE); - - wrap_start_dir.val = defWRAP_START_DIR; - wrap_start_dir.f.start_addr = WRAP_BUF_BASE_VALUE >> 1; - writel((u32) (wrap_start_dir.val), remapped_regs + mmWRAP_START_DIR); - - wrap_top_dir.val = defWRAP_TOP_DIR; - wrap_top_dir.f.top_addr = WRAP_BUF_TOP_VALUE >> 1; - writel((u32) (wrap_top_dir.val), remapped_regs + mmWRAP_TOP_DIR); - - writel((u32) 0x2440, remapped_regs + mmRBBM_CNTL); - - /* Set the hardware to 565 colour */ - temp32 = readl(remapped_regs + mmDISP_DEBUG2); - temp32 &= 0xff7fffff; - temp32 |= 0x00800000; - writel(temp32, remapped_regs + mmDISP_DEBUG2); - - /* Initialise the GPIO lines */ - if (gpio) { - writel(gpio->init_data1, remapped_regs + mmGPIO_DATA); - writel(gpio->init_data2, remapped_regs + mmGPIO_DATA2); - writel(gpio->gpio_dir1, remapped_regs + mmGPIO_CNTL1); - writel(gpio->gpio_oe1, remapped_regs + mmGPIO_CNTL2); - writel(gpio->gpio_dir2, remapped_regs + mmGPIO_CNTL3); - writel(gpio->gpio_oe2, remapped_regs + mmGPIO_CNTL4); - } -} - - -struct power_state { - union clk_pin_cntl_u clk_pin_cntl; - union pll_ref_fb_div_u pll_ref_fb_div; - union pll_cntl_u pll_cntl; - union sclk_cntl_u sclk_cntl; - union pclk_cntl_u pclk_cntl; - union pwrmgt_cntl_u pwrmgt_cntl; - int auto_mode; /* system clock auto changing? */ -}; - - -static struct power_state w100_pwr_state; - -/* The PLL Fout is determined by (XtalFreq/(M+1)) * ((N_int+1) + (N_fac/8)) */ - -/* 12.5MHz Crystal PLL Table */ -static struct w100_pll_info xtal_12500000[] = { - /*freq M N_int N_fac tfgoal lock_time */ - { 50, 0, 1, 0, 0xe0, 56}, /* 50.00 MHz */ - { 75, 0, 5, 0, 0xde, 37}, /* 75.00 MHz */ - {100, 0, 7, 0, 0xe0, 28}, /* 100.00 MHz */ - {125, 0, 9, 0, 0xe0, 22}, /* 125.00 MHz */ - {150, 0, 11, 0, 0xe0, 17}, /* 150.00 MHz */ - { 0, 0, 0, 0, 0, 0}, /* Terminator */ -}; - -/* 14.318MHz Crystal PLL Table */ -static struct w100_pll_info xtal_14318000[] = { - /*freq M N_int N_fac tfgoal lock_time */ - { 40, 4, 13, 0, 0xe0, 80}, /* tfgoal guessed */ - { 50, 1, 6, 0, 0xe0, 64}, /* 50.05 MHz */ - { 57, 2, 11, 0, 0xe0, 53}, /* tfgoal guessed */ - { 75, 0, 4, 3, 0xe0, 43}, /* 75.08 MHz */ - {100, 0, 6, 0, 0xe0, 32}, /* 100.10 MHz */ - { 0, 0, 0, 0, 0, 0}, -}; - -/* 16MHz Crystal PLL Table */ -static struct w100_pll_info xtal_16000000[] = { - /*freq M N_int N_fac tfgoal lock_time */ - { 72, 1, 8, 0, 0xe0, 48}, /* tfgoal guessed */ - { 80, 1, 9, 0, 0xe0, 13}, /* tfgoal guessed */ - { 95, 1, 10, 7, 0xe0, 38}, /* tfgoal guessed */ - { 96, 1, 11, 0, 0xe0, 36}, /* tfgoal guessed */ - { 0, 0, 0, 0, 0, 0}, -}; - -static struct pll_entries { - int xtal_freq; - struct w100_pll_info *pll_table; -} w100_pll_tables[] = { - { 12500000, &xtal_12500000[0] }, - { 14318000, &xtal_14318000[0] }, - { 16000000, &xtal_16000000[0] }, - { 0 }, -}; - -struct w100_pll_info *w100_get_xtal_table(unsigned int freq) -{ - struct pll_entries *pll_entry = w100_pll_tables; - - do { - if (freq == pll_entry->xtal_freq) - return pll_entry->pll_table; - pll_entry++; - } while (pll_entry->xtal_freq); - - return NULL; -} - - -static unsigned int w100_get_testcount(unsigned int testclk_sel) -{ - union clk_test_cntl_u clk_test_cntl; - - udelay(5); - - /* Select the test clock source and reset */ - clk_test_cntl.f.start_check_freq = 0x0; - clk_test_cntl.f.testclk_sel = testclk_sel; - clk_test_cntl.f.tstcount_rst = 0x1; /* set reset */ - writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL); - - clk_test_cntl.f.tstcount_rst = 0x0; /* clear reset */ - writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL); - - /* Run clock test */ - clk_test_cntl.f.start_check_freq = 0x1; - writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL); - - /* Give the test time to complete */ - udelay(20); - - /* Return the result */ - clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL); - clk_test_cntl.f.start_check_freq = 0x0; - writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL); - - return clk_test_cntl.f.test_count; -} - - -static int w100_pll_adjust(struct w100_pll_info *pll) -{ - unsigned int tf80; - unsigned int tf20; - - /* Initial Settings */ - w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0; /* power down */ - w100_pwr_state.pll_cntl.f.pll_reset = 0x0; /* not reset */ - w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1; /* Hi-Z */ - w100_pwr_state.pll_cntl.f.pll_pvg = 0x0; /* VCO gain = 0 */ - w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0; /* VCO frequency range control = off */ - w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0; /* current offset inside VCO = 0 */ - w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0; - - /* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V - * therefore, commented out the following lines - * tf80 meant tf100 - */ - do { - /* set VCO input = 0.8 * VDD */ - w100_pwr_state.pll_cntl.f.pll_dactal = 0xd; - writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); - - tf80 = w100_get_testcount(TESTCLK_SRC_PLL); - if (tf80 >= (pll->tfgoal)) { - /* set VCO input = 0.2 * VDD */ - w100_pwr_state.pll_cntl.f.pll_dactal = 0x7; - writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); - - tf20 = w100_get_testcount(TESTCLK_SRC_PLL); - if (tf20 <= (pll->tfgoal)) - return 1; /* Success */ - - if ((w100_pwr_state.pll_cntl.f.pll_vcofr == 0x0) && - ((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) || - (w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) { - /* slow VCO config */ - w100_pwr_state.pll_cntl.f.pll_vcofr = 0x1; - w100_pwr_state.pll_cntl.f.pll_pvg = 0x0; - w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0; - continue; - } - } - if ((w100_pwr_state.pll_cntl.f.pll_ioffset) < 0x3) { - w100_pwr_state.pll_cntl.f.pll_ioffset += 0x1; - } else if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) { - w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0; - w100_pwr_state.pll_cntl.f.pll_pvg += 0x1; - } else { - return 0; /* Error */ - } - } while(1); -} - - -/* - * w100_pll_calibration - */ -static int w100_pll_calibration(struct w100_pll_info *pll) -{ - int status; - - status = w100_pll_adjust(pll); - - /* PLL Reset And Lock */ - /* set VCO input = 0.5 * VDD */ - w100_pwr_state.pll_cntl.f.pll_dactal = 0xa; - writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); - - udelay(1); /* reset time */ - - /* enable charge pump */ - w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0; /* normal */ - writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); - - /* set VCO input = Hi-Z, disable DAC */ - w100_pwr_state.pll_cntl.f.pll_dactal = 0x0; - writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); - - udelay(400); /* lock time */ - - /* PLL locked */ - - return status; -} - - -static int w100_pll_set_clk(struct w100_pll_info *pll) -{ - int status; - - if (w100_pwr_state.auto_mode == 1) /* auto mode */ - { - w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0; /* disable fast to normal */ - w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0; /* disable normal to fast */ - writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL); - } - - /* Set system clock source to XTAL whilst adjusting the PLL! */ - w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL; - writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL); - - w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = pll->M; - w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = pll->N_int; - w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = pll->N_fac; - w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = pll->lock_time; - writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV); - - w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0; - writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL); - - status = w100_pll_calibration(pll); - - if (w100_pwr_state.auto_mode == 1) /* auto mode */ - { - w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1; /* reenable fast to normal */ - w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1; /* reenable normal to fast */ - writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL); - } - return status; -} - -/* freq = target frequency of the PLL */ -static int w100_set_pll_freq(struct w100fb_par *par, unsigned int freq) -{ - struct w100_pll_info *pll = par->pll_table; - - do { - if (freq == pll->freq) { - return w100_pll_set_clk(pll); - } - pll++; - } while(pll->freq); - return 0; -} - -/* Set up an initial state. Some values/fields set - here will be overwritten. */ -static void w100_pwm_setup(struct w100fb_par *par) -{ - w100_pwr_state.clk_pin_cntl.f.osc_en = 0x1; - w100_pwr_state.clk_pin_cntl.f.osc_gain = 0x1f; - w100_pwr_state.clk_pin_cntl.f.dont_use_xtalin = 0x0; - w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x0; - w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = par->mach->xtal_dbl ? 1 : 0; - w100_pwr_state.clk_pin_cntl.f.cg_debug = 0x0; - writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL); - - w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL; - w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0; /* Pfast = 1 */ - w100_pwr_state.sclk_cntl.f.sclk_clkon_hys = 0x3; - w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0; /* Pslow = 1 */ - w100_pwr_state.sclk_cntl.f.disp_cg_ok2switch_en = 0x0; - w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0; /* Dynamic */ - w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0; /* Dynamic */ - w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0; /* Dynamic */ - w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0; /* Dynamic */ - w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0; /* Dynamic */ - w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0; /* Dynamic */ - w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0; /* Dynamic */ - w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0; /* Dynamic */ - w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0; /* Dynamic */ - w100_pwr_state.sclk_cntl.f.busy_extend_cp = 0x0; - w100_pwr_state.sclk_cntl.f.busy_extend_e2 = 0x0; - w100_pwr_state.sclk_cntl.f.busy_extend_e3 = 0x0; - w100_pwr_state.sclk_cntl.f.busy_extend_idct = 0x0; - writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL); - - w100_pwr_state.pclk_cntl.f.pclk_src_sel = CLK_SRC_XTAL; - w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1; /* P = 2 */ - w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0; /* Dynamic */ - writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL); - - w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0; /* M = 1 */ - w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0; /* N = 1.0 */ - w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = 0x0; - w100_pwr_state.pll_ref_fb_div.f.pll_reset_time = 0x5; - w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = 0xff; - writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV); - - w100_pwr_state.pll_cntl.f.pll_pwdn = 0x1; - w100_pwr_state.pll_cntl.f.pll_reset = 0x1; - w100_pwr_state.pll_cntl.f.pll_pm_en = 0x0; - w100_pwr_state.pll_cntl.f.pll_mode = 0x0; /* uses VCO clock */ - w100_pwr_state.pll_cntl.f.pll_refclk_sel = 0x0; - w100_pwr_state.pll_cntl.f.pll_fbclk_sel = 0x0; - w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0; - w100_pwr_state.pll_cntl.f.pll_pcp = 0x4; - w100_pwr_state.pll_cntl.f.pll_pvg = 0x0; - w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0; - w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0; - w100_pwr_state.pll_cntl.f.pll_pecc_mode = 0x0; - w100_pwr_state.pll_cntl.f.pll_pecc_scon = 0x0; - w100_pwr_state.pll_cntl.f.pll_dactal = 0x0; /* Hi-Z */ - w100_pwr_state.pll_cntl.f.pll_cp_clip = 0x3; - w100_pwr_state.pll_cntl.f.pll_conf = 0x2; - w100_pwr_state.pll_cntl.f.pll_mbctrl = 0x2; - w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0; - writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL); - - w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x0; - w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1; /* normal mode (0, 1, 3) */ - w100_pwr_state.pwrmgt_cntl.f.pwm_wakeup_cond = 0x0; - w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0; - w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0; - w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1; /* PM4,ENG */ - w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1; /* PM4,ENG */ - w100_pwr_state.pwrmgt_cntl.f.pwm_idle_timer = 0xFF; - w100_pwr_state.pwrmgt_cntl.f.pwm_busy_timer = 0xFF; - writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL); - - w100_pwr_state.auto_mode = 0; /* manual mode */ -} - - -/* - * Setup the w100 clocks for the specified mode - */ -static void w100_init_clocks(struct w100fb_par *par) -{ - struct w100_mode *mode = par->mode; - - if (mode->pixclk_src == CLK_SRC_PLL || mode->sysclk_src == CLK_SRC_PLL) - w100_set_pll_freq(par, (par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq); - - w100_pwr_state.sclk_cntl.f.sclk_src_sel = mode->sysclk_src; - w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = mode->sysclk_divider; - w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = mode->sysclk_divider; - writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL); -} - -static void w100_init_lcd(struct w100fb_par *par) -{ - u32 temp32; - struct w100_mode *mode = par->mode; - struct w100_gen_regs *regs = par->mach->regs; - union active_h_disp_u active_h_disp; - union active_v_disp_u active_v_disp; - union graphic_h_disp_u graphic_h_disp; - union graphic_v_disp_u graphic_v_disp; - union crtc_total_u crtc_total; - - /* w3200 doesn't like undefined bits being set so zero register values first */ - - active_h_disp.val = 0; - active_h_disp.f.active_h_start=mode->left_margin; - active_h_disp.f.active_h_end=mode->left_margin + mode->xres; - writel(active_h_disp.val, remapped_regs + mmACTIVE_H_DISP); - - active_v_disp.val = 0; - active_v_disp.f.active_v_start=mode->upper_margin; - active_v_disp.f.active_v_end=mode->upper_margin + mode->yres; - writel(active_v_disp.val, remapped_regs + mmACTIVE_V_DISP); - - graphic_h_disp.val = 0; - graphic_h_disp.f.graphic_h_start=mode->left_margin; - graphic_h_disp.f.graphic_h_end=mode->left_margin + mode->xres; - writel(graphic_h_disp.val, remapped_regs + mmGRAPHIC_H_DISP); - - graphic_v_disp.val = 0; - graphic_v_disp.f.graphic_v_start=mode->upper_margin; - graphic_v_disp.f.graphic_v_end=mode->upper_margin + mode->yres; - writel(graphic_v_disp.val, remapped_regs + mmGRAPHIC_V_DISP); - - crtc_total.val = 0; - crtc_total.f.crtc_h_total=mode->left_margin + mode->xres + mode->right_margin; - crtc_total.f.crtc_v_total=mode->upper_margin + mode->yres + mode->lower_margin; - writel(crtc_total.val, remapped_regs + mmCRTC_TOTAL); - - writel(mode->crtc_ss, remapped_regs + mmCRTC_SS); - writel(mode->crtc_ls, remapped_regs + mmCRTC_LS); - writel(mode->crtc_gs, remapped_regs + mmCRTC_GS); - writel(mode->crtc_vpos_gs, remapped_regs + mmCRTC_VPOS_GS); - writel(mode->crtc_rev, remapped_regs + mmCRTC_REV); - writel(mode->crtc_dclk, remapped_regs + mmCRTC_DCLK); - writel(mode->crtc_gclk, remapped_regs + mmCRTC_GCLK); - writel(mode->crtc_goe, remapped_regs + mmCRTC_GOE); - writel(mode->crtc_ps1_active, remapped_regs + mmCRTC_PS1_ACTIVE); - - writel(regs->lcd_format, remapped_regs + mmLCD_FORMAT); - writel(regs->lcdd_cntl1, remapped_regs + mmLCDD_CNTL1); - writel(regs->lcdd_cntl2, remapped_regs + mmLCDD_CNTL2); - writel(regs->genlcd_cntl1, remapped_regs + mmGENLCD_CNTL1); - writel(regs->genlcd_cntl2, remapped_regs + mmGENLCD_CNTL2); - writel(regs->genlcd_cntl3, remapped_regs + mmGENLCD_CNTL3); - - writel(0x00000000, remapped_regs + mmCRTC_FRAME); - writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS); - writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT); - writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR); - - /* Hack for overlay in ext memory */ - temp32 = readl(remapped_regs + mmDISP_DEBUG2); - temp32 |= 0xc0000000; - writel(temp32, remapped_regs + mmDISP_DEBUG2); -} - - -static void w100_setup_memory(struct w100fb_par *par) -{ - union mc_ext_mem_location_u extmem_location; - union mc_fb_location_u intmem_location; - struct w100_mem_info *mem = par->mach->mem; - struct w100_bm_mem_info *bm_mem = par->mach->bm_mem; - - if (!par->extmem_active) { - w100_suspend(W100_SUSPEND_EXTMEM); - - /* Map Internal Memory at FB Base */ - intmem_location.f.mc_fb_start = W100_FB_BASE >> 8; - intmem_location.f.mc_fb_top = (W100_FB_BASE+MEM_INT_SIZE) >> 8; - writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION); - - /* Unmap External Memory - value is *probably* irrelevant but may have meaning - to acceleration libraries */ - extmem_location.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8; - extmem_location.f.mc_ext_mem_top = (MEM_EXT_BASE_VALUE-1) >> 8; - writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION); - } else { - /* Map Internal Memory to its default location */ - intmem_location.f.mc_fb_start = MEM_INT_BASE_VALUE >> 8; - intmem_location.f.mc_fb_top = (MEM_INT_BASE_VALUE+MEM_INT_SIZE) >> 8; - writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION); - - /* Map External Memory at FB Base */ - extmem_location.f.mc_ext_mem_start = W100_FB_BASE >> 8; - extmem_location.f.mc_ext_mem_top = (W100_FB_BASE+par->mach->mem->size) >> 8; - writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION); - - writel(0x00007800, remapped_regs + mmMC_BIST_CTRL); - writel(mem->ext_cntl, remapped_regs + mmMEM_EXT_CNTL); - writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG); - udelay(100); - writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG); - udelay(100); - writel(mem->sdram_mode_reg, remapped_regs + mmMEM_SDRAM_MODE_REG); - udelay(100); - writel(mem->ext_timing_cntl, remapped_regs + mmMEM_EXT_TIMING_CNTL); - writel(mem->io_cntl, remapped_regs + mmMEM_IO_CNTL); - if (bm_mem) { - writel(bm_mem->ext_mem_bw, remapped_regs + mmBM_EXT_MEM_BANDWIDTH); - writel(bm_mem->offset, remapped_regs + mmBM_OFFSET); - writel(bm_mem->ext_timing_ctl, remapped_regs + mmBM_MEM_EXT_TIMING_CNTL); - writel(bm_mem->ext_cntl, remapped_regs + mmBM_MEM_EXT_CNTL); - writel(bm_mem->mode_reg, remapped_regs + mmBM_MEM_MODE_REG); - writel(bm_mem->io_cntl, remapped_regs + mmBM_MEM_IO_CNTL); - writel(bm_mem->config, remapped_regs + mmBM_CONFIG); - } - } -} - -static void w100_set_dispregs(struct w100fb_par *par) -{ - unsigned long rot=0, divider, offset=0; - union graphic_ctrl_u graphic_ctrl; - - /* See if the mode has been rotated */ - if (par->xres == par->mode->xres) { - if (par->flip) { - rot=3; /* 180 degree */ - offset=(par->xres * par->yres) - 1; - } /* else 0 degree */ - divider = par->mode->pixclk_divider; - } else { - if (par->flip) { - rot=2; /* 270 degree */ - offset=par->xres - 1; - } else { - rot=1; /* 90 degree */ - offset=par->xres * (par->yres - 1); - } - divider = par->mode->pixclk_divider_rotated; - } - - graphic_ctrl.val = 0; /* w32xx doesn't like undefined bits */ - switch (par->chip_id) { - case CHIP_ID_W100: - graphic_ctrl.f_w100.color_depth=6; - graphic_ctrl.f_w100.en_crtc=1; - graphic_ctrl.f_w100.en_graphic_req=1; - graphic_ctrl.f_w100.en_graphic_crtc=1; - graphic_ctrl.f_w100.lcd_pclk_on=1; - graphic_ctrl.f_w100.lcd_sclk_on=1; - graphic_ctrl.f_w100.low_power_on=0; - graphic_ctrl.f_w100.req_freq=0; - graphic_ctrl.f_w100.portrait_mode=rot; - - /* Zaurus needs this */ - switch(par->xres) { - case 240: - case 320: - default: - graphic_ctrl.f_w100.total_req_graphic=0xa0; - break; - case 480: - case 640: - switch(rot) { - case 0: /* 0 */ - case 3: /* 180 */ - graphic_ctrl.f_w100.low_power_on=1; - graphic_ctrl.f_w100.req_freq=5; - break; - case 1: /* 90 */ - case 2: /* 270 */ - graphic_ctrl.f_w100.req_freq=4; - break; - default: - break; - } - graphic_ctrl.f_w100.total_req_graphic=0xf0; - break; - } - break; - case CHIP_ID_W3200: - case CHIP_ID_W3220: - graphic_ctrl.f_w32xx.color_depth=6; - graphic_ctrl.f_w32xx.en_crtc=1; - graphic_ctrl.f_w32xx.en_graphic_req=1; - graphic_ctrl.f_w32xx.en_graphic_crtc=1; - graphic_ctrl.f_w32xx.lcd_pclk_on=1; - graphic_ctrl.f_w32xx.lcd_sclk_on=1; - graphic_ctrl.f_w32xx.low_power_on=0; - graphic_ctrl.f_w32xx.req_freq=0; - graphic_ctrl.f_w32xx.total_req_graphic=par->mode->xres >> 1; /* panel xres, not mode */ - graphic_ctrl.f_w32xx.portrait_mode=rot; - break; - } - - /* Set the pixel clock source and divider */ - w100_pwr_state.pclk_cntl.f.pclk_src_sel = par->mode->pixclk_src; - w100_pwr_state.pclk_cntl.f.pclk_post_div = divider; - writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL); - - writel(graphic_ctrl.val, remapped_regs + mmGRAPHIC_CTRL); - writel(W100_FB_BASE + ((offset * BITS_PER_PIXEL/8)&~0x03UL), remapped_regs + mmGRAPHIC_OFFSET); - writel((par->xres*BITS_PER_PIXEL/8), remapped_regs + mmGRAPHIC_PITCH); -} - - -/* - * Work out how long the sync pulse lasts - * Value is 1/(time in seconds) - */ -static void calc_hsync(struct w100fb_par *par) -{ - unsigned long hsync; - struct w100_mode *mode = par->mode; - union crtc_ss_u crtc_ss; - - if (mode->pixclk_src == CLK_SRC_XTAL) - hsync=par->mach->xtal_freq; - else - hsync=((par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq)*100000; - - hsync /= (w100_pwr_state.pclk_cntl.f.pclk_post_div + 1); - - crtc_ss.val = readl(remapped_regs + mmCRTC_SS); - if (crtc_ss.val) - par->hsync_len = hsync / (crtc_ss.f.ss_end-crtc_ss.f.ss_start); - else - par->hsync_len = 0; -} - -static void w100_suspend(u32 mode) -{ - u32 val; - - writel(0x7FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION); - writel(0x00FF0000, remapped_regs + mmMC_PERF_MON_CNTL); - - val = readl(remapped_regs + mmMEM_EXT_TIMING_CNTL); - val &= ~(0x00100000); /* bit20=0 */ - val |= 0xFF000000; /* bit31:24=0xff */ - writel(val, remapped_regs + mmMEM_EXT_TIMING_CNTL); - - val = readl(remapped_regs + mmMEM_EXT_CNTL); - val &= ~(0x00040000); /* bit18=0 */ - val |= 0x00080000; /* bit19=1 */ - writel(val, remapped_regs + mmMEM_EXT_CNTL); - - udelay(1); /* wait 1us */ - - if (mode == W100_SUSPEND_EXTMEM) { - /* CKE: Tri-State */ - val = readl(remapped_regs + mmMEM_EXT_CNTL); - val |= 0x40000000; /* bit30=1 */ - writel(val, remapped_regs + mmMEM_EXT_CNTL); - - /* CLK: Stop */ - val = readl(remapped_regs + mmMEM_EXT_CNTL); - val &= ~(0x00000001); /* bit0=0 */ - writel(val, remapped_regs + mmMEM_EXT_CNTL); - } else { - writel(0x00000000, remapped_regs + mmSCLK_CNTL); - writel(0x000000BF, remapped_regs + mmCLK_PIN_CNTL); - writel(0x00000015, remapped_regs + mmPWRMGT_CNTL); - - udelay(5); - - val = readl(remapped_regs + mmPLL_CNTL); - val |= 0x00000004; /* bit2=1 */ - writel(val, remapped_regs + mmPLL_CNTL); - - writel(0x00000000, remapped_regs + mmLCDD_CNTL1); - writel(0x00000000, remapped_regs + mmLCDD_CNTL2); - writel(0x00000000, remapped_regs + mmGENLCD_CNTL1); - writel(0x00000000, remapped_regs + mmGENLCD_CNTL2); - writel(0x00000000, remapped_regs + mmGENLCD_CNTL3); - - val = readl(remapped_regs + mmMEM_EXT_CNTL); - val |= 0xF0000000; - val &= ~(0x00000001); - writel(val, remapped_regs + mmMEM_EXT_CNTL); - - writel(0x0000001d, remapped_regs + mmPWRMGT_CNTL); - } -} - -static void w100_vsync(void) -{ - u32 tmp; - int timeout = 30000; /* VSync timeout = 30[ms] > 16.8[ms] */ - - tmp = readl(remapped_regs + mmACTIVE_V_DISP); - - /* set vline pos */ - writel((tmp >> 16) & 0x3ff, remapped_regs + mmDISP_INT_CNTL); - - /* disable vline irq */ - tmp = readl(remapped_regs + mmGEN_INT_CNTL); - - tmp &= ~0x00000002; - writel(tmp, remapped_regs + mmGEN_INT_CNTL); - - /* clear vline irq status */ - writel(0x00000002, remapped_regs + mmGEN_INT_STATUS); - - /* enable vline irq */ - writel((tmp | 0x00000002), remapped_regs + mmGEN_INT_CNTL); - - /* clear vline irq status */ - writel(0x00000002, remapped_regs + mmGEN_INT_STATUS); - - while(timeout > 0) { - if (readl(remapped_regs + mmGEN_INT_STATUS) & 0x00000002) - break; - udelay(1); - timeout--; - } - - /* disable vline irq */ - writel(tmp, remapped_regs + mmGEN_INT_CNTL); - - /* clear vline irq status */ - writel(0x00000002, remapped_regs + mmGEN_INT_STATUS); -} - -static struct platform_driver w100fb_driver = { - .probe = w100fb_probe, - .remove = w100fb_remove, - .suspend = w100fb_suspend, - .resume = w100fb_resume, - .driver = { - .name = "w100fb", - .dev_groups = w100fb_groups, - }, -}; - -module_platform_driver(w100fb_driver); - -MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/w100fb.h b/drivers/video/fbdev/w100fb.h deleted file mode 100644 index 52c96d155b4c..000000000000 --- a/drivers/video/fbdev/w100fb.h +++ /dev/null @@ -1,924 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * linux/drivers/video/w100fb.h - * - * Frame Buffer Device for ATI w100 (Wallaby) - * - * Copyright (C) 2002, ATI Corp. - * Copyright (C) 2004-2005 Richard Purdie - * Copyright (c) 2005 Ian Molton <spyro@f2s.com> - * - * Modified to work with 2.6 by Richard Purdie <rpurdie@rpsys.net> - * - * w32xx support by Ian Molton - */ - -#if !defined (_W100FB_H) -#define _W100FB_H - -/* Block CIF Start: */ -#define mmCHIP_ID 0x0000 -#define mmREVISION_ID 0x0004 -#define mmWRAP_BUF_A 0x0008 -#define mmWRAP_BUF_B 0x000C -#define mmWRAP_TOP_DIR 0x0010 -#define mmWRAP_START_DIR 0x0014 -#define mmCIF_CNTL 0x0018 -#define mmCFGREG_BASE 0x001C -#define mmCIF_IO 0x0020 -#define mmCIF_READ_DBG 0x0024 -#define mmCIF_WRITE_DBG 0x0028 -#define cfgIND_ADDR_A_0 0x0000 -#define cfgIND_ADDR_A_1 0x0001 -#define cfgIND_ADDR_A_2 0x0002 -#define cfgIND_DATA_A 0x0003 -#define cfgREG_BASE 0x0004 -#define cfgINTF_CNTL 0x0005 -#define cfgSTATUS 0x0006 -#define cfgCPU_DEFAULTS 0x0007 -#define cfgIND_ADDR_B_0 0x0008 -#define cfgIND_ADDR_B_1 0x0009 -#define cfgIND_ADDR_B_2 0x000A -#define cfgIND_DATA_B 0x000B -#define cfgPM4_RPTR 0x000C -#define cfgSCRATCH 0x000D -#define cfgPM4_WRPTR_0 0x000E -#define cfgPM4_WRPTR_1 0x000F -/* Block CIF End: */ - -/* Block CP Start: */ -#define mmSCRATCH_UMSK 0x0280 -#define mmSCRATCH_ADDR 0x0284 -#define mmGEN_INT_CNTL 0x0200 -#define mmGEN_INT_STATUS 0x0204 -/* Block CP End: */ - -/* Block DISPLAY Start: */ -#define mmLCD_FORMAT 0x0410 -#define mmGRAPHIC_CTRL 0x0414 -#define mmGRAPHIC_OFFSET 0x0418 -#define mmGRAPHIC_PITCH 0x041C -#define mmCRTC_TOTAL 0x0420 -#define mmACTIVE_H_DISP 0x0424 -#define mmACTIVE_V_DISP 0x0428 -#define mmGRAPHIC_H_DISP 0x042C -#define mmGRAPHIC_V_DISP 0x0430 -#define mmVIDEO_CTRL 0x0434 -#define mmGRAPHIC_KEY 0x0438 -#define mmBRIGHTNESS_CNTL 0x045C -#define mmDISP_INT_CNTL 0x0488 -#define mmCRTC_SS 0x048C -#define mmCRTC_LS 0x0490 -#define mmCRTC_REV 0x0494 -#define mmCRTC_DCLK 0x049C -#define mmCRTC_GS 0x04A0 -#define mmCRTC_VPOS_GS 0x04A4 -#define mmCRTC_GCLK 0x04A8 -#define mmCRTC_GOE 0x04AC -#define mmCRTC_FRAME 0x04B0 -#define mmCRTC_FRAME_VPOS 0x04B4 -#define mmGPIO_DATA 0x04B8 -#define mmGPIO_CNTL1 0x04BC -#define mmGPIO_CNTL2 0x04C0 -#define mmLCDD_CNTL1 0x04C4 -#define mmLCDD_CNTL2 0x04C8 -#define mmGENLCD_CNTL1 0x04CC -#define mmGENLCD_CNTL2 0x04D0 -#define mmDISP_DEBUG 0x04D4 -#define mmDISP_DB_BUF_CNTL 0x04D8 -#define mmDISP_CRC_SIG 0x04DC -#define mmCRTC_DEFAULT_COUNT 0x04E0 -#define mmLCD_BACKGROUND_COLOR 0x04E4 -#define mmCRTC_PS2 0x04E8 -#define mmCRTC_PS2_VPOS 0x04EC -#define mmCRTC_PS1_ACTIVE 0x04F0 -#define mmCRTC_PS1_NACTIVE 0x04F4 -#define mmCRTC_GCLK_EXT 0x04F8 -#define mmCRTC_ALW 0x04FC -#define mmCRTC_ALW_VPOS 0x0500 -#define mmCRTC_PSK 0x0504 -#define mmCRTC_PSK_HPOS 0x0508 -#define mmCRTC_CV4_START 0x050C -#define mmCRTC_CV4_END 0x0510 -#define mmCRTC_CV4_HPOS 0x0514 -#define mmCRTC_ECK 0x051C -#define mmREFRESH_CNTL 0x0520 -#define mmGENLCD_CNTL3 0x0524 -#define mmGPIO_DATA2 0x0528 -#define mmGPIO_CNTL3 0x052C -#define mmGPIO_CNTL4 0x0530 -#define mmCHIP_STRAP 0x0534 -#define mmDISP_DEBUG2 0x0538 -#define mmDEBUG_BUS_CNTL 0x053C -#define mmGAMMA_VALUE1 0x0540 -#define mmGAMMA_VALUE2 0x0544 -#define mmGAMMA_SLOPE 0x0548 -#define mmGEN_STATUS 0x054C -#define mmHW_INT 0x0550 -/* Block DISPLAY End: */ - -/* Block GFX Start: */ -#define mmDST_OFFSET 0x1004 -#define mmDST_PITCH 0x1008 -#define mmDST_Y_X 0x1038 -#define mmDST_WIDTH_HEIGHT 0x1198 -#define mmDP_GUI_MASTER_CNTL 0x106C -#define mmBRUSH_OFFSET 0x108C -#define mmBRUSH_Y_X 0x1074 -#define mmDP_BRUSH_FRGD_CLR 0x107C -#define mmSRC_OFFSET 0x11AC -#define mmSRC_PITCH 0x11B0 -#define mmSRC_Y_X 0x1034 -#define mmDEFAULT_PITCH_OFFSET 0x10A0 -#define mmDEFAULT_SC_BOTTOM_RIGHT 0x10A8 -#define mmDEFAULT2_SC_BOTTOM_RIGHT 0x10AC -#define mmSC_TOP_LEFT 0x11BC -#define mmSC_BOTTOM_RIGHT 0x11C0 -#define mmSRC_SC_BOTTOM_RIGHT 0x11C4 -#define mmGLOBAL_ALPHA 0x1210 -#define mmFILTER_COEF 0x1214 -#define mmMVC_CNTL_START 0x11E0 -#define mmE2_ARITHMETIC_CNTL 0x1220 -#define mmDP_CNTL 0x11C8 -#define mmDP_CNTL_DST_DIR 0x11CC -#define mmDP_DATATYPE 0x12C4 -#define mmDP_MIX 0x12C8 -#define mmDP_WRITE_MSK 0x12CC -#define mmENG_CNTL 0x13E8 -#define mmENG_PERF_CNT 0x13F0 -/* Block GFX End: */ - -/* Block IDCT Start: */ -#define mmIDCT_RUNS 0x0C00 -#define mmIDCT_LEVELS 0x0C04 -#define mmIDCT_CONTROL 0x0C3C -#define mmIDCT_AUTH_CONTROL 0x0C08 -#define mmIDCT_AUTH 0x0C0C -/* Block IDCT End: */ - -/* Block MC Start: */ -#define mmMEM_CNTL 0x0180 -#define mmMEM_ARB 0x0184 -#define mmMC_FB_LOCATION 0x0188 -#define mmMEM_EXT_CNTL 0x018C -#define mmMC_EXT_MEM_LOCATION 0x0190 -#define mmMEM_EXT_TIMING_CNTL 0x0194 -#define mmMEM_SDRAM_MODE_REG 0x0198 -#define mmMEM_IO_CNTL 0x019C -#define mmMC_DEBUG 0x01A0 -#define mmMC_BIST_CTRL 0x01A4 -#define mmMC_BIST_COLLAR_READ 0x01A8 -#define mmTC_MISMATCH 0x01AC -#define mmMC_PERF_MON_CNTL 0x01B0 -#define mmMC_PERF_COUNTERS 0x01B4 -/* Block MC End: */ - -/* Block BM Start: */ -#define mmBM_EXT_MEM_BANDWIDTH 0x0A00 -#define mmBM_OFFSET 0x0A04 -#define mmBM_MEM_EXT_TIMING_CNTL 0x0A08 -#define mmBM_MEM_EXT_CNTL 0x0A0C -#define mmBM_MEM_MODE_REG 0x0A10 -#define mmBM_MEM_IO_CNTL 0x0A18 -#define mmBM_CONFIG 0x0A1C -#define mmBM_STATUS 0x0A20 -#define mmBM_DEBUG 0x0A24 -#define mmBM_PERF_MON_CNTL 0x0A28 -#define mmBM_PERF_COUNTERS 0x0A2C -#define mmBM_PERF2_MON_CNTL 0x0A30 -#define mmBM_PERF2_COUNTERS 0x0A34 -/* Block BM End: */ - -/* Block RBBM Start: */ -#define mmWAIT_UNTIL 0x1400 -#define mmISYNC_CNTL 0x1404 -#define mmRBBM_STATUS 0x0140 -#define mmRBBM_CNTL 0x0144 -#define mmNQWAIT_UNTIL 0x0150 -/* Block RBBM End: */ - -/* Block CG Start: */ -#define mmCLK_PIN_CNTL 0x0080 -#define mmPLL_REF_FB_DIV 0x0084 -#define mmPLL_CNTL 0x0088 -#define mmSCLK_CNTL 0x008C -#define mmPCLK_CNTL 0x0090 -#define mmCLK_TEST_CNTL 0x0094 -#define mmPWRMGT_CNTL 0x0098 -#define mmPWRMGT_STATUS 0x009C -/* Block CG End: */ - -/* default value definitions */ -#define defWRAP_TOP_DIR 0x00000000 -#define defWRAP_START_DIR 0x00000000 -#define defCFGREG_BASE 0x00000000 -#define defCIF_IO 0x000C0902 -#define defINTF_CNTL 0x00000011 -#define defCPU_DEFAULTS 0x00000006 -#define defHW_INT 0x00000000 -#define defMC_EXT_MEM_LOCATION 0x07ff0000 -#define defTC_MISMATCH 0x00000000 - -#define W100_CFG_BASE 0x0 -#define W100_CFG_LEN 0x10 -#define W100_REG_BASE 0x10000 -#define W100_REG_LEN 0x2000 -#define MEM_INT_BASE_VALUE 0x100000 -#define MEM_EXT_BASE_VALUE 0x800000 -#define MEM_INT_SIZE 0x05ffff -#define MEM_WINDOW_BASE 0x100000 -#define MEM_WINDOW_SIZE 0xf00000 - -#define WRAP_BUF_BASE_VALUE 0x80000 -#define WRAP_BUF_TOP_VALUE 0xbffff - -#define CHIP_ID_W100 0x57411002 -#define CHIP_ID_W3200 0x56441002 -#define CHIP_ID_W3220 0x57441002 - -/* Register structure definitions */ - -struct wrap_top_dir_t { - u32 top_addr : 23; - u32 : 9; -} __attribute__((packed)); - -union wrap_top_dir_u { - u32 val : 32; - struct wrap_top_dir_t f; -} __attribute__((packed)); - -struct wrap_start_dir_t { - u32 start_addr : 23; - u32 : 9; -} __attribute__((packed)); - -union wrap_start_dir_u { - u32 val : 32; - struct wrap_start_dir_t f; -} __attribute__((packed)); - -struct cif_cntl_t { - u32 swap_reg : 2; - u32 swap_fbuf_1 : 2; - u32 swap_fbuf_2 : 2; - u32 swap_fbuf_3 : 2; - u32 pmi_int_disable : 1; - u32 pmi_schmen_disable : 1; - u32 intb_oe : 1; - u32 en_wait_to_compensate_dq_prop_dly : 1; - u32 compensate_wait_rd_size : 2; - u32 wait_asserted_timeout_val : 2; - u32 wait_masked_val : 2; - u32 en_wait_timeout : 1; - u32 en_one_clk_setup_before_wait : 1; - u32 interrupt_active_high : 1; - u32 en_overwrite_straps : 1; - u32 strap_wait_active_hi : 1; - u32 lat_busy_count : 2; - u32 lat_rd_pm4_sclk_busy : 1; - u32 dis_system_bits : 1; - u32 dis_mr : 1; - u32 cif_spare_1 : 4; -} __attribute__((packed)); - -union cif_cntl_u { - u32 val : 32; - struct cif_cntl_t f; -} __attribute__((packed)); - -struct cfgreg_base_t { - u32 cfgreg_base : 24; - u32 : 8; -} __attribute__((packed)); - -union cfgreg_base_u { - u32 val : 32; - struct cfgreg_base_t f; -} __attribute__((packed)); - -struct cif_io_t { - u32 dq_srp : 1; - u32 dq_srn : 1; - u32 dq_sp : 4; - u32 dq_sn : 4; - u32 waitb_srp : 1; - u32 waitb_srn : 1; - u32 waitb_sp : 4; - u32 waitb_sn : 4; - u32 intb_srp : 1; - u32 intb_srn : 1; - u32 intb_sp : 4; - u32 intb_sn : 4; - u32 : 2; -} __attribute__((packed)); - -union cif_io_u { - u32 val : 32; - struct cif_io_t f; -} __attribute__((packed)); - -struct cif_read_dbg_t { - u32 unpacker_pre_fetch_trig_gen : 2; - u32 dly_second_rd_fetch_trig : 1; - u32 rst_rd_burst_id : 1; - u32 dis_rd_burst_id : 1; - u32 en_block_rd_when_packer_is_not_emp : 1; - u32 dis_pre_fetch_cntl_sm : 1; - u32 rbbm_chrncy_dis : 1; - u32 rbbm_rd_after_wr_lat : 2; - u32 dis_be_during_rd : 1; - u32 one_clk_invalidate_pulse : 1; - u32 dis_chnl_priority : 1; - u32 rst_read_path_a_pls : 1; - u32 rst_read_path_b_pls : 1; - u32 dis_reg_rd_fetch_trig : 1; - u32 dis_rd_fetch_trig_from_ind_addr : 1; - u32 dis_rd_same_byte_to_trig_fetch : 1; - u32 dis_dir_wrap : 1; - u32 dis_ring_buf_to_force_dec : 1; - u32 dis_addr_comp_in_16bit : 1; - u32 clr_w : 1; - u32 err_rd_tag_is_3 : 1; - u32 err_load_when_ful_a : 1; - u32 err_load_when_ful_b : 1; - u32 : 7; -} __attribute__((packed)); - -union cif_read_dbg_u { - u32 val : 32; - struct cif_read_dbg_t f; -} __attribute__((packed)); - -struct cif_write_dbg_t { - u32 packer_timeout_count : 2; - u32 en_upper_load_cond : 1; - u32 en_chnl_change_cond : 1; - u32 dis_addr_comp_cond : 1; - u32 dis_load_same_byte_addr_cond : 1; - u32 dis_timeout_cond : 1; - u32 dis_timeout_during_rbbm : 1; - u32 dis_packer_ful_during_rbbm_timeout : 1; - u32 en_dword_split_to_rbbm : 1; - u32 en_dummy_val : 1; - u32 dummy_val_sel : 1; - u32 mask_pm4_wrptr_dec : 1; - u32 dis_mc_clean_cond : 1; - u32 err_two_reqi_during_ful : 1; - u32 err_reqi_during_idle_clk : 1; - u32 err_global : 1; - u32 en_wr_buf_dbg_load : 1; - u32 en_wr_buf_dbg_path : 1; - u32 sel_wr_buf_byte : 3; - u32 dis_rd_flush_wr : 1; - u32 dis_packer_ful_cond : 1; - u32 dis_invalidate_by_ops_chnl : 1; - u32 en_halt_when_reqi_err : 1; - u32 cif_spare_2 : 5; - u32 : 1; -} __attribute__((packed)); - -union cif_write_dbg_u { - u32 val : 32; - struct cif_write_dbg_t f; -} __attribute__((packed)); - - -struct intf_cntl_t { - unsigned char ad_inc_a : 1; - unsigned char ring_buf_a : 1; - unsigned char rd_fetch_trigger_a : 1; - unsigned char rd_data_rdy_a : 1; - unsigned char ad_inc_b : 1; - unsigned char ring_buf_b : 1; - unsigned char rd_fetch_trigger_b : 1; - unsigned char rd_data_rdy_b : 1; -} __attribute__((packed)); - -union intf_cntl_u { - unsigned char val : 8; - struct intf_cntl_t f; -} __attribute__((packed)); - -struct cpu_defaults_t { - unsigned char unpack_rd_data : 1; - unsigned char access_ind_addr_a : 1; - unsigned char access_ind_addr_b : 1; - unsigned char access_scratch_reg : 1; - unsigned char pack_wr_data : 1; - unsigned char transition_size : 1; - unsigned char en_read_buf_mode : 1; - unsigned char rd_fetch_scratch : 1; -} __attribute__((packed)); - -union cpu_defaults_u { - unsigned char val : 8; - struct cpu_defaults_t f; -} __attribute__((packed)); - -struct crtc_total_t { - u32 crtc_h_total : 10; - u32 : 6; - u32 crtc_v_total : 10; - u32 : 6; -} __attribute__((packed)); - -union crtc_total_u { - u32 val : 32; - struct crtc_total_t f; -} __attribute__((packed)); - -struct crtc_ss_t { - u32 ss_start : 10; - u32 : 6; - u32 ss_end : 10; - u32 : 2; - u32 ss_align : 1; - u32 ss_pol : 1; - u32 ss_run_mode : 1; - u32 ss_en : 1; -} __attribute__((packed)); - -union crtc_ss_u { - u32 val : 32; - struct crtc_ss_t f; -} __attribute__((packed)); - -struct active_h_disp_t { - u32 active_h_start : 10; - u32 : 6; - u32 active_h_end : 10; - u32 : 6; -} __attribute__((packed)); - -union active_h_disp_u { - u32 val : 32; - struct active_h_disp_t f; -} __attribute__((packed)); - -struct active_v_disp_t { - u32 active_v_start : 10; - u32 : 6; - u32 active_v_end : 10; - u32 : 6; -} __attribute__((packed)); - -union active_v_disp_u { - u32 val : 32; - struct active_v_disp_t f; -} __attribute__((packed)); - -struct graphic_h_disp_t { - u32 graphic_h_start : 10; - u32 : 6; - u32 graphic_h_end : 10; - u32 : 6; -} __attribute__((packed)); - -union graphic_h_disp_u { - u32 val : 32; - struct graphic_h_disp_t f; -} __attribute__((packed)); - -struct graphic_v_disp_t { - u32 graphic_v_start : 10; - u32 : 6; - u32 graphic_v_end : 10; - u32 : 6; -} __attribute__((packed)); - -union graphic_v_disp_u{ - u32 val : 32; - struct graphic_v_disp_t f; -} __attribute__((packed)); - -struct graphic_ctrl_t_w100 { - u32 color_depth : 3; - u32 portrait_mode : 2; - u32 low_power_on : 1; - u32 req_freq : 4; - u32 en_crtc : 1; - u32 en_graphic_req : 1; - u32 en_graphic_crtc : 1; - u32 total_req_graphic : 9; - u32 lcd_pclk_on : 1; - u32 lcd_sclk_on : 1; - u32 pclk_running : 1; - u32 sclk_running : 1; - u32 : 6; -} __attribute__((packed)); - -struct graphic_ctrl_t_w32xx { - u32 color_depth : 3; - u32 portrait_mode : 2; - u32 low_power_on : 1; - u32 req_freq : 4; - u32 en_crtc : 1; - u32 en_graphic_req : 1; - u32 en_graphic_crtc : 1; - u32 total_req_graphic : 10; - u32 lcd_pclk_on : 1; - u32 lcd_sclk_on : 1; - u32 pclk_running : 1; - u32 sclk_running : 1; - u32 : 5; -} __attribute__((packed)); - -union graphic_ctrl_u { - u32 val : 32; - struct graphic_ctrl_t_w100 f_w100; - struct graphic_ctrl_t_w32xx f_w32xx; -} __attribute__((packed)); - -struct video_ctrl_t { - u32 video_mode : 1; - u32 keyer_en : 1; - u32 en_video_req : 1; - u32 en_graphic_req_video : 1; - u32 en_video_crtc : 1; - u32 video_hor_exp : 2; - u32 video_ver_exp : 2; - u32 uv_combine : 1; - u32 total_req_video : 9; - u32 video_ch_sel : 1; - u32 video_portrait : 2; - u32 yuv2rgb_en : 1; - u32 yuv2rgb_option : 1; - u32 video_inv_hor : 1; - u32 video_inv_ver : 1; - u32 gamma_sel : 2; - u32 dis_limit : 1; - u32 en_uv_hblend : 1; - u32 rgb_gamma_sel : 2; -} __attribute__((packed)); - -union video_ctrl_u { - u32 val : 32; - struct video_ctrl_t f; -} __attribute__((packed)); - -struct disp_db_buf_cntl_rd_t { - u32 en_db_buf : 1; - u32 update_db_buf_done : 1; - u32 db_buf_cntl : 6; - u32 : 24; -} __attribute__((packed)); - -union disp_db_buf_cntl_rd_u { - u32 val : 32; - struct disp_db_buf_cntl_rd_t f; -} __attribute__((packed)); - -struct disp_db_buf_cntl_wr_t { - u32 en_db_buf : 1; - u32 update_db_buf : 1; - u32 db_buf_cntl : 6; - u32 : 24; -} __attribute__((packed)); - -union disp_db_buf_cntl_wr_u { - u32 val : 32; - struct disp_db_buf_cntl_wr_t f; -} __attribute__((packed)); - -struct gamma_value1_t { - u32 gamma1 : 8; - u32 gamma2 : 8; - u32 gamma3 : 8; - u32 gamma4 : 8; -} __attribute__((packed)); - -union gamma_value1_u { - u32 val : 32; - struct gamma_value1_t f; -} __attribute__((packed)); - -struct gamma_value2_t { - u32 gamma5 : 8; - u32 gamma6 : 8; - u32 gamma7 : 8; - u32 gamma8 : 8; -} __attribute__((packed)); - -union gamma_value2_u { - u32 val : 32; - struct gamma_value2_t f; -} __attribute__((packed)); - -struct gamma_slope_t { - u32 slope1 : 3; - u32 slope2 : 3; - u32 slope3 : 3; - u32 slope4 : 3; - u32 slope5 : 3; - u32 slope6 : 3; - u32 slope7 : 3; - u32 slope8 : 3; - u32 : 8; -} __attribute__((packed)); - -union gamma_slope_u { - u32 val : 32; - struct gamma_slope_t f; -} __attribute__((packed)); - -struct mc_ext_mem_location_t { - u32 mc_ext_mem_start : 16; - u32 mc_ext_mem_top : 16; -} __attribute__((packed)); - -union mc_ext_mem_location_u { - u32 val : 32; - struct mc_ext_mem_location_t f; -} __attribute__((packed)); - -struct mc_fb_location_t { - u32 mc_fb_start : 16; - u32 mc_fb_top : 16; -} __attribute__((packed)); - -union mc_fb_location_u { - u32 val : 32; - struct mc_fb_location_t f; -} __attribute__((packed)); - -struct clk_pin_cntl_t { - u32 osc_en : 1; - u32 osc_gain : 5; - u32 dont_use_xtalin : 1; - u32 xtalin_pm_en : 1; - u32 xtalin_dbl_en : 1; - u32 : 7; - u32 cg_debug : 16; -} __attribute__((packed)); - -union clk_pin_cntl_u { - u32 val : 32; - struct clk_pin_cntl_t f; -} __attribute__((packed)); - -struct pll_ref_fb_div_t { - u32 pll_ref_div : 4; - u32 : 4; - u32 pll_fb_div_int : 6; - u32 : 2; - u32 pll_fb_div_frac : 3; - u32 : 1; - u32 pll_reset_time : 4; - u32 pll_lock_time : 8; -} __attribute__((packed)); - -union pll_ref_fb_div_u { - u32 val : 32; - struct pll_ref_fb_div_t f; -} __attribute__((packed)); - -struct pll_cntl_t { - u32 pll_pwdn : 1; - u32 pll_reset : 1; - u32 pll_pm_en : 1; - u32 pll_mode : 1; - u32 pll_refclk_sel : 1; - u32 pll_fbclk_sel : 1; - u32 pll_tcpoff : 1; - u32 pll_pcp : 3; - u32 pll_pvg : 3; - u32 pll_vcofr : 1; - u32 pll_ioffset : 2; - u32 pll_pecc_mode : 2; - u32 pll_pecc_scon : 2; - u32 pll_dactal : 4; - u32 pll_cp_clip : 2; - u32 pll_conf : 3; - u32 pll_mbctrl : 2; - u32 pll_ring_off : 1; -} __attribute__((packed)); - -union pll_cntl_u { - u32 val : 32; - struct pll_cntl_t f; -} __attribute__((packed)); - -struct sclk_cntl_t { - u32 sclk_src_sel : 2; - u32 : 2; - u32 sclk_post_div_fast : 4; - u32 sclk_clkon_hys : 3; - u32 sclk_post_div_slow : 4; - u32 disp_cg_ok2switch_en : 1; - u32 sclk_force_reg : 1; - u32 sclk_force_disp : 1; - u32 sclk_force_mc : 1; - u32 sclk_force_extmc : 1; - u32 sclk_force_cp : 1; - u32 sclk_force_e2 : 1; - u32 sclk_force_e3 : 1; - u32 sclk_force_idct : 1; - u32 sclk_force_bist : 1; - u32 busy_extend_cp : 1; - u32 busy_extend_e2 : 1; - u32 busy_extend_e3 : 1; - u32 busy_extend_idct : 1; - u32 : 3; -} __attribute__((packed)); - -union sclk_cntl_u { - u32 val : 32; - struct sclk_cntl_t f; -} __attribute__((packed)); - -struct pclk_cntl_t { - u32 pclk_src_sel : 2; - u32 : 2; - u32 pclk_post_div : 4; - u32 : 8; - u32 pclk_force_disp : 1; - u32 : 15; -} __attribute__((packed)); - -union pclk_cntl_u { - u32 val : 32; - struct pclk_cntl_t f; -} __attribute__((packed)); - - -#define TESTCLK_SRC_PLL 0x01 -#define TESTCLK_SRC_SCLK 0x02 -#define TESTCLK_SRC_PCLK 0x03 -/* 4 and 5 seem to by XTAL/M */ -#define TESTCLK_SRC_XTAL 0x06 - -struct clk_test_cntl_t { - u32 testclk_sel : 4; - u32 : 3; - u32 start_check_freq : 1; - u32 tstcount_rst : 1; - u32 : 15; - u32 test_count : 8; -} __attribute__((packed)); - -union clk_test_cntl_u { - u32 val : 32; - struct clk_test_cntl_t f; -} __attribute__((packed)); - -struct pwrmgt_cntl_t { - u32 pwm_enable : 1; - u32 : 1; - u32 pwm_mode_req : 2; - u32 pwm_wakeup_cond : 2; - u32 pwm_fast_noml_hw_en : 1; - u32 pwm_noml_fast_hw_en : 1; - u32 pwm_fast_noml_cond : 4; - u32 pwm_noml_fast_cond : 4; - u32 pwm_idle_timer : 8; - u32 pwm_busy_timer : 8; -} __attribute__((packed)); - -union pwrmgt_cntl_u { - u32 val : 32; - struct pwrmgt_cntl_t f; -} __attribute__((packed)); - -#define SRC_DATATYPE_EQU_DST 3 - -#define ROP3_SRCCOPY 0xcc -#define ROP3_PATCOPY 0xf0 - -#define GMC_BRUSH_SOLID_COLOR 13 -#define GMC_BRUSH_NONE 15 - -#define DP_SRC_MEM_RECTANGULAR 2 - -#define DP_OP_ROP 0 - -struct dp_gui_master_cntl_t { - u32 gmc_src_pitch_offset_cntl : 1; - u32 gmc_dst_pitch_offset_cntl : 1; - u32 gmc_src_clipping : 1; - u32 gmc_dst_clipping : 1; - u32 gmc_brush_datatype : 4; - u32 gmc_dst_datatype : 4; - u32 gmc_src_datatype : 3; - u32 gmc_byte_pix_order : 1; - u32 gmc_default_sel : 1; - u32 gmc_rop3 : 8; - u32 gmc_dp_src_source : 3; - u32 gmc_clr_cmp_fcn_dis : 1; - u32 : 1; - u32 gmc_wr_msk_dis : 1; - u32 gmc_dp_op : 1; -} __attribute__((packed)); - -union dp_gui_master_cntl_u { - u32 val : 32; - struct dp_gui_master_cntl_t f; -} __attribute__((packed)); - -struct rbbm_status_t { - u32 cmdfifo_avail : 7; - u32 : 1; - u32 hirq_on_rbb : 1; - u32 cprq_on_rbb : 1; - u32 cfrq_on_rbb : 1; - u32 hirq_in_rtbuf : 1; - u32 cprq_in_rtbuf : 1; - u32 cfrq_in_rtbuf : 1; - u32 cf_pipe_busy : 1; - u32 eng_ev_busy : 1; - u32 cp_cmdstrm_busy : 1; - u32 e2_busy : 1; - u32 rb2d_busy : 1; - u32 rb3d_busy : 1; - u32 se_busy : 1; - u32 re_busy : 1; - u32 tam_busy : 1; - u32 tdm_busy : 1; - u32 pb_busy : 1; - u32 : 6; - u32 gui_active : 1; -} __attribute__((packed)); - -union rbbm_status_u { - u32 val : 32; - struct rbbm_status_t f; -} __attribute__((packed)); - -struct dp_datatype_t { - u32 dp_dst_datatype : 4; - u32 : 4; - u32 dp_brush_datatype : 4; - u32 dp_src2_type : 1; - u32 dp_src2_datatype : 3; - u32 dp_src_datatype : 3; - u32 : 11; - u32 dp_byte_pix_order : 1; - u32 : 1; -} __attribute__((packed)); - -union dp_datatype_u { - u32 val : 32; - struct dp_datatype_t f; -} __attribute__((packed)); - -struct dp_mix_t { - u32 : 8; - u32 dp_src_source : 3; - u32 dp_src2_source : 3; - u32 : 2; - u32 dp_rop3 : 8; - u32 dp_op : 1; - u32 : 7; -} __attribute__((packed)); - -union dp_mix_u { - u32 val : 32; - struct dp_mix_t f; -} __attribute__((packed)); - -struct eng_cntl_t { - u32 erc_reg_rd_ws : 1; - u32 erc_reg_wr_ws : 1; - u32 erc_idle_reg_wr : 1; - u32 dis_engine_triggers : 1; - u32 dis_rop_src_uses_dst_w_h : 1; - u32 dis_src_uses_dst_dirmaj : 1; - u32 : 6; - u32 force_3dclk_when_2dclk : 1; - u32 : 19; -} __attribute__((packed)); - -union eng_cntl_u { - u32 val : 32; - struct eng_cntl_t f; -} __attribute__((packed)); - -struct dp_cntl_t { - u32 dst_x_dir : 1; - u32 dst_y_dir : 1; - u32 src_x_dir : 1; - u32 src_y_dir : 1; - u32 dst_major_x : 1; - u32 src_major_x : 1; - u32 : 26; -} __attribute__((packed)); - -union dp_cntl_u { - u32 val : 32; - struct dp_cntl_t f; -} __attribute__((packed)); - -struct dp_cntl_dst_dir_t { - u32 : 15; - u32 dst_y_dir : 1; - u32 : 15; - u32 dst_x_dir : 1; -} __attribute__((packed)); - -union dp_cntl_dst_dir_u { - u32 val : 32; - struct dp_cntl_dst_dir_t f; -} __attribute__((packed)); - -#endif - diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c index 8752d389e382..d7f3e6281ce4 100644 --- a/drivers/video/fbdev/xen-fbfront.c +++ b/drivers/video/fbdev/xen-fbfront.c @@ -67,7 +67,7 @@ MODULE_PARM_DESC(video, "Video memory size in MB, width, height in pixels (default 2,800,600)"); static void xenfb_make_preferred_console(void); -static int xenfb_remove(struct xenbus_device *); +static void xenfb_remove(struct xenbus_device *); static void xenfb_init_shared_page(struct xenfb_info *, struct fb_info *); static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); static void xenfb_disconnect_backend(struct xenfb_info *); @@ -523,7 +523,7 @@ static int xenfb_resume(struct xenbus_device *dev) return xenfb_connect_backend(dev, info); } -static int xenfb_remove(struct xenbus_device *dev) +static void xenfb_remove(struct xenbus_device *dev) { struct xenfb_info *info = dev_get_drvdata(&dev->dev); @@ -538,8 +538,6 @@ static int xenfb_remove(struct xenbus_device *dev) vfree(info->gfns); vfree(info->fb); kfree(info); - - return 0; } static unsigned long vmalloc_to_gfn(void *address) diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 828ced060742..b9a80aedee1b 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -15,7 +15,7 @@ static ssize_t device_show(struct device *_d, struct device_attribute *attr, char *buf) { struct virtio_device *dev = dev_to_virtio(_d); - return sprintf(buf, "0x%04x\n", dev->id.device); + return sysfs_emit(buf, "0x%04x\n", dev->id.device); } static DEVICE_ATTR_RO(device); @@ -23,7 +23,7 @@ static ssize_t vendor_show(struct device *_d, struct device_attribute *attr, char *buf) { struct virtio_device *dev = dev_to_virtio(_d); - return sprintf(buf, "0x%04x\n", dev->id.vendor); + return sysfs_emit(buf, "0x%04x\n", dev->id.vendor); } static DEVICE_ATTR_RO(vendor); @@ -31,7 +31,7 @@ static ssize_t status_show(struct device *_d, struct device_attribute *attr, char *buf) { struct virtio_device *dev = dev_to_virtio(_d); - return sprintf(buf, "0x%08x\n", dev->config->get_status(dev)); + return sysfs_emit(buf, "0x%08x\n", dev->config->get_status(dev)); } static DEVICE_ATTR_RO(status); @@ -39,7 +39,7 @@ static ssize_t modalias_show(struct device *_d, struct device_attribute *attr, char *buf) { struct virtio_device *dev = dev_to_virtio(_d); - return sprintf(buf, "virtio:d%08Xv%08X\n", + return sysfs_emit(buf, "virtio:d%08Xv%08X\n", dev->id.device, dev->id.vendor); } static DEVICE_ATTR_RO(modalias); @@ -54,9 +54,9 @@ static ssize_t features_show(struct device *_d, /* We actually represent this as a bitstring, as it could be * arbitrary length in future. */ for (i = 0; i < sizeof(dev->features)*8; i++) - len += sprintf(buf+len, "%c", + len += sysfs_emit_at(buf, len, "%c", __virtio_test_bit(dev, i) ? '1' : '0'); - len += sprintf(buf+len, "\n"); + len += sysfs_emit_at(buf, len, "\n"); return len; } static DEVICE_ATTR_RO(features); diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c index c3b9f2761849..9e496e288cfa 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c @@ -303,14 +303,14 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, int err; if (index >= vp_modern_get_num_queues(mdev)) - return ERR_PTR(-ENOENT); + return ERR_PTR(-EINVAL); /* Check if queue is either not available or already active. */ num = vp_modern_get_queue_size(mdev, index); if (!num || vp_modern_get_queue_enable(mdev, index)) return ERR_PTR(-ENOENT); - if (num & (num - 1)) { + if (!is_power_of_2(num)) { dev_warn(&vp_dev->pci_dev->dev, "bad queue size %u", num); return ERR_PTR(-EINVAL); } diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 2e7689bb933b..723c4e29e1d3 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -1052,7 +1052,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split, dma_addr_t dma_addr; /* We assume num is a power of 2. */ - if (num & (num - 1)) { + if (!is_power_of_2(num)) { dev_warn(&vdev->dev, "Bad virtqueue length %u\n", num); return -EINVAL; } diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 24b9a8e05f64..692cac3ff0ee 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -41,13 +41,6 @@ config W1_MASTER_MXC help Say Y here to enable MXC 1-wire host -config W1_MASTER_DS1WM - tristate "Maxim DS1WM 1-wire busmaster" - help - Say Y here to enable the DS1WM 1-wire driver, such as that - in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like - hx4700. - config W1_MASTER_GPIO tristate "GPIO 1-wire busmaster" depends on GPIOLIB || COMPILE_TEST diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile index dae629b7ab49..c5d85a827e52 100644 --- a/drivers/w1/masters/Makefile +++ b/drivers/w1/masters/Makefile @@ -8,7 +8,6 @@ obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o obj-$(CONFIG_W1_MASTER_MXC) += mxc_w1.o -obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o obj-$(CONFIG_W1_MASTER_SGI) += sgi_w1.o diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c deleted file mode 100644 index f661695fb589..000000000000 --- a/drivers/w1/masters/ds1wm.c +++ /dev/null @@ -1,675 +0,0 @@ -/* - * 1-wire busmaster driver for DS1WM and ASICs with embedded DS1WMs - * such as HP iPAQs (including h5xxx, h2200, and devices with ASIC3 - * like hx4700). - * - * Copyright (c) 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> - * Copyright (c) 2004-2007, Matt Reimer <mreimer@vpop.net> - * - * Use consistent with the GNU GPL is permitted, - * provided that this copyright notice is - * preserved in its entirety in all copies and derived works. - */ - -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/pm.h> -#include <linux/platform_device.h> -#include <linux/err.h> -#include <linux/delay.h> -#include <linux/mfd/core.h> -#include <linux/mfd/ds1wm.h> -#include <linux/slab.h> - -#include <asm/io.h> - -#include <linux/w1.h> - - -#define DS1WM_CMD 0x00 /* R/W 4 bits command */ -#define DS1WM_DATA 0x01 /* R/W 8 bits, transmit/receive buffer */ -#define DS1WM_INT 0x02 /* R/W interrupt status */ -#define DS1WM_INT_EN 0x03 /* R/W interrupt enable */ -#define DS1WM_CLKDIV 0x04 /* R/W 5 bits of divisor and pre-scale */ -#define DS1WM_CNTRL 0x05 /* R/W master control register (not used yet) */ - -#define DS1WM_CMD_1W_RESET (1 << 0) /* force reset on 1-wire bus */ -#define DS1WM_CMD_SRA (1 << 1) /* enable Search ROM accelerator mode */ -#define DS1WM_CMD_DQ_OUTPUT (1 << 2) /* write only - forces bus low */ -#define DS1WM_CMD_DQ_INPUT (1 << 3) /* read only - reflects state of bus */ -#define DS1WM_CMD_RST (1 << 5) /* software reset */ -#define DS1WM_CMD_OD (1 << 7) /* overdrive */ - -#define DS1WM_INT_PD (1 << 0) /* presence detect */ -#define DS1WM_INT_PDR (1 << 1) /* presence detect result */ -#define DS1WM_INT_TBE (1 << 2) /* tx buffer empty */ -#define DS1WM_INT_TSRE (1 << 3) /* tx shift register empty */ -#define DS1WM_INT_RBF (1 << 4) /* rx buffer full */ -#define DS1WM_INT_RSRF (1 << 5) /* rx shift register full */ - -#define DS1WM_INTEN_EPD (1 << 0) /* enable presence detect int */ -#define DS1WM_INTEN_IAS (1 << 1) /* INTR active state */ -#define DS1WM_INTEN_ETBE (1 << 2) /* enable tx buffer empty int */ -#define DS1WM_INTEN_ETMT (1 << 3) /* enable tx shift register empty int */ -#define DS1WM_INTEN_ERBF (1 << 4) /* enable rx buffer full int */ -#define DS1WM_INTEN_ERSRF (1 << 5) /* enable rx shift register full int */ -#define DS1WM_INTEN_DQO (1 << 6) /* enable direct bus driving ops */ - -#define DS1WM_INTEN_NOT_IAS (~DS1WM_INTEN_IAS) /* all but INTR active state */ - -#define DS1WM_TIMEOUT (HZ * 5) - -static struct { - unsigned long freq; - unsigned long divisor; -} freq[] = { - { 1000000, 0x80 }, - { 2000000, 0x84 }, - { 3000000, 0x81 }, - { 4000000, 0x88 }, - { 5000000, 0x82 }, - { 6000000, 0x85 }, - { 7000000, 0x83 }, - { 8000000, 0x8c }, - { 10000000, 0x86 }, - { 12000000, 0x89 }, - { 14000000, 0x87 }, - { 16000000, 0x90 }, - { 20000000, 0x8a }, - { 24000000, 0x8d }, - { 28000000, 0x8b }, - { 32000000, 0x94 }, - { 40000000, 0x8e }, - { 48000000, 0x91 }, - { 56000000, 0x8f }, - { 64000000, 0x98 }, - { 80000000, 0x92 }, - { 96000000, 0x95 }, - { 112000000, 0x93 }, - { 128000000, 0x9c }, -/* you can continue this table, consult the OPERATION - CLOCK DIVISOR - section of the ds1wm spec sheet. */ -}; - -struct ds1wm_data { - void __iomem *map; - unsigned int bus_shift; /* # of shifts to calc register offsets */ - bool is_hw_big_endian; - struct platform_device *pdev; - const struct mfd_cell *cell; - int irq; - int slave_present; - void *reset_complete; - void *read_complete; - void *write_complete; - int read_error; - /* last byte received */ - u8 read_byte; - /* byte to write that makes all intr disabled, */ - /* considering active_state (IAS) (optimization) */ - u8 int_en_reg_none; - unsigned int reset_recover_delay; /* see ds1wm.h */ -}; - -static inline void ds1wm_write_register(struct ds1wm_data *ds1wm_data, u32 reg, - u8 val) -{ - if (ds1wm_data->is_hw_big_endian) { - switch (ds1wm_data->bus_shift) { - case 0: - iowrite8(val, ds1wm_data->map + (reg << 0)); - break; - case 1: - iowrite16be((u16)val, ds1wm_data->map + (reg << 1)); - break; - case 2: - iowrite32be((u32)val, ds1wm_data->map + (reg << 2)); - break; - } - } else { - switch (ds1wm_data->bus_shift) { - case 0: - iowrite8(val, ds1wm_data->map + (reg << 0)); - break; - case 1: - iowrite16((u16)val, ds1wm_data->map + (reg << 1)); - break; - case 2: - iowrite32((u32)val, ds1wm_data->map + (reg << 2)); - break; - } - } -} - -static inline u8 ds1wm_read_register(struct ds1wm_data *ds1wm_data, u32 reg) -{ - u32 val = 0; - - if (ds1wm_data->is_hw_big_endian) { - switch (ds1wm_data->bus_shift) { - case 0: - val = ioread8(ds1wm_data->map + (reg << 0)); - break; - case 1: - val = ioread16be(ds1wm_data->map + (reg << 1)); - break; - case 2: - val = ioread32be(ds1wm_data->map + (reg << 2)); - break; - } - } else { - switch (ds1wm_data->bus_shift) { - case 0: - val = ioread8(ds1wm_data->map + (reg << 0)); - break; - case 1: - val = ioread16(ds1wm_data->map + (reg << 1)); - break; - case 2: - val = ioread32(ds1wm_data->map + (reg << 2)); - break; - } - } - dev_dbg(&ds1wm_data->pdev->dev, - "ds1wm_read_register reg: %d, 32 bit val:%x\n", reg, val); - return (u8)val; -} - - -static irqreturn_t ds1wm_isr(int isr, void *data) -{ - struct ds1wm_data *ds1wm_data = data; - u8 intr; - u8 inten = ds1wm_read_register(ds1wm_data, DS1WM_INT_EN); - /* if no bits are set in int enable register (except the IAS) - than go no further, reading the regs below has side effects */ - if (!(inten & DS1WM_INTEN_NOT_IAS)) - return IRQ_NONE; - - ds1wm_write_register(ds1wm_data, - DS1WM_INT_EN, ds1wm_data->int_en_reg_none); - - /* this read action clears the INTR and certain flags in ds1wm */ - intr = ds1wm_read_register(ds1wm_data, DS1WM_INT); - - ds1wm_data->slave_present = (intr & DS1WM_INT_PDR) ? 0 : 1; - - if ((intr & DS1WM_INT_TSRE) && ds1wm_data->write_complete) { - inten &= ~DS1WM_INTEN_ETMT; - complete(ds1wm_data->write_complete); - } - if (intr & DS1WM_INT_RBF) { - /* this read clears the RBF flag */ - ds1wm_data->read_byte = ds1wm_read_register(ds1wm_data, - DS1WM_DATA); - inten &= ~DS1WM_INTEN_ERBF; - if (ds1wm_data->read_complete) - complete(ds1wm_data->read_complete); - } - if ((intr & DS1WM_INT_PD) && ds1wm_data->reset_complete) { - inten &= ~DS1WM_INTEN_EPD; - complete(ds1wm_data->reset_complete); - } - - ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, inten); - return IRQ_HANDLED; -} - -static int ds1wm_reset(struct ds1wm_data *ds1wm_data) -{ - unsigned long timeleft; - DECLARE_COMPLETION_ONSTACK(reset_done); - - ds1wm_data->reset_complete = &reset_done; - - /* enable Presence detect only */ - ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, DS1WM_INTEN_EPD | - ds1wm_data->int_en_reg_none); - - ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_1W_RESET); - - timeleft = wait_for_completion_timeout(&reset_done, DS1WM_TIMEOUT); - ds1wm_data->reset_complete = NULL; - if (!timeleft) { - dev_err(&ds1wm_data->pdev->dev, "reset failed, timed out\n"); - return 1; - } - - if (!ds1wm_data->slave_present) { - dev_dbg(&ds1wm_data->pdev->dev, "reset: no devices found\n"); - return 1; - } - - if (ds1wm_data->reset_recover_delay) - msleep(ds1wm_data->reset_recover_delay); - - return 0; -} - -static int ds1wm_write(struct ds1wm_data *ds1wm_data, u8 data) -{ - unsigned long timeleft; - DECLARE_COMPLETION_ONSTACK(write_done); - ds1wm_data->write_complete = &write_done; - - ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, - ds1wm_data->int_en_reg_none | DS1WM_INTEN_ETMT); - - ds1wm_write_register(ds1wm_data, DS1WM_DATA, data); - - timeleft = wait_for_completion_timeout(&write_done, DS1WM_TIMEOUT); - - ds1wm_data->write_complete = NULL; - if (!timeleft) { - dev_err(&ds1wm_data->pdev->dev, "write failed, timed out\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static u8 ds1wm_read(struct ds1wm_data *ds1wm_data, unsigned char write_data) -{ - unsigned long timeleft; - u8 intEnable = DS1WM_INTEN_ERBF | ds1wm_data->int_en_reg_none; - DECLARE_COMPLETION_ONSTACK(read_done); - - ds1wm_read_register(ds1wm_data, DS1WM_DATA); - - ds1wm_data->read_complete = &read_done; - ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, intEnable); - - ds1wm_write_register(ds1wm_data, DS1WM_DATA, write_data); - timeleft = wait_for_completion_timeout(&read_done, DS1WM_TIMEOUT); - - ds1wm_data->read_complete = NULL; - if (!timeleft) { - dev_err(&ds1wm_data->pdev->dev, "read failed, timed out\n"); - ds1wm_data->read_error = -ETIMEDOUT; - return 0xFF; - } - ds1wm_data->read_error = 0; - return ds1wm_data->read_byte; -} - -static int ds1wm_find_divisor(int gclk) -{ - int i; - - for (i = ARRAY_SIZE(freq)-1; i >= 0; --i) - if (gclk >= freq[i].freq) - return freq[i].divisor; - - return 0; -} - -static void ds1wm_up(struct ds1wm_data *ds1wm_data) -{ - int divisor; - struct device *dev = &ds1wm_data->pdev->dev; - struct ds1wm_driver_data *plat = dev_get_platdata(dev); - - if (ds1wm_data->cell->enable) - ds1wm_data->cell->enable(ds1wm_data->pdev); - - divisor = ds1wm_find_divisor(plat->clock_rate); - dev_dbg(dev, "found divisor 0x%x for clock %d\n", - divisor, plat->clock_rate); - if (divisor == 0) { - dev_err(dev, "no suitable divisor for %dHz clock\n", - plat->clock_rate); - return; - } - ds1wm_write_register(ds1wm_data, DS1WM_CLKDIV, divisor); - - /* Let the w1 clock stabilize. */ - msleep(1); - - ds1wm_reset(ds1wm_data); -} - -static void ds1wm_down(struct ds1wm_data *ds1wm_data) -{ - ds1wm_reset(ds1wm_data); - - /* Disable interrupts. */ - ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, - ds1wm_data->int_en_reg_none); - - if (ds1wm_data->cell->disable) - ds1wm_data->cell->disable(ds1wm_data->pdev); -} - -/* --------------------------------------------------------------------- */ -/* w1 methods */ - -static u8 ds1wm_read_byte(void *data) -{ - struct ds1wm_data *ds1wm_data = data; - - return ds1wm_read(ds1wm_data, 0xff); -} - -static void ds1wm_write_byte(void *data, u8 byte) -{ - struct ds1wm_data *ds1wm_data = data; - - ds1wm_write(ds1wm_data, byte); -} - -static u8 ds1wm_reset_bus(void *data) -{ - struct ds1wm_data *ds1wm_data = data; - - ds1wm_reset(ds1wm_data); - - return 0; -} - -static void ds1wm_search(void *data, struct w1_master *master_dev, - u8 search_type, w1_slave_found_callback slave_found) -{ - struct ds1wm_data *ds1wm_data = data; - int i; - int ms_discrep_bit = -1; - u64 r = 0; /* holds the progress of the search */ - u64 r_prime, d; - unsigned slaves_found = 0; - unsigned int pass = 0; - - dev_dbg(&ds1wm_data->pdev->dev, "search begin\n"); - while (true) { - ++pass; - if (pass > 100) { - dev_dbg(&ds1wm_data->pdev->dev, - "too many attempts (100), search aborted\n"); - return; - } - - mutex_lock(&master_dev->bus_mutex); - if (ds1wm_reset(ds1wm_data)) { - mutex_unlock(&master_dev->bus_mutex); - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d reset error (or no slaves)\n", pass); - break; - } - - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d r : %0#18llx writing SEARCH_ROM\n", pass, r); - ds1wm_write(ds1wm_data, search_type); - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d entering ASM\n", pass); - ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_SRA); - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d beginning nibble loop\n", pass); - - r_prime = 0; - d = 0; - /* we work one nibble at a time */ - /* each nibble is interleaved to form a byte */ - for (i = 0; i < 16; i++) { - - unsigned char resp, _r, _r_prime, _d; - - _r = (r >> (4*i)) & 0xf; - _r = ((_r & 0x1) << 1) | - ((_r & 0x2) << 2) | - ((_r & 0x4) << 3) | - ((_r & 0x8) << 4); - - /* writes _r, then reads back: */ - resp = ds1wm_read(ds1wm_data, _r); - - if (ds1wm_data->read_error) { - dev_err(&ds1wm_data->pdev->dev, - "pass: %d nibble: %d read error\n", pass, i); - break; - } - - _r_prime = ((resp & 0x02) >> 1) | - ((resp & 0x08) >> 2) | - ((resp & 0x20) >> 3) | - ((resp & 0x80) >> 4); - - _d = ((resp & 0x01) >> 0) | - ((resp & 0x04) >> 1) | - ((resp & 0x10) >> 2) | - ((resp & 0x40) >> 3); - - r_prime |= (unsigned long long) _r_prime << (i * 4); - d |= (unsigned long long) _d << (i * 4); - - } - if (ds1wm_data->read_error) { - mutex_unlock(&master_dev->bus_mutex); - dev_err(&ds1wm_data->pdev->dev, - "pass: %d read error, retrying\n", pass); - break; - } - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d r\': %0#18llx d:%0#18llx\n", - pass, r_prime, d); - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d nibble loop complete, exiting ASM\n", pass); - ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA); - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d resetting bus\n", pass); - ds1wm_reset(ds1wm_data); - mutex_unlock(&master_dev->bus_mutex); - if ((r_prime & ((u64)1 << 63)) && (d & ((u64)1 << 63))) { - dev_err(&ds1wm_data->pdev->dev, - "pass: %d bus error, retrying\n", pass); - continue; /* start over */ - } - - - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d found %0#18llx\n", pass, r_prime); - slave_found(master_dev, r_prime); - ++slaves_found; - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d complete, preparing next pass\n", pass); - - /* any discrepency found which we already choose the - '1' branch is now is now irrelevant we reveal the - next branch with this: */ - d &= ~r; - /* find last bit set, i.e. the most signif. bit set */ - ms_discrep_bit = fls64(d) - 1; - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d new d:%0#18llx MS discrep bit:%d\n", - pass, d, ms_discrep_bit); - - /* prev_ms_discrep_bit = ms_discrep_bit; - prepare for next ROM search: */ - if (ms_discrep_bit == -1) - break; - - r = (r & ~(~0ull << (ms_discrep_bit))) | 1 << ms_discrep_bit; - } /* end while true */ - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d total: %d search done ms d bit pos: %d\n", pass, - slaves_found, ms_discrep_bit); -} - -/* --------------------------------------------------------------------- */ - -static struct w1_bus_master ds1wm_master = { - .read_byte = ds1wm_read_byte, - .write_byte = ds1wm_write_byte, - .reset_bus = ds1wm_reset_bus, - .search = ds1wm_search, -}; - -static int ds1wm_probe(struct platform_device *pdev) -{ - struct ds1wm_data *ds1wm_data; - struct ds1wm_driver_data *plat; - struct resource *res; - int ret; - u8 inten; - - if (!pdev) - return -ENODEV; - - ds1wm_data = devm_kzalloc(&pdev->dev, sizeof(*ds1wm_data), GFP_KERNEL); - if (!ds1wm_data) - return -ENOMEM; - - platform_set_drvdata(pdev, ds1wm_data); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; - ds1wm_data->map = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!ds1wm_data->map) - return -ENOMEM; - - ds1wm_data->pdev = pdev; - ds1wm_data->cell = mfd_get_cell(pdev); - if (!ds1wm_data->cell) - return -ENODEV; - plat = dev_get_platdata(&pdev->dev); - if (!plat) - return -ENODEV; - - /* how many bits to shift register number to get register offset */ - if (plat->bus_shift > 2) { - dev_err(&ds1wm_data->pdev->dev, - "illegal bus shift %d, not written", - ds1wm_data->bus_shift); - return -EINVAL; - } - - ds1wm_data->bus_shift = plat->bus_shift; - /* make sure resource has space for 8 registers */ - if ((8 << ds1wm_data->bus_shift) > resource_size(res)) { - dev_err(&ds1wm_data->pdev->dev, - "memory resource size %d to small, should be %d\n", - (int)resource_size(res), - 8 << ds1wm_data->bus_shift); - return -EINVAL; - } - - ds1wm_data->is_hw_big_endian = plat->is_hw_big_endian; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) - return -ENXIO; - ds1wm_data->irq = res->start; - ds1wm_data->int_en_reg_none = (plat->active_high ? DS1WM_INTEN_IAS : 0); - ds1wm_data->reset_recover_delay = plat->reset_recover_delay; - - /* Mask interrupts, set IAS before claiming interrupt */ - inten = ds1wm_read_register(ds1wm_data, DS1WM_INT_EN); - ds1wm_write_register(ds1wm_data, - DS1WM_INT_EN, ds1wm_data->int_en_reg_none); - - if (res->flags & IORESOURCE_IRQ_HIGHEDGE) - irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING); - if (res->flags & IORESOURCE_IRQ_LOWEDGE) - irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING); - if (res->flags & IORESOURCE_IRQ_HIGHLEVEL) - irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_LEVEL_HIGH); - if (res->flags & IORESOURCE_IRQ_LOWLEVEL) - irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_LEVEL_LOW); - - ret = devm_request_irq(&pdev->dev, ds1wm_data->irq, ds1wm_isr, - IRQF_SHARED, "ds1wm", ds1wm_data); - if (ret) { - dev_err(&ds1wm_data->pdev->dev, - "devm_request_irq %d failed with errno %d\n", - ds1wm_data->irq, - ret); - - return ret; - } - - ds1wm_up(ds1wm_data); - - ds1wm_master.data = (void *)ds1wm_data; - - ret = w1_add_master_device(&ds1wm_master); - if (ret) - goto err; - - dev_dbg(&ds1wm_data->pdev->dev, - "ds1wm: probe successful, IAS: %d, rec.delay: %d, clockrate: %d, bus-shift: %d, is Hw Big Endian: %d\n", - plat->active_high, - plat->reset_recover_delay, - plat->clock_rate, - ds1wm_data->bus_shift, - ds1wm_data->is_hw_big_endian); - return 0; - -err: - ds1wm_down(ds1wm_data); - - return ret; -} - -#ifdef CONFIG_PM -static int ds1wm_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev); - - ds1wm_down(ds1wm_data); - - return 0; -} - -static int ds1wm_resume(struct platform_device *pdev) -{ - struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev); - - ds1wm_up(ds1wm_data); - - return 0; -} -#else -#define ds1wm_suspend NULL -#define ds1wm_resume NULL -#endif - -static int ds1wm_remove(struct platform_device *pdev) -{ - struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev); - - w1_remove_master_device(&ds1wm_master); - ds1wm_down(ds1wm_data); - - return 0; -} - -static struct platform_driver ds1wm_driver = { - .driver = { - .name = "ds1wm", - }, - .probe = ds1wm_probe, - .remove = ds1wm_remove, - .suspend = ds1wm_suspend, - .resume = ds1wm_resume -}; - -static int __init ds1wm_init(void) -{ - pr_info("DS1WM w1 busmaster driver - (c) 2004 Szabolcs Gyurko\n"); - return platform_driver_register(&ds1wm_driver); -} - -static void __exit ds1wm_exit(void) -{ - platform_driver_unregister(&ds1wm_driver); -} - -module_init(ds1wm_init); -module_exit(ds1wm_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, " - "Matt Reimer <mreimer@vpop.net>," - "Jean-Francois Dagenais <dagenaisj@sonatest.com>"); -MODULE_DESCRIPTION("DS1WM w1 busmaster driver"); diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index f2ae2e563dc5..4a2ddf730a3a 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -1166,6 +1166,8 @@ int w1_process(void *data) /* remainder if it woke up early */ unsigned long jremain = 0; + atomic_inc(&dev->refcnt); + for (;;) { if (!jremain && dev->search_count) { @@ -1193,8 +1195,10 @@ int w1_process(void *data) */ mutex_unlock(&dev->list_mutex); - if (kthread_should_stop()) + if (kthread_should_stop()) { + __set_current_state(TASK_RUNNING); break; + } /* Only sleep when the search is active. */ if (dev->search_count) { diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index b3e1792d9c49..3a71c5eb2f83 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c @@ -51,10 +51,9 @@ static struct w1_master *w1_alloc_dev(u32 id, int slave_count, int slave_ttl, dev->search_count = w1_search_count; dev->enable_pullup = w1_enable_pullup; - /* 1 for w1_process to decrement - * 1 for __w1_remove_master_device to decrement + /* For __w1_remove_master_device to decrement */ - atomic_set(&dev->refcnt, 2); + atomic_set(&dev->refcnt, 1); INIT_LIST_HEAD(&dev->slist); INIT_LIST_HEAD(&dev->async_list); diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 0bc40b763b06..5de74686f12b 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -491,14 +491,13 @@ config IXP4XX_WATCHDOG Say N if you are unsure. config S3C2410_WATCHDOG - tristate "S3C2410 Watchdog" - depends on ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS || \ - COMPILE_TEST + tristate "S3C6410/S5Pv210/Exynos Watchdog" + depends on ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST select WATCHDOG_CORE select MFD_SYSCON if ARCH_EXYNOS help - Watchdog timer block in the Samsung S3C24xx, S3C64xx, S5Pv210 and - Exynos SoCs. This will reboot the system when the timer expires with + Watchdog timer block in the Samsung S3C64xx, S5Pv210 and Exynos + SoCs. This will reboot the system when the timer expires with the watchdog enabled. The driver is limited by the speed of the system's PCLK diff --git a/drivers/watchdog/diag288_wdt.c b/drivers/watchdog/diag288_wdt.c index 4cb10877017c..6ca5d9515d85 100644 --- a/drivers/watchdog/diag288_wdt.c +++ b/drivers/watchdog/diag288_wdt.c @@ -86,7 +86,7 @@ static int __diag288(unsigned int func, unsigned int timeout, "1:\n" EX_TABLE(0b, 1b) : "+d" (err) : "d"(__func), "d"(__timeout), - "d"(__action), "d"(__len) : "1", "cc"); + "d"(__action), "d"(__len) : "1", "cc", "memory"); return err; } @@ -268,12 +268,21 @@ static int __init diag288_init(void) char ebc_begin[] = { 194, 197, 199, 201, 213 }; + char *ebc_cmd; watchdog_set_nowayout(&wdt_dev, nowayout_info); if (MACHINE_IS_VM) { - if (__diag288_vm(WDT_FUNC_INIT, 15, - ebc_begin, sizeof(ebc_begin)) != 0) { + ebc_cmd = kmalloc(sizeof(ebc_begin), GFP_KERNEL); + if (!ebc_cmd) { + pr_err("The watchdog cannot be initialized\n"); + return -ENOMEM; + } + memcpy(ebc_cmd, ebc_begin, sizeof(ebc_begin)); + ret = __diag288_vm(WDT_FUNC_INIT, 15, + ebc_cmd, sizeof(ebc_begin)); + kfree(ebc_cmd); + if (ret != 0) { pr_err("The watchdog cannot be initialized\n"); return -EINVAL; } diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index d3fc8ed886ff..200ba236a72e 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -562,73 +562,6 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param) return IRQ_HANDLED; } -#ifdef CONFIG_ARM_S3C24XX_CPUFREQ - -static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb, - unsigned long val, void *data) -{ - int ret; - struct s3c2410_wdt *wdt = freq_to_wdt(nb); - - if (!s3c2410wdt_is_running(wdt)) - goto done; - - if (val == CPUFREQ_PRECHANGE) { - /* To ensure that over the change we don't cause the - * watchdog to trigger, we perform an keep-alive if - * the watchdog is running. - */ - - s3c2410wdt_keepalive(&wdt->wdt_device); - } else if (val == CPUFREQ_POSTCHANGE) { - s3c2410wdt_stop(&wdt->wdt_device); - - ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device, - wdt->wdt_device.timeout); - - if (ret >= 0) - s3c2410wdt_start(&wdt->wdt_device); - else - goto err; - } - -done: - return 0; - - err: - dev_err(wdt->dev, "cannot set new value for timeout %d\n", - wdt->wdt_device.timeout); - return ret; -} - -static inline int s3c2410wdt_cpufreq_register(struct s3c2410_wdt *wdt) -{ - wdt->freq_transition.notifier_call = s3c2410wdt_cpufreq_transition; - - return cpufreq_register_notifier(&wdt->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt) -{ - wdt->freq_transition.notifier_call = s3c2410wdt_cpufreq_transition; - - cpufreq_unregister_notifier(&wdt->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -#else - -static inline int s3c2410wdt_cpufreq_register(struct s3c2410_wdt *wdt) -{ - return 0; -} - -static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt) -{ -} -#endif - static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt) { unsigned int rst_stat; @@ -761,12 +694,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev) wdt->wdt_device.min_timeout = 1; wdt->wdt_device.max_timeout = s3c2410wdt_max_timeout(wdt); - ret = s3c2410wdt_cpufreq_register(wdt); - if (ret < 0) { - dev_err(dev, "failed to register cpufreq\n"); - goto err_src_clk; - } - watchdog_set_drvdata(&wdt->wdt_device, wdt); /* see if we can actually set the requested timer margin, and if @@ -783,7 +710,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) S3C2410_WATCHDOG_DEFAULT_TIME); } else { dev_err(dev, "failed to use default timeout\n"); - goto err_cpufreq; + goto err_src_clk; } } @@ -791,7 +718,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) pdev->name, pdev); if (ret != 0) { dev_err(dev, "failed to install irq (%d)\n", ret); - goto err_cpufreq; + goto err_src_clk; } watchdog_set_nowayout(&wdt->wdt_device, nowayout); @@ -817,7 +744,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) ret = watchdog_register_device(&wdt->wdt_device); if (ret) - goto err_cpufreq; + goto err_src_clk; ret = s3c2410wdt_enable(wdt, true); if (ret < 0) @@ -839,9 +766,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev) err_unregister: watchdog_unregister_device(&wdt->wdt_device); - err_cpufreq: - s3c2410wdt_cpufreq_deregister(wdt); - err_src_clk: clk_disable_unprepare(wdt->src_clk); @@ -862,8 +786,6 @@ static int s3c2410wdt_remove(struct platform_device *dev) watchdog_unregister_device(&wdt->wdt_device); - s3c2410wdt_cpufreq_deregister(wdt); - clk_disable_unprepare(wdt->src_clk); clk_disable_unprepare(wdt->bus_clk); diff --git a/drivers/watchdog/wdt285.c b/drivers/watchdog/wdt285.c index 110249e5f642..5b7be7a62d54 100644 --- a/drivers/watchdog/wdt285.c +++ b/drivers/watchdog/wdt285.c @@ -206,8 +206,6 @@ static int __init footbridge_watchdog_init(void) pr_info("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n", soft_margin); - if (machine_is_cats()) - pr_warn("Warning: Watchdog reset may not work on this machine\n"); return 0; } diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c index 28b2a1fa25ab..0d4f8f4f4948 100644 --- a/drivers/xen/pvcalls-back.c +++ b/drivers/xen/pvcalls-back.c @@ -1181,9 +1181,8 @@ static void pvcalls_back_changed(struct xenbus_device *dev, } } -static int pvcalls_back_remove(struct xenbus_device *dev) +static void pvcalls_back_remove(struct xenbus_device *dev) { - return 0; } static int pvcalls_back_uevent(struct xenbus_device *xdev, diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c index 1826e8e67125..d5d589bda243 100644 --- a/drivers/xen/pvcalls-front.c +++ b/drivers/xen/pvcalls-front.c @@ -225,6 +225,8 @@ again: return IRQ_HANDLED; } +static void free_active_ring(struct sock_mapping *map); + static void pvcalls_front_free_map(struct pvcalls_bedata *bedata, struct sock_mapping *map) { @@ -240,7 +242,7 @@ static void pvcalls_front_free_map(struct pvcalls_bedata *bedata, for (i = 0; i < (1 << PVCALLS_RING_ORDER); i++) gnttab_end_foreign_access(map->active.ring->ref[i], NULL); gnttab_end_foreign_access(map->active.ref, NULL); - free_page((unsigned long)map->active.ring); + free_active_ring(map); kfree(map); } @@ -1085,7 +1087,7 @@ static const struct xenbus_device_id pvcalls_front_ids[] = { { "" } }; -static int pvcalls_front_remove(struct xenbus_device *dev) +static void pvcalls_front_remove(struct xenbus_device *dev) { struct pvcalls_bedata *bedata; struct sock_mapping *map = NULL, *n; @@ -1121,7 +1123,6 @@ static int pvcalls_front_remove(struct xenbus_device *dev) kfree(bedata->ring.sring); kfree(bedata); xenbus_switch_state(dev, XenbusStateClosed); - return 0; } static int pvcalls_front_probe(struct xenbus_device *dev, diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c index d171091eec12..b11e401f1b1e 100644 --- a/drivers/xen/xen-pciback/xenbus.c +++ b/drivers/xen/xen-pciback/xenbus.c @@ -716,14 +716,12 @@ out: return err; } -static int xen_pcibk_xenbus_remove(struct xenbus_device *dev) +static void xen_pcibk_xenbus_remove(struct xenbus_device *dev) { struct xen_pcibk_device *pdev = dev_get_drvdata(&dev->dev); if (pdev != NULL) free_pdev(pdev); - - return 0; } static const struct xenbus_device_id xen_pcibk_ids[] = { diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 6106ed93817d..954188b0b858 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1249,7 +1249,7 @@ static void scsiback_release_translation_entry(struct vscsibk_info *info) spin_unlock_irqrestore(&info->v2p_lock, flags); } -static int scsiback_remove(struct xenbus_device *dev) +static void scsiback_remove(struct xenbus_device *dev) { struct vscsibk_info *info = dev_get_drvdata(&dev->dev); @@ -1261,8 +1261,6 @@ static int scsiback_remove(struct xenbus_device *dev) gnttab_page_cache_shrink(&info->free_pages, 0); dev_set_drvdata(&dev->dev, NULL); - - return 0; } static int scsiback_probe(struct xenbus_device *dev, |